diff --git a/packages/opencode/src/session/index.ts b/packages/opencode/src/session/index.ts index ebe18ac4..97ea5db4 100644 --- a/packages/opencode/src/session/index.ts +++ b/packages/opencode/src/session/index.ts @@ -552,7 +552,7 @@ export namespace Session { await updateMessage(next) return step }, - toolCallStreaming: true, + toolCallStreaming: false, abortSignal: abort.signal, stopWhen: stepCountIs(1000), messages: convertToModelMessages(msgs), diff --git a/packages/opencode/src/session/message.ts b/packages/opencode/src/session/message.ts index 190cbd7b..a5b56cc8 100644 --- a/packages/opencode/src/session/message.ts +++ b/packages/opencode/src/session/message.ts @@ -147,7 +147,18 @@ export namespace Message { ]) .optional(), sessionID: z.string(), - tool: z.record(z.string(), z.any()), + tool: z.record( + z.string(), + z + .object({ + title: z.string().optional(), + time: z.object({ + start: z.number(), + end: z.number(), + }), + }) + .catchall(z.any()), + ), assistant: z .object({ modelID: z.string(), diff --git a/packages/opencode/src/tool/bash.ts b/packages/opencode/src/tool/bash.ts index d87332bb..e2502fa1 100644 --- a/packages/opencode/src/tool/bash.ts +++ b/packages/opencode/src/tool/bash.ts @@ -64,6 +64,7 @@ export const BashTool = Tool.define({ stderr, stdout, description: params.description, + title: params.command, }, output: stdout.replaceAll(/\x1b\[[0-9;]*m/g, ""), } diff --git a/packages/opencode/src/tool/edit.ts b/packages/opencode/src/tool/edit.ts index c00a3a11..78e29e28 100644 --- a/packages/opencode/src/tool/edit.ts +++ b/packages/opencode/src/tool/edit.ts @@ -6,6 +6,7 @@ import { LSP } from "../lsp" import { createTwoFilesPatch } from "diff" import { Permission } from "../permission" import DESCRIPTION from "./edit.txt" +import { App } from "../app/app" export const EditTool = Tool.define({ id: "opencode.edit", @@ -28,9 +29,10 @@ export const EditTool = Tool.define({ throw new Error("filePath is required") } + const app = App.info() const filepath = path.isAbsolute(params.filePath) ? params.filePath - : path.join(process.cwd(), params.filePath) + : path.join(app.path.cwd, params.filePath) await Permission.ask({ id: "opencode.edit", @@ -105,6 +107,7 @@ export const EditTool = Tool.define({ metadata: { diagnostics, diff, + title: `${path.relative(app.path.root, filepath)}`, }, output, } diff --git a/packages/opencode/src/tool/tool.ts b/packages/opencode/src/tool/tool.ts index f046e95b..b573f758 100644 --- a/packages/opencode/src/tool/tool.ts +++ b/packages/opencode/src/tool/tool.ts @@ -1,13 +1,17 @@ import type { StandardSchemaV1 } from "@standard-schema/spec" export namespace Tool { + interface Metadata { + title: string + [key: string]: any + } export type Context = { sessionID: string abort: AbortSignal } export interface Info< Parameters extends StandardSchemaV1 = StandardSchemaV1, - Metadata extends Record = Record, + M extends Metadata = Metadata, > { id: string description: string @@ -16,14 +20,14 @@ export namespace Tool { args: StandardSchemaV1.InferOutput, ctx: Context, ): Promise<{ - metadata: Metadata + metadata: M output: string }> } export function define< Parameters extends StandardSchemaV1, - Result extends Record, + Result extends Metadata, >(input: Info): Info { return input } diff --git a/packages/opencode/src/tool/webfetch.ts b/packages/opencode/src/tool/webfetch.ts index 55190898..0c7f2e62 100644 --- a/packages/opencode/src/tool/webfetch.ts +++ b/packages/opencode/src/tool/webfetch.ts @@ -72,26 +72,57 @@ export const WebFetchTool = Tool.define({ const content = new TextDecoder().decode(arrayBuffer) const contentType = response.headers.get("content-type") || "" + const title = `${params.url} (${contentType})` switch (params.format) { case "text": if (contentType.includes("text/html")) { const text = extractTextFromHTML(content) - return { output: text, metadata: {} } + return { + output: text, + metadata: { + title, + }, + } + } + return { + output: content, + metadata: { + title, + }, } - return { output: content, metadata: {} } case "markdown": if (contentType.includes("text/html")) { const markdown = convertHTMLToMarkdown(content) - return { output: markdown, metadata: {} } + return { + output: markdown, + metadata: { + title, + }, + } + } + return { + output: "```\n" + content + "\n```", + metadata: { + title, + }, } - return { output: "```\n" + content + "\n```", metadata: {} } case "html": - return { output: content, metadata: {} } + return { + output: content, + metadata: { + title, + }, + } default: - return { output: content, metadata: {} } + return { + output: content, + metadata: { + title, + }, + } } }, })