feat(agents): surface timeout budget in tool schemas and errors #82

Closed
opened 2026-07-30 15:30:16 +00:00 by CoreRasurae · 0 comments
Member

Metadata

Field Value
Commit Message feat(agents): surface timeout budget in tool schemas and errors
Branch feature/m2-tool-timeout-awareness

Background and context

The tool agent timeout config field (Actor Configuration Standard §4.5, default 1 second) bounds "the maximum execution time in seconds for any single tool invocation." Of the tools that actually enforce it today, only two do: cleveractors.agents.tool.ToolAgent._execute_shell_command (backing the shell tool) and cleveractors.agents.tool.ToolAgent._http_request_tool.

The LLM-facing tool schemas sent to the model for function calling — cleveractors.agents.llm_tools._BUILTIN_TOOL_SCHEMAS, bound via cleveractors.agents.llm_tools.normalize_tool_entry and consumed by cleveractors.agents.llm.LLMAgent — never mention this constraint. The LLM has no way to know, ahead of a call, that shell/http_request invocations are time-boxed, or that the limit is adjustable via the agent's timeout config field. This is the same class of gap that ADR-2030 (D-4) already fixed for file_read vs. shell commands: give the LLM an actionable signal instead of an opaque failure. We're missing the equivalent for timeouts.

Separately, when a timeout does fire today, only the shell path names a number of seconds, and neither path names the config field that controls it.

Current behavior

  1. _BUILTIN_TOOL_SCHEMAS["shell"] and _BUILTIN_TOOL_SCHEMAS["http_request"] (in cleveractors.agents.llm_tools) describe only the functional arguments (command/args, url/method/headers/data) — neither mentions that the call is subject to an execution timeout.
  2. On a shell timeout, ToolAgent._execute_shell_command raises:
    ExecutionError(f"Command '{command}' timed out after {self.timeout} seconds")
    — this names the elapsed seconds but never the timeout config field that controls it.
  3. On an HTTP request timeout, ToolAgent._http_request_tool does not distinguish a timeout from any other request failure: the whole call is wrapped in a single except Exception as e: raise ExecutionError(f"HTTP request failed: {e}"). The LLM sees a generic failure with no indication the cause was a timeout, let alone that a timeout config field exists.

Expected behavior

  1. Every built-in tool whose execution actually honors self.timeout (currently shell and http_request) has a schema description telling the LLM the call is bounded by a configurable execution timeout, so the model can factor that in (e.g. avoid issuing commands it can predict will run long).
  2. When either tool times out, the raised ExecutionError message states both the number of seconds involved AND explicitly names timeout as the agent config field that controls it, so the model (or a human reading logs) knows what to adjust.
  3. ToolAgent._http_request_tool distinguishes a request timeout from other request failures (connection errors, HTTP error statuses, etc.) instead of collapsing everything into one generic message.
  4. No change to enforcement mechanics — this is schema/message content only. self.timeout remains the sole config field (default 1s, per §4.5); its default value and semantics are unchanged.

Out of scope (noted for awareness, not addressed here): ToolAgent._file_read_tool does not use self.timeout at all today — the read is a plain synchronous open()/.read() call with no timeout wrapping, even though §4.5 says timeout applies to "any single tool invocation." That is a separate enforcement gap (not a schema/message gap) and is left for a follow-up issue if the project decides to pursue it.

Acceptance criteria

  • _BUILTIN_TOOL_SCHEMAS["shell"]["description"] states that shell command execution is bounded by the agent's configured timeout (seconds).
  • _BUILTIN_TOOL_SCHEMAS["http_request"]["description"] states that the request is bounded by the agent's configured timeout (seconds).
  • ToolAgent._execute_shell_command's timeout ExecutionError message explicitly names timeout as the adjustable agent config field, in addition to the elapsed seconds it already reports.
  • ToolAgent._http_request_tool raises a distinct ExecutionError on request timeout (as opposed to other request failures) whose message states the configured timeout value and names timeout as the adjustable agent config field.
  • Non-timeout HTTP request failures (e.g. connection refused) continue to raise ExecutionError with their existing (non-timeout) message shape — behavior for non-timeout failures is unchanged.
  • nox -s coverage_report stays ≥ 97%.

Supporting information

  • Actor Configuration Standard, §4.5 (docs/index.md) — defines timeout as "Maximum execution time in seconds for any single tool invocation."
  • docs/adr/ADR-2030-tool-calling-spec-extensions.md — D-1 establishes _BUILTIN_TOOL_SCHEMAS as LLM-facing hints (not part of the normative contract); D-4/D-6 establish the precedent of enriching error messages with actionable, self-correction guidance for the LLM. This issue extends both precedents to the timeout field.
  • Relevant symbols at commit a8f68b8:
    • cleveractors.agents.llm_tools._BUILTIN_TOOL_SCHEMAS
    • cleveractors.agents.llm_tools.normalize_tool_entry
    • cleveractors.agents.tool.ToolAgent._execute_shell_command
    • cleveractors.agents.tool.ToolAgent._shell_tool
    • cleveractors.agents.tool.ToolAgent._http_request_tool
    • cleveractors.agents.llm.LLMAgent (binds _lc_tools from the schemas above; also reads self.config.get("timeout", 1) when constructing an internal ToolAgent to dispatch a tool call)

Subtasks

  • Update _BUILTIN_TOOL_SCHEMAS["shell"] and ["http_request"] descriptions in cleveractors.agents.llm_tools to mention the configurable execution timeout
  • Update ToolAgent._execute_shell_command's timeout error message to name the timeout config field
  • Update ToolAgent._http_request_tool to catch the request-timeout condition distinctly and raise an ExecutionError naming the timeout config field and its configured value
  • Confirm this falls within ADR-2030's already-accepted extensions (D-1 schema registry; D-4/D-6 error-quality improvements) — add an ADR addendum only if review determines a new decision record is warranted
  • Tests (Behave): scenarios asserting the shell/http_request schema descriptions mention the timeout budget
  • Tests (Behave): scenarios asserting the timeout ExecutionError message for both tools names the timeout config field
  • Tests (Behave): scenario asserting non-timeout HTTP failures keep their existing message shape (regression guard)
  • Verify coverage >=97% via nox -s coverage_report
  • Run nox (all default sessions), fix any errors

Definition of Done

This issue is complete when:

  • All subtasks above are completed and checked off.
  • A Git commit is created where the first line matches the Commit Message in Metadata exactly.
  • The commit is pushed to the branch matching the Branch in Metadata exactly.
  • The commit is submitted as a PR to master, reviewed, and merged.
## Metadata | Field | Value | |-------|-------| | Commit Message | feat(agents): surface timeout budget in tool schemas and errors | | Branch | feature/m2-tool-timeout-awareness | ## Background and context The tool agent `timeout` config field (Actor Configuration Standard §4.5, default `1` second) bounds "the maximum execution time in seconds for any single tool invocation." Of the tools that actually enforce it today, only two do: `cleveractors.agents.tool.ToolAgent._execute_shell_command` (backing the `shell` tool) and `cleveractors.agents.tool.ToolAgent._http_request_tool`. The LLM-facing tool schemas sent to the model for function calling — `cleveractors.agents.llm_tools._BUILTIN_TOOL_SCHEMAS`, bound via `cleveractors.agents.llm_tools.normalize_tool_entry` and consumed by `cleveractors.agents.llm.LLMAgent` — never mention this constraint. The LLM has no way to know, ahead of a call, that `shell`/`http_request` invocations are time-boxed, or that the limit is adjustable via the agent's `timeout` config field. This is the same class of gap that ADR-2030 (D-4) already fixed for `file_read` vs. shell commands: give the LLM an actionable signal instead of an opaque failure. We're missing the equivalent for timeouts. Separately, when a timeout does fire today, only the `shell` path names a number of seconds, and neither path names the config field that controls it. ## Current behavior 1. `_BUILTIN_TOOL_SCHEMAS["shell"]` and `_BUILTIN_TOOL_SCHEMAS["http_request"]` (in `cleveractors.agents.llm_tools`) describe only the functional arguments (`command`/`args`, `url`/`method`/`headers`/`data`) — neither mentions that the call is subject to an execution timeout. 2. On a shell timeout, `ToolAgent._execute_shell_command` raises: `ExecutionError(f"Command '{command}' timed out after {self.timeout} seconds")` — this names the elapsed seconds but never the `timeout` config field that controls it. 3. On an HTTP request timeout, `ToolAgent._http_request_tool` does not distinguish a timeout from any other request failure: the whole call is wrapped in a single `except Exception as e: raise ExecutionError(f"HTTP request failed: {e}")`. The LLM sees a generic failure with no indication the cause was a timeout, let alone that a `timeout` config field exists. ## Expected behavior 1. Every built-in tool whose execution actually honors `self.timeout` (currently `shell` and `http_request`) has a schema description telling the LLM the call is bounded by a configurable execution timeout, so the model can factor that in (e.g. avoid issuing commands it can predict will run long). 2. When either tool times out, the raised `ExecutionError` message states both the number of seconds involved AND explicitly names `timeout` as the agent config field that controls it, so the model (or a human reading logs) knows what to adjust. 3. `ToolAgent._http_request_tool` distinguishes a request timeout from other request failures (connection errors, HTTP error statuses, etc.) instead of collapsing everything into one generic message. 4. No change to enforcement mechanics — this is schema/message content only. `self.timeout` remains the sole config field (default `1`s, per §4.5); its default value and semantics are unchanged. **Out of scope** (noted for awareness, not addressed here): `ToolAgent._file_read_tool` does not use `self.timeout` at all today — the read is a plain synchronous `open()`/`.read()` call with no timeout wrapping, even though §4.5 says `timeout` applies to "any single tool invocation." That is a separate *enforcement* gap (not a schema/message gap) and is left for a follow-up issue if the project decides to pursue it. ## Acceptance criteria - [ ] `_BUILTIN_TOOL_SCHEMAS["shell"]["description"]` states that shell command execution is bounded by the agent's configured `timeout` (seconds). - [ ] `_BUILTIN_TOOL_SCHEMAS["http_request"]["description"]` states that the request is bounded by the agent's configured `timeout` (seconds). - [ ] `ToolAgent._execute_shell_command`'s timeout `ExecutionError` message explicitly names `timeout` as the adjustable agent config field, in addition to the elapsed seconds it already reports. - [ ] `ToolAgent._http_request_tool` raises a distinct `ExecutionError` on request timeout (as opposed to other request failures) whose message states the configured timeout value and names `timeout` as the adjustable agent config field. - [ ] Non-timeout HTTP request failures (e.g. connection refused) continue to raise `ExecutionError` with their existing (non-timeout) message shape — behavior for non-timeout failures is unchanged. - [ ] `nox -s coverage_report` stays ≥ 97%. ## Supporting information - Actor Configuration Standard, §4.5 (`docs/index.md`) — defines `timeout` as "Maximum execution time in seconds for any single tool invocation." - `docs/adr/ADR-2030-tool-calling-spec-extensions.md` — D-1 establishes `_BUILTIN_TOOL_SCHEMAS` as LLM-facing hints (not part of the normative contract); D-4/D-6 establish the precedent of enriching error messages with actionable, self-correction guidance for the LLM. This issue extends both precedents to the `timeout` field. - Relevant symbols at commit `a8f68b8`: - `cleveractors.agents.llm_tools._BUILTIN_TOOL_SCHEMAS` - `cleveractors.agents.llm_tools.normalize_tool_entry` - `cleveractors.agents.tool.ToolAgent._execute_shell_command` - `cleveractors.agents.tool.ToolAgent._shell_tool` - `cleveractors.agents.tool.ToolAgent._http_request_tool` - `cleveractors.agents.llm.LLMAgent` (binds `_lc_tools` from the schemas above; also reads `self.config.get("timeout", 1)` when constructing an internal `ToolAgent` to dispatch a tool call) ## Subtasks - [ ] Update `_BUILTIN_TOOL_SCHEMAS["shell"]` and `["http_request"]` descriptions in `cleveractors.agents.llm_tools` to mention the configurable execution timeout - [ ] Update `ToolAgent._execute_shell_command`'s timeout error message to name the `timeout` config field - [ ] Update `ToolAgent._http_request_tool` to catch the request-timeout condition distinctly and raise an `ExecutionError` naming the `timeout` config field and its configured value - [ ] Confirm this falls within ADR-2030's already-accepted extensions (D-1 schema registry; D-4/D-6 error-quality improvements) — add an ADR addendum only if review determines a new decision record is warranted - [ ] Tests (Behave): scenarios asserting the `shell`/`http_request` schema descriptions mention the timeout budget - [ ] Tests (Behave): scenarios asserting the timeout `ExecutionError` message for both tools names the `timeout` config field - [ ] Tests (Behave): scenario asserting non-timeout HTTP failures keep their existing message shape (regression guard) - [ ] Verify coverage >=97% via nox -s coverage_report - [ ] Run nox (all default sessions), fix any errors ## Definition of Done This issue is complete when: - All subtasks above are completed and checked off. - A Git commit is created where the first line matches the Commit Message in Metadata exactly. - The commit is pushed to the branch matching the Branch in Metadata exactly. - The commit is submitted as a PR to master, reviewed, and merged.
CoreRasurae added this to the v2.1.0 milestone 2026-07-30 15:30:16 +00:00
CoreRasurae added the
State
Unverified
Type
Feature
Priority
Medium
labels 2026-07-30 15:30:16 +00:00
CoreRasurae added
State
Verified
and removed
State
Unverified
labels 2026-07-30 16:14:07 +00:00
CoreRasurae added
State
In Review
and removed
State
Verified
labels 2026-07-30 17:45:00 +00:00
CoreRasurae added
State
Completed
and removed
State
In Review
labels 2026-07-31 08:31:56 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Reference: cleveragents/cleveractors-core#82