@@ -636,18 +636,31 @@ def default_params():
636636
637637class LlamaBatch :
638638 def __init__ (
639- self , * , n_tokens : int , embd : int , n_seq_max : int , verbose : bool = True
639+ self ,
640+ * ,
641+ n_tokens : int ,
642+ embd : int ,
643+ n_seq_max : int ,
644+ verbose : bool = True
640645 ):
641- self ._n_tokens = n_tokens
646+ # logical validity of parameters
647+ if n_tokens <= 0 :
648+ raise ValueError (f"n_tokens must be positive, got { n_tokens } " )
649+ if n_seq_max <= 0 :
650+ raise ValueError (f"n_seq_max must be positive, got { n_seq_max } " )
651+
652+ self .n_tokens_capacity = n_tokens
642653 self .embd = embd
643654 self .n_seq_max = n_seq_max
644655 self .verbose = verbose
645656 self ._exit_stack = ExitStack ()
646657
647- batch = llama_cpp .llama_batch_init (self ._n_tokens , self .embd , self .n_seq_max )
658+ batch = llama_cpp .llama_batch_init (self .n_tokens_capacity , self .embd , self .n_seq_max )
648659
649660 if batch is None :
650- raise ValueError ("Failed to create llama_batch" )
661+ raise MemoryError (
662+ f"Failed to allocate memory for llama_batch via llama_batch_init({ n_tokens } ,{ embd } ,{ n_seq_max } )"
663+ )
651664
652665 self .batch = batch
653666
@@ -660,18 +673,51 @@ def free_batch():
660673 self ._exit_stack .callback (free_batch )
661674
662675 def close (self ):
676+ """Manually free resources."""
663677 self ._exit_stack .close ()
664678
665679 def __del__ (self ):
666680 self .close ()
667681
668682 def n_tokens (self ) -> int :
683+ """
684+ Current number of tokens stored in the batch.
685+ """
686+ if self .batch is None : return 0
669687 return self .batch .n_tokens
670688
689+ def capacity (self ) -> int :
690+ """
691+ Total capacity of the batch.
692+ """
693+ return self .n_tokens_capacity
694+
695+ def space_left (self ) -> int :
696+ """
697+ Returns the number of empty slots remaining in the batch.
698+ Throws a RuntimeError if internal state implies an overflow.
699+ """
700+ if self .batch is None : return 0
701+ elif self .n_tokens_capacity >= self .batch .n_tokens :
702+ return self .n_tokens_capacity - self .batch .n_tokens
703+ else :
704+ raise RuntimeError (
705+ f"LlamaBatch Critical Error: n_tokens ({ self .batch .n_tokens } ) exceeds capacity ({ self .n_tokens_capacity } ). "
706+ "This implies a buffer overflow or corrupted internal state."
707+ )
708+
671709 def reset (self ):
672- self .batch .n_tokens = 0
710+ """
711+ Resets the batch counter to 0. Does not free memory, just resets the index.
712+ Call this before starting a new decoding step.
713+ """
714+ if self .batch is not None :
715+ self .batch .n_tokens = 0
673716
674717 def set_batch (self , batch : Sequence [int ], n_past : llama_cpp .llama_pos , logits_all : bool ):
718+ if len (batch ) > self .n_tokens_capacity :
719+ raise IndexError (f"Input batch size { len (batch )} exceeds capacity { self .n_tokens_capacity } " )
720+
675721 n_tokens = len (batch )
676722 self .batch .n_tokens = n_tokens
677723 for i in range (n_tokens ):
@@ -684,16 +730,21 @@ def set_batch(self, batch: Sequence[int], n_past: llama_cpp.llama_pos, logits_al
684730
685731 def add_sequence (self , batch : Sequence [int ], seq_id : int , logits_all : bool ):
686732 n_tokens = len (batch )
687- n_tokens0 = self .batch .n_tokens
733+ current_count = self .batch .n_tokens
734+ if current_count + n_tokens > self .n_tokens_capacity :
735+ raise IndexError (
736+ f"LlamaBatch overflow: Cannot add { n_tokens } tokens. "
737+ f"Space left: { self .n_tokens_capacity - current_count } "
738+ )
688739 self .batch .n_tokens += n_tokens
689740 for i in range (n_tokens ):
690- j = n_tokens0 + i
741+ j = current_count + i
691742 self .batch .token [j ] = batch [i ]
692743 self .batch .pos [j ] = i
693744 self .batch .seq_id [j ][0 ] = seq_id
694745 self .batch .n_seq_id [j ] = 1
695746 self .batch .logits [j ] = logits_all
696- self .batch .logits [n_tokens - 1 ] = True
747+ self .batch .logits [current_count + n_tokens - 1 ] = True
697748
698749
699750class LlamaTokenDataArray :
0 commit comments