diff --git a/packages/cli/bin/lildax.cjs b/packages/cli/bin/lildax.cjs index e3491f3a436..1b84ed76312 100644 --- a/packages/cli/bin/lildax.cjs +++ b/packages/cli/bin/lildax.cjs @@ -88,8 +88,17 @@ const names = (() => { return false } })() - if (musl) return arch === "x64" ? (baseline ? [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base] : [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]) : [`${base}-musl`, base] - return arch === "x64" ? (baseline ? [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`] : [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]) : [base, `${base}-musl`] + if (musl) + return arch === "x64" + ? baseline + ? [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base] + : [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`] + : [`${base}-musl`, base] + return arch === "x64" + ? baseline + ? [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`] + : [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`] + : [base, `${base}-musl`] } return arch === "x64" ? (baseline ? [`${base}-baseline`, base] : [base, `${base}-baseline`]) : [base] })() @@ -98,10 +107,11 @@ function findBinary(startDir) { let current = startDir for (;;) { const modules = path.join(current, "node_modules") - if (fs.existsSync(modules)) for (const name of names) { - const candidate = path.join(modules, name, "bin", binary) - if (fs.existsSync(candidate)) return candidate - } + if (fs.existsSync(modules)) + for (const name of names) { + const candidate = path.join(modules, name, "bin", binary) + if (fs.existsSync(candidate)) return candidate + } const parent = path.dirname(current) if (parent === current) return current = parent @@ -110,7 +120,11 @@ function findBinary(startDir) { const resolved = envPath || (fs.existsSync(cached) ? cached : findBinary(scriptDir)) if (!resolved) { - console.error("It seems that your package manager failed to install the right lildax CLI package. Try manually installing " + names.map((name) => `"${name}"`).join(" or ") + " package") + console.error( + "It seems that your package manager failed to install the right lildax CLI package. Try manually installing " + + names.map((name) => `"${name}"`).join(" or ") + + " package", + ) process.exit(1) } run(resolved) diff --git a/packages/cli/script/publish.ts b/packages/cli/script/publish.ts index 5c2ca591f97..b828d948196 100644 --- a/packages/cli/script/publish.ts +++ b/packages/cli/script/publish.ts @@ -44,5 +44,9 @@ await Bun.file(`./dist/${pkg.name}/package.json`).write( ), ) -await Promise.all(Object.entries(binaries).map(([name, version]) => publish(`./dist/${name.replace("@opencode-ai/", "")}`, name, version))) +await Promise.all( + Object.entries(binaries).map(([name, version]) => + publish(`./dist/${name.replace("@opencode-ai/", "")}`, name, version), + ), +) await publish(`./dist/${pkg.name}`, pkg.name, version) diff --git a/packages/cli/src/framework/runtime.ts b/packages/cli/src/framework/runtime.ts index eee9ff795b4..4ea94d764ec 100644 --- a/packages/cli/src/framework/runtime.ts +++ b/packages/cli/src/framework/runtime.ts @@ -11,7 +11,9 @@ export type Input = : never type RuntimeHandler = (input: unknown) => Effect.Effect -type Loader = () => Promise<{ default: (input: Input) => Effect.Effect }> +type Loader = () => Promise<{ + default: (input: Input) => Effect.Effect +}> type ProvidedCommand = Command.Command export type Handlers = keyof Node["commands"] extends never diff --git a/packages/cli/src/services/daemon.ts b/packages/cli/src/services/daemon.ts index 8500add61a4..58c56ac4f0c 100644 --- a/packages/cli/src/services/daemon.ts +++ b/packages/cli/src/services/daemon.ts @@ -125,11 +125,9 @@ export const layer = Layer.effect( const register = Effect.fn("cli.daemon.register")(function* (address: HttpServer.Address) { const temp = file + ".tmp" yield* fs.makeDirectory(directory, { recursive: true }) - yield* fs.writeFileString( - temp, - JSON.stringify({ url: HttpServer.formatAddress(address), pid: process.pid }), - { mode: 0o600 }, - ) + yield* fs.writeFileString(temp, JSON.stringify({ url: HttpServer.formatAddress(address), pid: process.pid }), { + mode: 0o600, + }) yield* fs.rename(temp, file) // The metadata file represents this live listener, not persistent config. // Scope shutdown removes it when the server exits normally. diff --git a/packages/core/migration/20260603040000_session_message_projection_order/migration.sql b/packages/core/migration/20260603040000_session_message_projection_order/migration.sql index a56b07b6761..dbec67f277c 100644 --- a/packages/core/migration/20260603040000_session_message_projection_order/migration.sql +++ b/packages/core/migration/20260603040000_session_message_projection_order/migration.sql @@ -1,3 +1,4 @@ +DELETE FROM `session_message`;--> statement-breakpoint ALTER TABLE `session_message` ADD `seq` integer NOT NULL;--> statement-breakpoint DROP INDEX IF EXISTS `session_message_session_time_created_id_idx`;--> statement-breakpoint DROP INDEX IF EXISTS `session_message_session_type_time_created_id_idx`;--> statement-breakpoint diff --git a/packages/core/src/config/plugin/command.ts b/packages/core/src/config/plugin/command.ts index d9055295452..fdc01773b36 100644 --- a/packages/core/src/config/plugin/command.ts +++ b/packages/core/src/config/plugin/command.ts @@ -19,12 +19,14 @@ export const Plugin = PluginV2.define({ const config = yield* Config.Service const fs = yield* FSUtil.Service const transform = yield* command.transform() - const documents = yield* Effect.forEach(yield* config.entries(), (entry) => { - if (entry.type === "document") return Effect.succeed([{ commands: entry.info.commands }]) - return loadDirectory(fs, entry.path).pipe( - Effect.map((commands) => [{ commands: Object.fromEntries(commands.map((command) => [command.name, command.info])) }]), - ) - }).pipe(Effect.map((documents) => documents.flat())) + const documents = yield* Effect.forEach(yield* config.entries(), (entry) => { + if (entry.type === "document") return Effect.succeed([{ commands: entry.info.commands }]) + return loadDirectory(fs, entry.path).pipe( + Effect.map((commands) => [ + { commands: Object.fromEntries(commands.map((command) => [command.name, command.info])) }, + ]), + ) + }).pipe(Effect.map((documents) => documents.flat())) yield* transform((editor) => { for (const document of documents) { diff --git a/packages/core/src/config/plugin/skill.ts b/packages/core/src/config/plugin/skill.ts index c4c4b6c0fd5..30b7a882766 100644 --- a/packages/core/src/config/plugin/skill.ts +++ b/packages/core/src/config/plugin/skill.ts @@ -23,8 +23,12 @@ export const Plugin = PluginV2.define({ yield* transform((editor) => { for (const directory of directories) { - editor.source(new SkillV2.DirectorySource({ type: "directory", path: AbsolutePath.make(path.join(directory, "skill")) })) - editor.source(new SkillV2.DirectorySource({ type: "directory", path: AbsolutePath.make(path.join(directory, "skills")) })) + editor.source( + new SkillV2.DirectorySource({ type: "directory", path: AbsolutePath.make(path.join(directory, "skill")) }), + ) + editor.source( + new SkillV2.DirectorySource({ type: "directory", path: AbsolutePath.make(path.join(directory, "skills")) }), + ) } for (const item of items) { if (URL.canParse(item) && /^(https?:)$/.test(new URL(item).protocol)) { diff --git a/packages/core/src/database/migration/20260603040000_session_message_projection_order.ts b/packages/core/src/database/migration/20260603040000_session_message_projection_order.ts index bb539d93d2d..1f3a43bcced 100644 --- a/packages/core/src/database/migration/20260603040000_session_message_projection_order.ts +++ b/packages/core/src/database/migration/20260603040000_session_message_projection_order.ts @@ -5,16 +5,10 @@ export default { id: "20260603040000_session_message_projection_order", up(tx) { return Effect.gen(function* () { - yield* tx.run(`ALTER TABLE \`session_message\` ADD COLUMN \`seq\` integer NOT NULL DEFAULT 0;`) - yield* tx.run( - `UPDATE \`session_message\` SET \`seq\` = COALESCE((SELECT \`seq\` + 1 FROM \`event\` WHERE \`event\`.\`id\` = \`session_message\`.\`id\`), 0);`, - ) - const unmatched = yield* tx.get<{ count: number }>( - `SELECT COUNT(*) AS \`count\` FROM \`session_message\` WHERE \`seq\` = 0;`, - ) - if ((unmatched?.count ?? 0) > 0) - return yield* Effect.die("Cannot migrate session_message projections without matching durable events") - yield* tx.run(`UPDATE \`session_message\` SET \`seq\` = \`seq\` - 1;`) + // Pre-launch Session projections were written before durable event persistence + // became unconditional, so they cannot be assigned truthful aggregate order. + yield* tx.run(`DELETE FROM \`session_message\`;`) + yield* tx.run(`ALTER TABLE \`session_message\` ADD COLUMN \`seq\` integer NOT NULL;`) yield* tx.run(`DROP INDEX IF EXISTS \`session_message_session_type_time_created_id_idx\`;`) yield* tx.run(`CREATE INDEX \`session_message_session_seq_idx\` ON \`session_message\` (\`session_id\`,\`seq\`);`) yield* tx.run( diff --git a/packages/core/src/plugin/skill.ts b/packages/core/src/plugin/skill.ts index c3e226f740e..ba4c5b639cc 100644 --- a/packages/core/src/plugin/skill.ts +++ b/packages/core/src/plugin/skill.ts @@ -10,7 +10,9 @@ export const Plugin = PluginV2.define({ effect: Effect.gen(function* () { const skill = yield* SkillV2.Service const transform = yield* skill.transform() - const content = yield* Effect.promise(() => Bun.file(new URL("./skill/customize-opencode.md", import.meta.url)).text()) + const content = yield* Effect.promise(() => + Bun.file(new URL("./skill/customize-opencode.md", import.meta.url)).text(), + ) yield* transform((editor) => { editor.source( diff --git a/packages/core/src/skill.ts b/packages/core/src/skill.ts index 0f1978653e0..daf9046fe7c 100644 --- a/packages/core/src/skill.ts +++ b/packages/core/src/skill.ts @@ -37,7 +37,11 @@ export const Source = Schema.Union([DirectorySource, UrlSource, EmbeddedSource]) return false }, key: (source: DirectorySource | UrlSource | EmbeddedSource) => - source.type === "directory" ? `directory:${source.path}` : source.type === "url" ? `url:${source.url}` : `embedded:${source.skill.name}`, + source.type === "directory" + ? `directory:${source.path}` + : source.type === "url" + ? `url:${source.url}` + : `embedded:${source.skill.name}`, })), ) export type Source = typeof Source.Type diff --git a/packages/core/test/database-migration.test.ts b/packages/core/test/database-migration.test.ts index 0a3ce9ef574..4c0ccb9832b 100644 --- a/packages/core/test/database-migration.test.ts +++ b/packages/core/test/database-migration.test.ts @@ -79,13 +79,20 @@ describe("DatabaseMigration", () => { ) }) - test("backfills projected Session message order from durable event sequence", async () => { + test("resets incompatible projected Session messages before adding sequence order", async () => { await run( Effect.gen(function* () { const db = yield* makeDb + yield* db.run(sql`CREATE TABLE session (id text PRIMARY KEY)`) + yield* db.run( + sql`CREATE TABLE message (id text PRIMARY KEY, session_id text NOT NULL, time_created integer NOT NULL, time_updated integer NOT NULL, data text NOT NULL)`, + ) + yield* db.run( + sql`CREATE TABLE part (id text PRIMARY KEY, message_id text NOT NULL, session_id text NOT NULL, time_created integer NOT NULL, time_updated integer NOT NULL, data text NOT NULL)`, + ) yield* db.run(sql`CREATE TABLE event (id text PRIMARY KEY, seq integer NOT NULL)`) yield* db.run( - sql`CREATE TABLE session_message (id text PRIMARY KEY, session_id text NOT NULL, type text NOT NULL, time_created integer NOT NULL, data text NOT NULL)`, + sql`CREATE TABLE session_message (id text PRIMARY KEY, session_id text NOT NULL, type text NOT NULL, time_created integer NOT NULL, time_updated integer NOT NULL, data text NOT NULL)`, ) yield* db.run( sql`CREATE INDEX session_message_session_time_created_id_idx ON session_message (session_id, time_created, id)`, @@ -93,40 +100,40 @@ describe("DatabaseMigration", () => { yield* db.run( sql`CREATE INDEX session_message_session_type_time_created_id_idx ON session_message (session_id, type, time_created, id)`, ) - yield* db.run(sql`INSERT INTO event (id, seq) VALUES ('evt_z', 0), ('evt_a', 1)`) + yield* db.run(sql`INSERT INTO session (id) VALUES ('session')`) yield* db.run( - sql`INSERT INTO session_message (id, session_id, type, time_created, data) VALUES ('evt_z', 'session', 'user', 0, '{}'), ('evt_a', 'session', 'user', 0, '{}')`, + sql`INSERT INTO message (id, session_id, time_created, time_updated, data) VALUES ('legacy_message', 'session', 1, 1, '{"role":"user"}')`, + ) + yield* db.run( + sql`INSERT INTO part (id, message_id, session_id, time_created, time_updated, data) VALUES ('legacy_part', 'legacy_message', 'session', 1, 1, '{"type":"text","text":"hello"}')`, + ) + yield* db.run( + sql`INSERT INTO session_message (id, session_id, type, time_created, time_updated, data) VALUES ('stale_projection', 'session', 'user', 1, 1, '{}')`, ) yield* DatabaseMigration.applyOnly(db, [sessionMessageProjectionOrderMigration]) - expect(yield* db.all(sql`SELECT id, seq FROM session_message ORDER BY seq`)).toEqual([ - { id: "evt_z", seq: 0 }, - { id: "evt_a", seq: 1 }, + expect(yield* db.all(sql`SELECT id, session_id, data FROM message`)).toEqual([ + { id: "legacy_message", session_id: "session", data: '{"role":"user"}' }, ]) + expect(yield* db.all(sql`SELECT id, message_id, session_id, data FROM part`)).toEqual([ + { + id: "legacy_part", + message_id: "legacy_message", + session_id: "session", + data: '{"type":"text","text":"hello"}', + }, + ]) + expect(yield* db.all(sql`SELECT id FROM session_message`)).toEqual([]) + + yield* db.run( + sql`INSERT INTO session_message (id, session_id, type, seq, time_created, time_updated, data) VALUES ('fresh_projection', 'session', 'user', 7, 2, 2, '{}')`, + ) + expect(yield* db.get(sql`SELECT id, seq FROM session_message`)).toEqual({ id: "fresh_projection", seq: 7 }) }), ) }) - test("fails projected Session message order backfill without a durable event", async () => { - await expect( - run( - Effect.gen(function* () { - const db = yield* makeDb - yield* db.run(sql`CREATE TABLE event (id text PRIMARY KEY, seq integer NOT NULL)`) - yield* db.run( - sql`CREATE TABLE session_message (id text PRIMARY KEY, session_id text NOT NULL, type text NOT NULL, time_created integer NOT NULL, data text NOT NULL)`, - ) - yield* db.run( - sql`INSERT INTO session_message (id, session_id, type, time_created, data) VALUES ('evt_missing', 'session', 'user', 0, '{}')`, - ) - - yield* DatabaseMigration.applyOnly(db, [sessionMessageProjectionOrderMigration]) - }), - ), - ).rejects.toThrow("Cannot migrate session_message projections without matching durable events") - }) - test("runs session usage backfill in order with schema changes", async () => { await run( Effect.gen(function* () { diff --git a/packages/core/test/plugin/command.test.ts b/packages/core/test/plugin/command.test.ts index f1136ee8112..099e1825185 100644 --- a/packages/core/test/plugin/command.test.ts +++ b/packages/core/test/plugin/command.test.ts @@ -12,10 +12,7 @@ const project = AbsolutePath.make("/repo") const it = testEffect( CommandV2.locationLayer.pipe( Layer.provide( - Layer.succeed( - Location.Service, - Location.Service.of(location({ directory }, { projectDirectory: project })), - ), + Layer.succeed(Location.Service, Location.Service.of(location({ directory }, { projectDirectory: project }))), ), ), ) @@ -26,7 +23,10 @@ describe("CommandPlugin.Plugin", () => { const command = yield* CommandV2.Service yield* CommandPlugin.Plugin.effect.pipe( Effect.provideService(CommandV2.Service, command), - Effect.provideService(Location.Service, Location.Service.of(location({ directory }, { projectDirectory: project }))), + Effect.provideService( + Location.Service, + Location.Service.of(location({ directory }, { projectDirectory: project })), + ), ) expect(yield* command.get("init")).toMatchObject({ diff --git a/packages/opencode/src/acp/event.ts b/packages/opencode/src/acp/event.ts index df105d6acf7..05b8b77b370 100644 --- a/packages/opencode/src/acp/event.ts +++ b/packages/opencode/src/acp/event.ts @@ -12,6 +12,7 @@ import type { import { Effect } from "effect" import { ACPSession } from "./session" import { ACPPermission } from "./permission" +import { partsToContentChunks, type ReplayPart } from "./content" import { duplicateRunningToolUpdate, errorToolUpdate, @@ -87,7 +88,31 @@ export class Subscription { await this.recordFetchedPart(message.info.sessionID, message, part) if (part.type === "tool") { await this.handleToolPart(message.info.sessionID, part) + continue } + await this.replayContentPart(message, part) + } + } + + private async replayContentPart(message: SessionMessageResponse, part: Part) { + if (part.type !== "text" && part.type !== "file" && part.type !== "reasoning") return + + const sessionUpdate = + part.type === "reasoning" + ? "agent_thought_chunk" + : message.info.role === "user" + ? "user_message_chunk" + : "agent_message_chunk" + + for (const chunk of partsToContentChunks([part as ReplayPart])) { + await this.input.connection.sessionUpdate({ + sessionId: message.info.sessionID, + update: { + sessionUpdate, + messageId: message.info.id, + ...chunk, + }, + }) } } diff --git a/packages/opencode/src/cli/cmd/tui/feature-plugins/session/dialog.tsx b/packages/opencode/src/cli/cmd/tui/feature-plugins/session/dialog.tsx index 816546b868c..d91045cc67d 100644 --- a/packages/opencode/src/cli/cmd/tui/feature-plugins/session/dialog.tsx +++ b/packages/opencode/src/cli/cmd/tui/feature-plugins/session/dialog.tsx @@ -8,7 +8,8 @@ import { useSDK } from "@tui/context/sdk" import { useLocal } from "@tui/context/local" import { useToast } from "@tui/ui/toast" import { useCommandShortcut } from "@tui/keymap" -import { createEffect, createMemo, createResource, createSignal, on, onMount, untrack } from "solid-js" +import { createEffect, createMemo, createResource, createSignal, on, Show, untrack } from "solid-js" +import { useTerminalDimensions } from "@opentui/solid" import { Spinner } from "@tui/component/spinner" import { DialogSessionRename } from "@tui/component/dialog-session-rename" import { DialogSessionDeleteFailed } from "@tui/component/dialog-session-delete-failed" @@ -31,6 +32,7 @@ export function SessionSwitcherDialog() { const sdk = useSDK() const local = useLocal() const toast = useToast() + const dimensions = useTerminalDimensions() const [toDelete, setToDelete] = createSignal() const [search, setSearch] = createDebouncedSignal("", 150) const deleteHint = useCommandShortcut("session.delete") @@ -151,11 +153,6 @@ export function SessionSwitcherDialog() { if (!first || !last) return undefined return quickSwitchRange(first, last) }) - const quickSwitchFooterHints = createMemo(() => { - const hint = quickSwitchHint() - return hint && local.session.slots().length > 0 ? [{ title: "switch", label: hint }] : [] - }) - const options = createMemo[]>(() => { const today = new Date().toDateString() const sessionMap = new Map( @@ -183,10 +180,18 @@ export function SessionSwitcherDialog() { const status = sync.data.session_status?.[x.id] const isWorking = status?.type === "busy" || status?.type === "retry" const slot = slotByID.get(x.id) - const gutter = isWorking - ? () => - : slot !== undefined - ? () => {slot} + const gutter = + slot !== undefined || isWorking + ? () => ( + + + {slot} + + + + + + ) : undefined const titleText = isDeleting ? `Press ${deleteHint()} again to confirm` : isWorktree ? `⎇ ${x.title}` : x.title return { @@ -194,6 +199,17 @@ export function SessionSwitcherDialog() { bg: isDeleting ? theme.error : undefined, value: x.id, category, + categoryView: + category === "Pinned" ? ( + + + Pinned + + + {(hint) => · switch {hint()}} + + + ) : undefined, footer, gutter, } @@ -224,8 +240,11 @@ export function SessionSwitcherDialog() { }), ) - onMount(() => { - dialog.setSize("xlarge") + const showPreview = createMemo(() => dimensions().width >= 100) + const height = createMemo(() => Math.max(8, Math.floor(dimensions().height / 2) - 4)) + + createEffect(() => { + dialog.setSize(showPreview() ? "xlarge" : "large") }) const list = ( @@ -253,6 +272,7 @@ export function SessionSwitcherDialog() { title: "pin/unpin", onTrigger: (option: { value: string }) => { local.session.togglePin(option.value) + queueMicrotask(() => select?.moveTo(option.value)) }, }, { @@ -311,19 +331,20 @@ export function SessionSwitcherDialog() { }, }, ]} - footerHints={quickSwitchFooterHints()} /> ) return ( - - + + {list} - - - - + + + + + + ) } diff --git a/packages/opencode/src/cli/cmd/tui/feature-plugins/session/preview-pane.tsx b/packages/opencode/src/cli/cmd/tui/feature-plugins/session/preview-pane.tsx index 8e75745a6c3..18141ef08e9 100644 --- a/packages/opencode/src/cli/cmd/tui/feature-plugins/session/preview-pane.tsx +++ b/packages/opencode/src/cli/cmd/tui/feature-plugins/session/preview-pane.tsx @@ -1,14 +1,14 @@ import { createResource, Show, createMemo, createSignal, onMount, type Accessor, type JSX } from "solid-js" -import { TextAttributes, type RGBA } from "@opentui/core" +import { TextAttributes } from "@opentui/core" import { useTerminalDimensions } from "@opentui/solid" import { debounce, leadingAndTrailing } from "@solid-primitives/scheduled" -import type { Message, Part, Session as SdkSession, SnapshotFileDiff } from "@opencode-ai/sdk/v2" +import type { Message, Part, Session as SdkSession } from "@opencode-ai/sdk/v2" import { useTheme } from "@tui/context/theme" import { useSDK } from "@tui/context/sdk" import { useSync } from "@tui/context/sync" import { Locale } from "@/util/locale" import { Spinner } from "@tui/component/spinner" -import { extractMessageMarkdown, extractMessageText, formatDiffSummary, relativeTime, shortModelLabel } from "./util" +import { extractMessageMarkdown, extractMessageText, relativeTime } from "./util" type WithParts = { info: Message; parts: Part[] } @@ -16,7 +16,6 @@ type Sdk = ReturnType type Sync = ReturnType const messageCache = new Map>() -const diffCache = new Map>() function cacheKey(sessionID: string, version: number) { return `${sessionID}:${version}` @@ -36,41 +35,21 @@ function loadMessages(sdk: Sdk, sessionID: string, version: number): Promise { - if (res.error) messageCache.delete(key) + if (res.error) throw res.error return (res.data as WithParts[] | undefined) ?? [] }) - .catch(() => { + .catch((error) => { messageCache.delete(key) - return [] as WithParts[] + throw error }) messageCache.set(key, promise) return promise } -function loadDiff(sdk: Sdk, sessionID: string, version: number): Promise { - const key = cacheKey(sessionID, version) - const cached = diffCache.get(key) - if (cached) return cached - - const promise = sdk.client.session - .diff({ sessionID }) - .then((res) => { - if (res.error) diffCache.delete(key) - return (res.data as SnapshotFileDiff[] | undefined) ?? [] - }) - .catch(() => { - diffCache.delete(key) - return [] as SnapshotFileDiff[] - }) - diffCache.set(key, promise) - return promise -} - export function prefetchPreviews(sdk: Sdk, sync: Sync, sessionIDs: readonly string[]) { for (const id of sessionIDs) { const version = sync.data.session.find((session) => session.id === id)?.time.updated ?? 0 if (!hydrateFromSync(sync, id)) loadMessages(sdk, id, version).catch(() => {}) - if (!sync.data.session_diff[id]?.length) loadDiff(sdk, id, version).catch(() => {}) } } @@ -121,13 +100,6 @@ export function SessionPreviewPane(props: { return hydrateFromSync(sync, id) }) - const syncedDiff = createMemo(() => { - const id = props.sessionID() - if (!id) return undefined - const diff = sync.data.session_diff[id] - return diff && diff.length > 0 ? (diff as SnapshotFileDiff[]) : undefined - }) - const [fetchedMessages] = createResource( () => { const id = props.sessionID() @@ -137,31 +109,7 @@ export function SessionPreviewPane(props: { async (input) => loadMessages(sdk, input.sessionID, input.version), ) - const [fetchedDiff] = createResource( - () => { - const id = props.sessionID() - if (!id || syncedDiff()) return undefined - return { sessionID: id, version: session()?.time.updated ?? 0 } - }, - async (input) => loadDiff(sdk, input.sessionID, input.version), - ) - const messages = createMemo(() => syncedMessages() ?? fetchedMessages() ?? []) - const diff = createMemo(() => syncedDiff() ?? fetchedDiff() ?? []) - - const diffSummary = createMemo(() => { - const live = diff() - if (live && live.length > 0) { - let additions = 0 - let deletions = 0 - for (const file of live) { - additions += file.additions ?? 0 - deletions += file.deletions ?? 0 - } - return formatDiffSummary({ additions, deletions, files: live.length }) - } - return formatDiffSummary(session()?.summary) - }) const exchange = createMemo(() => { const items = messages() @@ -174,13 +122,13 @@ export function SessionPreviewPane(props: { return { user, assistant } }) - const loading = createMemo(() => (fetchedMessages.loading || fetchedDiff.loading) && !exchange()) + const loading = createMemo(() => fetchedMessages.loading && !exchange()) const statusLabel = createMemo(() => { const s = status() - if (s === "busy") return { text: "working", color: theme.warning } - if (s === "retry") return { text: "retrying", color: theme.warning } - return { text: "idle", color: theme.textMuted } + if (s === "busy") return "working" + if (s === "retry") return "retrying" + return "idle" }) return ( @@ -191,7 +139,7 @@ export function SessionPreviewPane(props: { paddingTop={1} paddingBottom={1} gap={1} - maxHeight={maxHeight()} + height={maxHeight()} overflow="hidden" > {(s) => ( <> -
+
loading preview... @@ -213,7 +161,7 @@ export function SessionPreviewPane(props: { fallback={ - No messages yet + {fetchedMessages.error ? "Preview unavailable" : "No messages yet"} } @@ -241,24 +189,12 @@ function messageParentID(item: WithParts) { const ROW_WIDTH = 40 -function Header(props: { - session: SdkSession - statusLabel: { text: string; color: RGBA } - diff: { additions: number; deletions: number; files: number } | undefined -}) { +function Header(props: { session: SdkSession; statusLabel: string }) { const { theme } = useTheme() const title = createMemo(() => Locale.truncate(props.session.title, ROW_WIDTH)) - const modelAgent = createMemo(() => { - const m = shortModelLabel(props.session.model) - const a = props.session.agent ?? "" - if (m && a) return Locale.truncate(`${m} · ${a}`, ROW_WIDTH) - if (m) return Locale.truncate(m, ROW_WIDTH) - if (a) return Locale.truncate(a, ROW_WIDTH) - return "" - }) const statusRest = createMemo(() => { const joined = ` · ${relativeTime(props.session.time.updated)}` - return Locale.truncate(joined, Math.max(0, ROW_WIDTH - props.statusLabel.text.length)) + return Locale.truncate(joined, Math.max(0, ROW_WIDTH - props.statusLabel.length)) }) return ( @@ -268,20 +204,12 @@ function Header(props: { {title()} - - - - {modelAgent()} - - - - {props.statusLabel.text} + {props.statusLabel} {statusRest()} - {(d) => } ) } @@ -294,28 +222,6 @@ function Row(props: { height: number; children: JSX.Element }) { ) } -function DiffRow(props: { diff: { additions: number; deletions: number; files: number } }) { - const { theme } = useTheme() - const showAdds = () => props.diff.additions > 0 - const showDels = () => props.diff.deletions > 0 - if (!showAdds() && !showDels()) return null - return ( - - - - +{props.diff.additions} - - - - - - −{props.diff.deletions} - - - - ) -} - const PROMPT_MAX_CHARS = 240 const REPLY_MAX_LINES = 12 const REPLY_MAX_CHARS = 800 diff --git a/packages/opencode/src/cli/cmd/tui/feature-plugins/session/util.tsx b/packages/opencode/src/cli/cmd/tui/feature-plugins/session/util.tsx index 4323602ab73..d4d6f6d18a3 100644 --- a/packages/opencode/src/cli/cmd/tui/feature-plugins/session/util.tsx +++ b/packages/opencode/src/cli/cmd/tui/feature-plugins/session/util.tsx @@ -52,19 +52,3 @@ function collectTextParts(parts: readonly Part[]): string[] { } return chunks } - -export function formatDiffSummary( - summary: { additions: number; deletions: number; files: number } | undefined, -): { additions: number; deletions: number; files: number } | undefined { - if (!summary) return undefined - if (!summary.additions && !summary.deletions && !summary.files) return undefined - return summary -} - -export function shortModelLabel(model: { id: string; providerID?: string; variant?: string } | undefined): string { - if (!model) return "" - const id = model.id ?? "" - const stripped = - model.providerID && id.startsWith(`${model.providerID}/`) ? id.slice(model.providerID.length + 1) : id - return model.variant ? `${stripped} (${model.variant})` : stripped -} diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx index 464615e4863..ec4cc750c6d 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx @@ -66,6 +66,7 @@ export type DialogSelectRef = { filter: string filtered: DialogSelectOption[] selected: DialogSelectOption | undefined + moveTo(value: T): void } export function DialogSelect(props: DialogSelectProps) { @@ -341,6 +342,10 @@ export function DialogSelect(props: DialogSelectProps) { get selected() { return selected() }, + moveTo(value) { + const index = flat().findIndex((option) => isDeepEqual(option.value, value)) + if (index >= 0) moveTo(index, true) + }, } props.ref?.(ref) @@ -551,7 +556,7 @@ function Option(props: { ● - + {props.gutter?.()} diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index db881113856..8522432dff3 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -1017,20 +1017,14 @@ export type Error = ModelNotFoundError | InitError | NoProvidersError | NoModels export interface Interface { readonly list: () => Effect.Effect> readonly getProvider: (providerID: ProviderV2.ID) => Effect.Effect - readonly getModel: ( - providerID: ProviderV2.ID, - modelID: ModelV2.ID, - ) => Effect.Effect + readonly getModel: (providerID: ProviderV2.ID, modelID: ModelV2.ID) => Effect.Effect readonly getLanguage: (model: Model) => Effect.Effect readonly closest: ( providerID: ProviderV2.ID, query: string[], ) => Effect.Effect<{ providerID: ProviderV2.ID; modelID: string } | undefined> readonly getSmallModel: (providerID: ProviderV2.ID) => Effect.Effect - readonly defaultModel: () => Effect.Effect< - { providerID: ProviderV2.ID; modelID: ModelV2.ID }, - DefaultModelError - > + readonly defaultModel: () => Effect.Effect<{ providerID: ProviderV2.ID; modelID: ModelV2.ID }, DefaultModelError> } interface State { diff --git a/packages/opencode/src/server/routes/instance/httpapi/server.ts b/packages/opencode/src/server/routes/instance/httpapi/server.ts index 1ce65cb8f90..e3b097ec830 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/server.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/server.ts @@ -192,7 +192,15 @@ type RouteRequirements = export function createRoutes( corsOptions?: CorsOptions, ): Layer.Layer { - return Layer.mergeAll(rootApiRoutes, eventApiRoutes, ptyConnectApiRoutes, instanceRoutes, v2Routes, docRoute, uiRoute).pipe( + return Layer.mergeAll( + rootApiRoutes, + eventApiRoutes, + ptyConnectApiRoutes, + instanceRoutes, + v2Routes, + docRoute, + uiRoute, + ).pipe( Layer.provide([ errorLayer, compressionLayer, diff --git a/packages/opencode/src/session/session.ts b/packages/opencode/src/session/session.ts index 7e4e4fd4df1..c0f6488ae21 100644 --- a/packages/opencode/src/session/session.ts +++ b/packages/opencode/src/session/session.ts @@ -574,10 +574,7 @@ export const layer: Layer.Layer< } log.info("created", result) - yield* events.publish( - SessionV1.Event.Created, - { sessionID: result.id, info: result }, - ) + yield* events.publish(SessionV1.Event.Created, { sessionID: result.id, info: result }) return result }) @@ -664,10 +661,7 @@ export const layer: Layer.Layer< yield* remove(child.id) } - yield* events.publish( - SessionV1.Event.Deleted, - { sessionID, info: session }, - ) + yield* events.publish(SessionV1.Event.Deleted, { sessionID, info: session }) yield* events.remove(sessionID) } catch (e) { log.error(e) @@ -682,14 +676,11 @@ export const layer: Layer.Layer< const updatePart = (part: T): Effect.Effect => Effect.gen(function* () { - yield* events.publish( - SessionV1.Event.PartUpdated, - { - sessionID: part.sessionID, - part: structuredClone(part), - time: Date.now(), - }, - ) + yield* events.publish(SessionV1.Event.PartUpdated, { + sessionID: part.sessionID, + part: structuredClone(part), + time: Date.now(), + }) return part }).pipe(Effect.withSpan("Session.updatePart")) @@ -892,13 +883,10 @@ export const layer: Layer.Layer< sessionID: SessionID messageID: MessageID }) { - yield* events.publish( - SessionV1.Event.MessageRemoved, - { - sessionID: input.sessionID, - messageID: input.messageID, - }, - ) + yield* events.publish(SessionV1.Event.MessageRemoved, { + sessionID: input.sessionID, + messageID: input.messageID, + }) return input.messageID }) @@ -907,14 +895,11 @@ export const layer: Layer.Layer< messageID: MessageID partID: PartID }) { - yield* events.publish( - SessionV1.Event.PartRemoved, - { - sessionID: input.sessionID, - messageID: input.messageID, - partID: input.partID, - }, - ) + yield* events.publish(SessionV1.Event.PartRemoved, { + sessionID: input.sessionID, + messageID: input.messageID, + partID: input.partID, + }) return input.partID }) diff --git a/packages/opencode/test/acp/service-session.test.ts b/packages/opencode/test/acp/service-session.test.ts index 2a189293ece..890719072ab 100644 --- a/packages/opencode/test/acp/service-session.test.ts +++ b/packages/opencode/test/acp/service-session.test.ts @@ -316,6 +316,46 @@ describe("ACP service sessions", () => { expect(result.configOptions?.find((option) => option.id === "mode")?.currentValue).toBe("plan") }) + it("replays loaded session transcript chunks", async () => { + const { service, updates } = makeService([ + { + info: { id: "msg_user", sessionID: "ses_loaded", role: "user" }, + parts: [{ id: "part_user", sessionID: "ses_loaded", messageID: "msg_user", type: "text", text: "hello" }], + }, + { + info: { id: "msg_assistant", sessionID: "ses_loaded", role: "assistant" }, + parts: [ + { + id: "part_assistant", + sessionID: "ses_loaded", + messageID: "msg_assistant", + type: "text", + text: "hi there", + }, + ], + }, + ]) + + await Effect.runPromise(service.loadSession({ cwd: "/workspace", sessionId: "ses_loaded", mcpServers: [] })) + + expect( + updates + .map((item) => item.update) + .filter((item) => item.sessionUpdate === "user_message_chunk" || item.sessionUpdate === "agent_message_chunk"), + ).toEqual([ + { + sessionUpdate: "user_message_chunk", + messageId: "msg_user", + content: { type: "text", text: "hello" }, + }, + { + sessionUpdate: "agent_message_chunk", + messageId: "msg_assistant", + content: { type: "text", text: "hi there" }, + }, + ]) + }) + it("lists sessions sorted by updated time with cursor support", async () => { const { service } = makeService() const first = await Effect.runPromise(service.listSessions({ cwd: "/workspace" })) diff --git a/packages/opencode/test/provider/provider.test.ts b/packages/opencode/test/provider/provider.test.ts index aac08f26270..6edfc97ca06 100644 --- a/packages/opencode/test/provider/provider.test.ts +++ b/packages/opencode/test/provider/provider.test.ts @@ -980,14 +980,8 @@ it.instance( it.instance("getModel returns consistent results", () => Effect.gen(function* () { yield* set("ANTHROPIC_API_KEY", "test-api-key") - const model1 = yield* Provider.use.getModel( - ProviderV2.ID.anthropic, - ModelV2.ID.make("claude-sonnet-4-20250514"), - ) - const model2 = yield* Provider.use.getModel( - ProviderV2.ID.anthropic, - ModelV2.ID.make("claude-sonnet-4-20250514"), - ) + const model1 = yield* Provider.use.getModel(ProviderV2.ID.anthropic, ModelV2.ID.make("claude-sonnet-4-20250514")) + const model2 = yield* Provider.use.getModel(ProviderV2.ID.anthropic, ModelV2.ID.make("claude-sonnet-4-20250514")) expect(model1.providerID).toEqual(model2.providerID) expect(model1.id).toEqual(model2.id) expect(model1).toEqual(model2) diff --git a/packages/opencode/test/server/httpapi-v2-location.test.ts b/packages/opencode/test/server/httpapi-v2-location.test.ts index 481e05b1cbb..f8677c239a0 100644 --- a/packages/opencode/test/server/httpapi-v2-location.test.ts +++ b/packages/opencode/test/server/httpapi-v2-location.test.ts @@ -57,7 +57,10 @@ describe("v2 location HttpApi", () => { for (const route of ["/api/command", "/api/skill"]) { const response = await request(route, tmp.path) expect(response.status).toBe(200) - const body = (await response.json()) as { location: { directory: string; project: { id: string } }; data: unknown } + const body = (await response.json()) as { + location: { directory: string; project: { id: string } } + data: unknown + } expect(body.data).toBeArray() expect(body.location.directory).toBe(tmp.path) expect(body.location.project.id).toBeTruthy() diff --git a/packages/opencode/test/session/llm.test.ts b/packages/opencode/test/session/llm.test.ts index 6644599f434..0c5dadaf17d 100644 --- a/packages/opencode/test/session/llm.test.ts +++ b/packages/opencode/test/session/llm.test.ts @@ -1671,10 +1671,7 @@ describe("session.llm.stream", () => { ] const request = waitRequest("/messages", createEventResponse(chunks)) - const resolved = yield* Provider.use.getModel( - ProviderV2.ID.make("anthropic"), - ModelV2.ID.make(model.id), - ) + const resolved = yield* Provider.use.getModel(ProviderV2.ID.make("anthropic"), ModelV2.ID.make(model.id)) const sessionID = SessionID.make("session-test-anthropic-tools") const agent = { name: "test", diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index a8236b7f6f3..51eb2121d6e 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -8395,1671 +8395,6 @@ ] } }, - "/api/session": { - "get": { - "tags": ["v2"], - "operationId": "v2.session.list", - "parameters": [ - { - "name": "workspace", - "in": "query", - "schema": { - "type": "string", - "pattern": "^wrk" - }, - "required": false - }, - { - "name": "limit", - "in": "query", - "schema": { - "type": "number" - }, - "required": false - }, - { - "name": "order", - "in": "query", - "schema": { - "type": "string", - "enum": ["asc", "desc"] - }, - "required": false - }, - { - "name": "search", - "in": "query", - "schema": { - "type": "string" - }, - "required": false - }, - { - "name": "directory", - "in": "query", - "schema": { - "type": "string" - }, - "required": false - }, - { - "name": "project", - "in": "query", - "schema": { - "type": "string" - }, - "required": false - }, - { - "name": "subpath", - "in": "query", - "schema": { - "type": "string" - }, - "required": false - }, - { - "name": "cursor", - "in": "query", - "schema": { - "type": "string", - "description": "Opaque pagination cursor returned as cursor.previous or cursor.next in the previous response." - }, - "required": false - } - ], - "security": [], - "responses": { - "200": { - "description": "V2SessionsResponse", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/V2SessionsResponse" - } - } - } - }, - "400": { - "description": "InvalidCursorError | InvalidRequestError", - "content": { - "application/json": { - "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidCursorError" - }, - { - "$ref": "#/components/schemas/InvalidRequestError" - }, - { - "$ref": "#/components/schemas/InvalidRequestError" - } - ] - } - } - } - }, - "401": { - "description": "UnauthorizedError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnauthorizedError" - } - } - } - } - }, - "description": "Retrieve sessions in the requested order. Items keep that order across pages; use cursor.next or cursor.previous to move through the ordered list.", - "summary": "List v2 sessions", - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.session.list({\n ...\n})" - } - ] - } - }, - "/api/session/{sessionID}/prompt": { - "post": { - "tags": ["v2"], - "operationId": "v2.session.prompt", - "parameters": [ - { - "name": "sessionID", - "in": "path", - "schema": { - "type": "string", - "pattern": "^ses" - }, - "required": true - }, - { - "name": "directory", - "in": "query", - "schema": { - "type": "string" - }, - "required": false - }, - { - "name": "workspace", - "in": "query", - "schema": { - "type": "string" - }, - "required": false - } - ], - "security": [], - "responses": { - "200": { - "description": "Session.Message.User", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SessionMessageUser" - } - } - } - }, - "400": { - "description": "InvalidRequestError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequestError" - } - } - } - }, - "401": { - "description": "UnauthorizedError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnauthorizedError" - } - } - } - }, - "404": { - "description": "SessionNotFoundError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SessionNotFoundError" - } - } - } - }, - "409": { - "description": "ConflictError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ConflictError" - } - } - } - } - }, - "description": "Durably admit one v2 session input and schedule agent-loop execution unless resume is false.", - "summary": "Send v2 message", - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "prompt": { - "$ref": "#/components/schemas/Prompt" - }, - "delivery": { - "type": "string", - "enum": ["steer", "queue"] - }, - "resume": { - "type": "boolean" - } - }, - "required": ["prompt"], - "additionalProperties": false - } - } - }, - "required": true - }, - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.session.prompt({\n ...\n})" - } - ] - } - }, - "/api/session/{sessionID}/compact": { - "post": { - "tags": ["v2"], - "operationId": "v2.session.compact", - "parameters": [ - { - "name": "sessionID", - "in": "path", - "schema": { - "type": "string", - "pattern": "^ses" - }, - "required": true - }, - { - "name": "directory", - "in": "query", - "schema": { - "type": "string" - }, - "required": false - }, - { - "name": "workspace", - "in": "query", - "schema": { - "type": "string" - }, - "required": false - } - ], - "security": [], - "responses": { - "204": { - "description": "" - }, - "400": { - "description": "InvalidRequestError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequestError" - } - } - } - }, - "401": { - "description": "UnauthorizedError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnauthorizedError" - } - } - } - }, - "404": { - "description": "SessionNotFoundError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SessionNotFoundError" - } - } - } - }, - "503": { - "description": "ServiceUnavailableError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ServiceUnavailableError" - } - } - } - } - }, - "description": "Compact a v2 session conversation.", - "summary": "Compact v2 session", - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.session.compact({\n ...\n})" - } - ] - } - }, - "/api/session/{sessionID}/wait": { - "post": { - "tags": ["v2"], - "operationId": "v2.session.wait", - "parameters": [ - { - "name": "sessionID", - "in": "path", - "schema": { - "type": "string", - "pattern": "^ses" - }, - "required": true - }, - { - "name": "directory", - "in": "query", - "schema": { - "type": "string" - }, - "required": false - }, - { - "name": "workspace", - "in": "query", - "schema": { - "type": "string" - }, - "required": false - } - ], - "security": [], - "responses": { - "204": { - "description": "" - }, - "400": { - "description": "InvalidRequestError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequestError" - } - } - } - }, - "401": { - "description": "UnauthorizedError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnauthorizedError" - } - } - } - }, - "404": { - "description": "SessionNotFoundError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SessionNotFoundError" - } - } - } - }, - "503": { - "description": "ServiceUnavailableError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ServiceUnavailableError" - } - } - } - } - }, - "description": "Wait for a v2 session agent loop to become idle.", - "summary": "Wait for v2 session", - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.session.wait({\n ...\n})" - } - ] - } - }, - "/api/session/{sessionID}/context": { - "get": { - "tags": ["v2"], - "operationId": "v2.session.context", - "parameters": [ - { - "name": "sessionID", - "in": "path", - "schema": { - "type": "string", - "pattern": "^ses" - }, - "required": true - }, - { - "name": "directory", - "in": "query", - "schema": { - "type": "string" - }, - "required": false - }, - { - "name": "workspace", - "in": "query", - "schema": { - "type": "string" - }, - "required": false - } - ], - "security": [], - "responses": { - "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SessionMessage" - } - } - } - } - }, - "400": { - "description": "InvalidRequestError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequestError" - } - } - } - }, - "401": { - "description": "UnauthorizedError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnauthorizedError" - } - } - } - }, - "404": { - "description": "SessionNotFoundError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SessionNotFoundError" - } - } - } - }, - "500": { - "description": "UnknownError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnknownError1" - } - } - } - } - }, - "description": "Retrieve the active context messages for a v2 session (all messages after the last compaction).", - "summary": "Get v2 session context", - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.session.context({\n ...\n})" - } - ] - } - }, - "/api/session/{sessionID}/message": { - "get": { - "tags": ["v2 messages"], - "operationId": "v2.session.messages", - "parameters": [ - { - "name": "sessionID", - "in": "path", - "schema": { - "type": "string", - "pattern": "^ses" - }, - "required": true - }, - { - "name": "directory", - "in": "query", - "schema": { - "type": "string" - }, - "required": false - }, - { - "name": "workspace", - "in": "query", - "schema": { - "type": "string" - }, - "required": false - }, - { - "name": "limit", - "in": "query", - "schema": { - "type": "number" - }, - "required": false - }, - { - "name": "order", - "in": "query", - "schema": { - "type": "string", - "enum": ["asc", "desc"] - }, - "required": false - }, - { - "name": "cursor", - "in": "query", - "schema": { - "type": "string", - "description": "Opaque pagination cursor returned as cursor.previous or cursor.next in the previous response. Do not combine with order." - }, - "required": false - } - ], - "security": [], - "responses": { - "200": { - "description": "V2SessionMessagesResponse", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/V2SessionMessagesResponse" - } - } - } - }, - "400": { - "description": "InvalidCursorError | InvalidRequestError", - "content": { - "application/json": { - "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidCursorError" - }, - { - "$ref": "#/components/schemas/InvalidRequestError" - } - ] - } - } - } - }, - "401": { - "description": "UnauthorizedError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnauthorizedError" - } - } - } - }, - "404": { - "description": "SessionNotFoundError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SessionNotFoundError" - } - } - } - }, - "500": { - "description": "UnknownError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnknownError1" - } - } - } - } - }, - "description": "Retrieve projected v2 messages for a session. Items keep the requested order across pages; use cursor.next or cursor.previous to move through the ordered timeline.", - "summary": "Get v2 session messages", - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.session.messages({\n ...\n})" - } - ] - } - }, - "/api/model": { - "get": { - "tags": ["v2 models"], - "operationId": "v2.model.list", - "parameters": [ - { - "name": "location", - "in": "query", - "schema": { - "type": "object", - "properties": { - "directory": { - "type": "string" - }, - "workspace": { - "type": "string" - } - }, - "additionalProperties": false - }, - "required": false, - "style": "deepObject", - "explode": true - } - ], - "security": [], - "responses": { - "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ModelV2PublicInfo" - } - } - } - } - }, - "400": { - "description": "InvalidRequestError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequestError" - } - } - } - }, - "401": { - "description": "UnauthorizedError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnauthorizedError" - } - } - } - }, - "503": { - "description": "ServiceUnavailableError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ServiceUnavailableError" - } - } - } - } - }, - "description": "Retrieve available v2 models ordered by release date.", - "summary": "List v2 models", - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.model.list({\n ...\n})" - } - ] - } - }, - "/api/provider": { - "get": { - "tags": ["v2 providers"], - "operationId": "v2.provider.list", - "parameters": [ - { - "name": "location", - "in": "query", - "schema": { - "type": "object", - "properties": { - "directory": { - "type": "string" - }, - "workspace": { - "type": "string" - } - }, - "additionalProperties": false - }, - "required": false, - "style": "deepObject", - "explode": true - } - ], - "security": [], - "responses": { - "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProviderV2PublicInfo" - } - } - } - } - }, - "400": { - "description": "InvalidRequestError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequestError" - } - } - } - }, - "401": { - "description": "UnauthorizedError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnauthorizedError" - } - } - } - }, - "503": { - "description": "ServiceUnavailableError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ServiceUnavailableError" - } - } - } - } - }, - "description": "Retrieve active v2 AI providers so clients can show provider availability and configuration.", - "summary": "List v2 providers", - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.provider.list({\n ...\n})" - } - ] - } - }, - "/api/provider/{providerID}": { - "get": { - "tags": ["v2 providers"], - "operationId": "v2.provider.get", - "parameters": [ - { - "name": "providerID", - "in": "path", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "location", - "in": "query", - "schema": { - "type": "object", - "properties": { - "directory": { - "type": "string" - }, - "workspace": { - "type": "string" - } - }, - "additionalProperties": false - }, - "required": false, - "style": "deepObject", - "explode": true - } - ], - "security": [], - "responses": { - "200": { - "description": "ProviderV2.PublicInfo", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProviderV2PublicInfo" - } - } - } - }, - "400": { - "description": "InvalidRequestError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequestError" - } - } - } - }, - "401": { - "description": "UnauthorizedError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnauthorizedError" - } - } - } - }, - "404": { - "description": "ProviderNotFoundError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProviderNotFoundError" - } - } - } - }, - "503": { - "description": "ServiceUnavailableError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ServiceUnavailableError" - } - } - } - } - }, - "description": "Retrieve a single v2 AI provider so clients can inspect its availability and endpoint settings.", - "summary": "Get v2 provider", - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.provider.get({\n ...\n})" - } - ] - } - }, - "/api/permission/request": { - "get": { - "tags": ["v2 permissions"], - "operationId": "v2.permission.request.list", - "parameters": [ - { - "name": "location", - "in": "query", - "schema": { - "type": "object", - "properties": { - "directory": { - "type": "string" - }, - "workspace": { - "type": "string" - } - }, - "additionalProperties": false - }, - "required": false, - "style": "deepObject", - "explode": true - } - ], - "security": [], - "responses": { - "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PermissionV2Request" - } - } - } - } - }, - "400": { - "description": "InvalidRequestError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequestError" - } - } - } - }, - "401": { - "description": "UnauthorizedError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnauthorizedError" - } - } - } - } - }, - "description": "Retrieve pending permission requests for a location.", - "summary": "List pending permission requests", - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.permission.request.list({\n ...\n})" - } - ] - } - }, - "/api/session/{sessionID}/permission/request": { - "get": { - "tags": ["v2 session permissions"], - "operationId": "v2.session.permission.list", - "parameters": [ - { - "name": "sessionID", - "in": "path", - "schema": { - "type": "string", - "pattern": "^ses" - }, - "required": true - } - ], - "security": [], - "responses": { - "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PermissionV2Request" - } - } - } - } - }, - "400": { - "description": "InvalidRequestError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequestError" - } - } - } - }, - "401": { - "description": "UnauthorizedError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnauthorizedError" - } - } - } - }, - "404": { - "description": "SessionNotFoundError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SessionNotFoundError" - } - } - } - } - }, - "description": "Retrieve pending permission requests owned by a session.", - "summary": "List session permission requests", - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.session.permission.list({\n ...\n})" - } - ] - } - }, - "/api/session/{sessionID}/permission/request/{requestID}/reply": { - "post": { - "tags": ["v2 session permissions"], - "operationId": "v2.session.permission.reply", - "parameters": [ - { - "name": "sessionID", - "in": "path", - "schema": { - "type": "string", - "pattern": "^ses" - }, - "required": true - }, - { - "name": "requestID", - "in": "path", - "schema": { - "type": "string", - "pattern": "^per" - }, - "required": true - } - ], - "security": [], - "responses": { - "204": { - "description": "" - }, - "400": { - "description": "InvalidRequestError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequestError" - } - } - } - }, - "401": { - "description": "UnauthorizedError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnauthorizedError" - } - } - } - }, - "404": { - "description": "SessionNotFoundError | PermissionNotFoundError", - "content": { - "application/json": { - "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundError" - }, - { - "$ref": "#/components/schemas/PermissionNotFoundError" - } - ] - } - } - } - } - }, - "description": "Respond to a pending permission request owned by a session.", - "summary": "Reply to pending permission request", - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "reply": { - "$ref": "#/components/schemas/PermissionV2Reply" - }, - "message": { - "type": "string" - } - }, - "required": ["reply"], - "additionalProperties": false - } - } - }, - "required": true - }, - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.session.permission.reply({\n ...\n})" - } - ] - } - }, - "/api/permission/saved": { - "get": { - "tags": ["v2 saved permissions"], - "operationId": "v2.permission.saved.list", - "parameters": [ - { - "name": "projectID", - "in": "query", - "schema": { - "type": "string" - }, - "required": false - } - ], - "security": [], - "responses": { - "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PermissionSavedInfo" - } - } - } - } - }, - "400": { - "description": "InvalidRequestError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequestError" - } - } - } - }, - "401": { - "description": "UnauthorizedError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnauthorizedError" - } - } - } - } - }, - "description": "Retrieve saved permissions, optionally filtered by project.", - "summary": "List saved permissions", - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.permission.saved.list({\n ...\n})" - } - ] - } - }, - "/api/permission/saved/{id}": { - "delete": { - "tags": ["v2 saved permissions"], - "operationId": "v2.permission.saved.remove", - "parameters": [ - { - "name": "id", - "in": "path", - "schema": { - "type": "string" - }, - "required": true - } - ], - "security": [], - "responses": { - "204": { - "description": "" - }, - "400": { - "description": "InvalidRequestError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequestError" - } - } - } - }, - "401": { - "description": "UnauthorizedError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnauthorizedError" - } - } - } - } - }, - "description": "Remove a saved permission by ID.", - "summary": "Remove saved permission", - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.permission.saved.remove({\n ...\n})" - } - ] - } - }, - "/api/fs/read": { - "get": { - "tags": ["v2 filesystem"], - "operationId": "v2.fs.read", - "parameters": [ - { - "name": "location", - "in": "query", - "schema": { - "type": "object", - "properties": { - "directory": { - "type": "string" - }, - "workspace": { - "type": "string" - } - }, - "additionalProperties": false - }, - "required": false, - "style": "deepObject", - "explode": true - }, - { - "name": "path", - "in": "query", - "schema": { - "type": "string" - }, - "required": true - }, - { - "name": "reference", - "in": "query", - "schema": { - "type": "string" - }, - "required": false - } - ], - "security": [], - "responses": { - "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/FileSystemTextContent" - }, - { - "$ref": "#/components/schemas/FileSystemBinaryContent" - } - ] - } - } - } - }, - "400": { - "description": "InvalidRequestError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequestError" - } - } - } - }, - "401": { - "description": "UnauthorizedError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnauthorizedError" - } - } - } - } - }, - "description": "Read one file relative to the requested location.", - "summary": "Read file", - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.fs.read({\n ...\n})" - } - ] - } - }, - "/api/fs/list": { - "get": { - "tags": ["v2 filesystem"], - "operationId": "v2.fs.list", - "parameters": [ - { - "name": "location", - "in": "query", - "schema": { - "type": "object", - "properties": { - "directory": { - "type": "string" - }, - "workspace": { - "type": "string" - } - }, - "additionalProperties": false - }, - "required": false, - "style": "deepObject", - "explode": true - }, - { - "name": "path", - "in": "query", - "schema": { - "type": "string" - }, - "required": false - }, - { - "name": "reference", - "in": "query", - "schema": { - "type": "string" - }, - "required": false - } - ], - "security": [], - "responses": { - "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FileSystemEntry" - } - } - } - } - }, - "400": { - "description": "InvalidRequestError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequestError" - } - } - } - }, - "401": { - "description": "UnauthorizedError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnauthorizedError" - } - } - } - } - }, - "description": "List direct children of one directory relative to the requested location.", - "summary": "List directory", - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.fs.list({\n ...\n})" - } - ] - } - }, - "/api/question/request": { - "get": { - "tags": ["v2 questions"], - "operationId": "v2.question.request.list", - "parameters": [ - { - "name": "location", - "in": "query", - "schema": { - "type": "object", - "properties": { - "directory": { - "type": "string" - }, - "workspace": { - "type": "string" - } - }, - "additionalProperties": false - }, - "required": false, - "style": "deepObject", - "explode": true - } - ], - "security": [], - "responses": { - "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/QuestionV2Request" - } - } - } - } - }, - "400": { - "description": "InvalidRequestError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequestError" - } - } - } - }, - "401": { - "description": "UnauthorizedError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnauthorizedError" - } - } - } - } - }, - "description": "Retrieve pending question requests for a location.", - "summary": "List pending question requests", - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.question.request.list({\n ...\n})" - } - ] - } - }, - "/api/session/{sessionID}/question/request/{requestID}/reply": { - "post": { - "tags": ["v2 session questions"], - "operationId": "v2.session.question.reply", - "parameters": [ - { - "name": "sessionID", - "in": "path", - "schema": { - "type": "string", - "pattern": "^ses" - }, - "required": true - }, - { - "name": "requestID", - "in": "path", - "schema": { - "type": "string", - "pattern": "^que" - }, - "required": true - } - ], - "security": [], - "responses": { - "204": { - "description": "" - }, - "400": { - "description": "InvalidRequestError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequestError" - } - } - } - }, - "401": { - "description": "UnauthorizedError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnauthorizedError" - } - } - } - }, - "404": { - "description": "SessionNotFoundError | QuestionNotFoundError", - "content": { - "application/json": { - "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundError" - }, - { - "$ref": "#/components/schemas/QuestionNotFoundError" - } - ] - } - } - } - } - }, - "description": "Answer a pending question request owned by a session.", - "summary": "Reply to pending question request", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QuestionV2Reply" - } - } - }, - "required": true - }, - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.session.question.reply({\n ...\n})" - } - ] - } - }, - "/api/session/{sessionID}/question/request/{requestID}/reject": { - "post": { - "tags": ["v2 session questions"], - "operationId": "v2.session.question.reject", - "parameters": [ - { - "name": "sessionID", - "in": "path", - "schema": { - "type": "string", - "pattern": "^ses" - }, - "required": true - }, - { - "name": "requestID", - "in": "path", - "schema": { - "type": "string", - "pattern": "^que" - }, - "required": true - } - ], - "security": [], - "responses": { - "204": { - "description": "" - }, - "400": { - "description": "InvalidRequestError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InvalidRequestError" - } - } - } - }, - "401": { - "description": "UnauthorizedError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnauthorizedError" - } - } - } - }, - "404": { - "description": "SessionNotFoundError | QuestionNotFoundError", - "content": { - "application/json": { - "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundError" - }, - { - "$ref": "#/components/schemas/QuestionNotFoundError" - } - ] - } - } - } - } - }, - "description": "Reject a pending question request owned by a session.", - "summary": "Reject pending question request", - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.session.question.reject({\n ...\n})" - } - ] - } - }, "/tui/append-prompt": { "post": { "tags": ["tui"], @@ -11441,6 +9776,2056 @@ ] } }, + "/api/health": { + "get": { + "tags": ["opencode experimental HttpApi"], + "operationId": "v2.health.get", + "parameters": [], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "healthy": { + "type": "boolean", + "enum": [true] + } + }, + "required": ["healthy"], + "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": "Check whether the v2 API server is ready to accept requests.", + "summary": "Check v2 server health", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.health.get({\n ...\n})" + } + ] + } + }, + "/api/agent": { + "get": { + "tags": ["opencode experimental HttpApi"], + "operationId": "v2.agent.list", + "parameters": [ + { + "name": "location", + "in": "query", + "schema": { + "type": "object", + "properties": { + "directory": { + "type": "string" + }, + "workspace": { + "type": "string" + } + }, + "additionalProperties": false + }, + "required": false, + "style": "deepObject", + "explode": true + } + ], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "location": { + "$ref": "#/components/schemas/LocationInfo" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AgentV2Info" + } + } + }, + "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": "Retrieve currently registered v2 agents.", + "summary": "List v2 agents", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.agent.list({\n ...\n})" + } + ] + } + }, + "/api/session": { + "get": { + "tags": ["v2"], + "operationId": "v2.session.list", + "parameters": [ + { + "name": "workspace", + "in": "query", + "schema": { + "type": "string", + "pattern": "^wrk" + }, + "required": false + }, + { + "name": "limit", + "in": "query", + "schema": { + "type": "number" + }, + "required": false + }, + { + "name": "order", + "in": "query", + "schema": { + "type": "string", + "enum": ["asc", "desc"] + }, + "required": false + }, + { + "name": "search", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "directory", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "project", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "subpath", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "cursor", + "in": "query", + "schema": { + "type": "string", + "description": "Opaque pagination cursor returned as cursor.previous or cursor.next in the previous response." + }, + "required": false + } + ], + "security": [], + "responses": { + "200": { + "description": "V2SessionsResponse", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V2SessionsResponse" + } + } + } + }, + "400": { + "description": "InvalidCursorError | InvalidRequestError", + "content": { + "application/json": { + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/InvalidCursorError" + }, + { + "$ref": "#/components/schemas/InvalidRequestError" + }, + { + "$ref": "#/components/schemas/InvalidRequestError" + } + ] + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedError" + } + } + } + } + }, + "description": "Retrieve sessions in the requested order. Items keep that order across pages; use cursor.next or cursor.previous to move through the ordered list.", + "summary": "List v2 sessions", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.session.list({\n ...\n})" + } + ] + } + }, + "/api/session/{sessionID}/prompt": { + "post": { + "tags": ["v2"], + "operationId": "v2.session.prompt", + "parameters": [ + { + "name": "sessionID", + "in": "path", + "schema": { + "type": "string", + "pattern": "^ses" + }, + "required": true + } + ], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/SessionMessageUser" + } + }, + "required": ["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" + } + } + } + }, + "404": { + "description": "SessionNotFoundError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionNotFoundError" + } + } + } + }, + "409": { + "description": "ConflictError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConflictError" + } + } + } + } + }, + "description": "Durably admit one v2 session input and schedule agent-loop execution unless resume is false.", + "summary": "Send v2 message", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "prompt": { + "$ref": "#/components/schemas/Prompt" + }, + "delivery": { + "type": "string", + "enum": ["steer", "queue"] + }, + "resume": { + "type": "boolean" + } + }, + "required": ["prompt"], + "additionalProperties": false + } + } + }, + "required": true + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.session.prompt({\n ...\n})" + } + ] + } + }, + "/api/session/{sessionID}/compact": { + "post": { + "tags": ["v2"], + "operationId": "v2.session.compact", + "parameters": [ + { + "name": "sessionID", + "in": "path", + "schema": { + "type": "string", + "pattern": "^ses" + }, + "required": true + } + ], + "security": [], + "responses": { + "204": { + "description": "" + }, + "400": { + "description": "InvalidRequestError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequestError" + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedError" + } + } + } + }, + "404": { + "description": "SessionNotFoundError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionNotFoundError" + } + } + } + }, + "503": { + "description": "ServiceUnavailableError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceUnavailableError" + } + } + } + } + }, + "description": "Compact a v2 session conversation.", + "summary": "Compact v2 session", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.session.compact({\n ...\n})" + } + ] + } + }, + "/api/session/{sessionID}/wait": { + "post": { + "tags": ["v2"], + "operationId": "v2.session.wait", + "parameters": [ + { + "name": "sessionID", + "in": "path", + "schema": { + "type": "string", + "pattern": "^ses" + }, + "required": true + } + ], + "security": [], + "responses": { + "204": { + "description": "" + }, + "400": { + "description": "InvalidRequestError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequestError" + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedError" + } + } + } + }, + "404": { + "description": "SessionNotFoundError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionNotFoundError" + } + } + } + }, + "503": { + "description": "ServiceUnavailableError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceUnavailableError" + } + } + } + } + }, + "description": "Wait for a v2 session agent loop to become idle.", + "summary": "Wait for v2 session", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.session.wait({\n ...\n})" + } + ] + } + }, + "/api/session/{sessionID}/context": { + "get": { + "tags": ["v2"], + "operationId": "v2.session.context", + "parameters": [ + { + "name": "sessionID", + "in": "path", + "schema": { + "type": "string", + "pattern": "^ses" + }, + "required": true + } + ], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SessionMessage" + } + } + }, + "required": ["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" + } + } + } + }, + "404": { + "description": "SessionNotFoundError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionNotFoundError" + } + } + } + }, + "500": { + "description": "UnknownError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnknownError1" + } + } + } + } + }, + "description": "Retrieve the active context messages for a v2 session (all messages after the last compaction).", + "summary": "Get v2 session context", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.session.context({\n ...\n})" + } + ] + } + }, + "/api/session/{sessionID}/message": { + "get": { + "tags": ["v2 messages"], + "operationId": "v2.session.messages", + "parameters": [ + { + "name": "sessionID", + "in": "path", + "schema": { + "type": "string", + "pattern": "^ses" + }, + "required": true + }, + { + "name": "limit", + "in": "query", + "schema": { + "type": "number" + }, + "required": false + }, + { + "name": "order", + "in": "query", + "schema": { + "type": "string", + "enum": ["asc", "desc"] + }, + "required": false + }, + { + "name": "cursor", + "in": "query", + "schema": { + "type": "string", + "description": "Opaque pagination cursor returned as cursor.previous or cursor.next in the previous response. Do not combine with order." + }, + "required": false + } + ], + "security": [], + "responses": { + "200": { + "description": "V2SessionMessagesResponse", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/V2SessionMessagesResponse" + } + } + } + }, + "400": { + "description": "InvalidCursorError | InvalidRequestError", + "content": { + "application/json": { + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/InvalidCursorError" + }, + { + "$ref": "#/components/schemas/InvalidRequestError" + } + ] + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedError" + } + } + } + }, + "404": { + "description": "SessionNotFoundError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionNotFoundError" + } + } + } + }, + "500": { + "description": "UnknownError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnknownError1" + } + } + } + } + }, + "description": "Retrieve projected v2 messages for a session. Items keep the requested order across pages; use cursor.next or cursor.previous to move through the ordered timeline.", + "summary": "Get v2 session messages", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.session.messages({\n ...\n})" + } + ] + } + }, + "/api/model": { + "get": { + "tags": ["v2 models"], + "operationId": "v2.model.list", + "parameters": [ + { + "name": "location", + "in": "query", + "schema": { + "type": "object", + "properties": { + "directory": { + "type": "string" + }, + "workspace": { + "type": "string" + } + }, + "additionalProperties": false + }, + "required": false, + "style": "deepObject", + "explode": true + } + ], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "location": { + "$ref": "#/components/schemas/LocationInfo" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelV2Info" + } + } + }, + "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" + } + } + } + }, + "503": { + "description": "ServiceUnavailableError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceUnavailableError" + } + } + } + } + }, + "description": "Retrieve available v2 models ordered by release date.", + "summary": "List v2 models", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.model.list({\n ...\n})" + } + ] + } + }, + "/api/provider": { + "get": { + "tags": ["v2 providers"], + "operationId": "v2.provider.list", + "parameters": [ + { + "name": "location", + "in": "query", + "schema": { + "type": "object", + "properties": { + "directory": { + "type": "string" + }, + "workspace": { + "type": "string" + } + }, + "additionalProperties": false + }, + "required": false, + "style": "deepObject", + "explode": true + } + ], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "location": { + "$ref": "#/components/schemas/LocationInfo" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProviderV2Info" + } + } + }, + "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" + } + } + } + }, + "503": { + "description": "ServiceUnavailableError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceUnavailableError" + } + } + } + } + }, + "description": "Retrieve active v2 AI providers so clients can show provider availability and configuration.", + "summary": "List v2 providers", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.provider.list({\n ...\n})" + } + ] + } + }, + "/api/provider/{providerID}": { + "get": { + "tags": ["v2 providers"], + "operationId": "v2.provider.get", + "parameters": [ + { + "name": "providerID", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "location", + "in": "query", + "schema": { + "type": "object", + "properties": { + "directory": { + "type": "string" + }, + "workspace": { + "type": "string" + } + }, + "additionalProperties": false + }, + "required": false, + "style": "deepObject", + "explode": true + } + ], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "location": { + "$ref": "#/components/schemas/LocationInfo" + }, + "data": { + "$ref": "#/components/schemas/ProviderV2Info" + } + }, + "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" + } + } + } + }, + "404": { + "description": "ProviderNotFoundError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderNotFoundError" + } + } + } + }, + "503": { + "description": "ServiceUnavailableError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceUnavailableError" + } + } + } + } + }, + "description": "Retrieve a single v2 AI provider so clients can inspect its availability and endpoint settings.", + "summary": "Get v2 provider", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.provider.get({\n ...\n})" + } + ] + } + }, + "/api/permission/request": { + "get": { + "tags": ["v2 permissions"], + "operationId": "v2.permission.request.list", + "parameters": [ + { + "name": "location", + "in": "query", + "schema": { + "type": "object", + "properties": { + "directory": { + "type": "string" + }, + "workspace": { + "type": "string" + } + }, + "additionalProperties": false + }, + "required": false, + "style": "deepObject", + "explode": true + } + ], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "location": { + "$ref": "#/components/schemas/LocationInfo" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PermissionV2Request" + } + } + }, + "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": "Retrieve pending permission requests for a location.", + "summary": "List pending permission requests", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.permission.request.list({\n ...\n})" + } + ] + } + }, + "/api/session/{sessionID}/permission/request": { + "get": { + "tags": ["v2 session permissions"], + "operationId": "v2.session.permission.list", + "parameters": [ + { + "name": "sessionID", + "in": "path", + "schema": { + "type": "string", + "pattern": "^ses" + }, + "required": true + } + ], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PermissionV2Request" + } + } + }, + "required": ["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" + } + } + } + }, + "404": { + "description": "SessionNotFoundError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionNotFoundError" + } + } + } + } + }, + "description": "Retrieve pending permission requests owned by a session.", + "summary": "List session permission requests", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.session.permission.list({\n ...\n})" + } + ] + } + }, + "/api/session/{sessionID}/permission/request/{requestID}/reply": { + "post": { + "tags": ["v2 session permissions"], + "operationId": "v2.session.permission.reply", + "parameters": [ + { + "name": "sessionID", + "in": "path", + "schema": { + "type": "string", + "pattern": "^ses" + }, + "required": true + }, + { + "name": "requestID", + "in": "path", + "schema": { + "type": "string", + "pattern": "^per" + }, + "required": true + } + ], + "security": [], + "responses": { + "204": { + "description": "" + }, + "400": { + "description": "InvalidRequestError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequestError" + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedError" + } + } + } + }, + "404": { + "description": "SessionNotFoundError | PermissionNotFoundError", + "content": { + "application/json": { + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/SessionNotFoundError" + }, + { + "$ref": "#/components/schemas/PermissionNotFoundError" + } + ] + } + } + } + } + }, + "description": "Respond to a pending permission request owned by a session.", + "summary": "Reply to pending permission request", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "reply": { + "$ref": "#/components/schemas/PermissionV2Reply" + }, + "message": { + "type": "string" + } + }, + "required": ["reply"], + "additionalProperties": false + } + } + }, + "required": true + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.session.permission.reply({\n ...\n})" + } + ] + } + }, + "/api/permission/saved": { + "get": { + "tags": ["v2 saved permissions"], + "operationId": "v2.permission.saved.list", + "parameters": [ + { + "name": "projectID", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + } + ], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PermissionSavedInfo" + } + } + }, + "required": ["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": "Retrieve saved permissions, optionally filtered by project.", + "summary": "List saved permissions", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.permission.saved.list({\n ...\n})" + } + ] + } + }, + "/api/permission/saved/{id}": { + "delete": { + "tags": ["v2 saved permissions"], + "operationId": "v2.permission.saved.remove", + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "security": [], + "responses": { + "204": { + "description": "" + }, + "400": { + "description": "InvalidRequestError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequestError" + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedError" + } + } + } + } + }, + "description": "Remove a saved permission by ID.", + "summary": "Remove saved permission", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.permission.saved.remove({\n ...\n})" + } + ] + } + }, + "/api/fs/read": { + "get": { + "tags": ["v2 filesystem"], + "operationId": "v2.fs.read", + "parameters": [ + { + "name": "location", + "in": "query", + "schema": { + "type": "object", + "properties": { + "directory": { + "type": "string" + }, + "workspace": { + "type": "string" + } + }, + "additionalProperties": false + }, + "required": false, + "style": "deepObject", + "explode": true + }, + { + "name": "path", + "in": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "reference", + "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": { + "anyOf": [ + { + "$ref": "#/components/schemas/FileSystemTextContent" + }, + { + "$ref": "#/components/schemas/FileSystemBinaryContent" + } + ] + } + }, + "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": "Read one file relative to the requested location.", + "summary": "Read file", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.fs.read({\n ...\n})" + } + ] + } + }, + "/api/fs/list": { + "get": { + "tags": ["v2 filesystem"], + "operationId": "v2.fs.list", + "parameters": [ + { + "name": "location", + "in": "query", + "schema": { + "type": "object", + "properties": { + "directory": { + "type": "string" + }, + "workspace": { + "type": "string" + } + }, + "additionalProperties": false + }, + "required": false, + "style": "deepObject", + "explode": true + }, + { + "name": "path", + "in": "query", + "schema": { + "type": "string" + }, + "required": false + }, + { + "name": "reference", + "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": "List direct children of one directory relative to the requested location.", + "summary": "List directory", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.fs.list({\n ...\n})" + } + ] + } + }, + "/api/command": { + "get": { + "tags": ["v2 commands"], + "operationId": "v2.command.list", + "parameters": [ + { + "name": "location", + "in": "query", + "schema": { + "type": "object", + "properties": { + "directory": { + "type": "string" + }, + "workspace": { + "type": "string" + } + }, + "additionalProperties": false + }, + "required": false, + "style": "deepObject", + "explode": true + } + ], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "location": { + "$ref": "#/components/schemas/LocationInfo" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CommandV2Info" + } + } + }, + "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": "Retrieve currently registered v2 commands.", + "summary": "List v2 commands", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.command.list({\n ...\n})" + } + ] + } + }, + "/api/skill": { + "get": { + "tags": ["v2 skills"], + "operationId": "v2.skill.list", + "parameters": [ + { + "name": "location", + "in": "query", + "schema": { + "type": "object", + "properties": { + "directory": { + "type": "string" + }, + "workspace": { + "type": "string" + } + }, + "additionalProperties": false + }, + "required": false, + "style": "deepObject", + "explode": true + } + ], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "location": { + "$ref": "#/components/schemas/LocationInfo" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SkillV2Info" + } + } + }, + "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": "Retrieve currently registered v2 skills.", + "summary": "List v2 skills", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.skill.list({\n ...\n})" + } + ] + } + }, + "/api/event": { + "get": { + "tags": ["v2 events"], + "operationId": "v2.event.subscribe", + "parameters": [ + { + "name": "location", + "in": "query", + "schema": { + "type": "object", + "properties": { + "directory": { + "type": "string" + }, + "workspace": { + "type": "string" + } + }, + "additionalProperties": false + }, + "required": false, + "style": "deepObject", + "explode": true + } + ], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "text/event-stream": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "description": "InvalidRequestError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequestError" + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedError" + } + } + } + } + }, + "description": "Subscribe to native EventV2 payloads for a location.", + "summary": "Subscribe to v2 events", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.event.subscribe({\n ...\n})" + } + ] + } + }, + "/api/question/request": { + "get": { + "tags": ["v2 questions"], + "operationId": "v2.question.request.list", + "parameters": [ + { + "name": "location", + "in": "query", + "schema": { + "type": "object", + "properties": { + "directory": { + "type": "string" + }, + "workspace": { + "type": "string" + } + }, + "additionalProperties": false + }, + "required": false, + "style": "deepObject", + "explode": true + } + ], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "location": { + "$ref": "#/components/schemas/LocationInfo" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/QuestionV2Request" + } + } + }, + "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": "Retrieve pending question requests for a location.", + "summary": "List pending question requests", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.question.request.list({\n ...\n})" + } + ] + } + }, + "/api/session/{sessionID}/question/request/{requestID}/reply": { + "post": { + "tags": ["v2 session questions"], + "operationId": "v2.session.question.reply", + "parameters": [ + { + "name": "sessionID", + "in": "path", + "schema": { + "type": "string", + "pattern": "^ses" + }, + "required": true + }, + { + "name": "requestID", + "in": "path", + "schema": { + "type": "string", + "pattern": "^que" + }, + "required": true + } + ], + "security": [], + "responses": { + "204": { + "description": "" + }, + "400": { + "description": "InvalidRequestError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequestError" + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedError" + } + } + } + }, + "404": { + "description": "SessionNotFoundError | QuestionNotFoundError", + "content": { + "application/json": { + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/SessionNotFoundError" + }, + { + "$ref": "#/components/schemas/QuestionNotFoundError" + } + ] + } + } + } + } + }, + "description": "Answer a pending question request owned by a session.", + "summary": "Reply to pending question request", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QuestionV2Reply" + } + } + }, + "required": true + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.session.question.reply({\n ...\n})" + } + ] + } + }, + "/api/session/{sessionID}/question/request/{requestID}/reject": { + "post": { + "tags": ["v2 session questions"], + "operationId": "v2.session.question.reject", + "parameters": [ + { + "name": "sessionID", + "in": "path", + "schema": { + "type": "string", + "pattern": "^ses" + }, + "required": true + }, + { + "name": "requestID", + "in": "path", + "schema": { + "type": "string", + "pattern": "^que" + }, + "required": true + } + ], + "security": [], + "responses": { + "204": { + "description": "" + }, + "400": { + "description": "InvalidRequestError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequestError" + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedError" + } + } + } + }, + "404": { + "description": "SessionNotFoundError | QuestionNotFoundError", + "content": { + "application/json": { + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/SessionNotFoundError" + }, + { + "$ref": "#/components/schemas/QuestionNotFoundError" + } + ] + } + } + } + } + }, + "description": "Reject a pending question request owned by a session.", + "summary": "Reject pending question request", + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.v2.session.question.reject({\n ...\n})" + } + ] + } + }, "/pty/{ptyID}/connect": { "get": { "tags": ["pty"], @@ -17096,6 +17481,9 @@ "model": { "type": "string" }, + "variant": { + "type": "string" + }, "subtask": { "type": "boolean" } @@ -19186,169 +19574,6 @@ "required": ["_tag", "sessionID", "message"], "additionalProperties": false }, - "V2SessionsResponse": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SessionV2Info" - } - }, - "cursor": { - "type": "object", - "properties": { - "previous": { - "type": "string" - }, - "next": { - "type": "string" - } - }, - "additionalProperties": false - } - }, - "required": ["items", "cursor"], - "additionalProperties": false - }, - "InvalidCursorError": { - "type": "object", - "properties": { - "_tag": { - "type": "string", - "enum": ["InvalidCursorError"] - }, - "message": { - "type": "string" - } - }, - "required": ["_tag", "message"], - "additionalProperties": false - }, - "UnauthorizedError": { - "type": "object", - "properties": { - "_tag": { - "type": "string", - "enum": ["UnauthorizedError"] - }, - "message": { - "type": "string" - } - }, - "required": ["_tag", "message"], - "additionalProperties": false - }, - "ConflictError": { - "type": "object", - "properties": { - "_tag": { - "type": "string", - "enum": ["ConflictError"] - }, - "message": { - "type": "string" - }, - "resource": { - "type": "string" - } - }, - "required": ["_tag", "message"], - "additionalProperties": false - }, - "SessionNotFoundError": { - "type": "object", - "properties": { - "_tag": { - "type": "string", - "enum": ["SessionNotFoundError"] - }, - "sessionID": { - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": ["_tag", "sessionID", "message"], - "additionalProperties": false - }, - "ServiceUnavailableError": { - "type": "object", - "properties": { - "_tag": { - "type": "string", - "enum": ["ServiceUnavailableError"] - }, - "message": { - "type": "string" - }, - "service": { - "type": "string" - } - }, - "required": ["_tag", "message"], - "additionalProperties": false - }, - "UnknownError1": { - "type": "object", - "properties": { - "_tag": { - "type": "string", - "enum": ["UnknownError"] - }, - "message": { - "type": "string" - }, - "ref": { - "type": "string" - } - }, - "required": ["_tag", "message"], - "additionalProperties": false - }, - "V2SessionMessagesResponse": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SessionMessage" - } - }, - "cursor": { - "type": "object", - "properties": { - "previous": { - "type": "string" - }, - "next": { - "type": "string" - } - }, - "additionalProperties": false - } - }, - "required": ["items", "cursor"], - "additionalProperties": false - }, - "ProviderNotFoundError": { - "type": "object", - "properties": { - "_tag": { - "type": "string", - "enum": ["ProviderNotFoundError"] - }, - "providerID": { - "type": "string" - }, - "message": { - "type": "string" - } - }, - "required": ["_tag", "providerID", "message"], - "additionalProperties": false - }, "EventTuiPromptAppend": { "type": "object", "properties": { @@ -19584,6 +19809,169 @@ "required": ["name", "data"], "additionalProperties": false }, + "UnauthorizedError": { + "type": "object", + "properties": { + "_tag": { + "type": "string", + "enum": ["UnauthorizedError"] + }, + "message": { + "type": "string" + } + }, + "required": ["_tag", "message"], + "additionalProperties": false + }, + "V2SessionsResponse": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SessionV2Info" + } + }, + "cursor": { + "type": "object", + "properties": { + "previous": { + "type": "string" + }, + "next": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "required": ["data", "cursor"], + "additionalProperties": false + }, + "InvalidCursorError": { + "type": "object", + "properties": { + "_tag": { + "type": "string", + "enum": ["InvalidCursorError"] + }, + "message": { + "type": "string" + } + }, + "required": ["_tag", "message"], + "additionalProperties": false + }, + "ConflictError": { + "type": "object", + "properties": { + "_tag": { + "type": "string", + "enum": ["ConflictError"] + }, + "message": { + "type": "string" + }, + "resource": { + "type": "string" + } + }, + "required": ["_tag", "message"], + "additionalProperties": false + }, + "SessionNotFoundError": { + "type": "object", + "properties": { + "_tag": { + "type": "string", + "enum": ["SessionNotFoundError"] + }, + "sessionID": { + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": ["_tag", "sessionID", "message"], + "additionalProperties": false + }, + "ServiceUnavailableError": { + "type": "object", + "properties": { + "_tag": { + "type": "string", + "enum": ["ServiceUnavailableError"] + }, + "message": { + "type": "string" + }, + "service": { + "type": "string" + } + }, + "required": ["_tag", "message"], + "additionalProperties": false + }, + "UnknownError1": { + "type": "object", + "properties": { + "_tag": { + "type": "string", + "enum": ["UnknownError"] + }, + "message": { + "type": "string" + }, + "ref": { + "type": "string" + } + }, + "required": ["_tag", "message"], + "additionalProperties": false + }, + "V2SessionMessagesResponse": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SessionMessage" + } + }, + "cursor": { + "type": "object", + "properties": { + "previous": { + "type": "string" + }, + "next": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "required": ["data", "cursor"], + "additionalProperties": false + }, + "ProviderNotFoundError": { + "type": "object", + "properties": { + "_tag": { + "type": "string", + "enum": ["ProviderNotFoundError"] + }, + "providerID": { + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": ["_tag", "providerID", "message"], + "additionalProperties": false + }, "effect_HttpApiError_Forbidden": { "type": "object", "properties": { @@ -20359,36 +20747,45 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.created.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "sessionID": { + "type": { "type": "string", - "pattern": "^ses" + "enum": ["session.created.1"] }, - "info": { - "$ref": "#/components/schemas/Session" + "id": { + "type": "string" + }, + "seq": { + "type": "number" + }, + "aggregateID": { + "type": "string" + }, + "data": { + "type": "object", + "properties": { + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "info": { + "$ref": "#/components/schemas/Session" + } + }, + "required": ["sessionID", "info"], + "additionalProperties": false } }, - "required": ["sessionID", "info"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventSessionUpdated": { @@ -20398,36 +20795,45 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.updated.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "sessionID": { + "type": { "type": "string", - "pattern": "^ses" + "enum": ["session.updated.1"] }, - "info": { - "$ref": "#/components/schemas/Session" + "id": { + "type": "string" + }, + "seq": { + "type": "number" + }, + "aggregateID": { + "type": "string" + }, + "data": { + "type": "object", + "properties": { + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "info": { + "$ref": "#/components/schemas/Session" + } + }, + "required": ["sessionID", "info"], + "additionalProperties": false } }, - "required": ["sessionID", "info"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventSessionDeleted": { @@ -20437,36 +20843,45 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.deleted.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "sessionID": { + "type": { "type": "string", - "pattern": "^ses" + "enum": ["session.deleted.1"] }, - "info": { - "$ref": "#/components/schemas/Session" + "id": { + "type": "string" + }, + "seq": { + "type": "number" + }, + "aggregateID": { + "type": "string" + }, + "data": { + "type": "object", + "properties": { + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "info": { + "$ref": "#/components/schemas/Session" + } + }, + "required": ["sessionID", "info"], + "additionalProperties": false } }, - "required": ["sessionID", "info"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventMessageUpdated": { @@ -20476,36 +20891,45 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["message.updated.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "sessionID": { + "type": { "type": "string", - "pattern": "^ses" + "enum": ["message.updated.1"] }, - "info": { - "$ref": "#/components/schemas/Message" + "id": { + "type": "string" + }, + "seq": { + "type": "number" + }, + "aggregateID": { + "type": "string" + }, + "data": { + "type": "object", + "properties": { + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "info": { + "$ref": "#/components/schemas/Message" + } + }, + "required": ["sessionID", "info"], + "additionalProperties": false } }, - "required": ["sessionID", "info"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventMessageRemoved": { @@ -20515,37 +20939,46 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["message.removed.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "sessionID": { + "type": { "type": "string", - "pattern": "^ses" + "enum": ["message.removed.1"] }, - "messageID": { - "type": "string", - "pattern": "^msg" + "id": { + "type": "string" + }, + "seq": { + "type": "number" + }, + "aggregateID": { + "type": "string" + }, + "data": { + "type": "object", + "properties": { + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "messageID": { + "type": "string", + "pattern": "^msg" + } + }, + "required": ["sessionID", "messageID"], + "additionalProperties": false } }, - "required": ["sessionID", "messageID"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventMessagePartUpdated": { @@ -20555,39 +20988,48 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["message.part.updated.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "sessionID": { + "type": { "type": "string", - "pattern": "^ses" + "enum": ["message.part.updated.1"] }, - "part": { - "$ref": "#/components/schemas/Part" + "id": { + "type": "string" }, - "time": { + "seq": { "type": "number" + }, + "aggregateID": { + "type": "string" + }, + "data": { + "type": "object", + "properties": { + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "part": { + "$ref": "#/components/schemas/Part" + }, + "time": { + "type": "number" + } + }, + "required": ["sessionID", "part", "time"], + "additionalProperties": false } }, - "required": ["sessionID", "part", "time"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventMessagePartRemoved": { @@ -20597,41 +21039,50 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["message.part.removed.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "sessionID": { + "type": { "type": "string", - "pattern": "^ses" + "enum": ["message.part.removed.1"] }, - "messageID": { - "type": "string", - "pattern": "^msg" + "id": { + "type": "string" }, - "partID": { - "type": "string", - "pattern": "^prt" + "seq": { + "type": "number" + }, + "aggregateID": { + "type": "string" + }, + "data": { + "type": "object", + "properties": { + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "messageID": { + "type": "string", + "pattern": "^msg" + }, + "partID": { + "type": "string", + "pattern": "^prt" + } + }, + "required": ["sessionID", "messageID", "partID"], + "additionalProperties": false } }, - "required": ["sessionID", "messageID", "partID"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventSessionNextAgentSwitched": { @@ -20641,39 +21092,48 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.next.agent.switched.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "timestamp": { + "type": { + "type": "string", + "enum": ["session.next.agent.switched.1"] + }, + "id": { + "type": "string" + }, + "seq": { "type": "number" }, - "sessionID": { - "type": "string", - "pattern": "^ses" - }, - "agent": { + "aggregateID": { "type": "string" + }, + "data": { + "type": "object", + "properties": { + "timestamp": { + "type": "number" + }, + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "agent": { + "type": "string" + } + }, + "required": ["timestamp", "sessionID", "agent"], + "additionalProperties": false } }, - "required": ["timestamp", "sessionID", "agent"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventSessionNextModelSwitched": { @@ -20683,52 +21143,61 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.next.model.switched.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "timestamp": { + "type": { + "type": "string", + "enum": ["session.next.model.switched.1"] + }, + "id": { + "type": "string" + }, + "seq": { "type": "number" }, - "sessionID": { - "type": "string", - "pattern": "^ses" + "aggregateID": { + "type": "string" }, - "model": { + "data": { "type": "object", "properties": { - "id": { - "type": "string" + "timestamp": { + "type": "number" }, - "providerID": { - "type": "string" + "sessionID": { + "type": "string", + "pattern": "^ses" }, - "variant": { - "type": "string" + "model": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "providerID": { + "type": "string" + }, + "variant": { + "type": "string" + } + }, + "required": ["id", "providerID"], + "additionalProperties": false } }, - "required": ["id", "providerID"], + "required": ["timestamp", "sessionID", "model"], "additionalProperties": false } }, - "required": ["timestamp", "sessionID", "model"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventSessionNextPrompted": { @@ -20738,43 +21207,52 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.next.prompted.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "timestamp": { + "type": { + "type": "string", + "enum": ["session.next.prompted.1"] + }, + "id": { + "type": "string" + }, + "seq": { "type": "number" }, - "sessionID": { - "type": "string", - "pattern": "^ses" + "aggregateID": { + "type": "string" }, - "prompt": { - "$ref": "#/components/schemas/Prompt" - }, - "delivery": { - "type": "string", - "enum": ["steer", "queue"] + "data": { + "type": "object", + "properties": { + "timestamp": { + "type": "number" + }, + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "prompt": { + "$ref": "#/components/schemas/Prompt" + }, + "delivery": { + "type": "string", + "enum": ["steer", "queue"] + } + }, + "required": ["timestamp", "sessionID", "prompt", "delivery"], + "additionalProperties": false } }, - "required": ["timestamp", "sessionID", "prompt", "delivery"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventSessionNextSynthetic": { @@ -20784,39 +21262,48 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.next.synthetic.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "timestamp": { + "type": { + "type": "string", + "enum": ["session.next.synthetic.1"] + }, + "id": { + "type": "string" + }, + "seq": { "type": "number" }, - "sessionID": { - "type": "string", - "pattern": "^ses" - }, - "text": { + "aggregateID": { "type": "string" + }, + "data": { + "type": "object", + "properties": { + "timestamp": { + "type": "number" + }, + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "text": { + "type": "string" + } + }, + "required": ["timestamp", "sessionID", "text"], + "additionalProperties": false } }, - "required": ["timestamp", "sessionID", "text"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventSessionNextShellStarted": { @@ -20826,42 +21313,51 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.next.shell.started.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "timestamp": { + "type": { + "type": "string", + "enum": ["session.next.shell.started.1"] + }, + "id": { + "type": "string" + }, + "seq": { "type": "number" }, - "sessionID": { - "type": "string", - "pattern": "^ses" - }, - "callID": { + "aggregateID": { "type": "string" }, - "command": { - "type": "string" + "data": { + "type": "object", + "properties": { + "timestamp": { + "type": "number" + }, + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "callID": { + "type": "string" + }, + "command": { + "type": "string" + } + }, + "required": ["timestamp", "sessionID", "callID", "command"], + "additionalProperties": false } }, - "required": ["timestamp", "sessionID", "callID", "command"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventSessionNextShellEnded": { @@ -20871,42 +21367,51 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.next.shell.ended.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "timestamp": { + "type": { + "type": "string", + "enum": ["session.next.shell.ended.1"] + }, + "id": { + "type": "string" + }, + "seq": { "type": "number" }, - "sessionID": { - "type": "string", - "pattern": "^ses" - }, - "callID": { + "aggregateID": { "type": "string" }, - "output": { - "type": "string" + "data": { + "type": "object", + "properties": { + "timestamp": { + "type": "number" + }, + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "callID": { + "type": "string" + }, + "output": { + "type": "string" + } + }, + "required": ["timestamp", "sessionID", "callID", "output"], + "additionalProperties": false } }, - "required": ["timestamp", "sessionID", "callID", "output"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventSessionNextStepStarted": { @@ -20916,58 +21421,67 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.next.step.started.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "timestamp": { - "type": "number" - }, - "sessionID": { + "type": { "type": "string", - "pattern": "^ses" + "enum": ["session.next.step.started.1"] }, - "agent": { + "id": { "type": "string" }, - "model": { + "seq": { + "type": "number" + }, + "aggregateID": { + "type": "string" + }, + "data": { "type": "object", "properties": { - "id": { + "timestamp": { + "type": "number" + }, + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "agent": { "type": "string" }, - "providerID": { - "type": "string" + "model": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "providerID": { + "type": "string" + }, + "variant": { + "type": "string" + } + }, + "required": ["id", "providerID"], + "additionalProperties": false }, - "variant": { + "snapshot": { "type": "string" } }, - "required": ["id", "providerID"], + "required": ["timestamp", "sessionID", "agent", "model"], "additionalProperties": false - }, - "snapshot": { - "type": "string" } }, - "required": ["timestamp", "sessionID", "agent", "model"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventSessionNextStepEnded": { @@ -20977,77 +21491,86 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.next.step.ended.2"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "timestamp": { - "type": "number" - }, - "sessionID": { + "type": { "type": "string", - "pattern": "^ses" + "enum": ["session.next.step.ended.2"] }, - "assistantMessageID": { + "id": { "type": "string" }, - "finish": { - "type": "string" - }, - "cost": { + "seq": { "type": "number" }, - "tokens": { + "aggregateID": { + "type": "string" + }, + "data": { "type": "object", "properties": { - "input": { + "timestamp": { "type": "number" }, - "output": { + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "assistantMessageID": { + "type": "string" + }, + "finish": { + "type": "string" + }, + "cost": { "type": "number" }, - "reasoning": { - "type": "number" - }, - "cache": { + "tokens": { "type": "object", "properties": { - "read": { + "input": { "type": "number" }, - "write": { + "output": { "type": "number" + }, + "reasoning": { + "type": "number" + }, + "cache": { + "type": "object", + "properties": { + "read": { + "type": "number" + }, + "write": { + "type": "number" + } + }, + "required": ["read", "write"], + "additionalProperties": false } }, - "required": ["read", "write"], + "required": ["input", "output", "reasoning", "cache"], "additionalProperties": false + }, + "snapshot": { + "type": "string" } }, - "required": ["input", "output", "reasoning", "cache"], + "required": ["timestamp", "sessionID", "assistantMessageID", "finish", "cost", "tokens"], "additionalProperties": false - }, - "snapshot": { - "type": "string" } }, - "required": ["timestamp", "sessionID", "assistantMessageID", "finish", "cost", "tokens"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventSessionNextStepFailed": { @@ -21057,42 +21580,51 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.next.step.failed.2"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "timestamp": { - "type": "number" - }, - "sessionID": { + "type": { "type": "string", - "pattern": "^ses" + "enum": ["session.next.step.failed.2"] }, - "assistantMessageID": { + "id": { "type": "string" }, - "error": { - "$ref": "#/components/schemas/SessionErrorUnknown" + "seq": { + "type": "number" + }, + "aggregateID": { + "type": "string" + }, + "data": { + "type": "object", + "properties": { + "timestamp": { + "type": "number" + }, + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "assistantMessageID": { + "type": "string" + }, + "error": { + "$ref": "#/components/schemas/SessionErrorUnknown" + } + }, + "required": ["timestamp", "sessionID", "assistantMessageID", "error"], + "additionalProperties": false } }, - "required": ["timestamp", "sessionID", "assistantMessageID", "error"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventSessionNextTextStarted": { @@ -21102,39 +21634,48 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.next.text.started.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "timestamp": { + "type": { + "type": "string", + "enum": ["session.next.text.started.1"] + }, + "id": { + "type": "string" + }, + "seq": { "type": "number" }, - "sessionID": { - "type": "string", - "pattern": "^ses" - }, - "textID": { + "aggregateID": { "type": "string" + }, + "data": { + "type": "object", + "properties": { + "timestamp": { + "type": "number" + }, + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "textID": { + "type": "string" + } + }, + "required": ["timestamp", "sessionID", "textID"], + "additionalProperties": false } }, - "required": ["timestamp", "sessionID", "textID"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventSessionNextTextEnded": { @@ -21144,42 +21685,51 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.next.text.ended.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "timestamp": { + "type": { + "type": "string", + "enum": ["session.next.text.ended.1"] + }, + "id": { + "type": "string" + }, + "seq": { "type": "number" }, - "sessionID": { - "type": "string", - "pattern": "^ses" - }, - "textID": { + "aggregateID": { "type": "string" }, - "text": { - "type": "string" + "data": { + "type": "object", + "properties": { + "timestamp": { + "type": "number" + }, + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "textID": { + "type": "string" + }, + "text": { + "type": "string" + } + }, + "required": ["timestamp", "sessionID", "textID", "text"], + "additionalProperties": false } }, - "required": ["timestamp", "sessionID", "textID", "text"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventSessionNextReasoningStarted": { @@ -21189,45 +21739,54 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.next.reasoning.started.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "timestamp": { - "type": "number" - }, - "sessionID": { + "type": { "type": "string", - "pattern": "^ses" + "enum": ["session.next.reasoning.started.1"] }, - "reasoningID": { + "id": { "type": "string" }, - "providerMetadata": { + "seq": { + "type": "number" + }, + "aggregateID": { + "type": "string" + }, + "data": { "type": "object", - "additionalProperties": { - "type": "object" - } + "properties": { + "timestamp": { + "type": "number" + }, + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "reasoningID": { + "type": "string" + }, + "providerMetadata": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + }, + "required": ["timestamp", "sessionID", "reasoningID"], + "additionalProperties": false } }, - "required": ["timestamp", "sessionID", "reasoningID"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventSessionNextReasoningEnded": { @@ -21237,48 +21796,57 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.next.reasoning.ended.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "timestamp": { + "type": { + "type": "string", + "enum": ["session.next.reasoning.ended.1"] + }, + "id": { + "type": "string" + }, + "seq": { "type": "number" }, - "sessionID": { - "type": "string", - "pattern": "^ses" - }, - "reasoningID": { + "aggregateID": { "type": "string" }, - "text": { - "type": "string" - }, - "providerMetadata": { + "data": { "type": "object", - "additionalProperties": { - "type": "object" - } + "properties": { + "timestamp": { + "type": "number" + }, + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "reasoningID": { + "type": "string" + }, + "text": { + "type": "string" + }, + "providerMetadata": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + }, + "required": ["timestamp", "sessionID", "reasoningID", "text"], + "additionalProperties": false } }, - "required": ["timestamp", "sessionID", "reasoningID", "text"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventSessionNextToolInputStarted": { @@ -21288,45 +21856,54 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.next.tool.input.started.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "timestamp": { + "type": { + "type": "string", + "enum": ["session.next.tool.input.started.1"] + }, + "id": { + "type": "string" + }, + "seq": { "type": "number" }, - "sessionID": { - "type": "string", - "pattern": "^ses" - }, - "assistantMessageID": { + "aggregateID": { "type": "string" }, - "callID": { - "type": "string" - }, - "name": { - "type": "string" + "data": { + "type": "object", + "properties": { + "timestamp": { + "type": "number" + }, + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "assistantMessageID": { + "type": "string" + }, + "callID": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": ["timestamp", "sessionID", "assistantMessageID", "callID", "name"], + "additionalProperties": false } }, - "required": ["timestamp", "sessionID", "assistantMessageID", "callID", "name"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventSessionNextToolInputEnded": { @@ -21336,45 +21913,54 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.next.tool.input.ended.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "timestamp": { + "type": { + "type": "string", + "enum": ["session.next.tool.input.ended.1"] + }, + "id": { + "type": "string" + }, + "seq": { "type": "number" }, - "sessionID": { - "type": "string", - "pattern": "^ses" - }, - "assistantMessageID": { + "aggregateID": { "type": "string" }, - "callID": { - "type": "string" - }, - "text": { - "type": "string" + "data": { + "type": "object", + "properties": { + "timestamp": { + "type": "number" + }, + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "assistantMessageID": { + "type": "string" + }, + "callID": { + "type": "string" + }, + "text": { + "type": "string" + } + }, + "required": ["timestamp", "sessionID", "assistantMessageID", "callID", "text"], + "additionalProperties": false } }, - "required": ["timestamp", "sessionID", "assistantMessageID", "callID", "text"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventSessionNextToolCalled": { @@ -21384,64 +21970,73 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.next.tool.called.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "timestamp": { + "type": { + "type": "string", + "enum": ["session.next.tool.called.1"] + }, + "id": { + "type": "string" + }, + "seq": { "type": "number" }, - "sessionID": { - "type": "string", - "pattern": "^ses" - }, - "assistantMessageID": { + "aggregateID": { "type": "string" }, - "callID": { - "type": "string" - }, - "tool": { - "type": "string" - }, - "input": { - "type": "object" - }, - "provider": { + "data": { "type": "object", "properties": { - "executed": { - "type": "boolean" + "timestamp": { + "type": "number" }, - "metadata": { + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "assistantMessageID": { + "type": "string" + }, + "callID": { + "type": "string" + }, + "tool": { + "type": "string" + }, + "input": { + "type": "object" + }, + "provider": { "type": "object", - "additionalProperties": { - "type": "object" - } + "properties": { + "executed": { + "type": "boolean" + }, + "metadata": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + }, + "required": ["executed"], + "additionalProperties": false } }, - "required": ["executed"], + "required": ["timestamp", "sessionID", "assistantMessageID", "callID", "tool", "input", "provider"], "additionalProperties": false } }, - "required": ["timestamp", "sessionID", "assistantMessageID", "callID", "tool", "input", "provider"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventSessionNextToolProgress": { @@ -21451,58 +22046,67 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.next.tool.progress.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "timestamp": { + "type": { + "type": "string", + "enum": ["session.next.tool.progress.1"] + }, + "id": { + "type": "string" + }, + "seq": { "type": "number" }, - "sessionID": { - "type": "string", - "pattern": "^ses" - }, - "assistantMessageID": { + "aggregateID": { "type": "string" }, - "callID": { - "type": "string" - }, - "structured": { - "type": "object" - }, - "content": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/components/schemas/ToolTextContent" - }, - { - "$ref": "#/components/schemas/ToolFileContent" + "data": { + "type": "object", + "properties": { + "timestamp": { + "type": "number" + }, + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "assistantMessageID": { + "type": "string" + }, + "callID": { + "type": "string" + }, + "structured": { + "type": "object" + }, + "content": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/ToolTextContent" + }, + { + "$ref": "#/components/schemas/ToolFileContent" + } + ] } - ] - } + } + }, + "required": ["timestamp", "sessionID", "assistantMessageID", "callID", "structured", "content"], + "additionalProperties": false } }, - "required": ["timestamp", "sessionID", "assistantMessageID", "callID", "structured", "content"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventSessionNextToolSuccess": { @@ -21512,75 +22116,92 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.next.tool.success.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "timestamp": { + "type": { + "type": "string", + "enum": ["session.next.tool.success.1"] + }, + "id": { + "type": "string" + }, + "seq": { "type": "number" }, - "sessionID": { - "type": "string", - "pattern": "^ses" - }, - "assistantMessageID": { + "aggregateID": { "type": "string" }, - "callID": { - "type": "string" - }, - "structured": { - "type": "object" - }, - "content": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/components/schemas/ToolTextContent" - }, - { - "$ref": "#/components/schemas/ToolFileContent" - } - ] - } - }, - "result": {}, - "provider": { + "data": { "type": "object", "properties": { - "executed": { - "type": "boolean" + "timestamp": { + "type": "number" }, - "metadata": { - "type": "object", - "additionalProperties": { - "type": "object" + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "assistantMessageID": { + "type": "string" + }, + "callID": { + "type": "string" + }, + "structured": { + "type": "object" + }, + "content": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/ToolTextContent" + }, + { + "$ref": "#/components/schemas/ToolFileContent" + } + ] } + }, + "result": {}, + "provider": { + "type": "object", + "properties": { + "executed": { + "type": "boolean" + }, + "metadata": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + }, + "required": ["executed"], + "additionalProperties": false } }, - "required": ["executed"], + "required": [ + "timestamp", + "sessionID", + "assistantMessageID", + "callID", + "structured", + "content", + "provider" + ], "additionalProperties": false } }, - "required": ["timestamp", "sessionID", "assistantMessageID", "callID", "structured", "content", "provider"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventSessionNextToolFailed": { @@ -21590,62 +22211,71 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.next.tool.failed.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "timestamp": { + "type": { + "type": "string", + "enum": ["session.next.tool.failed.1"] + }, + "id": { + "type": "string" + }, + "seq": { "type": "number" }, - "sessionID": { - "type": "string", - "pattern": "^ses" - }, - "assistantMessageID": { + "aggregateID": { "type": "string" }, - "callID": { - "type": "string" - }, - "error": { - "$ref": "#/components/schemas/SessionErrorUnknown" - }, - "result": {}, - "provider": { + "data": { "type": "object", "properties": { - "executed": { - "type": "boolean" + "timestamp": { + "type": "number" }, - "metadata": { + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "assistantMessageID": { + "type": "string" + }, + "callID": { + "type": "string" + }, + "error": { + "$ref": "#/components/schemas/SessionErrorUnknown" + }, + "result": {}, + "provider": { "type": "object", - "additionalProperties": { - "type": "object" - } + "properties": { + "executed": { + "type": "boolean" + }, + "metadata": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + }, + "required": ["executed"], + "additionalProperties": false } }, - "required": ["executed"], + "required": ["timestamp", "sessionID", "assistantMessageID", "callID", "error", "provider"], "additionalProperties": false } }, - "required": ["timestamp", "sessionID", "assistantMessageID", "callID", "error", "provider"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventSessionNextRetried": { @@ -21655,42 +22285,51 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.next.retried.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "timestamp": { - "type": "number" - }, - "sessionID": { + "type": { "type": "string", - "pattern": "^ses" + "enum": ["session.next.retried.1"] }, - "attempt": { + "id": { + "type": "string" + }, + "seq": { "type": "number" }, - "error": { - "$ref": "#/components/schemas/SessionNextRetry_error" + "aggregateID": { + "type": "string" + }, + "data": { + "type": "object", + "properties": { + "timestamp": { + "type": "number" + }, + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "attempt": { + "type": "number" + }, + "error": { + "$ref": "#/components/schemas/SessionNextRetry_error" + } + }, + "required": ["timestamp", "sessionID", "attempt", "error"], + "additionalProperties": false } }, - "required": ["timestamp", "sessionID", "attempt", "error"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventSessionNextCompactionStarted": { @@ -21700,40 +22339,49 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.next.compaction.started.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "timestamp": { + "type": { + "type": "string", + "enum": ["session.next.compaction.started.1"] + }, + "id": { + "type": "string" + }, + "seq": { "type": "number" }, - "sessionID": { - "type": "string", - "pattern": "^ses" + "aggregateID": { + "type": "string" }, - "reason": { - "type": "string", - "enum": ["auto", "manual"] + "data": { + "type": "object", + "properties": { + "timestamp": { + "type": "number" + }, + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "reason": { + "type": "string", + "enum": ["auto", "manual"] + } + }, + "required": ["timestamp", "sessionID", "reason"], + "additionalProperties": false } }, - "required": ["timestamp", "sessionID", "reason"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventSessionNextCompactionDelta": { @@ -21743,39 +22391,48 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.next.compaction.delta.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "timestamp": { + "type": { + "type": "string", + "enum": ["session.next.compaction.delta.1"] + }, + "id": { + "type": "string" + }, + "seq": { "type": "number" }, - "sessionID": { - "type": "string", - "pattern": "^ses" - }, - "text": { + "aggregateID": { "type": "string" + }, + "data": { + "type": "object", + "properties": { + "timestamp": { + "type": "number" + }, + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "text": { + "type": "string" + } + }, + "required": ["timestamp", "sessionID", "text"], + "additionalProperties": false } }, - "required": ["timestamp", "sessionID", "text"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "SyncEventSessionNextCompactionEnded": { @@ -21785,42 +22442,51 @@ "type": "string", "enum": ["sync"] }, - "name": { - "type": "string", - "enum": ["session.next.compaction.ended.1"] - }, "id": { "type": "string" }, - "seq": { - "type": "number" - }, - "aggregateID": { - "type": "string", - "enum": ["sessionID"] - }, - "data": { + "syncEvent": { "type": "object", "properties": { - "timestamp": { + "type": { + "type": "string", + "enum": ["session.next.compaction.ended.1"] + }, + "id": { + "type": "string" + }, + "seq": { "type": "number" }, - "sessionID": { - "type": "string", - "pattern": "^ses" - }, - "text": { + "aggregateID": { "type": "string" }, - "include": { - "type": "string" + "data": { + "type": "object", + "properties": { + "timestamp": { + "type": "number" + }, + "sessionID": { + "type": "string", + "pattern": "^ses" + }, + "text": { + "type": "string" + }, + "include": { + "type": "string" + } + }, + "required": ["timestamp", "sessionID", "text"], + "additionalProperties": false } }, - "required": ["timestamp", "sessionID", "text"], + "required": ["type", "id", "seq", "aggregateID", "data"], "additionalProperties": false } }, - "required": ["type", "name", "id", "seq", "aggregateID", "data"], + "required": ["type", "id", "syncEvent"], "additionalProperties": false }, "PolicyEffect": { @@ -21860,6 +22526,133 @@ "required": ["directory"], "additionalProperties": false }, + "LocationInfo": { + "type": "object", + "properties": { + "directory": { + "type": "string" + }, + "workspaceID": { + "type": "string", + "pattern": "^wrk" + }, + "project": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "directory": { + "type": "string" + } + }, + "required": ["id", "directory"], + "additionalProperties": false + } + }, + "required": ["directory", "project"], + "additionalProperties": false + }, + "PermissionV2Effect": { + "type": "string", + "enum": ["allow", "deny", "ask"] + }, + "PermissionV2Rule": { + "type": "object", + "properties": { + "action": { + "type": "string" + }, + "resource": { + "type": "string" + }, + "effect": { + "$ref": "#/components/schemas/PermissionV2Effect" + } + }, + "required": ["action", "resource", "effect"], + "additionalProperties": false + }, + "PermissionV2Ruleset": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PermissionV2Rule" + } + }, + "AgentV2Info": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "model": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "providerID": { + "type": "string" + }, + "variant": { + "type": "string" + } + }, + "required": ["id", "providerID"], + "additionalProperties": false + }, + "request": { + "type": "object", + "properties": { + "headers": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "body": { + "type": "object" + } + }, + "required": ["headers", "body"], + "additionalProperties": false + }, + "system": { + "type": "string" + }, + "description": { + "type": "string" + }, + "mode": { + "type": "string", + "enum": ["subagent", "primary", "all"] + }, + "hidden": { + "type": "boolean" + }, + "color": { + "anyOf": [ + { + "type": "string", + "pattern": "^#[0-9a-fA-F]{6}$" + }, + { + "type": "string", + "enum": ["primary", "secondary", "accent", "success", "warning", "error", "info"] + } + ] + }, + "steps": { + "type": "integer", + "exclusiveMinimum": 0 + }, + "permissions": { + "$ref": "#/components/schemas/PermissionV2Ruleset" + } + }, + "required": ["id", "request", "mode", "hidden", "permissions"], + "additionalProperties": false + }, "LocationRef": { "type": "object", "properties": { @@ -22568,210 +23361,7 @@ } ] }, - "ModelV2PublicInfo": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "providerID": { - "type": "string" - }, - "family": { - "type": "string" - }, - "name": { - "type": "string" - }, - "api": { - "anyOf": [ - { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": ["aisdk"] - }, - "package": { - "type": "string" - }, - "url": { - "type": "string" - } - }, - "required": ["id", "type", "package"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": ["native"] - }, - "url": { - "type": "string" - } - }, - "required": ["id", "type"], - "additionalProperties": false - } - ] - }, - "capabilities": { - "type": "object", - "properties": { - "tools": { - "type": "boolean" - }, - "input": { - "type": "array", - "items": { - "type": "string" - } - }, - "output": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": ["tools", "input", "output"], - "additionalProperties": false - }, - "variants": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - } - }, - "required": ["id"], - "additionalProperties": false - } - }, - "time": { - "type": "object", - "properties": { - "released": { - "anyOf": [ - { - "type": "number" - }, - { - "type": "string", - "enum": ["NaN"] - }, - { - "type": "string", - "enum": ["Infinity"] - }, - { - "type": "string", - "enum": ["-Infinity"] - }, - { - "type": "string", - "enum": ["Infinity", "-Infinity", "NaN"] - } - ] - } - }, - "required": ["released"], - "additionalProperties": false - }, - "cost": { - "type": "array", - "items": { - "type": "object", - "properties": { - "tier": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": ["context"] - }, - "size": { - "type": "integer" - } - }, - "required": ["type", "size"], - "additionalProperties": false - }, - "input": { - "type": "number" - }, - "output": { - "type": "number" - }, - "cache": { - "type": "object", - "properties": { - "read": { - "type": "number" - }, - "write": { - "type": "number" - } - }, - "required": ["read", "write"], - "additionalProperties": false - } - }, - "required": ["input", "output", "cache"], - "additionalProperties": false - } - }, - "status": { - "type": "string", - "enum": ["alpha", "beta", "deprecated", "active"] - }, - "enabled": { - "type": "boolean" - }, - "limit": { - "type": "object", - "properties": { - "context": { - "type": "integer" - }, - "input": { - "type": "integer" - }, - "output": { - "type": "integer" - } - }, - "required": ["context", "output"], - "additionalProperties": false - } - }, - "required": [ - "id", - "providerID", - "name", - "api", - "capabilities", - "variants", - "time", - "cost", - "status", - "enabled", - "limit" - ], - "additionalProperties": false - }, - "ProviderV2PublicInfo": { + "ProviderV2Info": { "type": "object", "properties": { "id": { @@ -22820,9 +23410,12 @@ "via": { "type": "string", "enum": ["custom"] + }, + "data": { + "type": "object" } }, - "required": ["via"], + "required": ["via", "data"], "additionalProperties": false } ] @@ -22847,6 +23440,9 @@ }, "url": { "type": "string" + }, + "settings": { + "type": "object" } }, "required": ["type", "package"], @@ -22861,15 +23457,34 @@ }, "url": { "type": "string" + }, + "settings": { + "type": "object" } }, - "required": ["type"], + "required": ["type", "settings"], "additionalProperties": false } ] + }, + "request": { + "type": "object", + "properties": { + "headers": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "body": { + "type": "object" + } + }, + "required": ["headers", "body"], + "additionalProperties": false } }, - "required": ["id", "name", "enabled", "env", "api"], + "required": ["id", "name", "enabled", "env", "api", "request"], "additionalProperties": false }, "PermissionV2Request": { @@ -22985,6 +23600,66 @@ "required": ["path", "uri", "type", "mime"], "additionalProperties": false }, + "CommandV2Info": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "template": { + "type": "string" + }, + "description": { + "type": "string" + }, + "agent": { + "type": "string" + }, + "model": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "providerID": { + "type": "string" + }, + "variant": { + "type": "string" + } + }, + "required": ["id", "providerID"], + "additionalProperties": false + }, + "subtask": { + "type": "boolean" + } + }, + "required": ["name", "template"], + "additionalProperties": false + }, + "SkillV2Info": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "slash": { + "type": "boolean" + }, + "location": { + "type": "string" + }, + "content": { + "type": "string" + } + }, + "required": ["name", "location", "content"], + "additionalProperties": false + }, "QuestionV2Request": { "type": "object", "properties": { @@ -25949,6 +26624,22 @@ "name": "sync", "description": "Experimental HttpApi sync routes." }, + { + "name": "tui", + "description": "Experimental HttpApi TUI routes." + }, + { + "name": "workspace", + "description": "Experimental HttpApi workspace routes." + }, + { + "name": "opencode experimental HttpApi", + "description": "Experimental HttpApi surface for selected instance routes." + }, + { + "name": "opencode experimental HttpApi", + "description": "Experimental HttpApi surface for selected instance routes." + }, { "name": "v2", "description": "Experimental v2 routes." @@ -25981,6 +26672,18 @@ "name": "v2 filesystem", "description": "Experimental v2 location-scoped filesystem routes." }, + { + "name": "v2 commands", + "description": "Experimental v2 command routes." + }, + { + "name": "v2 skills", + "description": "Experimental v2 skill routes." + }, + { + "name": "v2 events", + "description": "Experimental v2 event stream route." + }, { "name": "v2 questions", "description": "Experimental v2 question routes." @@ -25989,14 +26692,6 @@ "name": "v2 session questions", "description": "Experimental v2 session question routes." }, - { - "name": "tui", - "description": "Experimental HttpApi TUI routes." - }, - { - "name": "workspace", - "description": "Experimental HttpApi workspace routes." - }, { "name": "pty", "description": "PTY websocket route." diff --git a/packages/server/src/handlers/v2/event.ts b/packages/server/src/handlers/v2/event.ts index c13fbcbebf5..cc6a01ac53c 100644 --- a/packages/server/src/handlers/v2/event.ts +++ b/packages/server/src/handlers/v2/event.ts @@ -34,13 +34,15 @@ export const eventHandlers = HttpApiBuilder.group(V2Api, "v2.event", (handlers) return HttpServerResponse.stream( Stream.make(connected).pipe( Stream.concat( - events.all().pipe( - Stream.filter( - (event) => - event.location?.directory === location.directory && - event.location.workspaceID === location.workspaceID, + events + .all() + .pipe( + Stream.filter( + (event) => + event.location?.directory === location.directory && + event.location.workspaceID === location.workspaceID, + ), ), - ), ), Stream.map(eventData), Stream.pipeThroughChannel(Sse.encode()), diff --git a/packages/server/src/routes.ts b/packages/server/src/routes.ts index 52fbe6ed4bd..c92f5b26ff2 100644 --- a/packages/server/src/routes.ts +++ b/packages/server/src/routes.ts @@ -14,23 +14,24 @@ import { schemaErrorLayer } from "./middleware/schema-error" export function createRoutes(password?: string) { return HttpApiBuilder.layer(V2Api).pipe( - Layer.provide(v2Handlers), - Layer.provide(v2AuthorizationLayer), - Layer.provide(schemaErrorLayer), - Layer.provide( - password - ? ServerAuth.Config.layer({ username: "opencode", password: Option.some(password) }) - : ServerAuth.Config.defaultLayer, - ), - Layer.provide(LocationServiceMap.layer), - Layer.provide(PermissionSaved.layer), - Layer.provide(SessionV2.defaultLayer), - Layer.provide(Database.defaultLayer), - Layer.provide(EventV2.defaultLayer), - Layer.provide(FetchHttpClient.layer), + Layer.provide(v2Handlers), + Layer.provide(v2AuthorizationLayer), + Layer.provide(schemaErrorLayer), + Layer.provide( + password + ? ServerAuth.Config.layer({ username: "opencode", password: Option.some(password) }) + : ServerAuth.Config.defaultLayer, + ), + Layer.provide(LocationServiceMap.layer), + Layer.provide(PermissionSaved.layer), + Layer.provide(SessionV2.defaultLayer), + Layer.provide(Database.defaultLayer), + Layer.provide(EventV2.defaultLayer), + Layer.provide(FetchHttpClient.layer), ) } export const routes = createRoutes() -export const webHandler = () => HttpRouter.toWebHandler(routes.pipe(Layer.provide(HttpServer.layerServices)), { disableLogger: true }) +export const webHandler = () => + HttpRouter.toWebHandler(routes.pipe(Layer.provide(HttpServer.layerServices)), { disableLogger: true }) diff --git a/specs/v2/schema-changelog.md b/specs/v2/schema-changelog.md index 8138227830b..0daa32a290e 100644 --- a/specs/v2/schema-changelog.md +++ b/specs/v2/schema-changelog.md @@ -103,7 +103,7 @@ Affected schema: Change: -- Add and backfill `session_message.seq` from matching synchronized events. +- Reset pre-launch Session-message projections and add `session_message.seq` for newly projected synchronized events. - Add event aggregate-sequence and aggregate-type-sequence indexes. - Add Session-message sequence, type-sequence, and compatibility timestamp indexes. @@ -114,7 +114,8 @@ Reason: Compatibility: -- Migration fails rather than inventing chronology if an existing projected Session message has no matching durable event. +- Pre-launch Session-message projections are disposable because historical versions could write them without durable creator events. +- The migration resets those projections rather than inventing chronology or blocking startup. - The timestamp compatibility index remains for legacy or transitional query shapes. ### Structured Tool Registry And Canonical Output