mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-23 10:45:33 -04:00
refactor: simplify canonical tool result seams
Review cleanups: dead imports, contentFrom happy-path flattening, codemodeTool shadow rename, call-site param naming for toModelOutput/toMetadata, spec Context fields matching the code, progress-metadata leniency comment, and PLAN.md marked implemented.
This commit is contained in:
@@ -2,9 +2,9 @@
|
||||
|
||||
## Status
|
||||
|
||||
This document describes the agreed target design for V2 tools. It is an implementation plan, not documentation for the current API.
|
||||
Implemented on this branch. This document is the historical plan kept for reviewer context; the authoritative semantic overview is [`specs/v2/tools.md`](../../../../specs/v2/tools.md), and where the two disagree the spec and code win. Delete this file at merge.
|
||||
|
||||
The current semantic overview remains in [`specs/v2/tools.md`](../../../../specs/v2/tools.md) until this plan is implemented. The plan's base is `origin/v2` at `b91dd78ab3`. Progress-event ephemerality already landed there (`5a9ed4d350`, `fix: make tool progress live-only`), including the failed-event partial snapshot this plan builds on. Delta-compressed progress is a later follow-up.
|
||||
The plan's base was `origin/v2` at `b91dd78ab3`. Progress-event ephemerality already landed there (`5a9ed4d350`, `fix: make tool progress live-only`), including the failed-event partial snapshot this plan builds on. Delta-compressed progress is a later follow-up.
|
||||
|
||||
## Reader And Job
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { FileSystem } from "../filesystem"
|
||||
import { FSUtil } from "@opencode-ai/util/fs-util"
|
||||
import { Location } from "../location"
|
||||
import { Ripgrep } from "../ripgrep"
|
||||
import { NonNegativeInt, RelativePath } from "../schema"
|
||||
import { RelativePath } from "../schema"
|
||||
import { PermissionV2 } from "../permission"
|
||||
import { Tool } from "./tool"
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { FSUtil } from "@opencode-ai/util/fs-util"
|
||||
import { Location } from "../location"
|
||||
import { PermissionV2 } from "../permission"
|
||||
import { Ripgrep } from "../ripgrep"
|
||||
import { NonNegativeInt, RelativePath } from "../schema"
|
||||
import { RelativePath } from "../schema"
|
||||
import { Tool } from "./tool"
|
||||
|
||||
export const name = "grep"
|
||||
|
||||
@@ -95,15 +95,12 @@ export type Definition<Input extends SchemaType<any>, Output extends SchemaType<
|
||||
* Optional model projection. Receives the typed domain output. When absent, an
|
||||
* encoded string becomes text and any other encoded JSON is serialized once.
|
||||
*/
|
||||
readonly toModelOutput?: (input: {
|
||||
readonly toModelOutput?: (call: {
|
||||
readonly input: InputValue<Input>
|
||||
readonly output: OutputValue<Output>
|
||||
}) => ModelOutput
|
||||
/** Optional compact UI metadata. Receives the typed domain output. Absent means absent: no defaults. */
|
||||
readonly toMetadata?: (input: {
|
||||
readonly input: InputValue<Input>
|
||||
readonly output: OutputValue<Output>
|
||||
}) => Metadata
|
||||
readonly toMetadata?: (call: { readonly input: InputValue<Input>; readonly output: OutputValue<Output> }) => Metadata
|
||||
}
|
||||
|
||||
/** A dynamic tool's split result: a machine value for Code Mode and content for the model. */
|
||||
|
||||
@@ -414,6 +414,9 @@ export namespace Tool {
|
||||
type: "session.tool.progress",
|
||||
schema: {
|
||||
...ToolBase,
|
||||
// Deliberately looser than terminal metadata (JSON-only): live snapshots
|
||||
// are ephemeral, and only the JSON-validated subset survives into a
|
||||
// durable failure snapshot.
|
||||
metadata: Schema.Record(Schema.String, Schema.Unknown),
|
||||
content: Schema.Array(ToolContent),
|
||||
},
|
||||
|
||||
+7
-8
@@ -34,14 +34,13 @@ Every local tool receives the same concrete invocation context:
|
||||
interface Tool.Context {
|
||||
readonly sessionID: Session.ID
|
||||
readonly agent: Agent.ID
|
||||
readonly assistantMessageID: SessionMessage.ID
|
||||
readonly toolCallID: string
|
||||
readonly messageID: SessionMessage.ID
|
||||
readonly callID: string
|
||||
readonly progress: (update: Progress) => Effect.Effect<void>
|
||||
}
|
||||
```
|
||||
|
||||
`assistantMessageID` is the durable ID of the assistant message containing the call. The Session runner owns this association and supplies the complete context to the registry; the registry does not infer it.
|
||||
|
||||
Durable events call the invocation identifier `callID`; `Tool.Context.toolCallID` is the same value at the executor boundary.
|
||||
`messageID` is the durable ID of the assistant message containing the call. The Session runner owns this association and supplies the complete context to the registry; the registry does not infer it. `callID` carries the same invocation identifier durable events use.
|
||||
|
||||
Decoded tool input is passed separately to `execute`. Raw provider input and domain services do not belong in the invocation context.
|
||||
|
||||
@@ -105,8 +104,8 @@ yield *
|
||||
agent: context.agent,
|
||||
source: {
|
||||
type: "tool",
|
||||
messageID: context.assistantMessageID,
|
||||
callID: context.toolCallID,
|
||||
messageID: context.messageID,
|
||||
callID: context.callID,
|
||||
},
|
||||
action: "grep",
|
||||
resources: [input.pattern],
|
||||
@@ -160,7 +159,7 @@ Outcomes remain distinct:
|
||||
- `ToolFailure` is an expected model-visible failure.
|
||||
- Interruption cancels the invocation and is not a tool result.
|
||||
- Unexpected typed errors and defects follow the runner's operational failure policy.
|
||||
- Unknown and invalid calls become explicit model-visible settlement errors without invoking a handler.
|
||||
- Unknown and invalid calls become explicit model-visible execution errors without invoking a handler.
|
||||
|
||||
Leaf tools translate only errors they deliberately classify as recoverable. Broad cause-catching around an executor is invalid because it consumes interruption and defects.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user