fix(pty): close final review gaps

This commit is contained in:
Tianyi Cui
2026-07-23 02:53:43 +08:00
parent db68a90f41
commit 2821826e2c
35 changed files with 271 additions and 114 deletions

View File

@@ -1,7 +1,15 @@
/** Typed tool-parameter DSL with argument inference and JSON Schema output. @module dsh-tools/schema */
import { assertNever, HarnessError } from '@deepseek-ai/dsh-llm'
import type { ToolDefinition, ToolExecuteReturn, ToolRunContext, ToolResult } from './index.ts'
import type { ContentBlock } from '@deepseek-ai/dsh-llm'
import type {
ToolDefinition,
ToolExecuteReturn,
ToolExecution,
ToolExecutionResult,
ToolRunContext,
ToolResult,
} from './index.ts'
import type { ToolCallView, ToolResultView } from './presentation.ts'
// ---------------------------------------------------------------------------
@@ -294,6 +302,15 @@ export interface DefineToolOptions<S extends SchemaSpec> {
* presentation payload (see {@link ToolExecuteReturn}).
*/
execute(args: InferArgs<S>, exec: ToolRunContext): Promise<ToolExecuteReturn>
/**
* Optional last-mile content transform for every normalized outcome. Unlike
* `execute`, arguments remain `unknown` because invalid-input failures also
* reach this callback. See {@link ToolDefinition.finalizeContent}.
* @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
/**
* Optional: how to present the PENDING state of one call in a UI (an editor
* tool-call card, a CLI log line). `args` is the typed, schema-validated
@@ -317,7 +334,7 @@ export interface DefineToolOptions<S extends SchemaSpec> {
* inferred from its per-property schema. Raw JSON-Schema definitions remain
* valid inputs to {@link ToolRegistry.register}; this helper is authoring sugar.
* @param options - the tool's name, description, typed parameter schema,
* execute body, and optional presenters.
* execute body, and optional finalization/presentation callbacks.
* @returns a registry-ready definition with strict execution validation and
* soft presenter and classifier validation for replay compatibility.
*/
@@ -326,6 +343,8 @@ export function defineTool<S extends SchemaSpec>(options: DefineToolOptions<S>):
// eslint-disable-next-line @typescript-eslint/unbound-method
const userExecute = options.execute
// eslint-disable-next-line @typescript-eslint/unbound-method
const userFinalizeContent = options.finalizeContent
// eslint-disable-next-line @typescript-eslint/unbound-method
const userPresentCall = options.presentCall
// eslint-disable-next-line @typescript-eslint/unbound-method
const userPresentResult = options.presentResult
@@ -349,6 +368,9 @@ export function defineTool<S extends SchemaSpec>(options: DefineToolOptions<S>):
return userExecute(args as InferArgs<S>, exec)
},
}
if (userFinalizeContent) {
tool.finalizeContent = (exec, result) => userFinalizeContent(exec, result)
}
// Presentation is display-only and may run on REPLAY of arbitrary logged args
// (possibly from an older schema), so it must never throw: validate softly and
// fall back to `undefined` (a generic UI presentation) on any mismatch, rather