Collects the settings for one agent turn, obtained from AgentOrchestratorManager.newRun and run by calling execute. Not thread safe, and intended to be used once and discarded. Annotated because the script sandbox's class filter whitelists by class, not by what returned it - without this, script code could call newRun but not then use what it got back. Same reason AgentManager.AgentDefBuilder carries it.
Group: Builders
Methods
requiredTools(List<String> requiredTools) · persistAs(Long agentId, String conversationId) · resumingConsentOn(String chatItemId, String toolId) · approvedCall(String toolName, String argumentsJson, String callId) · instructions(String instructions) · userMessage(String userMessage) · history(List<Map<String,Object>> history) · budgetBoost(Integer budgetBoost) · reasoningEffort(String reasoningEffort) · modelTier(String modelTier) · functions(List<String> functions) · sourceApp(String sourceApp) · profileId(String profileId) · execute()
requiredTools(List<String> requiredTools)
Returns: RunBuilder
Names tools this turn is not finished without, so Verify can send the run back to Plan if the model claimed the work without doing it. This is where FunctionCallAgentWorkflowStepCompletionType - "did function X get called" - maps onto the phase model. Left unset for open-ended chat, where there is no such thing as a required call.
| Parameter | Description |
|---|---|
requiredTools | tool names as the model would call them, or null for none |
persistAs(Long agentId, String conversationId)
Returns: RunBuilder
Records this turn against a persisted AgentRun, so the run has a durable identity beyond the request that started it. Optional: without it the loop still runs, just with no row - which is what the orchestrator's own unit tests do, and what a caller that has nothing to resume can keep doing. With it, a run that pauses for consent can be picked up later from any node.
| Parameter | Description |
|---|---|
agentId | the {@code Agent} this run acts for |
conversationId | the ai-lib conversation this turn belongs to, so a resume can find its way back to the transcript |
resumingConsentOn(String chatItemId, String toolId)
Returns: RunBuilder
Marks this turn as continuing the run that paused on a given consent request, rather than starting a new one. The in-page confirm button posts the chat item and tool id, not a token, so the run is found from those. Getting this wrong is not cosmetic: the paused row would never settle, and the expiry sweep would later close a request the owner had actually approved. Falls back to a fresh run if nothing matches - a conversation that paused before runs were persisted still has to be approvable.
| Parameter | Description |
|---|---|
chatItemId | the chat item carrying the consent block |
toolId | the model's call id for the gated call |
approvedCall(String toolName, String argumentsJson, String callId)
Returns: RunBuilder
Resumes a run the owner paused by approving a consent-gated call. The approved call runs first and exactly as approved - no fresh planning turn - so what executes is what the owner was shown. Establishing that the approval is genuine, and that it has not already been used, is the caller's job: by the time it reaches here it is taken as given.
| Parameter | Description |
|---|---|
toolName | the tool that was approved, as the model originally named it |
argumentsJson | the exact arguments it was approved to run with |
callId | the model's original call id, so the replayed call pairs with its result |
instructions(String instructions)
Returns: RunBuilder
Sets the system prompt for this turn.
| Parameter | Description |
|---|---|
instructions | the assembled system prompt for this agent |
userMessage(String userMessage)
Returns: RunBuilder
Sets this turn's user prompt.
| Parameter | Description |
|---|---|
userMessage | the prompt for this turn, or null if the instructions are self-contained |
history(List<Map<String,Object>> history)
Returns: RunBuilder
Seeds the prior turns of the conversation, so the model has memory of what came before this one.
| Parameter | Description |
|---|---|
history | the conversation so far as Responses API input items, as ai-lib's {@code ConversationContext} assembles them, or null for a run with no memory. These are sent to the model but are not echoed back in the result, so the caller does not re-persist them |
budgetBoost(Integer budgetBoost)
Returns: RunBuilder
Multiplies this run's ceilings, for work nobody is waiting on. The standard budget is sized for an interactive turn. A run started by an event handler is not one: it runs unattended and is often asked a question that takes real digging. See {@link AgentBudget.Builder#budgetBoost} for why the spawn count is deliberately left alone.
| Parameter | Description |
|---|---|
budgetBoost | the multiple, clamped to 1..{@link AgentBudget#MAX_BUDGET_BOOST}, or null for the standard budget |
reasoningEffort(String reasoningEffort)
Returns: RunBuilder
How hard this run should think, overriding what the definitions involved ask for. Effort is normally a per-phase property of a definition, tuned for what that phase usually does - Act, in particular, defaults to {@code low} because it is mostly deciding which tool to call next. That reasoning does not hold for every kind of work: in an investigation, deciding what to look at next <i>given what just came back</i> is the analysis, not a mechanical step. This is how a caller says which kind of run this is. Applies to every phase, and is passed down to any specialist this run delegates to - the specialist is where the work happens, so an override that stopped at the root would change nothing that matters.
| Parameter | Description |
|---|---|
reasoningEffort | an effort such as {@code high}, or null to leave each definition to its own settings |
modelTier(String modelTier)
Returns: RunBuilder
Runs this turn on a given class of model, whatever the definitions involved ask for. For when something about the turn rather than about the agent decides what it is worth spending - an event handler whose job is forensics rather than a lookup. It applies to the specialists too: they are where the work happens, so an override that stopped at the root would change little.
| Parameter | Description |
|---|---|
modelTier | a tier name such as {@code deep}, or null to let each definition choose |
functions(List<String> functions)
Returns: RunBuilder
Restricts which tools this turn may call.
| Parameter | Description |
|---|---|
functions | the agent's tool whitelist ({@code AgentDef.functions}), or null for no whitelist |
sourceApp(String sourceApp)
Returns: RunBuilder
Names the app this turn runs on behalf of, so it can be reported on the Before/AfterPromptFunctionCall events.
| Parameter | Description |
|---|---|
sourceApp | app name, for the Before/AfterPromptFunctionCall events |
profileId(String profileId)
Returns: RunBuilder
Names the profile acting for this turn, so it can be reported on the Before/AfterPromptFunctionCall events.
| Parameter | Description |
|---|---|
profileId | the acting profile id, for those same events |
execute()
Returns: Map<String,Object>
Runs one agent turn through the gather/plan/act/verify loop. All four phases do real work now. Gather loads the agent's knowledge assets, Plan states an approach when the definition allows it and the task is not trivial, Act carries it out, and Verify checks the result against both the required tools and the stated plan. An agent that configures neither knowledge nor planning still behaves as the legacy loop does, because both phases then skip.