-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Update close tool + add output to agent result #1505
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
🦋 Changeset detectedLatest commit: dfb703a The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No issues found across 8 files
Greptile Summary
Important Files Changed
Confidence score: 4/5
Sequence DiagramsequenceDiagram
participant User
participant AgentHandler as V3AgentHandler
participant LLMClient
participant CloseHandler as handleCloseToolCall
participant Model as LanguageModel
User->>AgentHandler: "execute(instruction, options)"
AgentHandler->>AgentHandler: "prepareAgent()"
AgentHandler->>LLMClient: "generateText(systemPrompt, messages, tools)"
loop Agent Steps (up to maxSteps)
LLMClient->>Model: "Generate next step"
Model-->>LLMClient: "Tool calls + reasoning"
LLMClient->>AgentHandler: "onStepFinish(toolCalls, results)"
AgentHandler->>AgentHandler: "Process tool results and update state"
alt Tool call is "close"
AgentHandler->>AgentHandler: "Mark state.completed = true"
end
end
LLMClient-->>AgentHandler: "Generation result"
alt state.completed == false
Note over AgentHandler,CloseHandler: Force close tool call
AgentHandler->>CloseHandler: "handleCloseToolCall(model, messages, instruction, outputSchema)"
CloseHandler->>Model: "generateText() with close tool only"
Model-->>CloseHandler: "Close tool call with reasoning + output"
CloseHandler-->>AgentHandler: "closeResult(reasoning, taskComplete, output)"
AgentHandler->>AgentHandler: "Update state with close result"
end
AgentHandler->>AgentHandler: "consolidateMetricsAndResult()"
AgentHandler-->>User: "AgentResult(success, message, actions, output)"
|
| { name: "wait", description: "Wait for a specified time" }, | ||
| { name: "navback", description: "Navigate back in browser history" }, | ||
| { name: "scroll", description: "Scroll the page x pixels up or down" }, | ||
| { name: "close", description: "Mark the task as complete or failed" }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| { name: "close", description: "Mark the task as complete or failed" }, | |
| { name: "close", description: "Mark the task as complete or failed" }, // TODO: consider renaming this tool to "done" |
| import { StagehandZodObject } from "../../zodCompat"; | ||
| interface CloseResult { | ||
| reasoning: string; | ||
| taskComplete: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think success: true | false may be better
Co-authored-by: Nick Sweeting <[email protected]>
| reasoning: string; | ||
| taskComplete: boolean; | ||
| messages: ModelMessage[]; | ||
| output?: Record<string, unknown>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I recommend making output required, LLMs are really good at inferring what the ideal output should be for a task.
e.g. if user is researching something often it nails it and puts the exact data they were looking for in output.
Why
Previously, agent executions could end without a structured final response - either by hitting
maxStepsor the LLM breaking out of its loop without calling theclosetool. This made it difficult to:What Changed
Ensured Close Tool is Always Called
handleCloseToolCallutility that forces aclosetool call via a separategenerateTextcall when the main agent loop ends without explicitly closingensureClosedprivate method inv3AgentHandler.tsexecute()andstream()modesmaxStepsis reached or the LLM stops ( completes its task)Added Output Schema Support (Experimental)
agent.execute({ output: z.object({...}) })to return structured data at the end of executionresult.outputStagehandInvalidArgumentError(not supported)experimental: true: ThrowsExperimentalNotConfiguredErrorExample Usage
Test Plan
maxStepsis reachedoutputschema extracts data correctly inexecute()modeoutputschema extracts data correctly instream()modeoutputthrowsStagehandInvalidArgumentErrorwhen used with CUA modeoutputthrowsExperimentalNotConfiguredErrorwhen used withoutexperimental: trueSummary by cubic
Ensures every agent run ends with a structured final response and adds optional structured output via a Zod schema. Improves reliability by always setting completion status and final reasoning.
Written for commit dfb703a. Summary will update on new commits.