chore: generate

This commit is contained in:
opencode-agent[bot] 2026-06-09 18:30:51 +00:00
commit cc52dc396c
20 changed files with 221 additions and 169 deletions

View file

@ -147,10 +147,7 @@ function collectPaths<T>(
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<string>()

View file

@ -35,7 +35,10 @@ export interface Interface {
readonly normalize: (
resource: string,
content: FileSystem.Content & { readonly encoding: "base64" },
) => Effect.Effect<FileSystem.Content & { readonly encoding: "base64" }, ResizerUnavailableError | DecodeError | SizeError>
) => Effect.Effect<
FileSystem.Content & { readonly encoding: "base64" },
ResizerUnavailableError | DecodeError | SizeError
>
}
export class Service extends Context.Service<Service, Interface>()("@opencode/Image") {}

View file

@ -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 }
})

View file

@ -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"

View file

@ -53,16 +53,45 @@ export class ListPage extends Schema.Class<ListPage>("ReadTool.ListPage")({
export interface Interface {
readonly inspect: (path: AbsolutePath) => Effect.Effect<"file" | "directory">
readonly read: (path: AbsolutePath, resource: string, page?: PageInput) => Effect.Effect<FileSystem.Content | TextPage>
readonly read: (
path: AbsolutePath,
resource: string,
page?: PageInput,
) => Effect.Effect<FileSystem.Content | TextPage>
readonly list: (path: AbsolutePath, page?: PageInput) => Effect.Effect<ListPage>
}
export class Service extends Context.Service<Service, Interface>()("@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

View file

@ -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,

View file

@ -92,11 +92,10 @@ export function make<Input extends SchemaType<any>, Output extends SchemaType<an
),
),
),
Effect.map((output) =>
({
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<Input extends SchemaType<any>, Output extends SchemaType<an
mime: part.mime,
name: part.name,
},
) ?? (typeof output === "string" ? [{ type: "text" as const, text: output }] : []),
}),
),
) ?? (typeof output === "string" ? [{ type: "text" as const, text: output }] : []),
})),
),
),
),