From 712d4e423b93826b400d000ea25d83a0781280f1 Mon Sep 17 00:00:00 2001 From: roboomp Date: Fri, 3 Jul 2026 06:13:52 +0000 Subject: [PATCH] docs(tool): documented bash timeout clamp Documented the 1-3600 second bash timeout clamp in the schema, model-facing prompt, and tool docs, including the async timeout behavior. Added coverage that the shipped schema and rendered prompt expose the contract. Fixes #4408 --- docs/tools/bash.md | 2 +- packages/coding-agent/CHANGELOG.md | 4 ++++ .../coding-agent/src/prompts/tools/bash.md | 6 +++--- packages/coding-agent/src/tools/bash.ts | 6 ++++-- .../test/tools/schema-validation.test.ts | 18 ++++++++++++++++++ 5 files changed, 30 insertions(+), 6 deletions(-) diff --git a/docs/tools/bash.md b/docs/tools/bash.md index f7dcc246d..5942af343 100644 --- a/docs/tools/bash.md +++ b/docs/tools/bash.md @@ -27,7 +27,7 @@ | `timeout` | `number` | No | Timeout in seconds. Default `300`; clamped to `1..3600` by `clampTimeout("bash", ...)`. | | `cwd` | `string` | No | Working directory, resolved against `session.cwd` via `resolveToCwd`. Must exist and be a directory. | | `pty` | `boolean` | No | Request PTY mode. Default `false`. PTY is used only when `pty: true`, `PI_NO_PTY !== "1"`, and the tool context has a UI. | -| `async` | `boolean` | No | Background execution request. Present only when `async.enabled` is true for the session. Returns immediately with a job id instead of waiting. | +| `async` | `boolean` | No | Background execution request. Present only when `async.enabled` is true for the session. Returns immediately with a job id instead of waiting; it does not extend the effective `timeout`, so jobs are still killed after the clamped `1..3600` second budget. | ## Outputs The tool returns a single `text` content block plus optional `details`. diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 860266c53..6105e0510 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Documented the bash tool timeout clamp in the model-facing schema and prompt so callers know `async` jobs remain capped at 3600 seconds ([#4408](https://github.com/can1357/oh-my-pi/issues/4408)). + ## [16.3.4] - 2026-07-03 ### Fixed diff --git a/packages/coding-agent/src/prompts/tools/bash.md b/packages/coding-agent/src/prompts/tools/bash.md index 0cfdd4238..11c47fc06 100644 --- a/packages/coding-agent/src/prompts/tools/bash.md +++ b/packages/coding-agent/src/prompts/tools/bash.md @@ -39,9 +39,9 @@ Anything below → `eval` cell, not bash: {{#if asyncEnabled}} # Timeout and async -- `timeout` (seconds) caps wall-clock duration; the process is killed on elapse. -- `async: true` defers only reporting — it does NOT extend the timeout; a daemon run with `async: true` is still killed when `timeout` elapses. -- Long-running daemons (dev servers, watchers): pass a large explicit `timeout`. The shell session persists across calls, so `cmd &` keeps running between bash calls. +- `timeout` is seconds, clamped to `1..3600`; the process is killed on elapse. +- `async: true` defers only reporting — it does NOT extend the timeout; a daemon with `async: true` is still killed at the clamped timeout. +- Need >3600s? Detach/manage lifecycle yourself (`cmd &`, supervisor, self-restarting script). The shell session persists across calls. {{/if}} {{#if autoBackgroundEnabled}} diff --git a/packages/coding-agent/src/tools/bash.ts b/packages/coding-agent/src/tools/bash.ts index 291206920..6b5100830 100644 --- a/packages/coding-agent/src/tools/bash.ts +++ b/packages/coding-agent/src/tools/bash.ts @@ -132,10 +132,12 @@ async function saveBashOriginalArtifact(session: ToolSession, originalText: stri } } +const BASH_TIMEOUT_DESCRIPTION = `timeout in seconds; clamped to ${TOOL_TIMEOUTS.bash.min}-${TOOL_TIMEOUTS.bash.max}`; + const bashSchemaBase = type({ command: type("string").describe("command to execute"), "env?": type({ "[string]": "string" }).describe("extra env vars"), - "timeout?": type("number").describe("timeout in seconds"), + "timeout?": type("number").describe(BASH_TIMEOUT_DESCRIPTION), "cwd?": type("string").describe("working directory"), "pty?": type("boolean").describe("run in pty mode"), }); @@ -143,7 +145,7 @@ const bashSchemaBase = type({ const bashSchemaWithAsync = type({ command: "string", "env?": { "[string]": "string" }, - "timeout?": "number", + "timeout?": type("number").describe(BASH_TIMEOUT_DESCRIPTION), "cwd?": "string", "pty?": "boolean", "async?": type("boolean").describe("run in background"), diff --git a/packages/coding-agent/test/tools/schema-validation.test.ts b/packages/coding-agent/test/tools/schema-validation.test.ts index 6f3cc33e4..231a0a0b4 100644 --- a/packages/coding-agent/test/tools/schema-validation.test.ts +++ b/packages/coding-agent/test/tools/schema-validation.test.ts @@ -288,6 +288,24 @@ describe("tool schema validation (post-sanitization)", () => { expect(description).toContain("pr://123"); }); + it("bash schema and prompt advertise the timeout clamp", async () => { + const session = createTestSession(); + session.settings.set("async.enabled", true); + const tools = await createTools(session); + const bashTool = tools.find(tool => tool.name === "bash"); + if (!bashTool?.parameters) throw new Error("bash tool parameters missing"); + + const schema = toolWireSchema(bashTool) as { + properties?: { timeout?: { description?: string } }; + }; + const timeoutDescription = schema.properties?.timeout?.description ?? ""; + + expect(timeoutDescription).toContain("clamped"); + expect(timeoutDescription).toContain("1-3600"); + expect(bashTool.description).toContain("clamped to `1..3600`"); + expect(bashTool.description).toContain("does NOT extend the timeout"); + }); + it("hidden tools also have valid sanitized schemas", async () => { const session = createTestSession();