TextGenerationLoop
class TextGenerationLoop
Traits
Constants
| private PRELIMINARY_OUTPUT_BYTES |
The minimum bytes a sub-agent must add before its unfinished output is reported again. |
| private REPAIR_TOOL_CALLS_CONTEXT_KEY |
|
| private TOOL_CONCURRENCY_CONTEXT_KEY |
|
| protected DEFAULT_MAX_STEPS |
The default ceiling for the derived step budget when it is not set explicitly. |
Methods
Get the unresolved tool calls in the latest assistant turn, plus the ids already answered.
Append a resume's tool results, merging into the pause turn's partial results so one assistant turn keeps one answering message.
Settle unresolved historical tool calls so the history remains replayable, optionally leaving the latest assistant turn for a resume to decide.
Find the index of the latest assistant message, or the message count when there is none.
Build pending approval requests for the given tool calls.
Get the milliseconds elapsed since the given monotonic nanosecond reading.
Execute the given tool with the given arguments.
Find a tool by its name from the given tools array.
Join reasoning blocks, separating each block with a blank line.
Generate a response through model and tool steps.
Stream a response through model and tool steps.
Get the runtime and declared middleware wrapping each generation step.
Each middleware receives a StepResult from $next, whether the inner layer streamed, short-circuited or replaced the step.
Normalize a middleware result to a step result.
Send the prepared step to the model, reporting its start and any synchronous failure.
A step that middleware answered itself was never attempted and reports nothing.
Report a failed generation attempt when one was made.
A continuation replays only unchanged history, model and instructions.
The stream events describing a step response that was produced without streaming.
Resolve the step budget: explicit maxSteps, else 1.5x tools capped at the ceiling, else 5.
Tool results to continue the loop with, plus any pending approvals that pause it.
The early outcome for steps that pause or execute nothing, or null when tools should run.
Get tool results while streaming sub-agent activity.
Report the output a still running tool has produced so far.
Execute a sub-agent tool, streaming its activity while reporting through the run context.
Run the executable tools and collect any pending approvals.
Execute the resolved tool call, or mark it as repaired or exhausted when it can no longer run.
Execute the tool for the given call, returning a failure to the model instead of ending the run.
Answer the recorded step with the result its tool just produced.
Create a tool result for the given tool call.
Split the step's tool calls into executable [ToolCall, Tool] pairs and pending approvals.
The names of the locally executable tools, as advertised back to a model that called an unknown one.
Apply the approval's decisions to the pending pause, returning the updated history and resume state.
Claim the pending calls and record each decision's outcome before executing the next.
Determine whether the history ends in a pause a real run could have left: every pending call is for a tool the agent still has, and at least one of them asks for approval.
Find the tool each pending call is for, keyed by the call's id.
Validate the approval's decisions against the pending tool calls, throwing on any mismatch.
Resolve the approval requirement for a tool call, or null when it is not gated.
Generate a unique stream event ID.
Build an assistant message from the given step response.
Build the response for a run that ended before any step completed.
Build the final text response from all generated steps.
Ensure at most one tool search wrapper is registered per request.
Drop provider tools the provider cannot run, unwrapping tool search into its deferred tools.
Details
in
HandlesToolApprovals at line 24
protected array
pendingToolCalls(array $messages)
Get the unresolved tool calls in the latest assistant turn, plus the ids already answered.
in
HandlesToolApprovals at line 57
protected array
appendApprovalResults(array $messages, array $toolResults)
Append a resume's tool results, merging into the pause turn's partial results so one assistant turn keeps one answering message.
in
HandlesToolApprovals at line 80
protected array
settleAbandonedToolCalls(array $messages, bool $exceptLatestAssistantTurn = false)
Settle unresolved historical tool calls so the history remains replayable, optionally leaving the latest assistant turn for a resume to decide.
in
HandlesToolApprovals at line 140
protected int
latestAssistantTurnIndex(array $messages)
Find the index of the latest assistant message, or the message count when there is none.
in
HandlesToolApprovals at line 158
protected Collection
pendingApprovalsFor(Collection $toolCalls, Collection $approvals)
Build pending approval requests for the given tool calls.
in
MeasuresDuration at line 12
protected float
elapsedMilliseconds(int $startedAt)
Get the milliseconds elapsed since the given monotonic nanosecond reading.
in
InvokesTools at line 28
protected string
executeTool(Tool $tool, array $arguments, string|null $toolCallId = null, RunContext|null $context = null)
Execute the given tool with the given arguments.
in
InvokesTools at line 63
protected Tool|null
findTool(string $name, array $tools)
Find a tool by its name from the given tools array.
in
JoinsReasoning at line 16
static protected string
joinReasoning(iterable $blocks)
Join reasoning blocks, separating each block with a blank line.
at line 107
__construct(StepTextGateway $gateway)
Create a new text generation loop instance.
at line 118
TextResponse
generate(TextProvider $provider, string $model, string|null $instructions, array $messages = [], array $tools = [], array|null $schema = null, TextGenerationOptions|null $options = null, int|null $timeout = null, array|null $approval = null, Closure|null $recordApprovalResults = null, RunContext|null $context = null)
Generate a response through model and tool steps.
at line 261
Generator
stream(string $invocationId, TextProvider $provider, string $model, string|null $instructions, array $messages = [], array $tools = [], array|null $schema = null, TextGenerationOptions|null $options = null, int|null $timeout = null, array|null $approval = null, Closure|null $recordApprovalResults = null, array|null $validatedApproval = null, RunContext|null $context = null)
Stream a response through model and tool steps.
at line 490
protected array
middlewareFor(TextGenerationOptions|null $options)
Get the runtime and declared middleware wrapping each generation step.
at line 511
protected StepResult
runStep(PendingStep $step, array $middleware, Closure $run)
Each middleware receives a StepResult from $next, whether the inner layer streamed, short-circuited or replaced the step.
at line 527
protected StepResult
toStepResult(mixed $result)
Normalize a middleware result to a step result.
at line 542
protected StepResult
attempt(PendingStep $step, PendingStep|null $previous, array $history, string|null $continuationToken, RunContext|null $context, Closure $call)
Send the prepared step to the model, reporting its start and any synchronous failure.
at line 567
protected void
stepCompleted(RunContext|null $context, StepResult|null $attempt, StepResponse $response)
A step that middleware answered itself was never attempted and reports nothing.
at line 577
protected void
stepFailed(RunContext|null $context, StepResult|null $attempt, Throwable $exception)
Report a failed generation attempt when one was made.
at line 589
protected StepContext
stepContextFor(PendingStep $step, PendingStep|null $previous, array $history, string|null $continuationToken)
A continuation replays only unchanged history, model and instructions.
at line 605
protected Generator
eventsFor(string $invocationId, TextProvider $provider, string $model, StepResponse $response)
The stream events describing a step response that was produced without streaming.
at line 639
protected int
resolveMaxSteps(TextGenerationOptions|null $options, array $tools)
Resolve the step budget: explicit maxSteps, else 1.5x tools capped at the ceiling, else 5.
at line 717
protected array
stepToolResults(StepResponse $result, bool $isFinalStep, array $tools, RunContext|null $context = null)
Tool results to continue the loop with, plus any pending approvals that pause it.
at line 728
protected array|null
earlyStepToolResults(StepResponse $result)
The early outcome for steps that pause or execute nothing, or null when tools should run.
at line 747
protected Generator
streamedStepToolResults(StepResponse $result, bool $isFinalStep, array $tools, string $invocationId, TextGenerationOptions|null $options = null, RunContext|null $context = null)
Get tool results while streaming sub-agent activity.
at line 805
protected Generator
preliminaryToolResults(Generator $events, ToolCall $toolCall, string $invocationId)
Report the output a still running tool has produced so far.
at line 851
protected Generator
executeAgentToolStreaming(AgentTool $tool, array $arguments, string|null $toolCallId = null, RunContext|null $context = null)
Execute a sub-agent tool, streaming its activity while reporting through the run context.
at line 894
protected array
approvalAwareToolResults(array $toolCalls, array $tools, bool $isFinalStep = false, RunContext|null $context = null)
Run the executable tools and collect any pending approvals.
at line 1015
protected ToolResult
resolvedToolResult(ToolCall $toolCall, Tool|null $tool, bool $isFinalStep, array $tools = [], RunContext|null $context = null)
Execute the resolved tool call, or mark it as repaired or exhausted when it can no longer run.
at line 1027
protected ToolResult
executedToolResult(ToolCall $toolCall, Tool $tool, RunContext|null $context = null)
Execute the tool for the given call, returning a failure to the model instead of ending the run.
at line 1041
protected string
failedToolResultText(Throwable $exception)
Get the result the model receives for a tool that threw.
at line 1053
protected ToolResult
recordedToolResult(ToolResult $result, RunContext|null $context)
Answer the recorded step with the result its tool just produced.
at line 1063
protected ToolResult
toolResult(ToolCall $toolCall, mixed $result, bool $failed = false)
Create a tool result for the given tool call.
at line 1082
protected array
resolveToolCalls(array $toolCalls, array $tools, bool $isFinalStep)
Split the step's tool calls into executable [ToolCall, Tool] pairs and pending approvals.
at line 1118
protected string
availableToolNames(array $tools)
The names of the locally executable tools, as advertised back to a model that called an unknown one.
at line 1134
protected ApprovalResumption
resumeFromApproval(array $approval, array $messages, array $tools, array|null $validatedApproval = null, RunContext|null $context = null)
Apply the approval's decisions to the pending pause, returning the updated history and resume state.
at line 1163
protected array
resolveApprovalResults(array $approval, array $messages, array $tools, array|null $validatedApproval = null, RunContext|null $context = null)
Claim the pending calls and record each decision's outcome before executing the next.
at line 1236
bool
pausedForApproval(array $messages, array $tools)
Determine whether the history ends in a pause a real run could have left: every pending call is for a tool the agent still has, and at least one of them asks for approval.
at line 1253
protected Collection
toolsForPendingCalls(Collection $pendingToolCalls, array $tools)
Find the tool each pending call is for, keyed by the call's id.
at line 1268
array
validateApproval(array $approval, array $messages, array $tools)
Validate the approval's decisions against the pending tool calls, throwing on any mismatch.
at line 1312
protected Approval|null
approvalForTool(Tool|null $tool, ToolCall $toolCall)
Resolve the approval requirement for a tool call, or null when it is not gated.
at line 1322
protected string
generateEventId()
Generate a unique stream event ID.
at line 1330
protected AssistantMessage
buildAssistantMessage(StepResponse $result)
Build an assistant message from the given step response.
at line 1342
protected Step
buildStep(StepResponse $result)
Build the recorded step from its provider response.
at line 1362
protected TextResponse
emptyResponse(TextProvider $provider, string $model, array $newMessages)
Build the response for a run that ended before any step completed.
at line 1371
protected TextResponse
buildFinalResponse(Collection $steps, array $newMessages, StepResponse|null $lastResult)
Build the final text response from all generated steps.
at line 1413
protected void
ensureSingleToolSearch(array $tools)
Ensure at most one tool search wrapper is registered per request.
at line 1426
protected array
toolsSupportedBy(TextProvider $provider, array $tools)
Drop provider tools the provider cannot run, unwrapping tool search into its deferred tools.