fix(pty): close final review gaps
This commit is contained in:
@@ -1383,7 +1383,7 @@ export interface Config {
|
||||
}
|
||||
```
|
||||
|
||||
Source: [`packages/pty/tool-pty/src/index.ts:44`](../packages/pty/tool-pty/src/index.ts)
|
||||
Source: [`packages/pty/tool-pty/src/index.ts:35`](../packages/pty/tool-pty/src/index.ts)
|
||||
|
||||
## `@deepseek-ai/dsh-tool-ralph`
|
||||
|
||||
@@ -1549,7 +1549,7 @@ export interface Config {
|
||||
export type ToolPresentationMode = 'native' | 'code' | 'both'
|
||||
```
|
||||
|
||||
Source: [`packages/core/tools/src/index.ts:419`](../packages/core/tools/src/index.ts)
|
||||
Source: [`packages/core/tools/src/index.ts:431`](../packages/core/tools/src/index.ts)
|
||||
|
||||
## `@deepseek-ai/dsh-tui`
|
||||
|
||||
|
||||
@@ -1547,7 +1547,7 @@ Tool registry and execution pipeline. Scoped registrations shadow globals; one v
|
||||
/**
|
||||
* Register globally or in the calling agent scope. Scoped tools shadow
|
||||
* globals; duplicates within one layer and the reserved `run_code` name fail.
|
||||
* @param definition - the tool schema, execution, and optional presentation functions.
|
||||
* @param definition - tool schema, execution, and optional finalization/presentation callbacks.
|
||||
* @returns the exact disposer that unregisters the tool.
|
||||
*/
|
||||
register(definition: ToolDefinition): () => void
|
||||
@@ -1602,10 +1602,11 @@ schemas(scope?: ScopeKey): ToolSchema[]
|
||||
executionMode(exec: ToolExecutionInput): ToolExecutionMode
|
||||
|
||||
/**
|
||||
* Execute through pre-policy, guards, around-dispatch, post-policy, and final
|
||||
* notification. Tool and listener failures resolve as materialized error
|
||||
* results; an invisible tool reports `UNKNOWN_TOOL`. The returned outcome is
|
||||
* the same lossless, frozen snapshot final observers receive. Cancellation
|
||||
* Execute through pre-policy, guards, around-dispatch, post-policy,
|
||||
* definition-owned content finalization, and final notification. Tool and
|
||||
* listener failures resolve as materialized error results; an invisible tool
|
||||
* reports `UNKNOWN_TOOL`. The returned outcome is the same lossless, frozen
|
||||
* snapshot final observers receive. Cancellation
|
||||
* arriving after entry and before final result materialization skips a
|
||||
* not-yet-started body with `ABORTED_BEFORE_DISPATCH` or replaces a
|
||||
* successful started outcome with `ABORTED`; already-started work is still
|
||||
@@ -1619,7 +1620,7 @@ async execute(exec: ToolExecutionInput): Promise<ToolExecutionResult>
|
||||
|
||||
Types: [ScopeKey](../core-data-structures/scope.md) · [ToolDefinition](../core-data-structures/tools.md) · [ToolExecutionInput](../core-data-structures/tools.md) · [ToolExecutionMode](../core-data-structures/tools.md) · [ToolExecutionResult](../core-data-structures/tools.md) · [ToolGuard](../core-data-structures/tools.md) · [ToolRestriction](../core-data-structures/tools.md) · [ToolSchema](../core-data-structures/tools.md)
|
||||
|
||||
Source: [`packages/core/tools/src/index.ts:524`](../../packages/core/tools/src/index.ts)
|
||||
Source: [`packages/core/tools/src/index.ts:536`](../../packages/core/tools/src/index.ts)
|
||||
|
||||
## `ctx.userInteraction` — `UserInteractionService`
|
||||
|
||||
|
||||
@@ -544,6 +544,6 @@ type SessionStartSource = 'startup' | 'resume' | 'clear' | 'compact'
|
||||
|
||||
## `ToolDefinition`
|
||||
|
||||
The one pipeline-authoring type that is core: what every registered tool *is* — a model-facing `ToolSchema` plus an `execute` function and optional UI presenters. A tool author rarely constructs it by hand (the `defineTool` DSL builds it with typed args), but it is the contract the registry holds and the loop dispatches through.
|
||||
The one pipeline-authoring type that is core: what every registered tool *is* — a model-facing `ToolSchema` plus an `execute` function and optional final-content and UI callbacks. A tool author rarely constructs it by hand (the `defineTool` DSL builds it with typed args), but it is the contract the registry holds and the loop dispatches through.
|
||||
|
||||
Its full fields, the `defineTool`/`SchemaSpec`/`InferArgs` typed schema DSL, the `ToolExecution`/`ToolExecutionResult` waterfall shapes, and the tool-presentation UI vocabulary are on **[tools.md](tools.md)**.
|
||||
|
||||
@@ -6,7 +6,7 @@ Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index
|
||||
|
||||
## `ToolDefinition` — a registered tool
|
||||
|
||||
A `ToolSchema` (the model-facing fields) plus the `execute` function, host-only scheduler metadata, and optional UI presenters. The registry holds these; the loop dispatches calls through them. The registry's `schemas()` builds the model-facing `ToolSchema[]` by an explicit allowlist — `execute`/`timeoutMs`/`isConcurrencySafe`/`presentCall`/`presentResult` must never leak into a model request.
|
||||
A `ToolSchema` (the model-facing fields) plus the `execute` function, host-only scheduler metadata, final-content callback, and optional UI presenters. The registry holds these; the loop dispatches calls through them. The registry's `schemas()` builds the model-facing `ToolSchema[]` by an explicit allowlist — `execute`/`finalizeContent`/`timeoutMs`/`isConcurrencySafe`/`presentCall`/`presentResult` must never leak into a model request.
|
||||
|
||||
```ts type-equiv
|
||||
/** A registered tool: its schema plus the execution function. */
|
||||
@@ -21,6 +21,18 @@ interface ToolDefinition extends ToolSchema {
|
||||
* @returns model-facing content plus optional private presentation metadata.
|
||||
*/
|
||||
execute(args: unknown, exec: ToolRunContext): Promise<ToolExecuteReturn>
|
||||
/**
|
||||
* Synchronous last-mile transform for model-facing content. The registry
|
||||
* snapshots this callback when execution starts and invokes it exactly once
|
||||
* for every normalized outcome, including pipeline failures that bypass
|
||||
* `tools/post-execute`, immediately before lossless materialization.
|
||||
* Returning `undefined` preserves the content; every other result field
|
||||
* remains registry-owned. The callback must be total and must not throw.
|
||||
* @param exec - immutable execution identity and arguments.
|
||||
* @param result - complete normalized outcome before materialization.
|
||||
* @returns replacement content, or `undefined` to preserve it.
|
||||
*/
|
||||
finalizeContent?(exec: Readonly<ToolExecution>, result: Readonly<ToolExecutionResult>): ContentBlock[] | undefined
|
||||
/**
|
||||
* Cooperative tool-call timeout budget in milliseconds. Omit for no deadline.
|
||||
* Enforced by `@deepseek-ai/dsh-timeout-policy` (a `tools/execute` wrapper); it
|
||||
@@ -64,7 +76,7 @@ interface ToolDefinition extends ToolSchema {
|
||||
}
|
||||
```
|
||||
|
||||
`execute` receives `args: unknown` — a raw `ToolDefinition` validates its own input. First-party tools don't write that by hand; they use `defineTool`, which validates and narrows for them.
|
||||
`execute` receives `args: unknown` — a raw `ToolDefinition` validates its own input. First-party tools don't write that by hand; they use `defineTool`, which validates and narrows for them. `finalizeContent` deliberately receives the immutable execution instead of typed arguments because invalid-input and outer pipeline failures reach it too; it may enforce a tool-owned content bound while preserving `isError`, structured error identity, deferred contexts, and presentation metadata.
|
||||
|
||||
## The typed schema DSL
|
||||
|
||||
@@ -147,7 +159,7 @@ interface ToolRestriction {
|
||||
|
||||
## Execution: extensible waterfalls plus monotonic policy
|
||||
|
||||
`ctx.tools.execute()` accepts a caller-owned `ToolExecutionInput` with a required readonly `signal`, materializes its parsed JSON arguments once into a pipeline-owned `ToolExecution`, and runs that call through `tools/pre-execute` (the reorderable allow/deny/ask waterfall) → registered monotonic guards → `tools/execute` (around-dispatch wrappers) → `tools/post-execute` (inspect/replace the result) → `tools/result` (the immutable authoritative outcome). Only the `tools/execute` view may replace the required signal. The outcome is a `ToolExecutionResult`.
|
||||
`ctx.tools.execute()` accepts a caller-owned `ToolExecutionInput` with a required readonly `signal`, materializes its parsed JSON arguments once into a pipeline-owned `ToolExecution`, and runs that call through `tools/pre-execute` (the reorderable allow/deny/ask waterfall) → registered monotonic guards → `tools/execute` (around-dispatch wrappers) → `tools/post-execute` (inspect/replace the result) → optional definition-owned `finalizeContent` → `tools/result` (the immutable authoritative outcome). Only the `tools/execute` view may replace the required signal. The outcome is a `ToolExecutionResult`.
|
||||
|
||||
```ts type-equiv
|
||||
/** Opaque call identity that permits correlation without exposing mutable execution state. */
|
||||
|
||||
@@ -43,7 +43,7 @@ This matrix shows which packages dispatch each harness-owned event and which pac
|
||||
| `system-prompt/change` | `emit` | [`packages/core/system-prompt/src/index.ts:35`](../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../packages/core/system-prompt) (`emit`) | - |
|
||||
| `tools/change` | `emit` | [`packages/core/tools/src/index.ts:123`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`emit`) | - |
|
||||
| `tools/execute` | `waterfall` | [`packages/core/tools/src/index.ts:93`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`session-checkpoint-policy`](../packages/session-persistence/session-checkpoint-policy), [`timeout-policy`](../packages/timeout/timeout-policy) |
|
||||
| `tools/post-execute` | `waterfall` | [`packages/core/tools/src/index.ts:105`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`repeat-tool-guard`](../packages/guard/repeat-tool-guard), [`spill-policy`](../packages/spill/spill-policy), [`tool-pty`](../packages/pty/tool-pty), [`tool-tasks`](../packages/tasks/tool-tasks), [`workspace-context`](../packages/context/workspace-context) |
|
||||
| `tools/post-execute` | `waterfall` | [`packages/core/tools/src/index.ts:105`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`repeat-tool-guard`](../packages/guard/repeat-tool-guard), [`spill-policy`](../packages/spill/spill-policy), [`workspace-context`](../packages/context/workspace-context) |
|
||||
| `tools/pre-execute` | `waterfall` | [`packages/core/tools/src/index.ts:82`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`tool-tasks`](../packages/tasks/tool-tasks) |
|
||||
| `tools/result` | `emit` | [`packages/core/tools/src/index.ts:113`](../packages/core/tools/src/index.ts) | [`tools`](../packages/core/tools) (`events.dispatch`) | [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`workspace-context`](../packages/context/workspace-context) |
|
||||
| `workflow/agent-end` | `emit` | [`packages/workflow/workflow/src/index.ts:81`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`workflow`](../packages/workflow/workflow) |
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
# Tool Execution Pipeline
|
||||
|
||||
This graph shows where policy, hooks, sandboxing, filesystem guards, result rewriting, final-outcome observation, and UI rendering fit without changing the loop. The transformable extension points are the `tools/pre-execute`, `tools/execute`, and `tools/post-execute` waterfalls; monotonic guards and `tools/result` are the owner-enforced boundaries around them.
|
||||
This graph shows where policy, hooks, sandboxing, filesystem guards, result rewriting, final-outcome observation, and UI rendering fit without changing the loop. The transformable extension points are the `tools/pre-execute`, `tools/execute`, and `tools/post-execute` waterfalls; monotonic guards, definition-owned `finalizeContent`, and `tools/result` are the owner-enforced boundaries around them.
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
@@ -19,6 +19,8 @@ flowchart TD
|
||||
fsGate["<code>fs/write-intent</code> or <code>fs/edit-intent</code><br/>tool-fs mutations only"]
|
||||
owned["Tool-owned session events<br/><code>todo/write</code>, <code>fs/observed</code>, <code>hook/invoked</code>, <code>hook/result</code>, <code>tool/code-dispatch</code>"]
|
||||
post["<code>tools/post-execute</code> waterfall<br/>accept, block, replace, add context"]
|
||||
normalized["Registry outer normalization<br/>pipeline throws become isError"]
|
||||
finalize["ToolDefinition.finalizeContent<br/>last content-only invariant"]
|
||||
final["<code>tools/result</code> synchronous notification<br/>frozen authoritative outcome"]
|
||||
context["Active-batch additionalContexts FIFO<br/>context/message after recorded tool results"]
|
||||
toolResult["Session event: <code>tool/result</code><br/>single model-facing outcome"]
|
||||
@@ -30,24 +32,31 @@ flowchart TD
|
||||
pre -->|allow| guards
|
||||
guards -->|allow| around
|
||||
guards -->|deny| denied
|
||||
guards -.->|throw| normalized
|
||||
around --> toolBody
|
||||
pre -->|deny| denied
|
||||
pre -->|ask| approval
|
||||
approval -->|allowed-once| guards
|
||||
approval -->|rejected, cancelled, unavailable| denied
|
||||
approval -.->|throw| normalized
|
||||
denied --> post
|
||||
pre -.->|throw| normalized
|
||||
toolBody --> fsGate
|
||||
fsGate --> toolBody
|
||||
toolBody --> owned
|
||||
toolBody --> around
|
||||
around --> post
|
||||
post --> final
|
||||
around -.->|wrapper throws| normalized
|
||||
post -.->|throw| normalized
|
||||
post --> finalize
|
||||
normalized --> finalize
|
||||
finalize --> final
|
||||
final --> toolResult
|
||||
toolResult --> presentResult
|
||||
toolResult --> allResults
|
||||
allResults --> context
|
||||
```
|
||||
|
||||
Filesystem read-before-edit checks stay below `tool-fs` on `fs/*` events. Generic pre/post waterfalls host hooks and approval policy; `ctx.approval` resolves asks before monotonic guards, and owner policy that must not be reordered remains a registered guard. Around-dispatch concerns such as timeouts wrap `tools/execute`, while `tools/result` observes the immutable outcome after transforms, lossless-JSON validation, and outer error normalization. This lets hooks span tool families without coupling the tools to one policy service. Code Mode sends both the reserved `run_code` transport and its serialized sub-calls through the pipeline; sub-calls carry the parent token, log `tool/code-dispatch`, surface denials as binding rejections, and omit `additionalContexts` to preserve call/result adjacency.
|
||||
Filesystem read-before-edit checks stay below `tool-fs` on `fs/*` events. Generic pre/post waterfalls host hooks and approval policy; `ctx.approval` resolves asks before monotonic guards, and owner policy that must not be reordered remains a registered guard. Around-dispatch concerns such as timeouts wrap `tools/execute`. The visible definition's snapshotted `finalizeContent` callback then enforces a synchronous content-only invariant across ordinary decisions and normalized pipeline failures before `tools/result` observes the immutable, lossless-JSON outcome. This lets hooks span tool families without coupling the tools to one policy service. Code Mode sends both the reserved `run_code` transport and its serialized sub-calls through the pipeline; sub-calls carry the parent token, log `tool/code-dispatch`, surface denials as binding rejections, and omit `additionalContexts` to preserve call/result adjacency.
|
||||
|
||||
Maintenance mode: curated Mermaid flow; exact tool schemas and event signatures live in generated catalogs.
|
||||
|
||||
Reference in New Issue
Block a user