Repository navigation
Add MaximumFunctionCallsPerRequest to toolautocall (#1202) - #1331
Lokesh Nelapati (Lokesh118) wants to merge 1 commit into
Conversation
This comment has been minimized.
This comment has been minimized.
ffb3fcd to
29f7445
Compare
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
🟡 Changes recommended
Tool-call budget enforcement can incorrectly block retries, allow approved calls beyond the limit, and leave an invalid forced tool choice when schema tools are removed.
4 open issues
What changed in this PR
Adds a configurable tool-call budget to toolautocall, complementing its existing iteration limit and addressing the cost-control use case in #1202.
Changes:
- Adds
MaximumFunctionCallsPerRequest, with negative-value validation, an unlimited default, and zero-budget handling. - Tracks calls across tool rounds, including failures and approved calls, and removes schema tools once the budget is reached while allowing active batches to finish.
- Adds tests for limits, batch overshoot, failed executions, provider-handled calls, and approval resumption.
| File | Description |
|---|---|
agent/harness/toolautocall/autocall.go |
Adds configuration, call accounting, and budget-based loop termination. |
agent/harness/toolautocall/autocall_test.go |
Tests validation, budget boundaries, batch completion, and execution accounting. |
agent/harness/toolautocall/autocall_approval_test.go |
Tests counting approved calls toward the budget. |
Review effort: Max
|
@microsoft-github-policy-service agree |
29f7445 to
f6f93ad
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
4d1b78d to
91c3ca5
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
|
||
| // RunToken returns an opaque unique identity for the current agent run, | ||
| // or nil if the context was not created by an agent run. | ||
| func RunToken(ctx context.Context) any { |
There was a problem hiding this comment.
Don't like passing params around in the context, unless the value they provide is high. I don't think this meets the bar. Any alternative design?
There was a problem hiding this comment.
Thanks for the feedback! Updated the design.
I have completely reverted the changes to agent/agent.go to match upstream/main, eliminating RunToken and context injection altogether.
Instead, toolautocall now manages the budget lifecycle strictly through agent.Session, aligning with the existing conventions in toolapproval, filememory, and todo:
- Approval Resumption & Re-entries: When incoming messages contain approval content (
hasAnyApprovalContent(messages) == true)—whether from human approval across turns or an auto-approval loop intoolapproval—toolautocallcontinues from the session's recorded consumed count. - Independent Runs: A new user prompt (
hasAnyApprovalContent(messages) == false) resets any leftover state in the session and starts with a fresh budget of0. - Cleanup: At the end of a run, if no pending approval requests were produced, a
defercleans up the state from the session.
Please let me know your thoughts on the updated design, thanks!
1b3edd2 to
4d2bb3d
Compare
API consistency review
Changed Go contractNew exported field Upstream evidence reviewedNo equivalent found. Upstream evidence was not retrievable: code search was rate-limited (HTTP 429), and the file-read payload for Python AssessmentThe PR claims parity with Python
|

Description
Adds
MaximumFunctionCallsPerRequesttotoolautocall.Configto allow callers to cap the total cumulative number of tool invocations performed in a single run (addressing #1202 and achieving parity with Python'smax_function_calls).Summary of Changes
Configuration:
MaximumFunctionCallsPerRequest *inttotoolautocall.Config.MaximumFunctionCallsPerRequest must be 0 or greater).nilpreserves the default unlimited behavior.0disables automatic function calls while allowing the model to return a final response without schema tools.Accounting, Batch Handling & Review Follow-ups:
totalFunctionCalls) across iterations.functionInvocationStatusNotFound(unknown tools) from execution attempts so models can retry real tools whenTerminateOnUnknownCalls=false.FunctionResultContentin streamed updates and are not locally executed).prepareOptionsForLastIterationwhen its associated schema tool is stripped even if non-schema tools remain.toolapprovalmiddleware re-entries within the sameagent.Runvia run-scoped session tracking, and resets cleanly for independent runs.Tests:
TestFunctionInvoking_NegativeMaximumFunctionCallsReturnsErrorTestFunctionInvoking_ZeroMaximumFunctionCallsDisablesAutomaticCallsAndReturnsFinalResponseTestFunctionInvoking_MaximumFunctionCallsCapsSingleCallsPerIterationTestFunctionInvoking_MaximumFunctionCallsAllowsCurrentBatchToFinishTestFunctionInvoking_MaximumFunctionCallsCountsFailedExecutionsTestFunctionInvoking_MaximumFunctionCallsCountsPanickingExecutionsTestFunctionInvoking_MaximumFunctionCallsIgnoresNotFoundCallsTestFunctionInvoking_MaximumFunctionCallsIgnoresProviderHandledCallsTestFunctionInvoking_MaximumFunctionCallsIncludesApprovedCallsTestFunctionInvoking_ResumedApprovalWithZeroBudgetSkipsExecutionTestFunctionInvoking_ZeroBudgetClearsRequiredToolChoiceWhenSchemaToolRemovedTestToolApproval_SharesMaximumFunctionCallsAcrossAutoApprovedReEntriesgo test ./...) and race detector (go test -race ./agent/harness/...).Fixes #1202