From cc52dc396c5f25ebedac7ed93841b0250e309cbb Mon Sep 17 00:00:00 2001 From: "opencode-agent[bot]" Date: Tue, 9 Jun 2026 18:30:51 +0000 Subject: [PATCH] chore: generate --- packages/core/src/filesystem/search.ts | 5 +- packages/core/src/image.ts | 5 +- packages/core/src/location-search.ts | 3 +- .../src/session/runner/publish-llm-event.ts | 8 +- packages/core/src/tool/read-filesystem.ts | 52 ++++- packages/core/src/tool/read.ts | 6 +- packages/core/src/tool/tool.ts | 14 +- .../core/test/location-filesystem.test.ts | 16 +- packages/core/test/tool-glob.test.ts | 6 +- packages/core/test/tool-grep.test.ts | 6 +- packages/core/test/tool-read.test.ts | 9 +- .../llm/src/protocols/bedrock-converse.ts | 7 +- packages/llm/src/protocols/openai-chat.ts | 4 +- .../llm/test/provider/openai-chat.test.ts | 10 +- packages/llm/test/tool-runtime.test.ts | 20 +- packages/opencode/script/bench-search.ts | 4 +- packages/opencode/src/cli/cmd/debug/file.ts | 8 +- packages/opencode/src/session/processor.ts | 15 +- packages/sdk/openapi.json | 189 +++++++++++------- .../src/feature-plugins/system/session-v2.tsx | 3 +- 20 files changed, 221 insertions(+), 169 deletions(-) diff --git a/packages/core/src/filesystem/search.ts b/packages/core/src/filesystem/search.ts index ab6a488ca..8128bab8d 100644 --- a/packages/core/src/filesystem/search.ts +++ b/packages/core/src/filesystem/search.ts @@ -147,10 +147,7 @@ function collectPaths( return [{ ...result, score: scores[index]?.total ?? 0 }] }) rows.sort( - (a, b) => - b.score - a.score || - a.path.length - b.path.length || - (a.path < b.path ? -1 : a.path > b.path ? 1 : 0), + (a, b) => b.score - a.score || a.path.length - b.path.length || (a.path < b.path ? -1 : a.path > b.path ? 1 : 0), ) const seen = new Set() diff --git a/packages/core/src/image.ts b/packages/core/src/image.ts index 243aaaaec..9c69d6aeb 100644 --- a/packages/core/src/image.ts +++ b/packages/core/src/image.ts @@ -35,7 +35,10 @@ export interface Interface { readonly normalize: ( resource: string, content: FileSystem.Content & { readonly encoding: "base64" }, - ) => Effect.Effect + ) => Effect.Effect< + FileSystem.Content & { readonly encoding: "base64" }, + ResizerUnavailableError | DecodeError | SizeError + > } export class Service extends Context.Service()("@opencode/Image") {} diff --git a/packages/core/src/location-search.ts b/packages/core/src/location-search.ts index bdc6627dc..a23f3b60c 100644 --- a/packages/core/src/location-search.ts +++ b/packages/core/src/location-search.ts @@ -112,7 +112,8 @@ export const layer = Layer.effect( const root = yield* fs.realPath(directory).pipe(Effect.orDie) if (!FSUtil.contains(root, real)) return yield* Effect.die(new globalThis.Error("Path escapes the search root")) const info = yield* fs.stat(real).pipe(Effect.orDie) - const type = info.type === "File" ? ("file" as const) : info.type === "Directory" ? ("directory" as const) : undefined + const type = + info.type === "File" ? ("file" as const) : info.type === "Directory" ? ("directory" as const) : undefined if (!type) return yield* Effect.die(new globalThis.Error("Search root is not a file or directory")) return { real, root, resource: slash(path.relative(root, real)) || ".", type } }) diff --git a/packages/core/src/session/runner/publish-llm-event.ts b/packages/core/src/session/runner/publish-llm-event.ts index bd6507bd1..5390a26e3 100644 --- a/packages/core/src/session/runner/publish-llm-event.ts +++ b/packages/core/src/session/runner/publish-llm-event.ts @@ -1,10 +1,4 @@ -import { - ToolOutput, - type LLMEvent, - type ProviderMetadata, - type ToolResultValue, - type Usage, -} from "@opencode-ai/llm" +import { ToolOutput, type LLMEvent, type ProviderMetadata, type ToolResultValue, type Usage } from "@opencode-ai/llm" import { DateTime, Effect } from "effect" import { EventV2 } from "../../event" import { ModelV2 } from "../../model" diff --git a/packages/core/src/tool/read-filesystem.ts b/packages/core/src/tool/read-filesystem.ts index 8f2c0f5aa..fcfe2f4c9 100644 --- a/packages/core/src/tool/read-filesystem.ts +++ b/packages/core/src/tool/read-filesystem.ts @@ -53,16 +53,45 @@ export class ListPage extends Schema.Class("ReadTool.ListPage")({ export interface Interface { readonly inspect: (path: AbsolutePath) => Effect.Effect<"file" | "directory"> - readonly read: (path: AbsolutePath, resource: string, page?: PageInput) => Effect.Effect + readonly read: ( + path: AbsolutePath, + resource: string, + page?: PageInput, + ) => Effect.Effect readonly list: (path: AbsolutePath, page?: PageInput) => Effect.Effect } export class Service extends Context.Service()("@opencode/ReadToolFileSystem") {} const extensions = new Set([ - ".zip", ".tar", ".gz", ".exe", ".dll", ".so", ".class", ".jar", ".war", ".7z", ".doc", ".docx", - ".xls", ".xlsx", ".ppt", ".pptx", ".odt", ".ods", ".odp", ".bin", ".dat", ".obj", ".o", ".a", - ".lib", ".wasm", ".pyc", ".pyo", + ".zip", + ".tar", + ".gz", + ".exe", + ".dll", + ".so", + ".class", + ".jar", + ".war", + ".7z", + ".doc", + ".docx", + ".xls", + ".xlsx", + ".ppt", + ".pptx", + ".odt", + ".ods", + ".odp", + ".bin", + ".dat", + ".obj", + ".o", + ".a", + ".lib", + ".wasm", + ".pyc", + ".pyo", ]) const startsWith = (bytes: Uint8Array, prefix: number[]) => prefix.every((value, index) => bytes[index] === value) const imageMime = (bytes: Uint8Array) => { @@ -113,7 +142,9 @@ export const read = Effect.fn("ReadTool.read")(function* ( const chunks = [first] let total = first.length while (total <= MAX_MEDIA_INGEST_BYTES) { - const chunk = yield* file.readAlloc(Math.min(64 * 1024, MAX_MEDIA_INGEST_BYTES + 1 - total)).pipe(Effect.orDie) + const chunk = yield* file + .readAlloc(Math.min(64 * 1024, MAX_MEDIA_INGEST_BYTES + 1 - total)) + .pipe(Effect.orDie) if (Option.isNone(chunk)) break chunks.push(chunk.value) total += chunk.value.length @@ -123,7 +154,10 @@ export const read = Effect.fn("ReadTool.read")(function* ( return { uri: pathToFileURL(real).href, name: path.basename(real), - content: Buffer.concat(chunks.map((chunk) => Buffer.from(chunk)), total).toString("base64"), + content: Buffer.concat( + chunks.map((chunk) => Buffer.from(chunk)), + total, + ).toString("base64"), encoding: "base64" as const, mime, } @@ -226,11 +260,7 @@ export const read = Effect.fn("ReadTool.read")(function* ( ) }) -export const list = Effect.fn("ReadTool.list")(function* ( - fs: FSUtil.Interface, - input: string, - page: PageInput = {}, -) { +export const list = Effect.fn("ReadTool.list")(function* (fs: FSUtil.Interface, input: string, page: PageInput = {}) { const real = yield* fs.realPath(input).pipe(Effect.orDie) const items = yield* fs.readDirectoryEntries(real).pipe(Effect.orDie) const offset = page.offset ?? 1 diff --git a/packages/core/src/tool/read.ts b/packages/core/src/tool/read.ts index 95326aed8..64f02d813 100644 --- a/packages/core/src/tool/read.ts +++ b/packages/core/src/tool/read.ts @@ -59,7 +59,8 @@ export const layer = Layer.effectDiscard( return yield* Effect.die(new Error("Path escapes the allowed read root")) const real = yield* fs.realPath(absolute).pipe(Effect.orDie) const root = yield* fs.realPath(selected).pipe(Effect.orDie) - if (!FSUtil.contains(root, real)) return yield* Effect.die(new Error("Path escapes the allowed read root")) + if (!FSUtil.contains(root, real)) + return yield* Effect.die(new Error("Path escapes the allowed read root")) const resource = path.relative(root, real).replaceAll("\\", "/") || "." const target = AbsolutePath.make(real) const type = yield* reader.inspect(target) @@ -71,8 +72,7 @@ export const layer = Layer.effectDiscard( agent: context.agent, source: { type: "tool", messageID: context.assistantMessageID, callID: context.toolCallID }, }) - if (type === "directory") - return yield* reader.list(target, { offset: input.offset, limit: input.limit }) + if (type === "directory") return yield* reader.list(target, { offset: input.offset, limit: input.limit }) const content = yield* reader.read(target, resource, { offset: input.offset, limit: input.limit, diff --git a/packages/core/src/tool/tool.ts b/packages/core/src/tool/tool.ts index 803140e7d..eb70f2cb4 100644 --- a/packages/core/src/tool/tool.ts +++ b/packages/core/src/tool/tool.ts @@ -92,11 +92,10 @@ export function make, Output extends SchemaType - ({ - structured: output, - content: - config.toModelOutput?.({ input, output }).map((part) => + Effect.map((output) => ({ + structured: output, + content: + config.toModelOutput?.({ input, output }).map((part) => part.type === "text" ? { type: "text" as const, text: part.text } : { @@ -105,9 +104,8 @@ export function make, Output extends SchemaType { { path: RelativePath.make("src"), type: "directory", mime: "application/x-directory" }, { path: RelativePath.make("README.md"), type: "file", mime: "text/markdown" }, ]) - expect(yield* Effect.promise(() => Promise.all(entries.map((entry) => fs.realpath(fileURLToPath(entry.uri)))))).toEqual( - yield* Effect.promise(() => Promise.all([fs.realpath(path.join(directory, "src")), fs.realpath(path.join(directory, "README.md"))])), + expect( + yield* Effect.promise(() => Promise.all(entries.map((entry) => fs.realpath(fileURLToPath(entry.uri))))), + ).toEqual( + yield* Effect.promise(() => + Promise.all([fs.realpath(path.join(directory, "src")), fs.realpath(path.join(directory, "README.md"))]), + ), ) }).pipe(provide(directory)), ), @@ -84,12 +88,16 @@ describe("FileSystem", () => { withTmp((directory) => Effect.gen(function* () { const service = yield* FileSystem.Service - expect(Exit.isFailure(yield* service.read({ path: RelativePath.make("../outside.txt") }).pipe(Effect.exit))).toBe(true) + expect( + Exit.isFailure(yield* service.read({ path: RelativePath.make("../outside.txt") }).pipe(Effect.exit)), + ).toBe(true) if (process.platform === "win32") return const outside = `${directory}-outside.txt` yield* Effect.promise(() => fs.writeFile(outside, "outside")) yield* Effect.promise(() => fs.symlink(outside, path.join(directory, "link.txt"))) - expect(Exit.isFailure(yield* service.read({ path: RelativePath.make("link.txt") }).pipe(Effect.exit))).toBe(true) + expect(Exit.isFailure(yield* service.read({ path: RelativePath.make("link.txt") }).pipe(Effect.exit))).toBe( + true, + ) yield* Effect.promise(() => fs.rm(outside, { force: true })) }).pipe(provide(directory)), ), diff --git a/packages/core/test/tool-glob.test.ts b/packages/core/test/tool-glob.test.ts index 25e92a5ac..e323f18d2 100644 --- a/packages/core/test/tool-glob.test.ts +++ b/packages/core/test/tool-glob.test.ts @@ -43,11 +43,7 @@ const search = Layer.succeed( ) const registry = ToolRegistry.defaultLayer.pipe(Layer.provide(permission)) -const glob = GlobTool.layer.pipe( - Layer.provide(registry), - Layer.provide(permission), - Layer.provide(search), -) +const glob = GlobTool.layer.pipe(Layer.provide(registry), Layer.provide(permission), Layer.provide(search)) const it = testEffect(Layer.mergeAll(registry, permission, search, glob)) const reset = () => { diff --git a/packages/core/test/tool-grep.test.ts b/packages/core/test/tool-grep.test.ts index e09d1f652..38d9ec48f 100644 --- a/packages/core/test/tool-grep.test.ts +++ b/packages/core/test/tool-grep.test.ts @@ -54,11 +54,7 @@ const permission = Layer.succeed( }), ) const registry = ToolRegistry.defaultLayer.pipe(Layer.provide(permission)) -const grep = GrepTool.layer.pipe( - Layer.provide(registry), - Layer.provide(search), - Layer.provide(permission), -) +const grep = GrepTool.layer.pipe(Layer.provide(registry), Layer.provide(search), Layer.provide(permission)) const it = testEffect(Layer.mergeAll(registry, search, permission, grep)) const sessionID = SessionV2.ID.make("ses_grep_tool_test") diff --git a/packages/core/test/tool-read.test.ts b/packages/core/test/tool-read.test.ts index e8f2bf703..605a1e17d 100644 --- a/packages/core/test/tool-read.test.ts +++ b/packages/core/test/tool-read.test.ts @@ -37,10 +37,7 @@ let configEntries: Config.Entry[] = [] const reader = Layer.succeed( ReadToolFileSystem.Service, ReadToolFileSystem.Service.of({ - inspect: () => - resolveFailure === undefined - ? Effect.succeed(resolvedType) - : Effect.die(resolveFailure), + inspect: () => (resolveFailure === undefined ? Effect.succeed(resolvedType) : Effect.die(resolveFailure)), read: (input, _resource, page = {}) => { readCalls.push({ input, page }) if (readFailure !== undefined) return Effect.die(readFailure) @@ -73,9 +70,7 @@ const config = Layer.succeed(Config.Service, Config.Service.of({ entries: () => const image = Image.layer.pipe(Layer.provide(config)) const testFileSystem = Layer.effect( FSUtil.Service, - FSUtil.Service.use((fs) => - Effect.succeed(FSUtil.Service.of({ ...fs, realPath: (path) => Effect.succeed(path) })), - ), + FSUtil.Service.use((fs) => Effect.succeed(FSUtil.Service.of({ ...fs, realPath: (path) => Effect.succeed(path) }))), ).pipe(Layer.provide(FSUtil.defaultLayer)) const infrastructure = Layer.mergeAll( testFileSystem, diff --git a/packages/llm/src/protocols/bedrock-converse.ts b/packages/llm/src/protocols/bedrock-converse.ts index 4cd5f2c87..42dcaef54 100644 --- a/packages/llm/src/protocols/bedrock-converse.ts +++ b/packages/llm/src/protocols/bedrock-converse.ts @@ -269,7 +269,12 @@ const lowerToolResultContent = Effect.fn("BedrockConverse.lowerToolResultContent content.push({ text: item.text }) continue } - const media = yield* BedrockMedia.lower({ type: "media", mediaType: item.mime, data: item.uri, filename: item.name }) + const media = yield* BedrockMedia.lower({ + type: "media", + mediaType: item.mime, + data: item.uri, + filename: item.name, + }) if (!("image" in media)) return yield* ProviderShared.invalidRequest("Bedrock Converse only supports image media in tool results") content.push(media) diff --git a/packages/llm/src/protocols/openai-chat.ts b/packages/llm/src/protocols/openai-chat.ts index d4d16e8c9..e37eec95e 100644 --- a/packages/llm/src/protocols/openai-chat.ts +++ b/packages/llm/src/protocols/openai-chat.ts @@ -200,9 +200,7 @@ const lowerToolCall = (part: ToolCallPart): OpenAIChatAssistantToolCall => ({ }, }) -const lowerMedia = Effect.fn("OpenAIChat.lowerMedia")(function* ( - part: MediaPart, -) { +const lowerMedia = Effect.fn("OpenAIChat.lowerMedia")(function* (part: MediaPart) { const media = yield* ProviderShared.validateMedia("OpenAI Chat", part, IMAGE_MIMES) return { type: "image_url" as const, image_url: { url: media.dataUrl } } }) diff --git a/packages/llm/test/provider/openai-chat.test.ts b/packages/llm/test/provider/openai-chat.test.ts index 184015c58..9966b92e3 100644 --- a/packages/llm/test/provider/openai-chat.test.ts +++ b/packages/llm/test/provider/openai-chat.test.ts @@ -327,12 +327,18 @@ describe("OpenAI Chat route", () => { Message.tool({ id: "call_1", name: "read", - result: { type: "content", value: [{ type: "file", uri: "data:image/png;base64,AAEC", mime: "image/png" }] }, + result: { + type: "content", + value: [{ type: "file", uri: "data:image/png;base64,AAEC", mime: "image/png" }], + }, }), Message.tool({ id: "call_2", name: "read", - result: { type: "content", value: [{ type: "file", uri: "data:image/webp;base64,UklG", mime: "image/webp" }] }, + result: { + type: "content", + value: [{ type: "file", uri: "data:image/webp;base64,UklG", mime: "image/webp" }], + }, }), Message.system("Inspect both images."), ], diff --git a/packages/llm/test/tool-runtime.test.ts b/packages/llm/test/tool-runtime.test.ts index db5a67cee..c69456e42 100644 --- a/packages/llm/test/tool-runtime.test.ts +++ b/packages/llm/test/tool-runtime.test.ts @@ -241,16 +241,12 @@ describe("LLMClient tools", () => { uri: "data:image/png;base64,AAAA", mime: "image/png", }) - expect( - decode({ type: "file", uri: "https://example.test/image.png", mime: "image/png" }), - ).toEqual({ + expect(decode({ type: "file", uri: "https://example.test/image.png", mime: "image/png" })).toEqual({ type: "file", uri: "https://example.test/image.png", mime: "image/png", }) - expect( - decode({ type: "file", uri: "file:///tmp/image.png", mime: "image/png" }), - ).toEqual({ + expect(decode({ type: "file", uri: "file:///tmp/image.png", mime: "image/png" })).toEqual({ type: "file", uri: "file:///tmp/image.png", mime: "image/png", @@ -270,9 +266,7 @@ describe("LLMClient tools", () => { }) expect( ToolOutput.toResultValue( - ToolOutput.make({}, [ - { type: "file", uri: "https://example.test/image.png", mime: "image/png" }, - ]), + ToolOutput.make({}, [{ type: "file", uri: "https://example.test/image.png", mime: "image/png" }]), ), ).toEqual({ type: "content", @@ -280,9 +274,7 @@ describe("LLMClient tools", () => { }) expect( ToolOutput.toResultValue( - ToolOutput.make({}, [ - { type: "file", uri: "file:///tmp/image.png", mime: "image/png" }, - ]), + ToolOutput.make({}, [{ type: "file", uri: "file:///tmp/image.png", mime: "image/png" }]), ), ).toEqual({ type: "content", @@ -307,9 +299,7 @@ describe("LLMClient tools", () => { parameters: Schema.Struct({}), success: Schema.Struct({ ok: Schema.Boolean }), execute: () => Effect.succeed({ ok: true }), - toModelOutput: () => [ - { type: "file", uri: "https://example.test/image.png", mime: "image/png" }, - ], + toModelOutput: () => [{ type: "file", uri: "https://example.test/image.png", mime: "image/png" }], }) const dispatched = yield* ToolRuntime.dispatch( diff --git a/packages/opencode/script/bench-search.ts b/packages/opencode/script/bench-search.ts index 4e9ff4ce3..42afe7220 100644 --- a/packages/opencode/script/bench-search.ts +++ b/packages/opencode/script/bench-search.ts @@ -91,9 +91,7 @@ console.log("--- Search service (warm) ---") for (const q of FILE_QUERIES) { const t = performance.now() const r = await run(Search.Service.use((svc) => svc.file({ cwd: dir, query: q, limit: FILE_LIMIT }))) - console.log( - `[Search.file] "${q}": ${(performance.now() - t).toFixed(1)}ms (${r.length} results)`, - ) + console.log(`[Search.file] "${q}": ${(performance.now() - t).toFixed(1)}ms (${r.length} results)`) } for (const q of GREP_QUERIES) { diff --git a/packages/opencode/src/cli/cmd/debug/file.ts b/packages/opencode/src/cli/cmd/debug/file.ts index d36aa4824..afbcf69ad 100644 --- a/packages/opencode/src/cli/cmd/debug/file.ts +++ b/packages/opencode/src/cli/cmd/debug/file.ts @@ -38,9 +38,7 @@ const FileReadCommand = effectCmd({ description: "File path to read", }), handler: Effect.fn("Cli.debug.file.read")(function* (args) { - const content = yield* filesystem( - FileSystem.Service.use((svc) => svc.read({ path: RelativePath.make(args.path) })), - ) + const content = yield* filesystem(FileSystem.Service.use((svc) => svc.read({ path: RelativePath.make(args.path) }))) process.stdout.write(JSON.stringify(content, null, 2) + EOL) }), }) @@ -55,9 +53,7 @@ const FileListCommand = effectCmd({ description: "File path to list", }), handler: Effect.fn("Cli.debug.file.list")(function* (args) { - const files = yield* filesystem( - FileSystem.Service.use((svc) => svc.list({ path: RelativePath.make(args.path) })), - ) + const files = yield* filesystem(FileSystem.Service.use((svc) => svc.list({ path: RelativePath.make(args.path) }))) process.stdout.write(JSON.stringify(files, null, 2) + EOL) }), }) diff --git a/packages/opencode/src/session/processor.ts b/packages/opencode/src/session/processor.ts index 79f486cbb..2a19f393b 100644 --- a/packages/opencode/src/session/processor.ts +++ b/packages/opencode/src/session/processor.ts @@ -595,13 +595,14 @@ export const layer = Layer.effect( const assistantMessageID = yield* requireV2AssistantMessage(toolCall?.call) const content = [ { type: "text" as const, text: output.output }, - ...(output.attachments?.map((item: SessionV1.FilePart) => - ({ - type: "file", - uri: item.url, - mime: item.mime, - name: item.filename, - }) as const, + ...(output.attachments?.map( + (item: SessionV1.FilePart) => + ({ + type: "file", + uri: item.url, + mime: item.mime, + name: item.filename, + }) as const, ) ?? []), ] const unsupported = content.find((item) => item.type === "file" && !item.uri.startsWith("data:")) diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index 3c0f536cb..540bafe0b 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -11371,14 +11371,7 @@ "$ref": "#/components/schemas/LocationInfo" }, "data": { - "anyOf": [ - { - "$ref": "#/components/schemas/FileSystemTextContent" - }, - { - "$ref": "#/components/schemas/FileSystemBinaryContent" - } - ] + "$ref": "#/components/schemas/FileSystemContent" } }, "required": ["location", "data"], @@ -11507,6 +11500,112 @@ ] } }, + "/api/fs/find": { + "get": { + "tags": ["filesystem"], + "operationId": "v2.fs.find", + "parameters": [ + { + "name": "location", + "in": "query", + "schema": { + "type": "object", + "properties": { + "directory": { + "type": "string" + }, + "workspace": { + "type": "string" + } + }, + "additionalProperties": false + }, + "required": false, + "style": "deepObject", + "explode": true + }, + { + "name": "query", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "type", + "in": "query", + "schema": { + "type": "string", + "enum": ["file", "directory"] + }, + "required": false + }, + { + "name": "limit", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + } + ], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "location": { + "$ref": "#/components/schemas/LocationInfo" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileSystemEntry" + } + } + }, + "required": ["location", "data"], + "additionalProperties": false + } + } + } + }, + "400": { + "description": "InvalidRequestError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequestError" + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedError" + } + } + } + } + }, + "description": "Find recursively ranked filesystem entries relative to the requested location.", + "summary": "Find files", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.fs.find({\n ...\n})" + } + ] + } + }, "/api/command": { "get": { "tags": ["commands"], @@ -21492,51 +21591,8 @@ "type": "string", "enum": ["file"] }, - "source": { - "anyOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": ["data"] - }, - "data": { - "type": "string" - } - }, - "required": ["type", "data"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": ["url"] - }, - "url": { - "type": "string" - } - }, - "required": ["type", "url"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": ["file"] - }, - "uri": { - "type": "string" - } - }, - "required": ["type", "uri"], - "additionalProperties": false - } - ] + "uri": { + "type": "string" }, "mime": { "type": "string" @@ -21545,7 +21601,7 @@ "type": "string" } }, - "required": ["type", "source", "mime"], + "required": ["type", "uri", "mime"], "additionalProperties": false }, "SessionNextRetry_error": { @@ -24986,42 +25042,27 @@ "required": ["id", "projectID", "action", "resource"], "additionalProperties": false }, - "FileSystemTextContent": { + "FileSystemContent": { "type": "object", "properties": { - "type": { - "type": "string", - "enum": ["text"] - }, - "content": { + "uri": { "type": "string" }, - "mime": { + "name": { "type": "string" - } - }, - "required": ["type", "content", "mime"], - "additionalProperties": false - }, - "FileSystemBinaryContent": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": ["binary"] }, "content": { "type": "string" }, "encoding": { "type": "string", - "enum": ["base64"] + "enum": ["utf8", "base64"] }, "mime": { "type": "string" } }, - "required": ["type", "content", "encoding", "mime"], + "required": ["uri", "content", "encoding", "mime"], "additionalProperties": false }, "FileSystemEntry": { diff --git a/packages/tui/src/feature-plugins/system/session-v2.tsx b/packages/tui/src/feature-plugins/system/session-v2.tsx index d95c49fff..8a03ec5dd 100644 --- a/packages/tui/src/feature-plugins/system/session-v2.tsx +++ b/packages/tui/src/feature-plugins/system/session-v2.tsx @@ -1073,8 +1073,7 @@ function toolOutput(content?: Array) { return (content ?? []) .map((item) => { if (item.type === "text") return item.text.trim() - const source = - item.uri + const source = item.uri return `[file ${item.name ?? source}]` }) .filter(Boolean)