feat(coding-agent): deferrable tools, LIFO pending-action stack, custom tool pushPendingAction
- Introduce `deferrable?: boolean` on AgentTool, CustomTool, and ToolDefinition. AstEditTool sets it to true; resolve is now injected only when at least one active tool is deferrable (previously unconditional). - Replace single-slot PendingActionStore (set/get/clear) with a LIFO stack (push/peek/pop/clear). Multiple deferrable tools can stage independent preview actions; resolve always consumes the topmost one first. - Wire pendingActionStore through discoverAndLoadCustomTools / loadCustomTools / CustomToolLoader so custom tools can call pushPendingAction(action) to register a resolve-compatible pending action with label, apply callback, optional details, and optional sourceToolName. - Export HIDDEN_TOOLS and ResolveTool from the SDK for manual tool composition. - Add CustomToolPendingAction type and pushPendingAction to CustomToolAPI. - Update createAgentSession to re-inject or remove resolve after the deferrable audit, consistent with createTools behavior. - Add LIFO resolve test, update existing tests (set -> push, get -> peek). - Add docs/resolve-tool-runtime.md covering PendingActionStore internals, built-in producer example, and custom tool usage guide.
This commit is contained in:
@@ -396,8 +396,8 @@ A `ToolFactory` is `(session: ToolSession) => Tool | null | Promise<Tool | null>
|
||||
- feature toggles (`find.enabled`, `grep.enabled`, etc.)
|
||||
- recursion guard for `task` (`task.maxRecursionDepth` vs `session.taskDepth`)
|
||||
- submit-result mode (`requireSubmitResultTool`) and `todo_write` suppression
|
||||
5. Instantiates tools in parallel with `Promise.all`, records slow factory timings when `PI_TIMING=1`.
|
||||
6. Wraps every tool with `wrapToolWithMetaNotice` before returning.
|
||||
5. Instantiates selected tools in parallel with `Promise.all`, records slow factory timings when `PI_TIMING=1`, and wraps results with `wrapToolWithMetaNotice`.
|
||||
6. Includes `resolve` only when at least one instantiated tool has `deferrable: true` (deferred preview/apply workflows).
|
||||
|
||||
The wrapper step is not cosmetic: it enforces uniform meta-notice behavior and normalized error rendering across all tools.
|
||||
|
||||
@@ -1131,14 +1131,15 @@ Primary file: `packages/coding-agent/src/tools/index.ts`.
|
||||
- `export const BUILTIN_TOOLS: Record<string, ToolFactory> = { ... }`
|
||||
- Key is the external tool name (e.g. `"read"`, `"web_search"`).
|
||||
4. If it should be hidden/system-only, register under `HIDDEN_TOOLS` instead.
|
||||
- Existing hidden names: `submit_result`, `report_finding`, `exit_plan_mode`.
|
||||
- Existing hidden names: `submit_result`, `report_finding`, `exit_plan_mode`, `resolve`.
|
||||
5. Wire feature gates in `isToolAllowed(name)` when the tool needs runtime enable/disable behavior.
|
||||
- Existing gates use `session.settings.get("<tool>.enabled")` and recursion limits for `task`.
|
||||
6. If the tool should be selectable by type, update `ToolName = keyof typeof BUILTIN_TOOLS` consumers as needed.
|
||||
|
||||
Notes from current behavior:
|
||||
|
||||
- `createTools()` automatically injects `exit_plan_mode` when `toolNames` are specified.
|
||||
- `createTools()` always injects `exit_plan_mode` when `toolNames` are specified.
|
||||
- `resolve` is included only when at least one active tool is marked `deferrable: true` (built-in or extension/custom).
|
||||
- `submit_result` is force-added when `session.requireSubmitResultTool === true`.
|
||||
- Python/Bash availability is mode-driven (`PI_PY`, `python.toolMode`) and can auto-fallback to bash.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user