diff --git a/packages/opencode/src/permission/index.ts b/packages/opencode/src/permission/index.ts index 98f9c3ff..b84081ae 100644 --- a/packages/opencode/src/permission/index.ts +++ b/packages/opencode/src/permission/index.ts @@ -62,7 +62,7 @@ export namespace Permission { async (state) => { for (const pending of Object.values(state.pending)) { for (const item of Object.values(pending)) { - item.reject(new RejectedError(item.info.sessionID, item.info.id, item.info.callID)) + item.reject(new RejectedError(item.info.sessionID, item.info.id, item.info.callID, item.info.metadata)) } } }, @@ -105,7 +105,7 @@ export namespace Permission { }).then((x) => x.status) ) { case "deny": - throw new RejectedError(info.sessionID, info.id, info.callID) + throw new RejectedError(info.sessionID, info.id, info.callID, info.metadata) case "allow": return } @@ -131,7 +131,7 @@ export namespace Permission { if (!match) return delete pending[input.sessionID][input.permissionID] if (input.response === "reject") { - match.reject(new RejectedError(input.sessionID, input.permissionID, match.info.callID)) + match.reject(new RejectedError(input.sessionID, input.permissionID, match.info.callID, match.info.metadata)) return } match.resolve() @@ -156,6 +156,7 @@ export namespace Permission { public readonly sessionID: string, public readonly permissionID: string, public readonly toolCallID?: string, + public readonly metadata?: Record, ) { super(`The user rejected permission to use this specific tool call. You may try again with different parameters.`) } diff --git a/packages/opencode/src/session/index.ts b/packages/opencode/src/session/index.ts index 741f965f..843b1f02 100644 --- a/packages/opencode/src/session/index.ts +++ b/packages/opencode/src/session/index.ts @@ -1268,6 +1268,7 @@ export namespace Session { status: "error", input: value.input, error: (value.error as any).toString(), + metadata: value.error instanceof Permission.RejectedError ? value.error.metadata : undefined, time: { start: match.state.time.start, end: Date.now(), diff --git a/packages/opencode/src/session/message-v2.ts b/packages/opencode/src/session/message-v2.ts index 6fabd521..be09d31d 100644 --- a/packages/opencode/src/session/message-v2.ts +++ b/packages/opencode/src/session/message-v2.ts @@ -64,6 +64,7 @@ export namespace MessageV2 { status: z.literal("error"), input: z.record(z.any()), error: z.string(), + metadata: z.record(z.any()).optional(), time: z.object({ start: z.number(), end: z.number(), diff --git a/packages/sdk/go/session.go b/packages/sdk/go/session.go index 76a9d46f..c6f197a7 100644 --- a/packages/sdk/go/session.go +++ b/packages/sdk/go/session.go @@ -2023,17 +2023,19 @@ func (r toolStateCompletedTimeJSON) RawJSON() string { } type ToolStateError struct { - Error string `json:"error,required"` - Input map[string]interface{} `json:"input,required"` - Status ToolStateErrorStatus `json:"status,required"` - Time ToolStateErrorTime `json:"time,required"` - JSON toolStateErrorJSON `json:"-"` + Error string `json:"error,required"` + Input map[string]interface{} `json:"input,required"` + Metadata map[string]interface{} `json:"metadata"` + Status ToolStateErrorStatus `json:"status,required"` + Time ToolStateErrorTime `json:"time,required"` + JSON toolStateErrorJSON `json:"-"` } // toolStateErrorJSON contains the JSON metadata for the struct [ToolStateError] type toolStateErrorJSON struct { Error apijson.Field Input apijson.Field + Metadata apijson.Field Status apijson.Field Time apijson.Field raw string diff --git a/packages/sdk/js/src/gen/types.gen.ts b/packages/sdk/js/src/gen/types.gen.ts index 59294057..dbd69bcb 100644 --- a/packages/sdk/js/src/gen/types.gen.ts +++ b/packages/sdk/js/src/gen/types.gen.ts @@ -347,6 +347,9 @@ export type ToolStateError = { input: { [key: string]: unknown } + metadata: { + [key: string]: unknown + } error: string time: { start: number diff --git a/packages/tui/internal/components/chat/message.go b/packages/tui/internal/components/chat/message.go index 188dfee8..c72ad6e2 100644 --- a/packages/tui/internal/components/chat/message.go +++ b/packages/tui/internal/components/chat/message.go @@ -554,6 +554,17 @@ func renderToolDetails( title := renderToolTitle(toolCall, width) title = style.Render(title) content := title + "\n" + body + + if toolCall.State.Status == opencode.ToolPartStateStatusError { + errorStyle := styles.NewStyle(). + Background(backgroundColor). + Foreground(t.Error()). + Padding(1, 2). + Width(width - 4) + errorContent := errorStyle.Render(toolCall.State.Error) + content += "\n" + errorContent + } + if permissionContent != "" { permissionContent = styles.NewStyle(). Background(backgroundColor). @@ -652,11 +663,17 @@ func renderToolDetails( } if error != "" { - body = styles.NewStyle(). + errorContent := styles.NewStyle(). Width(width - 6). Foreground(t.Error()). Background(backgroundColor). Render(error) + + if body == "" { + body = errorContent + } else { + body += "\n\n" + errorContent + } } if body == "" && error == "" && result != nil {