Ephemeral tool-call ToolAgent instances do not inherit tools_max_timeout/shell_max_timeout from the parent LLM agent #140
Labels
No labels
auto/blocked-by-deps
auto/ci-timeout
auto/claimed-implementer
auto/claimed-merge
auto/claimed-reviewer
auto/driver-down
auto/invariant-violation
auto/last-attempt-tier-0
auto/last-attempt-tier-1
auto/last-attempt-tier-2
auto/last-attempt-tier-min
Automation Tracking
auto/needs-conflict-resolution
auto/needs-implementer
auto/postmortem
auto/ready-to-merge
auto/restart-throttled
auto/revert
auto/sentinel
auto/stale-inactivity
auto/unstable
Blocked
Bounty
$100
Bounty
$1000
Bounty
$10000
Bounty
$20
Bounty
$2000
Bounty
$250
Bounty
$50
Bounty
$500
Bounty
$5000
Bounty
$750
MoSCoW
Could have
MoSCoW
Must have
MoSCoW
Should have
Needs Feedback
Points
1
Points
13
Points
2
Points
21
Points
3
Points
34
Points
5
Points
55
Points
8
Points
88
Priority
Backlog
Priority
CI Blocker
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Signed-off: Owner
Signed-off: Scrum Master
Signed-off: Tech Lead
Spike
State
Completed
State
Duplicate
State
In Progress
State
In Review
State
Paused
State
Unverified
State
Verified
State
Wont Do
Type
Automation
Type
Bug
Type
Discussion
Type
Documentation
Type
Epic
Type
Feature
Type
Legendary
Type
Refactor
Type
Support
Type
Task
Type
Testing
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Blocks
Depends on
#77 Epic: LLM Agent Runtime Stabilization — reliability, resource enforcement & correctness hardening
cleveragents/cleveractors-core
#141 feat(agents): inherit tool timeout ceilings from parent LLM agent
cleveragents/cleveractors-core
Reference
cleveragents/cleveractors-core#140
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Metadata
feat(agents): inherit tool timeout ceilings from parent LLM agentfeature/m1-inherit-tool-timeout-ceilingsBackground and context
The Actor Configuration Standard (
docs/index.md§4.5) defines three tool-agentconfig fields that bound tool execution:
timeout(default1s), and — added byADR-2030 D-9 — the generic
tools_max_timeout(default120s, the ceiling aper-invocation
timeouttool-call argument may request) and the shell-onlyshell_max_timeoutrefinement. §4.4 (LLM agents) defines no equivalent fields atall —
timeout/tools_max_timeout/shell_max_timeoutsimply do not appear inthe
type: llmconfig table.Despite that,
cleveractors.agents.llm.LLMAgentdispatches every built-in toolcall (
shell,http_request, etc.) by constructing an ephemeralcleveractors.agents.tool.ToolAgentper call — three near-identical call sitesinside
LLMAgent._execute_tool_loopat commit0880b02(the normal per-roundpath, the budget-exhaustion synthesis retry, and the post-loop stuck-model
synthesis retry). Each site builds a small
configmapping for that ephemeralagent (
tool_cfg/tool_config/tool_config_s), including"timeout": self.config.get("timeout", 1)— i.e. it already readstimeoutoff the parent LLM agent's own config, even though §4.4 never documents
that key as meaningful there.
None of the three sites do the same for
tools_max_timeoutorshell_max_timeout, and this issue is scoped to those two fields only —timeoutalready inherits correctly and is out of scope here, referencedbelow only as context/precedent.
cleveractors.agents.tool.ToolAgent.__init__always falls back to its own hardcoded defaults (
120.0/None) for theephemeral agent, regardless of what the parent
type: llmagent's configcontains under those keys. Since the ephemeral agent's config is synthesized
internally and never authored directly by an end user, the parent LLM agent's
own config is the only place an actor author could realistically express "let
this agent's internally-dispatched shell/http_request calls request a higher
per-call
timeoutoverride" — and today there is no way to do that: everyLLM-agent-dispatched tool call is capped at the built-in 120s ceiling no
matter what.
This is the same code area, and the same "ephemeral
ToolAgentconfig isimplicitly, only partially derived from the parent LLM agent's config" defect
class, as #115/#116 (dead
unsafe_modeconfig key, fixed by deriving_resolve_parent_unsafefrom the realsafe_mode/contextsignals) and #111(the
timeouttool-call-argument override mechanism this issue's ceilingfields bound). Extending
docs/adr/ADR-2030-tool-calling-spec-extensions.md(D-9) is the natural home for the design decision, following the same
ADR-before-code process #111 already used for the sibling
timeout-argumentfeature.
Current behavior
LLMAgent._execute_tool_loop's three ephemeral-ToolAgent-constructionsites already read
self.config.get("timeout", 1)into the ephemeralagent's config, so a
timeoutvalue on the parenttype: llmagent'sconfig reaches the ephemeral agent as intended — no change needed here,
included only as context for how the ceiling fields below should behave
the same way.
tools_max_timeoutorshell_max_timeoutoff the parent config, so the ephemeral
ToolAgentalways constructs withthe class defaults (
120.0/None) no matter what the parenttype: llmagent's config contains.
timeouttool-call-argument ceiling (ADR-2030 D-9) for tool calls atype: llmagent dispatches internally.Expected behavior
ToolAgent-construction sites inLLMAgent._execute_tool_loopbuild theirconfigmapping withtools_max_timeoutandshell_max_timeoutread from the parent LLMagent's own config (
self.config.get("tools_max_timeout", 120.0),self.config.get("shell_max_timeout", None)), exactly mirroring howtimeoutis already threaded through today.timeoutitself is nottouched by this change.
timeouttool-call argument (ADR-2030 D-9,cleveractors.agents.timeout_policy.TimeoutPolicy) is completelyunaffected by this change. When the model itself supplies a
timeoutargument inside a specific tool call's
args(e.g.{"tool": "shell", "args": {"command": "...", "timeout": 30}}), thatper-call value still takes precedence over the (now-inherited) default for
that one call, bounded by the (now-inherited) ceiling — inheritance only
changes where the ephemeral agent's default/ceiling originate from; it
must never be confused with, shadow, or bypass the model's own per-call
override argument.
tools_max_timeout/shell_max_timeouton the parenttype: llmagent's config reproduces today's behavior byte-for-byte (fallback to
120.0/None, identical toToolAgent.__init__'s own defaults).non-finite) fails fast at ephemeral-
ToolAgent-construction time with theexisting
AgentCreationError, exactly as it already does for adirectly-configured
type: toolagent.Acceptance criteria
tools_max_timeout: 300on atype: llmagent's config raises theper-call
timeouttool-argument ceiling to300forshell/http_requestcalls that agent dispatches (verifiable via the ephemeral agent's resolved
TimeoutPolicy), for all three dispatch sites (normal round, budget-exhaustion synthesis, post-loop synthesis).
shell_max_timeouton atype: llmagent's config overrides theshell-only ceiling for tool calls it dispatches, without changing thehttp_requestceiling (still governed bytools_max_timeout).type: llmagent's config reproduces currentdefault behavior exactly: ephemeral agent ceilings are
120.0/ unset.shell/http_requesttool call carrying its own per-invocationtimeoutargument still uses that value (bounded by the inherited ceiling) in
preference to the inherited default — verified both when the parent config
sets
tools_max_timeout/shell_max_timeoutand when it omits them.tools_max_timeoutorshell_max_timeouton atype: llmagent's config raises anAgentCreationErrorat ephemeral-tool-agent construction, not silently oron first tool call.
nox(all default sessions) is green andnox -s coverage_reportstays≥ 97%.
Supporting information
docs/adr/ADR-2030-tool-calling-spec-extensions.mdD-9 — introducestools_max_timeout/shell_max_timeoutand enumerates where aToolAgentreads them ("an agent-package config, a
type: toolnode in an actorgraph, and the streaming/interactive runtime"); this enumeration predates,
and does not mention, the ephemeral tool-call-dispatch
ToolAgentthisissue covers, and needs a decision extending it.
docs/index.md§4.4 (LLM agents) / §4.5 (tool agents,tools_max_timeout/shell_max_timeoutfield definitions).timeouttool-call-argument override thisissue's ceiling fields bound; used the same ADR-before-code process this
issue should follow.
ToolAgent'sconfig being only partially/incorrectly derived from the parent
type: llmagent's own config/context).
0880b02:cleveractors.agents.llm.LLMAgent._execute_tool_loop(all threeephemeral-
ToolAgent-construction sites)cleveractors.agents.tool.ToolAgent.__init__(readstools_max_timeout/shell_max_timeout, validates them eagerly)cleveractors.agents.timeout_policy.TimeoutPolicy(per-call overrideresolution — must remain untouched by this change)
Subtasks
ADR-2030documenting thatephemeral tool-call
ToolAgentinstances constructed by atype: llmagent inherit
tools_max_timeout/shell_max_timeoutfrom the parent'sown config (same fallback defaults as today when absent, mirroring how
timeoutalready inherits), and that a model-supplied per-calltimeouttool argument continues to take precedence exactly as it doesfor a directly-configured
type: toolagent; submit for review and getit accepted before writing code
docs/index.mdis warranted, update it via the spec-revision procedure(bump Version, add a §21.1 Revision History row attributing the change
to the ADR) — do not edit spec prose inline without it
configconstruction at all three ephemeral-ToolAgentsites in
LLMAgent._execute_tool_loop(
src/cleveractors/agents/llm.py) to readtools_max_timeoutandshell_max_timeoutfromself.config, falling back toToolAgent'sown defaults when absent
tools_max_timeoutraises the per-callceiling; inherited
shell_max_timeoutraises the shell-only ceilingwithout affecting
http_request; omitting both preserves currentdefaults; a per-call
timeouttool-call argument still takesprecedence over the inherited default in both cases; an invalid
inherited ceiling raises
AgentCreationErrorat ephemeral-agentconstruction; coverage across all three dispatch sites
type: llmagentconfigured with
tools_max_timeout/shell_max_timeout, dispatching areal
shelltool call that needs more than the default ceiling(expected N/A — this only threads config values through); document the
assessment
nox -s coverage_reportnox(all default sessions), fix any errorsDefinition of Done
This issue is complete when:
docs/index.mdupdated per thespec-revision procedure, if the ADR calls for it) before implementation code
is merged.
Metadata exactly.