From 650d7743726dada59c30c56d0118783e34ad65ff Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Fri, 3 Jul 2026 17:30:25 -0400 Subject: [PATCH] refactor(schema): session shell payloads and event prefix restore (#35229) --- .../src/components/dialog-custom-provider.tsx | 2 +- .../app/src/components/settings-providers.tsx | 2 +- .../src/components/settings-v2/providers.tsx | 2 +- .../client/src/promise/generated/types.ts | 274 +++- packages/client/test/effect.test.ts | 10 +- packages/client/test/promise.test.ts | 4 +- packages/core/src/database/migration.gen.ts | 1 + ...703190000_reset_v2_shell_event_payloads.ts | 14 + packages/core/src/session.ts | 66 +- packages/core/src/session/compaction.ts | 2 +- packages/core/src/session/message-updater.ts | 106 +- packages/core/src/session/projector.ts | 21 +- .../core/src/session/runner/to-llm-message.ts | 2 +- packages/core/test/session-create.test.ts | 18 +- packages/core/test/session-log.test.ts | 8 +- packages/core/test/session-projector.test.ts | 31 +- packages/core/test/session-prompt.test.ts | 10 +- .../core/test/session-runner-message.test.ts | 16 +- .../core/test/session-runner-recorded.test.ts | 12 +- .../test/session-runner-tool-events.test.ts | 8 +- packages/core/test/session-runner.test.ts | 6 +- .../src/cli/cmd/run/noninteractive.ts | 30 +- .../opencode/src/cli/cmd/run/session-data.ts | 30 +- .../src/cli/cmd/run/stream-v2.subagent.ts | 30 +- .../src/cli/cmd/run/stream-v2.transport.ts | 125 +- .../test/cli/run/noninteractive.test.ts | 4 +- .../test/cli/run/session-data.test.ts | 12 +- .../test/cli/run/stream-v2.transport.test.ts | 139 +- .../opencode/test/server/httpapi-pty.test.ts | 4 +- .../opencode/test/server/httpapi-sdk.test.ts | 2 +- .../opencode/test/tool/apply_patch.test.ts | 4 +- .../test/tool/fixtures/models-api.json | 4 +- .../test/v2/session-message-updater.test.ts | 26 +- packages/schema/src/session-event.ts | 76 +- packages/schema/src/session-message.ts | 6 +- packages/schema/test/event-manifest.test.ts | 64 +- packages/sdk-next/test/embedded.test.ts | 12 +- packages/sdk/js/script/build.ts | 4 +- packages/sdk/js/src/v2/gen/types.gen.ts | 1324 +++++++++-------- packages/sdk/openapi.json | 6 +- packages/tui/src/context/data.tsx | 77 +- .../feature-plugins/system/notifications.ts | 16 +- packages/tui/src/routes/session/index.tsx | 18 +- packages/tui/src/routes/session/rows.ts | 28 +- .../test/cli/cmd/tui/notifications.test.ts | 6 +- packages/tui/test/cli/tui/data.test.tsx | 32 +- packages/ui/src/components/provider-icon.tsx | 2 +- specs/v2/schema-changelog.md | 23 +- specs/v2/session.md | 2 +- 49 files changed, 1521 insertions(+), 1200 deletions(-) create mode 100644 packages/core/src/database/migration/20260703190000_reset_v2_shell_event_payloads.ts diff --git a/packages/app/src/components/dialog-custom-provider.tsx b/packages/app/src/components/dialog-custom-provider.tsx index 647e5002a2..dfc1bb8c22 100644 --- a/packages/app/src/components/dialog-custom-provider.tsx +++ b/packages/app/src/components/dialog-custom-provider.tsx @@ -177,7 +177,7 @@ export function DialogCustomProvider(props: Props) { >
- +
{language.t("provider.custom.title")}
diff --git a/packages/app/src/components/settings-providers.tsx b/packages/app/src/components/settings-providers.tsx index 24e7a60104..ca6413e4ba 100644 --- a/packages/app/src/components/settings-providers.tsx +++ b/packages/app/src/components/settings-providers.tsx @@ -226,7 +226,7 @@ const SettingsProvidersContent: Component = () => { >
- + {language.t("provider.custom.title")} {language.t("settings.providers.tag.custom")}
diff --git a/packages/app/src/components/settings-v2/providers.tsx b/packages/app/src/components/settings-v2/providers.tsx index cd24bbd455..e244581b97 100644 --- a/packages/app/src/components/settings-v2/providers.tsx +++ b/packages/app/src/components/settings-v2/providers.tsx @@ -223,7 +223,7 @@ export const SettingsProvidersV2: Component = () => {
event.type)).toEqual(["server.connected", "model.selected"]) + expect(Array.from(events).map((event) => event.type)).toEqual(["server.connected", "session.model.selected"]) const durable = events[1] - if (durable?.type !== "model.selected") throw new Error("Expected model event") + if (durable?.type !== "session.model.selected") throw new Error("Expected model event") expect(DateTime.toEpochMillis(durable.created)).toBe(1_717_171_717_000) expect(durable.durable).toEqual({ aggregateID: "ses_test", seq: 1, version: 1 }) }) @@ -159,8 +159,8 @@ test("session methods retain decoded Effect inputs and outputs", async () => { expect(result.context).toEqual([]) expect(logQueries[0]).toEqual({ after: "0" }) const logged = Array.from(result.log) - expect(logged.map((item) => item.type)).toEqual(["model.selected", "log.synced"]) - expect(logged[0]?.type === "model.selected" && DateTime.toEpochMillis(logged[0].created)).toBe( + expect(logged.map((item) => item.type)).toEqual(["session.model.selected", "log.synced"]) + expect(logged[0]?.type === "session.model.selected" && DateTime.toEpochMillis(logged[0].created)).toBe( 1_717_171_717_000, ) expect(logged.at(-1)).toEqual(synced) @@ -228,7 +228,7 @@ const modelSwitchedMessage = { const modelSwitchedEvent = { id: "evt_model", created: 1_717_171_717_000, - type: "model.selected", + type: "session.model.selected", durable: { aggregateID: "ses_test", seq: 1, version: 1 }, data: { sessionID: "ses_test", diff --git a/packages/client/test/promise.test.ts b/packages/client/test/promise.test.ts index 9e8ea7acfe..d445a69c08 100644 --- a/packages/client/test/promise.test.ts +++ b/packages/client/test/promise.test.ts @@ -160,7 +160,7 @@ test("event.subscribe exposes the Promise event stream wire projection", async ( for await (const event of client.event.subscribe()) events.push(event) expect(events).toEqual([{ id: "evt_connected", created: 0, type: "server.connected", data: {} }, modelSwitchedEvent]) - expect(events[1]?.type === "model.selected" && events[1].created).toBe(1_717_171_717_000) + expect(events[1]?.type === "session.model.selected" && events[1].created).toBe(1_717_171_717_000) }) test("event.subscribe terminates on malformed Promise SSE data", async () => { @@ -329,7 +329,7 @@ const synced = { type: "log.synced", aggregateID: "ses_test", seq: 1 } const modelSwitchedEvent = { id: "evt_model", created: 1_717_171_717_000, - type: "model.selected", + type: "session.model.selected", durable: { aggregateID: "ses_test", seq: 1, version: 1 }, data: { sessionID: "ses_test", diff --git a/packages/core/src/database/migration.gen.ts b/packages/core/src/database/migration.gen.ts index 7956b64f4d..e6a236f527 100644 --- a/packages/core/src/database/migration.gen.ts +++ b/packages/core/src/database/migration.gen.ts @@ -43,5 +43,6 @@ export const migrations = ( import("./migration/20260702134641_add_session_context_entry"), import("./migration/20260703090000_reset_v2_event_rename_sweep"), import("./migration/20260703181610_event_created_column"), + import("./migration/20260703190000_reset_v2_shell_event_payloads"), ]) ).map((module) => module.default) satisfies DatabaseMigration.Migration[] diff --git a/packages/core/src/database/migration/20260703190000_reset_v2_shell_event_payloads.ts b/packages/core/src/database/migration/20260703190000_reset_v2_shell_event_payloads.ts new file mode 100644 index 0000000000..ffbe40652c --- /dev/null +++ b/packages/core/src/database/migration/20260703190000_reset_v2_shell_event_payloads.ts @@ -0,0 +1,14 @@ +import { Effect } from "effect" +import type { DatabaseMigration } from "../migration" + +export default { + id: "20260703190000_reset_v2_shell_event_payloads", + up(tx) { + return Effect.gen(function* () { + yield* tx.run(`DELETE FROM \`session_input\`;`) + yield* tx.run(`DELETE FROM \`session_message\`;`) + yield* tx.run(`DELETE FROM \`event\`;`) + yield* tx.run(`DELETE FROM \`event_sequence\`;`) + }) + }, +} satisfies DatabaseMigration.Migration diff --git a/packages/core/src/session.ts b/packages/core/src/session.ts index 108d36707a..e8928a7520 100644 --- a/packages/core/src/session.ts +++ b/packages/core/src/session.ts @@ -41,8 +41,8 @@ import type { EventLog } from "@opencode-ai/schema/event-log" import { SkillV2 } from "./skill" import { Job } from "./job" import { CommandV2 } from "./command" -import { Identifier } from "./util/identifier" import { Shell } from "./shell" +import { Shell as ShellSchema } from "@opencode-ai/schema/shell" import { KeyedMutex } from "./effect/keyed-mutex" export const RevertState = Revert.State @@ -272,19 +272,6 @@ const layer = Layer.effect( ), ) - // Session shell is user-initiated and synchronous at the API boundary, while - // the Location shell service owns process lifecycle and file-backed output. - const runShellCommand = (command: string, cwd: string) => - Effect.gen(function* () { - const shell = yield* Shell.Service - const info = yield* shell.create({ command, cwd }) - yield* shell.wait(info.id) - const output = yield* shell.output(info.id, { limit: SHELL_MAX_CAPTURE_BYTES }) - return output.output || "(no output)" - }).pipe( - Effect.catchTag("Shell.NotFoundError", () => Effect.succeed("Shell command output is no longer available.")), - ) - const result = Service.of({ create: Effect.fn("V2Session.create")(function* (input) { const sessionID = input.id ?? SessionSchema.ID.create() @@ -550,23 +537,38 @@ const layer = Layer.effect( Effect.gen(function* () { activeShells.add(input.sessionID) if ((yield* execution.active).has(input.sessionID)) yield* execution.awaitIdle(input.sessionID) - const callID = Identifier.ascending() + const started = yield* Effect.gen(function* () { + const shell = yield* Shell.Service + return yield* shell.create({ command: input.command, cwd: session.location.directory }) + }).pipe(Effect.provide(locations.get(session.location))) yield* events.publish( SessionEvent.Shell.Started, { sessionID: input.sessionID, - callID, - command: input.command, + shell: started, }, { id: input.id }, ) - const output = yield* runShellCommand(input.command, session.location.directory).pipe( - Effect.provide(locations.get(session.location)), - ) + const completed = yield* Effect.gen(function* () { + const shell = yield* Shell.Service + const terminal = yield* shell.wait(started.id).pipe( + Effect.map((info) => ({ info, retained: true as const })), + Effect.catchTag("Shell.NotFoundError", () => + Effect.succeed({ info: synthesizeTerminalShellInfo(started), retained: false as const }), + ), + ) + const output = terminal.retained + ? yield* shell + .output(started.id, { limit: SHELL_MAX_CAPTURE_BYTES }) + .pipe(Effect.catchTag("Shell.NotFoundError", () => Effect.succeed(missingShellOutput()))) + : missingShellOutput() + return { shell: terminal.info, output } + }) + .pipe(Effect.provide(locations.get(session.location))) yield* events.publish(SessionEvent.Shell.Ended, { sessionID: input.sessionID, - callID, - output, + shell: completed.shell, + output: completed.output, }) }).pipe( Effect.ensuring( @@ -706,6 +708,26 @@ const layer = Layer.effect( }), ) +function missingShellOutput() { + const output = "Shell command output is no longer available." + return { + output, + cursor: Buffer.byteLength(output), + size: Buffer.byteLength(output), + truncated: false, + } +} + +function synthesizeTerminalShellInfo(started: ShellSchema.Info): ShellSchema.Info { + return { + ...started, + // The Shell record was removed before waiters could observe it; publish a terminal + // boundary instead of leaving the Session shell message permanently running. + status: "killed", + time: { ...started.time, completed: Date.now() }, + } +} + const resolvePrompt = (input: PromptInput.Prompt) => Prompt.make({ text: input.text, diff --git a/packages/core/src/session/compaction.ts b/packages/core/src/session/compaction.ts index 1174b65f40..9ad9ddc81a 100644 --- a/packages/core/src/session/compaction.ts +++ b/packages/core/src/session/compaction.ts @@ -129,7 +129,7 @@ const serialize = (message: SessionMessage.Message) => { if (message.type === "system") return `[System update]: ${message.text}` if (message.type === "synthetic") return `[Synthetic context]: ${message.text}` if (message.type === "skill") return `[Skill activated: ${message.name}]\n${message.text}` - if (message.type === "shell") return `[Shell]: ${message.command}\n${truncate(message.output)}` + if (message.type === "shell") return `[Shell]: ${message.shell.command}\n${truncate(message.output?.output ?? "")}` return "" } diff --git a/packages/core/src/session/message-updater.ts b/packages/core/src/session/message-updater.ts index a23ecb224c..3658e67c0f 100644 --- a/packages/core/src/session/message-updater.ts +++ b/packages/core/src/session/message-updater.ts @@ -8,21 +8,25 @@ export type MemoryState = { } export interface Adapter { - readonly getCurrentAssistant: () => Effect.Effect - readonly getAssistant: (messageID: SessionMessage.ID) => Effect.Effect - readonly getCurrentShell: (callID: string) => Effect.Effect - readonly updateAssistant: (assistant: SessionMessage.Assistant) => Effect.Effect - readonly updateShell: (shell: SessionMessage.Shell) => Effect.Effect - readonly appendMessage: (message: SessionMessage.Message) => Effect.Effect + readonly getCurrentAssistant: () => Effect.Effect + readonly getAssistant: ( + messageID: SessionMessage.ID, + ) => Effect.Effect + readonly getShell: ( + shellID: SessionMessage.Shell["shell"]["id"], + ) => Effect.Effect + readonly updateAssistant: (assistant: SessionMessage.Assistant) => Effect.Effect + readonly updateShell: (shell: SessionMessage.Shell) => Effect.Effect + readonly appendMessage: (message: SessionMessage.Message) => Effect.Effect } export function memory(state: MemoryState): Adapter { const assistantIndex = (messageID: SessionMessage.ID) => state.messages.findLastIndex((message) => message.id === messageID) + const shellIndex = (messageID: SessionMessage.ID) => + state.messages.findLastIndex((message) => message.id === messageID) // A newer step supersedes stale incomplete rows; never resume an older assistant projection. const latestAssistantIndex = () => state.messages.findLastIndex((message) => message.type === "assistant") - const activeShellIndex = (callID: string) => - state.messages.findLastIndex((message) => message.type === "shell" && message.callID === callID) return { getCurrentAssistant() { @@ -41,12 +45,11 @@ export function memory(state: MemoryState): Adapter { return assistant?.type === "assistant" ? assistant : undefined }) }, - getCurrentShell(callID) { + getShell(shellID) { return Effect.sync(() => { - const index = activeShellIndex(callID) - if (index < 0) return - const shell = state.messages[index] - return shell?.type === "shell" ? shell : undefined + return state.messages.find((message): message is SessionMessage.Shell => { + return message.type === "shell" && message.shell.id === shellID + }) }) }, updateAssistant(assistant) { @@ -60,7 +63,7 @@ export function memory(state: MemoryState): Adapter { }, updateShell(shell) { return Effect.sync(() => { - const index = activeShellIndex(shell.callID) + const index = shellIndex(shell.id) if (index < 0) return const current = state.messages[index] if (current?.type !== "shell") return @@ -100,7 +103,7 @@ export function update(adapter: Adapter, event: SessionEvent.Event) { return Effect.gen(function* () { yield* SessionEvent.All.match(event, { - "agent.selected": (event) => { + "session.agent.selected": (event) => { return adapter.appendMessage( SessionMessage.AgentSelected.make({ id: SessionMessage.ID.fromEvent(event.id), @@ -111,7 +114,7 @@ export function update(adapter: Adapter, event: SessionEvent.Event) { }), ) }, - "model.selected": (event) => { + "session.model.selected": (event) => { return adapter.appendMessage( SessionMessage.ModelSelected.make({ id: SessionMessage.ID.fromEvent(event.id), @@ -123,11 +126,11 @@ export function update(adapter: Adapter, event: SessionEvent.Event) { ) }, "session.moved": () => Effect.void, - renamed: () => Effect.void, - forked: () => Effect.void, - "prompt.promoted": () => Effect.void, - "prompt.admitted": () => Effect.void, - "execution.settled": () => Effect.void, + "session.renamed": () => Effect.void, + "session.forked": () => Effect.void, + "session.prompt.promoted": () => Effect.void, + "session.prompt.admitted": () => Effect.void, + "session.execution.settled": () => Effect.void, "session.context.updated": (event) => adapter.appendMessage( SessionMessage.System.make({ @@ -137,7 +140,7 @@ export function update(adapter: Adapter, event: SessionEvent.Event) { time: { created: event.created }, }), ), - synthetic: (event) => { + "session.synthetic": (event) => { return adapter.appendMessage( SessionMessage.Synthetic.make({ sessionID: event.data.sessionID, @@ -150,7 +153,7 @@ export function update(adapter: Adapter, event: SessionEvent.Event) { }), ) }, - "skill.activated": (event) => { + "session.skill.activated": (event) => { return adapter.appendMessage( SessionMessage.Skill.make({ id: SessionMessage.ID.fromEvent(event.id), @@ -161,25 +164,24 @@ export function update(adapter: Adapter, event: SessionEvent.Event) { }), ) }, - "shell.started": (event) => { + "session.shell.started": (event) => { return adapter.appendMessage( SessionMessage.Shell.make({ id: SessionMessage.ID.fromEvent(event.id), type: "shell", metadata: event.metadata, - callID: event.data.callID, - command: event.data.command, - output: "", + shell: event.data.shell, time: { created: event.created }, }), ) }, - "shell.ended": (event) => { + "session.shell.ended": (event) => { return Effect.gen(function* () { - const currentShell = yield* adapter.getCurrentShell(event.data.callID) + const currentShell = yield* adapter.getShell(event.data.shell.id) if (currentShell) { yield* adapter.updateShell( produce(currentShell, (draft) => { + draft.shell = castDraft(event.data.shell) draft.output = event.data.output draft.time.completed = event.created }), @@ -187,7 +189,7 @@ export function update(adapter: Adapter, event: SessionEvent.Event) { } }) }, - "step.started": (event) => { + "session.step.started": (event) => { return Effect.gen(function* () { const currentAssistant = yield* adapter.getCurrentAssistant() if (currentAssistant) { @@ -210,7 +212,7 @@ export function update(adapter: Adapter, event: SessionEvent.Event) { ) }) }, - "step.ended": (event) => { + "session.step.ended": (event) => { return updateOwnedAssistant(event.data.assistantMessageID, (draft) => { draft.time.completed = event.created draft.finish = event.data.finish @@ -224,33 +226,33 @@ export function update(adapter: Adapter, event: SessionEvent.Event) { } }) }, - "step.failed": (event) => { + "session.step.failed": (event) => { return updateOwnedAssistant(event.data.assistantMessageID, (draft) => { draft.time.completed = event.created draft.finish = "error" draft.error = event.data.error }) }, - "text.started": (event) => { + "session.text.started": (event) => { return updateOwnedAssistant(event.data.assistantMessageID, (draft) => { draft.content.push( castDraft(SessionMessage.AssistantText.make({ type: "text", id: event.data.textID, text: "" })), ) }) }, - "text.delta": (event) => { + "session.text.delta": (event) => { return updateOwnedAssistant(event.data.assistantMessageID, (draft) => { const match = latestText(draft, event.data.textID) if (match) match.text += event.data.delta }) }, - "text.ended": (event) => { + "session.text.ended": (event) => { return updateOwnedAssistant(event.data.assistantMessageID, (draft) => { const match = latestText(draft, event.data.textID) if (match) match.text = event.data.text }) }, - "tool.input.started": (event) => { + "session.tool.input.started": (event) => { return updateOwnedAssistant(event.data.assistantMessageID, (draft) => { draft.content.push( castDraft( @@ -265,14 +267,14 @@ export function update(adapter: Adapter, event: SessionEvent.Event) { ) }) }, - "tool.input.delta": () => Effect.void, - "tool.input.ended": (event) => { + "session.tool.input.delta": () => Effect.void, + "session.tool.input.ended": (event) => { return updateOwnedAssistant(event.data.assistantMessageID, (draft) => { const match = latestTool(draft, event.data.callID) if (match && match.state.status === "pending") match.state.input = event.data.text }) }, - "tool.called": (event) => { + "session.tool.called": (event) => { return updateOwnedAssistant(event.data.assistantMessageID, (draft) => { const match = latestTool(draft, event.data.callID) if (match) { @@ -289,7 +291,7 @@ export function update(adapter: Adapter, event: SessionEvent.Event) { } }) }, - "tool.progress": (event) => { + "session.tool.progress": (event) => { return updateOwnedAssistant(event.data.assistantMessageID, (draft) => { const match = latestTool(draft, event.data.callID) if (match && match.state.status === "running") { @@ -298,7 +300,7 @@ export function update(adapter: Adapter, event: SessionEvent.Event) { } }) }, - "tool.success": (event) => { + "session.tool.success": (event) => { return updateOwnedAssistant(event.data.assistantMessageID, (draft) => { const match = latestTool(draft, event.data.callID) if (match && match.state.status === "running") { @@ -321,7 +323,7 @@ export function update(adapter: Adapter, event: SessionEvent.Event) { } }) }, - "tool.failed": (event) => { + "session.tool.failed": (event) => { return updateOwnedAssistant(event.data.assistantMessageID, (draft) => { const match = latestTool(draft, event.data.callID) if (match && (match.state.status === "pending" || match.state.status === "running")) { @@ -344,7 +346,7 @@ export function update(adapter: Adapter, event: SessionEvent.Event) { } }) }, - "reasoning.started": (event) => { + "session.reasoning.started": (event) => { return updateOwnedAssistant(event.data.assistantMessageID, (draft) => { draft.content.push( castDraft( @@ -359,13 +361,13 @@ export function update(adapter: Adapter, event: SessionEvent.Event) { ) }) }, - "reasoning.delta": (event) => { + "session.reasoning.delta": (event) => { return updateOwnedAssistant(event.data.assistantMessageID, (draft) => { const match = latestReasoning(draft, event.data.reasoningID) if (match) match.text += event.data.delta }) }, - "reasoning.ended": (event) => { + "session.reasoning.ended": (event) => { return updateOwnedAssistant(event.data.assistantMessageID, (draft) => { const match = latestReasoning(draft, event.data.reasoningID) if (match) { @@ -375,10 +377,10 @@ export function update(adapter: Adapter, event: SessionEvent.Event) { } }) }, - retried: () => Effect.void, - "compaction.started": () => Effect.void, - "compaction.delta": () => Effect.void, - "compaction.ended": (event) => { + "session.retried": () => Effect.void, + "session.compaction.started": () => Effect.void, + "session.compaction.delta": () => Effect.void, + "session.compaction.ended": (event) => { return adapter.appendMessage( SessionMessage.Compaction.make({ id: SessionMessage.ID.fromEvent(event.id), @@ -391,9 +393,9 @@ export function update(adapter: Adapter, event: SessionEvent.Event) { }), ) }, - "revert.staged": () => Effect.void, - "revert.cleared": () => Effect.void, - "revert.committed": () => Effect.void, + "session.revert.staged": () => Effect.void, + "session.revert.cleared": () => Effect.void, + "session.revert.committed": () => Effect.void, }) }) } diff --git a/packages/core/src/session/projector.ts b/packages/core/src/session/projector.ts index c5b552e8b4..746e448a3b 100644 --- a/packages/core/src/session/projector.ts +++ b/packages/core/src/session/projector.ts @@ -393,18 +393,25 @@ function run(db: DatabaseService, event: MessageEvent) { return message.type === "assistant" ? message : undefined }) }, - getCurrentShell(callID) { + getShell(shellID) { return Effect.gen(function* () { - const rows = yield* db + const row = yield* db .select() .from(SessionMessageTable) - .where(and(eq(SessionMessageTable.session_id, event.data.sessionID), eq(SessionMessageTable.type, "shell"))) + .where( + and( + eq(SessionMessageTable.session_id, event.data.sessionID), + eq(SessionMessageTable.type, "shell"), + sql`json_extract(${SessionMessageTable.data}, '$.shell.id') = ${shellID}`, + ), + ) .orderBy(desc(SessionMessageTable.seq)) - .all() + .limit(1) + .get() .pipe(Effect.orDie) - return rows - .map(decodeRow) - .find((message): message is SessionMessage.Shell => message.type === "shell" && message.callID === callID) + if (!row) return + const message = decodeRow(row) + return message.type === "shell" ? message : undefined }) }, updateAssistant: updateMessage, diff --git a/packages/core/src/session/runner/to-llm-message.ts b/packages/core/src/session/runner/to-llm-message.ts index 0d9055e480..e6a91a9ef1 100644 --- a/packages/core/src/session/runner/to-llm-message.ts +++ b/packages/core/src/session/runner/to-llm-message.ts @@ -139,7 +139,7 @@ function toLLMMessage(message: SessionMessage.Message, model: Model): Message[] Message.make({ id: message.id, role: "user", - content: `Shell command: ${message.command}\n\n${message.output}`, + content: `Shell command: ${message.shell.command}\n\n${message.output?.output ?? ""}`, metadata: message.metadata, }), ] diff --git a/packages/core/test/session-create.test.ts b/packages/core/test/session-create.test.ts index 0100ca4ae9..d18c2c8e81 100644 --- a/packages/core/test/session-create.test.ts +++ b/packages/core/test/session-create.test.ts @@ -213,7 +213,7 @@ describe("SessionV2.create", () => { expect(forkContext.map((message) => message.id)).not.toEqual(parentContext.map((message) => message.id)) expect(history).toHaveLength(1) expect(history[0]).toMatchObject({ - type: "forked", + type: "session.forked", durable: { seq: 0 }, data: { sessionID: forked.id, parentID: parent.id }, }) @@ -378,8 +378,8 @@ describe("SessionV2.create", () => { expect( Array.from(yield* logEvents(session, created.id, true).pipe(Stream.take(2), Stream.runCollect)), ).toMatchObject([ - { durable: { seq: 1 }, type: "prompt.admitted", data: { prompt: { text: "Hello" } } }, - { durable: { seq: 2 }, type: "prompt.promoted" }, + { durable: { seq: 1 }, type: "session.prompt.admitted", data: { prompt: { text: "Hello" } } }, + { durable: { seq: 2 }, type: "session.prompt.promoted" }, ]) }), ) @@ -494,8 +494,9 @@ describe("SessionV2.create", () => { const messages = yield* session.messages({ sessionID: created.id, order: "asc" }) const shell = messages.find((message): message is SessionMessage.Shell => message.type === "shell") - expect(shell).toMatchObject({ type: "shell", command: "echo hello" }) - expect(shell?.output).toContain("hello") + expect(shell).toMatchObject({ type: "shell", shell: { command: "echo hello", status: "exited", exit: 0 } }) + expect(shell?.output?.output).toContain("hello") + expect(shell?.output?.truncated).toBe(false) expect(shell?.time.completed).toBeDefined() }), ), @@ -513,7 +514,8 @@ describe("SessionV2.create", () => { const messages = yield* session.messages({ sessionID: created.id, order: "asc" }) const shell = messages.find((message): message is SessionMessage.Shell => message.type === "shell") - expect(shell).toMatchObject({ type: "shell", command: "false" }) + expect(shell).toMatchObject({ type: "shell", shell: { command: "false", status: "exited" } }) + expect(shell?.shell.exit).not.toBe(0) expect(shell?.time.completed).toBeDefined() }), ), @@ -529,7 +531,7 @@ describe("SessionV2.create", () => { expect(yield* session.get(created.id)).toMatchObject({ agent: "plan" }) expect( Array.from(yield* logEvents(session, created.id, true).pipe(Stream.take(1), Stream.runCollect)), - ).toMatchObject([{ type: "agent.selected", data: { agent: "plan" } }]) + ).toMatchObject([{ type: "session.agent.selected", data: { agent: "plan" } }]) }), ) @@ -562,7 +564,7 @@ describe("SessionV2.create", () => { expect(yield* session.get(created.id)).toMatchObject({ model }) expect( Array.from(yield* logEvents(session, created.id, true).pipe(Stream.take(1), Stream.runCollect)), - ).toMatchObject([{ type: "model.selected", data: { model } }]) + ).toMatchObject([{ type: "session.model.selected", data: { model } }]) }), ) diff --git a/packages/core/test/session-log.test.ts b/packages/core/test/session-log.test.ts index 8c49b94582..ed8dda7f4d 100644 --- a/packages/core/test/session-log.test.ts +++ b/packages/core/test/session-log.test.ts @@ -40,14 +40,14 @@ describe("SessionV2.log", () => { const session = yield* SessionV2.Service const events = yield* EventV2.Service const created = yield* session.create({ location }) - yield* session.rename({ sessionID: created.id, title: "renamed" }) + yield* session.rename({ sessionID: created.id, title: "session.renamed" }) const items = Array.from(yield* Stream.runCollect(session.log({ sessionID: created.id }))) const watermark = (yield* events.sequences([created.id])).get(created.id) // Session creation commits a non-public durable event, so the marker's // seq covers more of the aggregate than the public events emitted. - expect(items.map((item) => item.type)).toEqual(["renamed", "log.synced"]) + expect(items.map((item) => item.type)).toEqual(["session.renamed", "log.synced"]) expect(items.at(-1)).toEqual({ type: "log.synced", aggregateID: created.id, seq: watermark }) }), ) @@ -64,7 +64,7 @@ describe("SessionV2.log", () => { yield* session.rename({ sessionID: created.id, title: "renamed live" }) const items = Array.from(yield* Fiber.join(fiber)) - expect(items.map((item) => item.type)).toEqual(["log.synced", "renamed"]) + expect(items.map((item) => item.type)).toEqual(["log.synced", "session.renamed"]) }), ) @@ -137,7 +137,7 @@ describe("SessionV2 watermarks", () => { const events = yield* EventV2.Service const first = yield* session.create({ location }) const second = yield* session.create({ location }) - yield* session.rename({ sessionID: first.id, title: "renamed" }) + yield* session.rename({ sessionID: first.id, title: "session.renamed" }) const page = yield* session.list() const sequences = yield* events.sequences([first.id, second.id]) diff --git a/packages/core/test/session-projector.test.ts b/packages/core/test/session-projector.test.ts index c0d172088e..c17b979076 100644 --- a/packages/core/test/session-projector.test.ts +++ b/packages/core/test/session-projector.test.ts @@ -19,6 +19,7 @@ import { SessionMessageUpdater } from "@opencode-ai/core/session/message-updater import { SessionProjector } from "@opencode-ai/core/session/projector" import { SessionExecution } from "@opencode-ai/core/session/execution" import { SessionInput } from "@opencode-ai/core/session/input" +import { Shell } from "@opencode-ai/schema/shell" import { SessionContextCheckpointTable, SessionInputTable, @@ -257,15 +258,32 @@ describe("SessionProjector", () => { }) yield* events.publish(SessionEvent.Shell.Started, { sessionID, - callID: "shell-1", - command: "pwd", + shell: Shell.Info.make({ + id: Shell.ID.make("sh_projector"), + status: "running", + command: "pwd", + cwd: "/project", + shell: "/bin/sh", + file: "/tmp/sh_projector.out", + metadata: {}, + time: { started: 0 }, + }), }) yield* events.publish(SessionEvent.Shell.Ended, { sessionID, - callID: "shell-1", - output: "/project", + shell: Shell.Info.make({ + id: Shell.ID.make("sh_projector"), + status: "exited", + command: "pwd", + cwd: "/project", + shell: "/bin/sh", + file: "/tmp/sh_projector.out", + exit: 0, + metadata: {}, + time: { started: 0, completed: 1 }, + }), + output: { output: "/project", cursor: 8, size: 8, truncated: false }, }) - const compactionID = SessionMessage.ID.create() yield* events.publish(SessionEvent.Compaction.Started, { sessionID, reason: "manual", @@ -320,7 +338,8 @@ describe("SessionProjector", () => { metadata: { source: "projector-test" }, }) expect(messages.find((message) => message.type === "shell")).toMatchObject({ - output: "/project", + shell: { command: "pwd", status: "exited", exit: 0 }, + output: { output: "/project", truncated: false }, time: { completed: DateTime.makeUnsafe(0) }, }) expect(messages.find((message) => message.type === "compaction")).toMatchObject({ diff --git a/packages/core/test/session-prompt.test.ts b/packages/core/test/session-prompt.test.ts index 58a613a324..e7d3f5189f 100644 --- a/packages/core/test/session-prompt.test.ts +++ b/packages/core/test/session-prompt.test.ts @@ -256,16 +256,16 @@ describe("SessionV2.prompt", () => { const streamed = Array.from(yield* Fiber.join(fiber)) expect(streamed.map((event): [number | undefined, string] => [event.durable?.seq, event.type])).toEqual([ - [0, "prompt.admitted"], - [1, "prompt.admitted"], - [2, "prompt.promoted"], - [3, "prompt.promoted"], + [0, "session.prompt.admitted"], + [1, "session.prompt.admitted"], + [2, "session.prompt.promoted"], + [3, "session.prompt.promoted"], ]) expect( Array.from( yield* publicEvents({ sessionID, after: streamed[0].durable?.seq }).pipe(Stream.take(1), Stream.runCollect), ).map((event): [number | undefined, string] => [event.durable?.seq, event.type]), - ).toEqual([[1, "prompt.admitted"]]) + ).toEqual([[1, "session.prompt.admitted"]]) }), ) diff --git a/packages/core/test/session-runner-message.test.ts b/packages/core/test/session-runner-message.test.ts index d33b44728d..9aed484858 100644 --- a/packages/core/test/session-runner-message.test.ts +++ b/packages/core/test/session-runner-message.test.ts @@ -7,6 +7,7 @@ import { SessionMessage } from "@opencode-ai/core/session/message" import { AgentAttachment, FileAttachment } from "@opencode-ai/core/session/prompt" import { toLLMMessages } from "@opencode-ai/core/session/runner/to-llm-message" import { SessionV2 } from "@opencode-ai/core/session" +import { Shell } from "@opencode-ai/schema/shell" import { DateTime } from "effect" const created = DateTime.makeUnsafe(0) @@ -87,9 +88,18 @@ describe("toLLMMessages", () => { SessionMessage.Shell.make({ id: id("shell"), type: "shell", - callID: "shell-1", - command: "pwd", - output: "/project", + shell: Shell.Info.make({ + id: Shell.ID.make("sh_test"), + status: "exited", + command: "pwd", + cwd: "/project", + shell: "/bin/sh", + file: "/tmp/sh_test.out", + exit: 0, + metadata: {}, + time: { started: 0, completed: 0 }, + }), + output: { output: "/project", cursor: 8, size: 8, truncated: false }, time: { created, completed: created }, }), SessionMessage.Compaction.make({ diff --git a/packages/core/test/session-runner-recorded.test.ts b/packages/core/test/session-runner-recorded.test.ts index 4f82baba96..35e84fcb6c 100644 --- a/packages/core/test/session-runner-recorded.test.ts +++ b/packages/core/test/session-runner-recorded.test.ts @@ -193,12 +193,12 @@ describe("SessionRunnerLLM recorded", () => { .orderBy(EventTable.seq) .all()).map((event) => event.type), ).toEqual([ - "prompt.admitted.1", - "prompt.promoted.1", - "step.started.1", - "text.started.1", - "text.ended.1", - "step.ended.1", + "session.prompt.admitted.1", + "session.prompt.promoted.1", + "session.step.started.1", + "session.text.started.1", + "session.text.ended.1", + "session.step.ended.1", ]) }), ) diff --git a/packages/core/test/session-runner-tool-events.test.ts b/packages/core/test/session-runner-tool-events.test.ts index 5c8d7e07f4..d016b2694b 100644 --- a/packages/core/test/session-runner-tool-events.test.ts +++ b/packages/core/test/session-runner-tool-events.test.ts @@ -76,7 +76,7 @@ test("local tool success serializes media base64 once and reconstructs from stru await Effect.runPromise(publisher.publish(call)) await Effect.runPromise(publisher.publish(result)) - const success = published.find((event) => event.type === "tool.success.1") + const success = published.find((event) => event.type === "session.tool.success.1") expect(success).toBeDefined() const serialized = JSON.stringify(success) expect(serialized.split(base64)).toHaveLength(2) @@ -94,7 +94,7 @@ test("provider-executed success retains its compatibility result", async () => { const { published, publisher } = capture() await Effect.runPromise(publisher.publish(LLMEvent.toolCall({ ...call, providerExecuted: true }))) await Effect.runPromise(publisher.publish(LLMEvent.toolResult({ ...result, providerExecuted: true }))) - const success = published.find((event) => event.type === "tool.success.1") + const success = published.find((event) => event.type === "session.tool.success.1") expect(success?.data).toHaveProperty("result") }) @@ -110,8 +110,8 @@ test("binary failure emits no success event", async () => { }), ), ) - expect(published.some((event) => event.type === "tool.success.1")).toBe(false) - expect(published.some((event) => event.type === "tool.failed.1")).toBe(true) + expect(published.some((event) => event.type === "session.tool.success.1")).toBe(false) + expect(published.some((event) => event.type === "session.tool.failed.1")).toBe(true) }) test("old success event data containing result still decodes", () => { diff --git a/packages/core/test/session-runner.test.ts b/packages/core/test/session-runner.test.ts index e6f14c8e19..6856b6a7ce 100644 --- a/packages/core/test/session-runner.test.ts +++ b/packages/core/test/session-runner.test.ts @@ -2985,7 +2985,7 @@ describe("SessionRunnerLLM", () => { { type: "user", text: "Interrupt provider" }, { type: "assistant", finish: "error", error: { type: "unknown", message: "Step interrupted" } }, ]) - expect(yield* recordedEventTypes(sessionID)).toContain("step.failed.1") + expect(yield* recordedEventTypes(sessionID)).toContain("session.step.failed.1") yield* session.interrupt(sessionID) }), ) @@ -3029,8 +3029,8 @@ describe("SessionRunnerLLM", () => { }, ]) const eventTypes = yield* recordedEventTypes(sessionID) - expect(eventTypes).toContain("step.failed.1") - expect(eventTypes).not.toContain("step.ended.1") + expect(eventTypes).toContain("session.step.failed.1") + expect(eventTypes).not.toContain("session.step.ended.1") }), ) diff --git a/packages/opencode/src/cli/cmd/run/noninteractive.ts b/packages/opencode/src/cli/cmd/run/noninteractive.ts index 60ded4ebd9..6874527222 100644 --- a/packages/opencode/src/cli/cmd/run/noninteractive.ts +++ b/packages/opencode/src/cli/cmd/run/noninteractive.ts @@ -158,14 +158,14 @@ export async function runNonInteractivePrompt(input: Input) { if (!("sessionID" in event.data) || event.data.sessionID !== input.sessionID) continue const time = toMillis(event.created) - if (event.type === "prompt.promoted") { + if (event.type === "session.prompt.promoted") { if (event.data.inputID === messageID) { promoted = true continue } } if ( - event.type === "execution.settled" && + event.type === "session.execution.settled" && event.data.outcome === "interrupted" && (interrupted || permissionRejected || questionRejected || formCancelled) ) { @@ -173,7 +173,7 @@ export async function runNonInteractivePrompt(input: Input) { } if (!promoted) continue - if (event.type === "step.started") { + if (event.type === "session.step.started") { const part: StepStartPart = { id: partID(event.id), sessionID: input.sessionID, @@ -189,11 +189,11 @@ export async function runNonInteractivePrompt(input: Input) { continue } - if (event.type === "text.started") { + if (event.type === "session.text.started") { starts.set(event.data.textID, { id: partID(event.id), timestamp: time }) continue } - if (event.type === "text.ended") { + if (event.type === "session.text.ended") { const started = starts.get(event.data.textID) const part: TextPart = { id: started?.id ?? partID(event.id), @@ -207,11 +207,11 @@ export async function runNonInteractivePrompt(input: Input) { continue } - if (event.type === "reasoning.started") { + if (event.type === "session.reasoning.started") { starts.set(event.data.reasoningID, { id: partID(event.id), timestamp: time }) continue } - if (event.type === "reasoning.ended" && input.thinking) { + if (event.type === "session.reasoning.ended" && input.thinking) { const started = starts.get(event.data.reasoningID) const part: ReasoningPart = { id: started?.id ?? partID(event.id), @@ -236,7 +236,7 @@ export async function runNonInteractivePrompt(input: Input) { continue } - if (event.type === "tool.input.started") { + if (event.type === "session.tool.input.started") { tools.set(event.data.callID, { id: partID(event.id), timestamp: time, @@ -246,12 +246,12 @@ export async function runNonInteractivePrompt(input: Input) { }) continue } - if (event.type === "tool.input.ended") { + if (event.type === "session.tool.input.ended") { const current = tools.get(event.data.callID) if (current) current.raw = event.data.text continue } - if (event.type === "tool.called") { + if (event.type === "session.tool.called") { const current = tools.get(event.data.callID) tools.set(event.data.callID, { id: current?.id ?? partID(event.id), @@ -264,7 +264,7 @@ export async function runNonInteractivePrompt(input: Input) { }) continue } - if (event.type === "tool.success") { + if (event.type === "session.tool.success") { const current = tools.get(event.data.callID) ?? fallbackTool(event) const part: ToolPart = { id: current.id, @@ -297,7 +297,7 @@ export async function runNonInteractivePrompt(input: Input) { if (!emit("tool_use", time, { part })) await input.renderTool(part) continue } - if (event.type === "tool.failed") { + if (event.type === "session.tool.failed") { const current = tools.get(event.data.callID) ?? fallbackTool(event) const error = event.data.error.message const part: ToolPart = { @@ -328,7 +328,7 @@ export async function runNonInteractivePrompt(input: Input) { continue } - if (event.type === "step.ended") { + if (event.type === "session.step.ended") { const part: StepFinishPart = { id: partID(event.id), sessionID: input.sessionID, @@ -342,14 +342,14 @@ export async function runNonInteractivePrompt(input: Input) { emit("step_finish", time, { part }) continue } - if (event.type === "step.failed") { + if (event.type === "session.step.failed") { if (interrupted || permissionRejected || questionRejected || formCancelled) continue emittedError = true process.exitCode = 1 if (!emit("error", time, { error: event.data.error })) UI.error(event.data.error.message) continue } - if (event.type === "execution.settled") { + if (event.type === "session.execution.settled") { if (event.data.outcome === "failure" && !emittedError && !questionRejected && !formCancelled) { emittedError = true process.exitCode = 1 diff --git a/packages/opencode/src/cli/cmd/run/session-data.ts b/packages/opencode/src/cli/cmd/run/session-data.ts index 9450f6cf78..ffce45bc94 100644 --- a/packages/opencode/src/cli/cmd/run/session-data.ts +++ b/packages/opencode/src/cli/cmd/run/session-data.ts @@ -62,7 +62,7 @@ type SessionCommit = StreamCommit // - sent: part ID → byte offset of last flushed text (for incremental output) // - visible: part ID → rendered text for an active part after display transforms // - end: part IDs whose time.end has arrived (part is finished) -// - shell: shell call ID → chosen transcript source for direct shell calls +// - shell: shell ID → chosen transcript source for direct shell calls // - echo: message ID → bash outputs to strip from the next assistant chunk type ShellCall = { source: "shell" | "tool" @@ -607,12 +607,12 @@ function toolCommit( } } -function shellPartID(callID: string): string { - return `shell:${callID}` +function shellPartID(shellID: string): string { + return `shell:${shellID}` } -function claimShell(data: SessionData, callID: string, source: ShellCall["source"], command?: string): ShellCall { - const current = data.shell.get(callID) +function claimShell(data: SessionData, shellID: string, source: ShellCall["source"], command?: string): ShellCall { + const current = data.shell.get(shellID) if (current) { if (command && !current.command) { current.command = command @@ -625,7 +625,7 @@ function claimShell(data: SessionData, callID: string, source: ShellCall["source source, ...(command ? { command } : {}), } satisfies ShellCall - data.shell.set(callID, next) + data.shell.set(shellID, next) return next } @@ -728,37 +728,37 @@ export function reduceSessionData(input: SessionDataInput): SessionDataOutput { const data = input.data const event = input.event - if (event.type === "shell.started") { + if (event.type === "session.shell.started") { if (event.properties.sessionID !== input.sessionID) { return out(data, commits) } - const shell = claimShell(data, event.properties.callID, "shell", event.properties.command) + const shell = claimShell(data, event.properties.shell.id, "shell", event.properties.shell.command) if (shell.source !== "shell") { return out(data, commits) } - const partID = shellPartID(event.properties.callID) + const partID = shellPartID(event.properties.shell.id) if (data.ids.has(partID) || data.tools.has(partID)) { return out(data, commits, patch({ status: "running shell" })) } data.tools.add(partID) - commits.push(startShell(event.properties.callID, shell.command ?? event.properties.command)) + commits.push(startShell(event.properties.shell.id, shell.command ?? event.properties.shell.command)) return out(data, commits, patch({ status: "running shell" })) } - if (event.type === "shell.ended") { + if (event.type === "session.shell.ended") { if (event.properties.sessionID !== input.sessionID) { return out(data, commits) } - const shell = claimShell(data, event.properties.callID, "shell") + const shell = claimShell(data, event.properties.shell.id, "shell") if (shell.source !== "shell") { return out(data, commits) } - const partID = shellPartID(event.properties.callID) + const partID = shellPartID(event.properties.shell.id) const seen = data.tools.has(partID) const command = shell.command ?? "" data.tools.delete(partID) @@ -767,11 +767,11 @@ export function reduceSessionData(input: SessionDataInput): SessionDataOutput { } if (!seen && command) { - commits.push(startShell(event.properties.callID, command)) + commits.push(startShell(event.properties.shell.id, command)) } data.ids.add(partID) - commits.push(doneShell(event.properties.callID, command, event.properties.output)) + commits.push(doneShell(event.properties.shell.id, command, event.properties.output.output)) return out(data, commits) } diff --git a/packages/opencode/src/cli/cmd/run/stream-v2.subagent.ts b/packages/opencode/src/cli/cmd/run/stream-v2.subagent.ts index ac652423a1..1e7b039fd8 100644 --- a/packages/opencode/src/cli/cmd/run/stream-v2.subagent.ts +++ b/packages/opencode/src/cli/cmd/run/stream-v2.subagent.ts @@ -424,21 +424,21 @@ export function createSubagentTracker(input: SubagentTrackerInput): SubagentTrac } const reduce = (child: ChildState, event: V2Event) => { - if (event.type === "prompt.promoted") { + if (event.type === "session.prompt.promoted") { if (userFrame(child, event.data.inputID, "")) { touch(child, event.created) notifyDetail(child) } return } - if (event.type === "step.started") { + if (event.type === "session.step.started") { touch(child, event.created) if (child.label === FALLBACK_LABEL && event.data.agent) child.label = Locale.titlecase(event.data.agent) if (child.status !== "running") child.status = "running" input.emit() return } - if (event.type === "text.delta") { + if (event.type === "session.text.delta") { const projected = child.projectedText.get(event.data.textID) const covered = projected?.indexOf(event.data.delta) ?? -1 if (projected && covered >= 0) { @@ -459,7 +459,7 @@ export function createSubagentTracker(input: SubagentTrackerInput): SubagentTrac notifyDetail(child) return } - if (event.type === "text.ended") { + if (event.type === "session.text.ended") { child.text.set(event.data.textID, event.data.text) child.projectedText.delete(event.data.textID) setFrame(child, `text:${event.data.textID}`, { @@ -474,7 +474,7 @@ export function createSubagentTracker(input: SubagentTrackerInput): SubagentTrac notifyDetail(child) return } - if (event.type === "reasoning.delta") { + if (event.type === "session.reasoning.delta") { const projected = child.projectedReasoning.get(event.data.reasoningID) const covered = projected?.indexOf(event.data.delta) ?? -1 if (projected && covered >= 0) { @@ -495,7 +495,7 @@ export function createSubagentTracker(input: SubagentTrackerInput): SubagentTrac notifyDetail(child) return } - if (event.type === "reasoning.ended") { + if (event.type === "session.reasoning.ended") { child.reasoning.set(event.data.reasoningID, event.data.text) child.projectedReasoning.delete(event.data.reasoningID) if (!input.thinking) return @@ -510,11 +510,11 @@ export function createSubagentTracker(input: SubagentTrackerInput): SubagentTrac notifyDetail(child) return } - if (event.type === "tool.input.started") { + if (event.type === "session.tool.input.started") { child.tools.set(event.data.callID, { name: event.data.name, input: {}, started: event.created }) return } - if (event.type === "tool.called") { + if (event.type === "session.tool.called") { const current = child.tools.get(event.data.callID) child.tools.set(event.data.callID, { name: event.data.tool, @@ -537,10 +537,10 @@ export function createSubagentTracker(input: SubagentTrackerInput): SubagentTrac notifyDetail(child) return } - if (event.type === "tool.success" || event.type === "tool.failed") { + if (event.type === "session.tool.success" || event.type === "session.tool.failed") { if (child.finishedTools.has(event.data.callID)) return const current = child.tools.get(event.data.callID) - const failed = event.type === "tool.failed" + const failed = event.type === "session.tool.failed" childTool( child, { @@ -577,7 +577,7 @@ export function createSubagentTracker(input: SubagentTrackerInput): SubagentTrac notifyDetail(child) return } - if (event.type === "step.failed") { + if (event.type === "session.step.failed") { setFrame(child, `error:step:${event.data.assistantMessageID}`, { kind: "error", source: "system", @@ -589,7 +589,7 @@ export function createSubagentTracker(input: SubagentTrackerInput): SubagentTrac notifyDetail(child) return } - if (event.type === "execution.settled") { + if (event.type === "session.execution.settled") { child.status = event.data.outcome === "success" ? "completed" : event.data.outcome === "interrupted" ? "cancelled" : "error" touch(child, event.created) @@ -613,15 +613,15 @@ export function createSubagentTracker(input: SubagentTrackerInput): SubagentTrac return { main(event) { - if (event.type === "tool.called") { + if (event.type === "session.tool.called") { if (event.data.tool === "subagent") pendingCalls.set(event.data.callID, event.data.input) return } - if (event.type === "tool.failed") { + if (event.type === "session.tool.failed") { pendingCalls.delete(event.data.callID) return } - if (event.type !== "tool.success") return + if (event.type !== "session.tool.success") return const pending = pendingCalls.get(event.data.callID) pendingCalls.delete(event.data.callID) const found = childSessionID(record(event.data.structured)) diff --git a/packages/opencode/src/cli/cmd/run/stream-v2.transport.ts b/packages/opencode/src/cli/cmd/run/stream-v2.transport.ts index c15ed48e5b..42e2c7bd53 100644 --- a/packages/opencode/src/cli/cmd/run/stream-v2.transport.ts +++ b/packages/opencode/src/cli/cmd/run/stream-v2.transport.ts @@ -213,7 +213,9 @@ function promptAgents(next: SessionTurnInput) { ? [ { name: part.name, - source: part.source ? { start: part.source.start, end: part.source.end, text: part.source.value } : undefined, + source: part.source + ? { start: part.source.start, end: part.source.end, text: part.source.value } + : undefined, }, ] : [], @@ -404,27 +406,39 @@ export async function createSessionTransport(input: StreamInput): Promise previous.length) @@ -604,7 +636,7 @@ export async function createSessionTransport(input: StreamInput): Promise previous.length) @@ -645,7 +677,7 @@ export async function createSessionTransport(input: StreamInput): Promise (file.text ? [file.text] : [])), - ].join("\n\n"), + text: [next.prompt.text, ...prepared.flatMap((file) => (file.text ? [file.text] : []))].join("\n\n"), files: attachments.length ? attachments : undefined, agents: agents.length ? agents : undefined, }, diff --git a/packages/opencode/test/cli/run/noninteractive.test.ts b/packages/opencode/test/cli/run/noninteractive.test.ts index 839b99656b..4462c53a97 100644 --- a/packages/opencode/test/cli/run/noninteractive.test.ts +++ b/packages/opencode/test/cli/run/noninteractive.test.ts @@ -25,7 +25,7 @@ function prompted(inputID: string): V2Event { return { id: "evt_prompted", created: 0, - type: "prompt.promoted", + type: "session.prompt.promoted", durable: { aggregateID: "ses_1", seq: 0, version: 1 }, data: { sessionID: "ses_1", inputID }, } @@ -35,7 +35,7 @@ function settled(outcome: "success" | "interrupted" = "success"): V2Event { return { id: "evt_settled", created: 0, - type: "execution.settled", + type: "session.execution.settled", data: { sessionID: "ses_1", outcome }, } } diff --git a/packages/opencode/test/cli/run/session-data.test.ts b/packages/opencode/test/cli/run/session-data.test.ts index 89a6751d1b..805bcd486f 100644 --- a/packages/opencode/test/cli/run/session-data.test.ts +++ b/packages/opencode/test/cli/run/session-data.test.ts @@ -329,7 +329,7 @@ describe("run session data", () => { test("renders direct shell mode from first-class shell events", () => { let data = createSessionData() const started = reduce(data, { - type: "shell.started", + type: "session.shell.started", properties: { sessionID: "session-1", timestamp: 1, @@ -353,7 +353,7 @@ describe("run session data", () => { data = started.data const ended = reduce(data, { - type: "shell.ended", + type: "session.shell.ended", properties: { sessionID: "session-1", timestamp: 2, @@ -380,7 +380,7 @@ describe("run session data", () => { test("suppresses legacy bash part updates once shell events claim the call", () => { let data = reduce(createSessionData(), { - type: "shell.started", + type: "session.shell.started", properties: { sessionID: "session-1", timestamp: 1, @@ -409,7 +409,7 @@ describe("run session data", () => { ).toEqual([]) data = reduce(data, { - type: "shell.ended", + type: "session.shell.ended", properties: { sessionID: "session-1", timestamp: 2, @@ -463,7 +463,7 @@ describe("run session data", () => { expect( reduce(data, { - type: "shell.started", + type: "session.shell.started", properties: { sessionID: "session-1", timestamp: 1, @@ -497,7 +497,7 @@ describe("run session data", () => { expect( reduce(data, { - type: "shell.ended", + type: "session.shell.ended", properties: { sessionID: "session-1", timestamp: 2, diff --git a/packages/opencode/test/cli/run/stream-v2.transport.test.ts b/packages/opencode/test/cli/run/stream-v2.transport.test.ts index e43e88f934..cd2d131642 100644 --- a/packages/opencode/test/cli/run/stream-v2.transport.test.ts +++ b/packages/opencode/test/cli/run/stream-v2.transport.test.ts @@ -200,7 +200,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_prompted", created: 0, - type: "prompt.promoted", + type: "session.prompt.promoted", durable: durable("ses_1"), data: { sessionID: "ses_1", @@ -210,7 +210,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_text", created: 0, - type: "text.delta", + type: "session.text.delta", data: { sessionID: "ses_1", assistantMessageID: "msg_assistant", @@ -221,7 +221,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_settled", created: 0, - type: "execution.settled", + type: "session.execution.settled", data: { sessionID: "ses_1", outcome: "success" }, }) await turn @@ -259,7 +259,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_prompted", created: 0, - type: "prompt.promoted", + type: "session.prompt.promoted", durable: durable("ses_1"), data: { sessionID: "ses_1", @@ -269,7 +269,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_settled", created: 0, - type: "execution.settled", + type: "session.execution.settled", data: { sessionID: "ses_1", outcome: "success" }, }) }) @@ -353,7 +353,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_prompted", created: 0, - type: "prompt.promoted", + type: "session.prompt.promoted", durable: durable("ses_1"), data: { sessionID: "ses_1", @@ -363,7 +363,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_settled", created: 0, - type: "execution.settled", + type: "session.execution.settled", data: { sessionID: "ses_1", outcome: "success" }, }) }) @@ -450,7 +450,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_prompted", created: 0, - type: "prompt.promoted", + type: "session.prompt.promoted", durable: durable("ses_1"), data: { sessionID: "ses_1", @@ -460,7 +460,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_settled", created: 0, - type: "execution.settled", + type: "session.execution.settled", data: { sessionID: "ses_1", outcome: "success" }, }) }) @@ -724,7 +724,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_text", created: 0, - type: "text.delta", + type: "session.text.delta", data: { sessionID: "ses_1", assistantMessageID: "msg_assistant", @@ -809,7 +809,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_reasoning", created: 0, - type: "reasoning.ended", + type: "session.reasoning.ended", durable: durable("ses_1"), data: { sessionID: "ses_1", @@ -865,7 +865,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_settled", created: 0, - type: "execution.settled", + type: "session.execution.settled", data: { sessionID: "ses_1", outcome: "success" }, }) await turn @@ -921,7 +921,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_prompted", created: 0, - type: "prompt.promoted", + type: "session.prompt.promoted", durable: durable("ses_1"), data: { sessionID: "ses_1", @@ -931,7 +931,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_settled", created: 0, - type: "execution.settled", + type: "session.execution.settled", data: { sessionID: "ses_1", outcome: "success" }, }) await turn @@ -981,7 +981,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_prompted", created: 0, - type: "prompt.promoted", + type: "session.prompt.promoted", durable: durable("ses_1"), data: { sessionID: "ses_1", @@ -993,7 +993,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_settled", created: 0, - type: "execution.settled", + type: "session.execution.settled", data: { sessionID: "ses_1", outcome: "success" }, }) await turn @@ -1021,16 +1021,42 @@ describe("V2 mini transport", () => { events.push({ id: "evt_shell_start", created: 0, - type: "shell.started", + type: "session.shell.started", durable: durable("ses_1"), - data: { sessionID: "ses_1", callID: "call_shell", command: "ls" }, + data: { + sessionID: "ses_1", + shell: { + id: "sh_shell", + status: "running", + command: "ls", + cwd: "/tmp", + shell: "/bin/sh", + file: "/tmp/opencode-shell", + metadata: {}, + time: { started: 0 }, + }, + }, }) events.push({ id: "evt_shell_end", created: 0, - type: "shell.ended", + type: "session.shell.ended", durable: durable("ses_1", 1), - data: { sessionID: "ses_1", callID: "call_shell", output: "file.txt" }, + data: { + sessionID: "ses_1", + shell: { + id: "sh_shell", + status: "exited", + command: "ls", + cwd: "/tmp", + shell: "/bin/sh", + file: "/tmp/opencode-shell", + exit: 0, + metadata: {}, + time: { started: 0, completed: 1 }, + }, + output: { output: "file.txt", cursor: 8, size: 8, truncated: false }, + }, }) }) return ok(undefined) as never @@ -1047,8 +1073,8 @@ describe("V2 mini transport", () => { expect(request).toMatchObject({ sessionID: "ses_1", command: "ls" }) expect(ui.commits.filter((item) => item.shell)).toMatchObject([ - { phase: "start", tool: "bash", toolState: "running", shell: { callID: "call_shell", command: "ls" } }, - { phase: "progress", text: "file.txt", toolState: "completed", shell: { callID: "call_shell", command: "ls" } }, + { phase: "start", tool: "bash", toolState: "running", shell: { callID: "sh_shell", command: "ls" } }, + { phase: "progress", text: "file.txt", toolState: "completed", shell: { callID: "sh_shell", command: "ls" } }, ]) expect(ui.events).toContainEqual({ type: "stream.patch", patch: { phase: "running", status: "running shell" } }) await transport.close() @@ -1107,9 +1133,18 @@ describe("V2 mini transport", () => { { id: "msg_shell", type: "shell" as const, - callID: "call_1", - command: "ls", - output: "file.txt", + shell: { + id: "sh_1", + status: "exited", + command: "ls", + cwd: "/tmp", + shell: "/bin/sh", + file: "/tmp/opencode-shell", + exit: 0, + metadata: {}, + time: { started: 0, completed: 1 }, + }, + output: { output: "file.txt", cursor: 8, size: 8, truncated: false }, time: { created: 1, completed: 2 }, }, ], @@ -1127,15 +1162,29 @@ describe("V2 mini transport", () => { events.push({ id: "evt_shell_end", created: 0, - type: "shell.ended", + type: "session.shell.ended", durable: durable("ses_1", 1), - data: { sessionID: "ses_1", callID: "call_1", output: "file.txt" }, + data: { + sessionID: "ses_1", + shell: { + id: "sh_1", + status: "exited", + command: "ls", + cwd: "/tmp", + shell: "/bin/sh", + file: "/tmp/opencode-shell", + exit: 0, + metadata: {}, + time: { started: 0, completed: 1 }, + }, + output: { output: "file.txt", cursor: 8, size: 8, truncated: false }, + }, }) await Bun.sleep(0) await Bun.sleep(0) expect(ui.commits.filter((item) => item.shell)).toMatchObject([ - { phase: "start", shell: { callID: "call_1", command: "ls" } }, + { phase: "start", shell: { callID: "sh_1", command: "ls" } }, { phase: "progress", text: "file.txt", toolState: "completed" }, ]) await transport.close() @@ -1160,7 +1209,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_prompted", created: 0, - type: "prompt.promoted", + type: "session.prompt.promoted", durable: durable("ses_1"), data: { sessionID: "ses_1", @@ -1170,7 +1219,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_settled", created: 0, - type: "execution.settled", + type: "session.execution.settled", data: { sessionID: "ses_1", outcome: "success" }, }) }) @@ -1236,7 +1285,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_skill", created: 0, - type: "skill.activated", + type: "session.skill.activated", durable: durable("ses_1"), data: { sessionID: "ses_1", @@ -1247,7 +1296,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_settled", created: 0, - type: "execution.settled", + type: "session.execution.settled", data: { sessionID: "ses_1", outcome: "success" }, }) }) @@ -1317,7 +1366,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_unrelated_settled", created: 0, - type: "execution.settled", + type: "session.execution.settled", data: { sessionID: "ses_1", outcome: "success" }, }) await Bun.sleep(0) @@ -1327,7 +1376,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_skill", created: 0, - type: "skill.activated", + type: "session.skill.activated", durable: durable("ses_1"), data: { sessionID: "ses_1", @@ -1338,7 +1387,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_skill_settled", created: 0, - type: "execution.settled", + type: "session.execution.settled", data: { sessionID: "ses_1", outcome: "success" }, }) await turn @@ -1376,7 +1425,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_skill", created: 0, - type: "skill.activated", + type: "session.skill.activated", durable: durable("ses_1"), data: { sessionID: "ses_1", @@ -1438,7 +1487,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_child_step", created: 0, - type: "step.started", + type: "session.step.started", durable: durable("ses_child"), data: { sessionID: "ses_child", @@ -1456,7 +1505,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_child_text", created: 0, - type: "text.delta", + type: "session.text.delta", data: { sessionID: "ses_child", assistantMessageID: "msg_child_a", @@ -1470,7 +1519,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_child_settled", created: 0, - type: "execution.settled", + type: "session.execution.settled", data: { sessionID: "ses_child", outcome: "success" }, }) while (!states().some((state) => state.tabs.some((tab) => tab.status === "completed"))) await Bun.sleep(0) @@ -1515,7 +1564,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_child_step", created: 0, - type: "step.started", + type: "session.step.started", durable: durable("ses_child"), data: { sessionID: "ses_child", @@ -1527,7 +1576,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_child_settled", created: 0, - type: "execution.settled", + type: "session.execution.settled", data: { sessionID: "ses_child", outcome: "interrupted" }, }) await Bun.sleep(0) @@ -1574,7 +1623,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_child_step", created: 0, - type: "step.started", + type: "session.step.started", durable: durable("ses_child"), data: { sessionID: "ses_child", @@ -1587,7 +1636,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_parent_call", created: 0, - type: "tool.called", + type: "session.tool.called", durable: durable("ses_1"), data: { sessionID: "ses_1", @@ -1601,7 +1650,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_parent_success", created: 0, - type: "tool.success", + type: "session.tool.success", durable: durable("ses_1", 1), data: { sessionID: "ses_1", @@ -1616,7 +1665,7 @@ describe("V2 mini transport", () => { events.push({ id: "evt_child_settled", created: 0, - type: "execution.settled", + type: "session.execution.settled", data: { sessionID: "ses_child", outcome: "interrupted" }, }) while (!states().some((state) => state.tabs.some((tab) => tab.status === "cancelled"))) await Bun.sleep(0) diff --git a/packages/opencode/test/server/httpapi-pty.test.ts b/packages/opencode/test/server/httpapi-pty.test.ts index 3eec0c9682..ac18a8a2cf 100644 --- a/packages/opencode/test/server/httpapi-pty.test.ts +++ b/packages/opencode/test/server/httpapi-pty.test.ts @@ -99,10 +99,10 @@ describe("pty HttpApi bridge", () => { const updated = await app().request(PtyPaths.update.replace(":ptyID", info.id), { method: "PUT", headers: { ...headers, "content-type": "application/json" }, - body: JSON.stringify({ title: "renamed", size: { cols: 80, rows: 24 } }), + body: JSON.stringify({ title: "session.renamed", size: { cols: 80, rows: 24 } }), }) expect(updated.status).toBe(200) - expect(await updated.json()).toMatchObject({ id: info.id, title: "renamed" }) + expect(await updated.json()).toMatchObject({ id: info.id, title: "session.renamed" }) } finally { await app().request(PtyPaths.remove.replace(":ptyID", info.id), { method: "DELETE", headers }) } diff --git a/packages/opencode/test/server/httpapi-sdk.test.ts b/packages/opencode/test/server/httpapi-sdk.test.ts index c81b3b771b..0af92ae382 100644 --- a/packages/opencode/test/server/httpapi-sdk.test.ts +++ b/packages/opencode/test/server/httpapi-sdk.test.ts @@ -573,7 +573,7 @@ describe("HttpApi SDK", () => { const child = yield* capture(() => sdk.session.create({ title: "child", parentID })) const childID = String(record(child.data).id) const get = yield* capture(() => sdk.session.get({ sessionID: parentID })) - const update = yield* capture(() => sdk.session.update({ sessionID: parentID, title: "renamed" })) + const update = yield* capture(() => sdk.session.update({ sessionID: parentID, title: "session.renamed" })) const roots = yield* capture(() => sdk.session.list({ roots: true, limit: 10 })) const all = yield* capture(() => sdk.session.list({ roots: false, limit: 10 })) const children = yield* capture(() => sdk.session.children({ sessionID: parentID })) diff --git a/packages/opencode/test/tool/apply_patch.test.ts b/packages/opencode/test/tool/apply_patch.test.ts index e394d8084f..57febfa06e 100644 --- a/packages/opencode/test/tool/apply_patch.test.ts +++ b/packages/opencode/test/tool/apply_patch.test.ts @@ -271,7 +271,7 @@ describe("tool.apply_patch freeform", () => { yield* execute({ patchText }, ctx) - const moved = path.join(test.directory, "renamed", "dir", "name.txt") + const moved = path.join(test.directory, "session.renamed", "dir", "name.txt") yield* expectReadFailure(original) expect(yield* readText(moved)).toBe("new content\n") }), @@ -282,7 +282,7 @@ describe("tool.apply_patch freeform", () => { const test = yield* TestInstance const { ctx } = makeCtx() const original = path.join(test.directory, "old", "name.txt") - const destination = path.join(test.directory, "renamed", "dir", "name.txt") + const destination = path.join(test.directory, "session.renamed", "dir", "name.txt") yield* makeDir(path.dirname(original)) yield* makeDir(path.dirname(destination)) yield* writeText(original, "from\n") diff --git a/packages/opencode/test/tool/fixtures/models-api.json b/packages/opencode/test/tool/fixtures/models-api.json index 6302a951dd..9432ee6635 100644 --- a/packages/opencode/test/tool/fixtures/models-api.json +++ b/packages/opencode/test/tool/fixtures/models-api.json @@ -79593,8 +79593,8 @@ } } }, - "synthetic": { - "id": "synthetic", + "session.synthetic": { + "id": "session.synthetic", "env": ["SYNTHETIC_API_KEY"], "npm": "@ai-sdk/openai-compatible", "api": "https://api.synthetic.new/openai/v1", diff --git a/packages/opencode/test/v2/session-message-updater.test.ts b/packages/opencode/test/v2/session-message-updater.test.ts index 4da4dc9d13..1fc3dda0df 100644 --- a/packages/opencode/test/v2/session-message-updater.test.ts +++ b/packages/opencode/test/v2/session-message-updater.test.ts @@ -22,7 +22,7 @@ test.skip("step snapshots carry over to assistant messages", () => { SessionMessageUpdater.update(SessionMessageUpdater.memory(state), { id: EventV2.ID.create(), created: DateTime.makeUnsafe(0), - type: "step.started", + type: "session.step.started", durable: durable(sessionID), data: { sessionID, @@ -44,7 +44,7 @@ test.skip("step snapshots carry over to assistant messages", () => { SessionMessageUpdater.update(SessionMessageUpdater.memory(state), { id: EventV2.ID.create(), created: DateTime.makeUnsafe(0), - type: "step.ended", + type: "session.step.ended", durable: durable(sessionID, 1, 2), data: { sessionID, @@ -77,7 +77,7 @@ test.skip("text ended populates assistant text content", () => { SessionMessageUpdater.update(SessionMessageUpdater.memory(state), { id: EventV2.ID.create(), created: DateTime.makeUnsafe(0), - type: "step.started", + type: "session.step.started", durable: durable(sessionID), data: { sessionID, @@ -96,7 +96,7 @@ test.skip("text ended populates assistant text content", () => { SessionMessageUpdater.update(SessionMessageUpdater.memory(state), { id: EventV2.ID.create(), created: DateTime.makeUnsafe(0), - type: "text.started", + type: "session.text.started", durable: durable(sessionID, 1), data: { sessionID, @@ -110,7 +110,7 @@ test.skip("text ended populates assistant text content", () => { SessionMessageUpdater.update(SessionMessageUpdater.memory(state), { id: EventV2.ID.create(), created: DateTime.makeUnsafe(0), - type: "text.ended", + type: "session.text.ended", durable: durable(sessionID, 2), data: { sessionID, @@ -136,7 +136,7 @@ test.skip("tool completion stores completed timestamp", () => { SessionMessageUpdater.update(SessionMessageUpdater.memory(state), { id: EventV2.ID.create(), created: DateTime.makeUnsafe(0), - type: "step.started", + type: "session.step.started", durable: durable(sessionID), data: { sessionID, @@ -155,7 +155,7 @@ test.skip("tool completion stores completed timestamp", () => { SessionMessageUpdater.update(SessionMessageUpdater.memory(state), { id: EventV2.ID.create(), created: DateTime.makeUnsafe(0), - type: "tool.input.started", + type: "session.tool.input.started", durable: durable(sessionID, 1), data: { sessionID, @@ -170,7 +170,7 @@ test.skip("tool completion stores completed timestamp", () => { SessionMessageUpdater.update(SessionMessageUpdater.memory(state), { id: EventV2.ID.create(), created: DateTime.makeUnsafe(0), - type: "tool.called", + type: "session.tool.called", durable: durable(sessionID, 2), data: { sessionID, @@ -187,7 +187,7 @@ test.skip("tool completion stores completed timestamp", () => { SessionMessageUpdater.update(SessionMessageUpdater.memory(state), { id: EventV2.ID.create(), created: DateTime.makeUnsafe(0), - type: "tool.success", + type: "session.tool.success", durable: durable(sessionID, 3), data: { sessionID, @@ -218,7 +218,7 @@ test("compaction events reduce to compaction message only when completed", () => SessionMessageUpdater.update(SessionMessageUpdater.memory(state), { id, created: DateTime.makeUnsafe(0), - type: "compaction.started", + type: "session.compaction.started", durable: durable(sessionID), data: { sessionID, @@ -233,7 +233,7 @@ test("compaction events reduce to compaction message only when completed", () => SessionMessageUpdater.update(SessionMessageUpdater.memory(state), { id: EventV2.ID.create(), created: DateTime.makeUnsafe(0), - type: "compaction.delta", + type: "session.compaction.delta", data: { sessionID, text: "hello ", @@ -245,7 +245,7 @@ test("compaction events reduce to compaction message only when completed", () => SessionMessageUpdater.update(SessionMessageUpdater.memory(state), { id: EventV2.ID.create(), created: DateTime.makeUnsafe(0), - type: "compaction.delta", + type: "session.compaction.delta", data: { sessionID, text: "summary", @@ -257,7 +257,7 @@ test("compaction events reduce to compaction message only when completed", () => SessionMessageUpdater.update(SessionMessageUpdater.memory(state), { id: endedID, created: DateTime.makeUnsafe(0), - type: "compaction.ended", + type: "session.compaction.ended", durable: durable(sessionID, 1), data: { sessionID, diff --git a/packages/schema/src/session-event.ts b/packages/schema/src/session-event.ts index fce091545a..824b1690db 100644 --- a/packages/schema/src/session-event.ts +++ b/packages/schema/src/session-event.ts @@ -12,6 +12,7 @@ import { SessionID } from "./session-id.js" import { Location } from "./location.js" import { SessionMessage } from "./session-message.js" import { Revert } from "./revert.js" +import { Shell as ShellSchema } from "./shell.js" export { FileAttachment } @@ -51,7 +52,7 @@ export const UnknownError = SessionMessage.UnknownError export type UnknownError = SessionMessage.UnknownError export const AgentSelected = Event.durable({ - type: "agent.selected", + type: "session.agent.selected", ...options, schema: { ...Base, @@ -61,7 +62,7 @@ export const AgentSelected = Event.durable({ export type AgentSelected = typeof AgentSelected.Type export const ModelSelected = Event.durable({ - type: "model.selected", + type: "session.model.selected", ...options, schema: { ...Base, @@ -82,7 +83,7 @@ export const Moved = Event.durable({ export type Moved = typeof Moved.Type export const Renamed = Event.durable({ - type: "renamed", + type: "session.renamed", ...options, schema: { ...Base, @@ -92,7 +93,7 @@ export const Renamed = Event.durable({ export type Renamed = typeof Renamed.Type export const Forked = Event.durable({ - type: "forked", + type: "session.forked", ...options, schema: { ...Base, @@ -103,7 +104,7 @@ export const Forked = Event.durable({ export type Forked = typeof Forked.Type export const PromptPromoted = Event.durable({ - type: "prompt.promoted", + type: "session.prompt.promoted", ...options, schema: { sessionID: SessionID, @@ -113,14 +114,14 @@ export const PromptPromoted = Event.durable({ export type PromptPromoted = typeof PromptPromoted.Type export const PromptAdmitted = Event.durable({ - type: "prompt.admitted", + type: "session.prompt.admitted", ...options, schema: PromptFields, }) export type PromptAdmitted = typeof PromptAdmitted.Type export const ExecutionSettled = Event.ephemeral({ - type: "execution.settled", + type: "session.execution.settled", schema: { ...Base, outcome: Schema.Literals(["success", "failure", "interrupted"]), @@ -140,7 +141,7 @@ export const ContextUpdated = Event.durable({ export type ContextUpdated = typeof ContextUpdated.Type export const Synthetic = Event.durable({ - type: "synthetic", + type: "session.synthetic", ...options, schema: { ...Base, @@ -153,7 +154,7 @@ export type Synthetic = typeof Synthetic.Type export namespace Skill { export const Activated = Event.durable({ - type: "skill.activated", + type: "session.skill.activated", ...options, schema: { ...Base, @@ -166,23 +167,22 @@ export namespace Skill { export namespace Shell { export const Started = Event.durable({ - type: "shell.started", + type: "session.shell.started", ...options, schema: { ...Base, - callID: Schema.String, - command: Schema.String, + shell: ShellSchema.Info, }, }) export type Started = typeof Started.Type export const Ended = Event.durable({ - type: "shell.ended", + type: "session.shell.ended", ...options, schema: { ...Base, - callID: Schema.String, - output: Schema.String, + shell: ShellSchema.Info, + output: ShellSchema.Output, }, }) export type Ended = typeof Ended.Type @@ -190,7 +190,7 @@ export namespace Shell { export namespace Step { export const Started = Event.durable({ - type: "step.started", + type: "session.step.started", ...options, schema: { ...Base, @@ -203,7 +203,7 @@ export namespace Step { export type Started = typeof Started.Type export const Ended = Event.durable({ - type: "step.ended", + type: "session.step.ended", ...stepSettlementOptions, schema: { ...Base, @@ -226,7 +226,7 @@ export namespace Step { export type Ended = typeof Ended.Type export const Failed = Event.durable({ - type: "step.failed", + type: "session.step.failed", ...stepSettlementOptions, schema: { ...Base, @@ -239,7 +239,7 @@ export namespace Step { export namespace Text { export const Started = Event.durable({ - type: "text.started", + type: "session.text.started", ...options, schema: { ...Base, @@ -251,7 +251,7 @@ export namespace Text { // Stream fragments are live-only; Text.Ended is the replayable full-value boundary. export const Delta = Event.ephemeral({ - type: "text.delta", + type: "session.text.delta", schema: { ...Base, assistantMessageID: SessionMessage.ID, @@ -262,7 +262,7 @@ export namespace Text { export type Delta = typeof Delta.Type export const Ended = Event.durable({ - type: "text.ended", + type: "session.text.ended", ...options, schema: { ...Base, @@ -276,7 +276,7 @@ export namespace Text { export namespace Reasoning { export const Started = Event.durable({ - type: "reasoning.started", + type: "session.reasoning.started", ...options, schema: { ...Base, @@ -289,7 +289,7 @@ export namespace Reasoning { // Stream fragments are live-only; Reasoning.Ended is the replayable full-value boundary. export const Delta = Event.ephemeral({ - type: "reasoning.delta", + type: "session.reasoning.delta", schema: { ...Base, assistantMessageID: SessionMessage.ID, @@ -300,7 +300,7 @@ export namespace Reasoning { export type Delta = typeof Delta.Type export const Ended = Event.durable({ - type: "reasoning.ended", + type: "session.reasoning.ended", ...options, schema: { ...Base, @@ -322,7 +322,7 @@ export namespace Tool { export namespace Input { export const Started = Event.durable({ - type: "tool.input.started", + type: "session.tool.input.started", ...options, schema: { ...ToolBase, @@ -333,7 +333,7 @@ export namespace Tool { // Stream fragments are live-only; Input.Ended is the replayable raw-input boundary. export const Delta = Event.ephemeral({ - type: "tool.input.delta", + type: "session.tool.input.delta", schema: { ...ToolBase, delta: Schema.String, @@ -342,7 +342,7 @@ export namespace Tool { export type Delta = typeof Delta.Type export const Ended = Event.durable({ - type: "tool.input.ended", + type: "session.tool.input.ended", ...options, schema: { ...ToolBase, @@ -353,7 +353,7 @@ export namespace Tool { } export const Called = Event.durable({ - type: "tool.called", + type: "session.tool.called", ...options, schema: { ...ToolBase, @@ -372,7 +372,7 @@ export namespace Tool { * transitions or at a bounded cadence, not persist every stdout/stderr chunk. */ export const Progress = Event.durable({ - type: "tool.progress", + type: "session.tool.progress", ...options, schema: { ...ToolBase, @@ -383,7 +383,7 @@ export namespace Tool { export type Progress = typeof Progress.Type export const Success = Event.durable({ - type: "tool.success", + type: "session.tool.success", ...options, schema: { ...ToolBase, @@ -400,7 +400,7 @@ export namespace Tool { export type Success = typeof Success.Type export const Failed = Event.durable({ - type: "tool.failed", + type: "session.tool.failed", ...options, schema: { ...ToolBase, @@ -428,7 +428,7 @@ export const RetryError = Schema.Struct({ export interface RetryError extends Schema.Schema.Type {} export const Retried = Event.durable({ - type: "retried", + type: "session.retried", ...options, schema: { ...Base, @@ -440,7 +440,7 @@ export type Retried = typeof Retried.Type export namespace Compaction { export const Started = Event.durable({ - type: "compaction.started", + type: "session.compaction.started", ...options, schema: { ...Base, @@ -450,7 +450,7 @@ export namespace Compaction { export type Started = typeof Started.Type export const Delta = Event.ephemeral({ - type: "compaction.delta", + type: "session.compaction.delta", schema: { ...Base, text: Schema.String, @@ -459,7 +459,7 @@ export namespace Compaction { export type Delta = typeof Delta.Type export const Ended = Event.durable({ - type: "compaction.ended", + type: "session.compaction.ended", ...options, schema: { ...Base, @@ -473,13 +473,13 @@ export namespace Compaction { export namespace RevertEvent { export const Staged = Event.durable({ - type: "revert.staged", + type: "session.revert.staged", ...options, schema: { ...Base, revert: Revert.State }, }) - export const Cleared = Event.durable({ type: "revert.cleared", ...options, schema: Base }) + export const Cleared = Event.durable({ type: "session.revert.cleared", ...options, schema: Base }) export const Committed = Event.durable({ - type: "revert.committed", + type: "session.revert.committed", ...options, schema: { ...Base, messageID: SessionMessage.ID }, }) diff --git a/packages/schema/src/session-message.ts b/packages/schema/src/session-message.ts index 349d04d06e..e3d81a31d7 100644 --- a/packages/schema/src/session-message.ts +++ b/packages/schema/src/session-message.ts @@ -9,6 +9,7 @@ import { DateTimeUtcFromMillis, RelativePath, statics } from "./schema.js" import { SessionID } from "./session-id.js" import { ascending } from "./identifier.js" import { Event } from "./event.js" +import { Shell as ShellSchema } from "./shell.js" export const ID = Schema.String.check(Schema.isStartsWith("msg_")).pipe( Schema.brand("Session.Message.ID"), @@ -82,9 +83,8 @@ export interface Shell extends Schema.Schema.Type {} export const Shell = Schema.Struct({ ...Base, type: Schema.Literal("shell"), - callID: Schema.String, - command: Schema.String, - output: Schema.String, + shell: ShellSchema.Info, + output: ShellSchema.Output.pipe(optional), time: Schema.Struct({ created: DateTimeUtcFromMillis, completed: DateTimeUtcFromMillis.pipe(optional), diff --git a/packages/schema/test/event-manifest.test.ts b/packages/schema/test/event-manifest.test.ts index 4fa23e75f7..873e415c61 100644 --- a/packages/schema/test/event-manifest.test.ts +++ b/packages/schema/test/event-manifest.test.ts @@ -53,7 +53,7 @@ describe("public event manifest", () => { expect(Session.Event.Definitions).toBe(SessionEvent.Definitions) expect(Workspace.Event).toBe(WorkspaceEvent) expect(Workspace.Event.Definitions).toBe(WorkspaceEvent.Definitions) - expect(EventManifest.Latest.get("step.ended")).toBe(SessionEvent.Step.Ended) + expect(EventManifest.Latest.get("session.step.ended")).toBe(SessionEvent.Step.Ended) expect(EventManifest.Latest.get("todo.updated")).toBe(SessionTodo.Event.Updated) expect(EventManifest.Latest.get("agent.updated")).toBe(Agent.Event.Updated) expect(EventManifest.Latest.get("project.updated")).toBe(Project.Event.Updated) @@ -74,8 +74,8 @@ describe("public event manifest", () => { SessionV1.Event.Diff, SessionV1.Event.Error, ]) - expect(EventManifest.Durable.get("step.ended.1")).toBe(SessionEvent.Step.Ended) - expect(EventManifest.Durable.has("step.ended.2")).toBe(false) + expect(EventManifest.Durable.get("session.step.ended.1")).toBe(SessionEvent.Step.Ended) + expect(EventManifest.Durable.has("session.step.ended.2")).toBe(false) }) test("derives durable definitions from explicit definition durability", () => { @@ -88,37 +88,37 @@ describe("public event manifest", () => { "message.removed.1", "message.part.updated.1", "message.part.removed.1", - "agent.selected.1", - "model.selected.1", + "session.agent.selected.1", + "session.model.selected.1", "session.moved.1", - "renamed.1", - "forked.1", - "prompt.promoted.1", - "prompt.admitted.1", + "session.renamed.1", + "session.forked.1", + "session.prompt.promoted.1", + "session.prompt.admitted.1", "session.context.updated.1", - "synthetic.1", - "skill.activated.1", - "shell.started.1", - "shell.ended.1", - "step.started.1", - "step.ended.1", - "step.failed.1", - "text.started.1", - "text.ended.1", - "tool.input.started.1", - "tool.input.ended.1", - "tool.called.1", - "tool.progress.1", - "tool.success.1", - "tool.failed.1", - "reasoning.started.1", - "reasoning.ended.1", - "retried.1", - "compaction.started.1", - "compaction.ended.1", - "revert.staged.1", - "revert.cleared.1", - "revert.committed.1", + "session.synthetic.1", + "session.skill.activated.1", + "session.shell.started.1", + "session.shell.ended.1", + "session.step.started.1", + "session.step.ended.1", + "session.step.failed.1", + "session.text.started.1", + "session.text.ended.1", + "session.tool.input.started.1", + "session.tool.input.ended.1", + "session.tool.called.1", + "session.tool.progress.1", + "session.tool.success.1", + "session.tool.failed.1", + "session.reasoning.started.1", + "session.reasoning.ended.1", + "session.retried.1", + "session.compaction.started.1", + "session.compaction.ended.1", + "session.revert.staged.1", + "session.revert.cleared.1", + "session.revert.committed.1", ].toSorted(), ) expect(SessionEvent.DurableDefinitions).toEqual( diff --git a/packages/sdk-next/test/embedded.test.ts b/packages/sdk-next/test/embedded.test.ts index 5419b7e838..4ac31b70ab 100644 --- a/packages/sdk-next/test/embedded.test.ts +++ b/packages/sdk-next/test/embedded.test.ts @@ -78,7 +78,7 @@ it.live( prompt: fixture.sdk.Prompt.make({ text: "Promote this input" }), }) const prompted = yield* opencode.sessions.log({ sessionID: id, follow: true }).pipe( - Stream.filter((event) => event.type === "prompt.promoted" && event.data.inputID === wake.id), + Stream.filter((event) => event.type === "session.prompt.promoted" && event.data.inputID === wake.id), Stream.runHead, Effect.timeout("10 seconds"), Effect.map(Option.getOrThrow), @@ -119,7 +119,7 @@ it.live( expect(page.data.some((session) => session.id === id)).toBe(true) expect(active).toEqual({ data: {}, watermarks: {} }) expect(admitted.sessionID).toBe(id) - expect(prompted.type).toBe("prompt.promoted") + expect(prompted.type).toBe("session.prompt.promoted") expect(wakeContext).toContainEqual(expect.objectContaining({ id: wake.id, type: "user" })) expect(contextEntries).toEqual([ { key: "deploy-target", value: "production" }, @@ -127,7 +127,7 @@ it.live( ]) expect(remainingContextEntries).toEqual([{ key: "deploy-target", value: "production" }]) expect(context.some((message) => message.type === "model-switched")).toBe(true) - expect(event).toMatchObject({ type: "model.selected", durable: { seq: 1 } }) + expect(event).toMatchObject({ type: "session.model.selected", durable: { seq: 1 } }) expect(message).toEqual(modelMessage) expect(missing.map((error) => error._tag)).toEqual([ "SessionNotFoundError", @@ -149,13 +149,13 @@ it.live( const opencode = yield* fixture.sdk.OpenCode.create() const id = sessionID(fixture) const connected = yield* Latch.make(false) - const prompted = yield* Deferred.make>() + const prompted = yield* Deferred.make>() yield* opencode.events.subscribe().pipe( Stream.runForEach((event) => event.type === "server.connected" ? connected.open - : event.type === "prompt.promoted" && event.data.sessionID === id + : event.type === "session.prompt.promoted" && event.data.sessionID === id ? Deferred.succeed(prompted, event).pipe(Effect.asVoid) : Effect.void, ), @@ -191,7 +191,7 @@ it.live( Stream.runForEach((notification: OpenCodeEvent) => notification.type === "server.connected" ? ready.open - : notification.type === "agent.selected" && notification.data.sessionID === id + : notification.type === "session.agent.selected" && notification.data.sessionID === id ? event.open : Effect.void, ) diff --git a/packages/sdk/js/script/build.ts b/packages/sdk/js/script/build.ts index d87f8bf98a..220bf43da3 100755 --- a/packages/sdk/js/script/build.ts +++ b/packages/sdk/js/script/build.ts @@ -60,7 +60,7 @@ if (schemas) { visit({ ...document, components: { ...document.components, schemas: undefined } }) for (const name of Object.keys(schemas)) { if ( - /^(AgentSelected|ModelSelected|SessionMoved|Renamed|Forked|PromptPromoted|PromptAdmitted|ExecutionSettled|ContextUpdated|Synthetic|SkillActivated|ShellStarted|ShellEnded|StepStarted|StepEnded|StepFailed|TextStarted|TextDelta|TextEnded|ReasoningStarted|ReasoningDelta|ReasoningEnded|ToolInputStarted|ToolInputDelta|ToolInputEnded|ToolCalled|ToolProgress|ToolSuccess|ToolFailed|Retried|CompactionStarted|CompactionDelta|CompactionEnded|RevertStaged|RevertCleared|RevertCommitted)1$/.test( + /^(SessionAgentSelected|SessionModelSelected|SessionMoved|SessionRenamed|SessionForked|SessionPromptPromoted|SessionPromptAdmitted|SessionExecutionSettled|SessionContextUpdated|SessionSynthetic|SessionSkillActivated|SessionShellStarted|SessionShellEnded|SessionStepStarted|SessionStepEnded|SessionStepFailed|SessionTextStarted|SessionTextDelta|SessionTextEnded|SessionReasoningStarted|SessionReasoningDelta|SessionReasoningEnded|SessionToolInputStarted|SessionToolInputDelta|SessionToolInputEnded|SessionToolCalled|SessionToolProgress|SessionToolSuccess|SessionToolFailed|SessionRetried|SessionCompactionStarted|SessionCompactionDelta|SessionCompactionEnded|SessionRevertStaged|SessionRevertCleared|SessionRevertCommitted)1$/.test( name, ) && !reachable.has(name) @@ -100,7 +100,7 @@ await createClient({ const generatedTypesPath = "./src/v2/gen/types.gen.ts" const generatedTypes = await Bun.file(generatedTypesPath).text() if ( - /export type (AgentSelected|ModelSelected|SessionMoved|Renamed|Forked|PromptPromoted|PromptAdmitted|ExecutionSettled|ContextUpdated|Synthetic|SkillActivated|ShellStarted|ShellEnded|StepStarted|StepEnded|StepFailed|TextStarted|TextDelta|TextEnded|ReasoningStarted|ReasoningDelta|ReasoningEnded|ToolInputStarted|ToolInputDelta|ToolInputEnded|ToolCalled|ToolProgress|ToolSuccess|ToolFailed|Retried|CompactionStarted|CompactionDelta|CompactionEnded|RevertStaged|RevertCleared|RevertCommitted)1 =/.test( + /export type (SessionAgentSelected|SessionModelSelected|SessionMoved|SessionRenamed|SessionForked|SessionPromptPromoted|SessionPromptAdmitted|SessionExecutionSettled|SessionContextUpdated|SessionSynthetic|SessionSkillActivated|SessionShellStarted|SessionShellEnded|SessionStepStarted|SessionStepEnded|SessionStepFailed|SessionTextStarted|SessionTextDelta|SessionTextEnded|SessionReasoningStarted|SessionReasoningDelta|SessionReasoningEnded|SessionToolInputStarted|SessionToolInputDelta|SessionToolInputEnded|SessionToolCalled|SessionToolProgress|SessionToolSuccess|SessionToolFailed|SessionRetried|SessionCompactionStarted|SessionCompactionDelta|SessionCompactionEnded|SessionRevertStaged|SessionRevertCleared|SessionRevertCommitted)1 =/.test( generatedTypes, ) ) { diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 56cdccf087..27ca0f00cd 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -17,42 +17,42 @@ export type Event = | EventMessageRemoved | EventMessagePartUpdated | EventMessagePartRemoved - | EventAgentSelected - | EventModelSelected + | EventSessionAgentSelected + | EventSessionModelSelected | EventSessionMoved - | EventRenamed - | EventForked - | EventPromptPromoted - | EventPromptAdmitted - | EventExecutionSettled + | EventSessionRenamed + | EventSessionForked + | EventSessionPromptPromoted + | EventSessionPromptAdmitted + | EventSessionExecutionSettled | EventSessionContextUpdated - | EventSynthetic - | EventSkillActivated - | EventShellStarted - | EventShellEnded - | EventStepStarted - | EventStepEnded - | EventStepFailed - | EventTextStarted - | EventTextDelta - | EventTextEnded - | EventReasoningStarted - | EventReasoningDelta - | EventReasoningEnded - | EventToolInputStarted - | EventToolInputDelta - | EventToolInputEnded - | EventToolCalled - | EventToolProgress - | EventToolSuccess - | EventToolFailed - | EventRetried - | EventCompactionStarted - | EventCompactionDelta - | EventCompactionEnded - | EventRevertStaged - | EventRevertCleared - | EventRevertCommitted + | EventSessionSynthetic + | EventSessionSkillActivated + | EventSessionShellStarted + | EventSessionShellEnded + | EventSessionStepStarted + | EventSessionStepEnded + | EventSessionStepFailed + | EventSessionTextStarted + | EventSessionTextDelta + | EventSessionTextEnded + | EventSessionReasoningStarted + | EventSessionReasoningDelta + | EventSessionReasoningEnded + | EventSessionToolInputStarted + | EventSessionToolInputDelta + | EventSessionToolInputEnded + | EventSessionToolCalled + | EventSessionToolProgress + | EventSessionToolSuccess + | EventSessionToolFailed + | EventSessionRetried + | EventSessionCompactionStarted + | EventSessionCompactionDelta + | EventSessionCompactionEnded + | EventSessionRevertStaged + | EventSessionRevertCleared + | EventSessionRevertCommitted | EventMessagePartDelta | EventSessionDiff | EventSessionError @@ -657,17 +657,6 @@ export type Prompt = { agents?: Array } -export type Pty = { - id: string - title: string - command: string - args: Array - cwd: string - status: "running" | "exited" - pid: number - exitCode?: number -} - export type Shell = { id: string status: "running" | "exited" | "timeout" | "killed" @@ -686,6 +675,17 @@ export type Shell = { } } +export type Pty = { + id: string + title: string + command: string + args: Array + cwd: string + status: "running" | "exited" + pid: number + exitCode?: number +} + export type Todo = { /** * Brief description of the task @@ -858,7 +858,7 @@ export type GlobalEvent = { } | { id: string - type: "agent.selected" + type: "session.agent.selected" properties: { sessionID: string agent: string @@ -866,7 +866,7 @@ export type GlobalEvent = { } | { id: string - type: "model.selected" + type: "session.model.selected" properties: { sessionID: string model: ModelRef @@ -883,7 +883,7 @@ export type GlobalEvent = { } | { id: string - type: "renamed" + type: "session.renamed" properties: { sessionID: string title: string @@ -891,7 +891,7 @@ export type GlobalEvent = { } | { id: string - type: "forked" + type: "session.forked" properties: { sessionID: string parentID: string @@ -900,7 +900,7 @@ export type GlobalEvent = { } | { id: string - type: "prompt.promoted" + type: "session.prompt.promoted" properties: { sessionID: string inputID: string @@ -908,7 +908,7 @@ export type GlobalEvent = { } | { id: string - type: "prompt.admitted" + type: "session.prompt.admitted" properties: { sessionID: string inputID: string @@ -918,7 +918,7 @@ export type GlobalEvent = { } | { id: string - type: "execution.settled" + type: "session.execution.settled" properties: { sessionID: string outcome: "success" | "failure" | "interrupted" @@ -935,7 +935,7 @@ export type GlobalEvent = { } | { id: string - type: "synthetic" + type: "session.synthetic" properties: { sessionID: string text: string @@ -947,7 +947,7 @@ export type GlobalEvent = { } | { id: string - type: "skill.activated" + type: "session.skill.activated" properties: { sessionID: string name: string @@ -956,25 +956,29 @@ export type GlobalEvent = { } | { id: string - type: "shell.started" + type: "session.shell.started" properties: { sessionID: string - callID: string - command: string + shell: Shell } } | { id: string - type: "shell.ended" + type: "session.shell.ended" properties: { sessionID: string - callID: string - output: string + shell: Shell + output: { + output: string + cursor: number + size: number + truncated: boolean + } } } | { id: string - type: "step.started" + type: "session.step.started" properties: { sessionID: string assistantMessageID: string @@ -985,7 +989,7 @@ export type GlobalEvent = { } | { id: string - type: "step.ended" + type: "session.step.ended" properties: { sessionID: string assistantMessageID: string @@ -1006,7 +1010,7 @@ export type GlobalEvent = { } | { id: string - type: "step.failed" + type: "session.step.failed" properties: { sessionID: string assistantMessageID: string @@ -1015,7 +1019,7 @@ export type GlobalEvent = { } | { id: string - type: "text.started" + type: "session.text.started" properties: { sessionID: string assistantMessageID: string @@ -1024,7 +1028,7 @@ export type GlobalEvent = { } | { id: string - type: "text.delta" + type: "session.text.delta" properties: { sessionID: string assistantMessageID: string @@ -1034,7 +1038,7 @@ export type GlobalEvent = { } | { id: string - type: "text.ended" + type: "session.text.ended" properties: { sessionID: string assistantMessageID: string @@ -1044,7 +1048,7 @@ export type GlobalEvent = { } | { id: string - type: "reasoning.started" + type: "session.reasoning.started" properties: { sessionID: string assistantMessageID: string @@ -1054,7 +1058,7 @@ export type GlobalEvent = { } | { id: string - type: "reasoning.delta" + type: "session.reasoning.delta" properties: { sessionID: string assistantMessageID: string @@ -1064,7 +1068,7 @@ export type GlobalEvent = { } | { id: string - type: "reasoning.ended" + type: "session.reasoning.ended" properties: { sessionID: string assistantMessageID: string @@ -1075,7 +1079,7 @@ export type GlobalEvent = { } | { id: string - type: "tool.input.started" + type: "session.tool.input.started" properties: { sessionID: string assistantMessageID: string @@ -1085,7 +1089,7 @@ export type GlobalEvent = { } | { id: string - type: "tool.input.delta" + type: "session.tool.input.delta" properties: { sessionID: string assistantMessageID: string @@ -1095,7 +1099,7 @@ export type GlobalEvent = { } | { id: string - type: "tool.input.ended" + type: "session.tool.input.ended" properties: { sessionID: string assistantMessageID: string @@ -1105,7 +1109,7 @@ export type GlobalEvent = { } | { id: string - type: "tool.called" + type: "session.tool.called" properties: { sessionID: string assistantMessageID: string @@ -1122,7 +1126,7 @@ export type GlobalEvent = { } | { id: string - type: "tool.progress" + type: "session.tool.progress" properties: { sessionID: string assistantMessageID: string @@ -1135,7 +1139,7 @@ export type GlobalEvent = { } | { id: string - type: "tool.success" + type: "session.tool.success" properties: { sessionID: string assistantMessageID: string @@ -1154,7 +1158,7 @@ export type GlobalEvent = { } | { id: string - type: "tool.failed" + type: "session.tool.failed" properties: { sessionID: string assistantMessageID: string @@ -1169,7 +1173,7 @@ export type GlobalEvent = { } | { id: string - type: "retried" + type: "session.retried" properties: { sessionID: string attempt: number @@ -1178,7 +1182,7 @@ export type GlobalEvent = { } | { id: string - type: "compaction.started" + type: "session.compaction.started" properties: { sessionID: string reason: "auto" | "manual" @@ -1186,7 +1190,7 @@ export type GlobalEvent = { } | { id: string - type: "compaction.delta" + type: "session.compaction.delta" properties: { sessionID: string text: string @@ -1194,7 +1198,7 @@ export type GlobalEvent = { } | { id: string - type: "compaction.ended" + type: "session.compaction.ended" properties: { sessionID: string reason: "auto" | "manual" @@ -1204,7 +1208,7 @@ export type GlobalEvent = { } | { id: string - type: "revert.staged" + type: "session.revert.staged" properties: { sessionID: string revert: RevertState @@ -1212,14 +1216,14 @@ export type GlobalEvent = { } | { id: string - type: "revert.cleared" + type: "session.revert.cleared" properties: { sessionID: string } } | { id: string - type: "revert.committed" + type: "session.revert.committed" properties: { sessionID: string messageID: string @@ -1704,37 +1708,37 @@ export type GlobalEvent = { | SyncEventMessageRemoved | SyncEventMessagePartUpdated | SyncEventMessagePartRemoved - | SyncEventAgentSelected - | SyncEventModelSelected + | SyncEventSessionAgentSelected + | SyncEventSessionModelSelected | SyncEventSessionMoved - | SyncEventRenamed - | SyncEventForked - | SyncEventPromptPromoted - | SyncEventPromptAdmitted + | SyncEventSessionRenamed + | SyncEventSessionForked + | SyncEventSessionPromptPromoted + | SyncEventSessionPromptAdmitted | SyncEventSessionContextUpdated - | SyncEventSynthetic - | SyncEventSkillActivated - | SyncEventShellStarted - | SyncEventShellEnded - | SyncEventStepStarted - | SyncEventStepEnded - | SyncEventStepFailed - | SyncEventTextStarted - | SyncEventTextEnded - | SyncEventReasoningStarted - | SyncEventReasoningEnded - | SyncEventToolInputStarted - | SyncEventToolInputEnded - | SyncEventToolCalled - | SyncEventToolProgress - | SyncEventToolSuccess - | SyncEventToolFailed - | SyncEventRetried - | SyncEventCompactionStarted - | SyncEventCompactionEnded - | SyncEventRevertStaged - | SyncEventRevertCleared - | SyncEventRevertCommitted + | SyncEventSessionSynthetic + | SyncEventSessionSkillActivated + | SyncEventSessionShellStarted + | SyncEventSessionShellEnded + | SyncEventSessionStepStarted + | SyncEventSessionStepEnded + | SyncEventSessionStepFailed + | SyncEventSessionTextStarted + | SyncEventSessionTextEnded + | SyncEventSessionReasoningStarted + | SyncEventSessionReasoningEnded + | SyncEventSessionToolInputStarted + | SyncEventSessionToolInputEnded + | SyncEventSessionToolCalled + | SyncEventSessionToolProgress + | SyncEventSessionToolSuccess + | SyncEventSessionToolFailed + | SyncEventSessionRetried + | SyncEventSessionCompactionStarted + | SyncEventSessionCompactionEnded + | SyncEventSessionRevertStaged + | SyncEventSessionRevertCleared + | SyncEventSessionRevertCommitted } /** @@ -2854,120 +2858,56 @@ export type UnknownError1 = { ref?: string } -export type Renamed = { +export type Shell1 = { id: string - created: number - metadata?: { + status: "running" | "exited" | "timeout" | "killed" + command: string + cwd: string + shell: string + file: string + pid?: number + exit?: number | "NaN" | "Infinity" | "-Infinity" + metadata: { [key: string]: unknown } - type: "renamed" - durable: { - aggregateID: string - seq: number - version: number - } - location?: LocationRef - data: { - sessionID: string - title: string - } -} - -export type Forked = { - id: string - created: number - metadata?: { - [key: string]: unknown - } - type: "forked" - durable: { - aggregateID: string - seq: number - version: number - } - location?: LocationRef - data: { - sessionID: string - parentID: string - from?: string - } -} - -export type Synthetic = { - id: string - created: number - metadata?: { - [key: string]: unknown - } - type: "synthetic" - durable: { - aggregateID: string - seq: number - version: number - } - location?: LocationRef - data: { - sessionID: string - text: string - description?: string - metadata?: { - [key: string]: unknown - } - } -} - -export type Retried = { - id: string - created: number - metadata?: { - [key: string]: unknown - } - type: "retried" - durable: { - aggregateID: string - seq: number - version: number - } - location?: LocationRef - data: { - sessionID: string - attempt: number - error: SessionRetryError + time: { + started: number | "NaN" | "Infinity" | "-Infinity" + completed?: number | "NaN" | "Infinity" | "-Infinity" } } export type SessionDurableEvent = - | AgentSelected - | ModelSelected + | SessionAgentSelected + | SessionModelSelected | SessionMoved - | Renamed - | Forked - | PromptPromoted - | PromptAdmitted + | SessionRenamed + | SessionForked + | SessionPromptPromoted + | SessionPromptAdmitted | SessionContextUpdated - | Synthetic - | SkillActivated - | ShellStarted - | ShellEnded - | StepStarted - | StepEnded - | StepFailed - | TextStarted - | TextEnded - | ReasoningStarted - | ReasoningEnded - | ToolInputStarted - | ToolInputEnded - | ToolCalled - | ToolProgress - | ToolSuccess - | ToolFailed - | Retried - | CompactionStarted - | CompactionEnded - | RevertStaged - | RevertCleared - | RevertCommitted + | SessionSynthetic + | SessionSkillActivated + | SessionShellStarted + | SessionShellEnded + | SessionStepStarted + | SessionStepEnded + | SessionStepFailed + | SessionTextStarted + | SessionTextEnded + | SessionReasoningStarted + | SessionReasoningEnded + | SessionToolInputStarted + | SessionToolInputEnded + | SessionToolCalled + | SessionToolProgress + | SessionToolSuccess + | SessionToolFailed + | SessionRetried + | SessionCompactionStarted + | SessionCompactionEnded + | SessionRevertStaged + | SessionRevertCleared + | SessionRevertCommitted export type SessionLogItem = SessionDurableEvent | EventLogSynced @@ -3022,24 +2962,6 @@ export type OutputFormat1 = retryCount?: number } -export type Shell1 = { - id: string - status: "running" | "exited" | "timeout" | "killed" - command: string - cwd: string - shell: string - file: string - pid?: number - exit?: number | "NaN" | "Infinity" | "-Infinity" - metadata: { - [key: string]: unknown - } - time: { - started: number | "NaN" | "Infinity" | "-Infinity" - completed?: number | "NaN" | "Infinity" | "-Infinity" - } -} - export type SessionStatus2 = { id: string created: number @@ -3096,42 +3018,42 @@ export type V2Event = | MessageRemoved | MessagePartUpdated | MessagePartRemoved - | AgentSelected - | ModelSelected + | SessionAgentSelected + | SessionModelSelected | SessionMoved - | Renamed - | Forked - | PromptPromoted - | PromptAdmitted - | ExecutionSettled + | SessionRenamed + | SessionForked + | SessionPromptPromoted + | SessionPromptAdmitted + | SessionExecutionSettled | SessionContextUpdated - | Synthetic - | SkillActivated - | ShellStarted - | ShellEnded - | StepStarted - | StepEnded - | StepFailed - | TextStarted - | TextDelta - | TextEnded - | ReasoningStarted - | ReasoningDelta - | ReasoningEnded - | ToolInputStarted - | ToolInputDelta - | ToolInputEnded - | ToolCalled - | ToolProgress - | ToolSuccess - | ToolFailed - | Retried - | CompactionStarted - | CompactionDelta - | CompactionEnded - | RevertStaged - | RevertCleared - | RevertCommitted + | SessionSynthetic + | SessionSkillActivated + | SessionShellStarted + | SessionShellEnded + | SessionStepStarted + | SessionStepEnded + | SessionStepFailed + | SessionTextStarted + | SessionTextDelta + | SessionTextEnded + | SessionReasoningStarted + | SessionReasoningDelta + | SessionReasoningEnded + | SessionToolInputStarted + | SessionToolInputDelta + | SessionToolInputEnded + | SessionToolCalled + | SessionToolProgress + | SessionToolSuccess + | SessionToolFailed + | SessionRetried + | SessionCompactionStarted + | SessionCompactionDelta + | SessionCompactionEnded + | SessionRevertStaged + | SessionRevertCleared + | SessionRevertCommitted | MessagePartDelta | SessionDiff | SessionError @@ -3689,11 +3611,11 @@ export type SyncEventMessagePartRemoved = { } } -export type SyncEventAgentSelected = { +export type SyncEventSessionAgentSelected = { type: "sync" id: string syncEvent: { - type: "agent.selected.1" + type: "session.agent.selected.1" id: string seq: number aggregateID: string @@ -3704,11 +3626,11 @@ export type SyncEventAgentSelected = { } } -export type SyncEventModelSelected = { +export type SyncEventSessionModelSelected = { type: "sync" id: string syncEvent: { - type: "model.selected.1" + type: "session.model.selected.1" id: string seq: number aggregateID: string @@ -3735,11 +3657,11 @@ export type SyncEventSessionMoved = { } } -export type SyncEventRenamed = { +export type SyncEventSessionRenamed = { type: "sync" id: string syncEvent: { - type: "renamed.1" + type: "session.renamed.1" id: string seq: number aggregateID: string @@ -3750,11 +3672,11 @@ export type SyncEventRenamed = { } } -export type SyncEventForked = { +export type SyncEventSessionForked = { type: "sync" id: string syncEvent: { - type: "forked.1" + type: "session.forked.1" id: string seq: number aggregateID: string @@ -3766,11 +3688,11 @@ export type SyncEventForked = { } } -export type SyncEventPromptPromoted = { +export type SyncEventSessionPromptPromoted = { type: "sync" id: string syncEvent: { - type: "prompt.promoted.1" + type: "session.prompt.promoted.1" id: string seq: number aggregateID: string @@ -3781,11 +3703,11 @@ export type SyncEventPromptPromoted = { } } -export type SyncEventPromptAdmitted = { +export type SyncEventSessionPromptAdmitted = { type: "sync" id: string syncEvent: { - type: "prompt.admitted.1" + type: "session.prompt.admitted.1" id: string seq: number aggregateID: string @@ -3813,11 +3735,11 @@ export type SyncEventSessionContextUpdated = { } } -export type SyncEventSynthetic = { +export type SyncEventSessionSynthetic = { type: "sync" id: string syncEvent: { - type: "synthetic.1" + type: "session.synthetic.1" id: string seq: number aggregateID: string @@ -3832,11 +3754,11 @@ export type SyncEventSynthetic = { } } -export type SyncEventSkillActivated = { +export type SyncEventSessionSkillActivated = { type: "sync" id: string syncEvent: { - type: "skill.activated.1" + type: "session.skill.activated.1" id: string seq: number aggregateID: string @@ -3848,43 +3770,47 @@ export type SyncEventSkillActivated = { } } -export type SyncEventShellStarted = { +export type SyncEventSessionShellStarted = { type: "sync" id: string syncEvent: { - type: "shell.started.1" + type: "session.shell.started.1" id: string seq: number aggregateID: string data: { sessionID: string - callID: string - command: string + shell: Shell } } } -export type SyncEventShellEnded = { +export type SyncEventSessionShellEnded = { type: "sync" id: string syncEvent: { - type: "shell.ended.1" + type: "session.shell.ended.1" id: string seq: number aggregateID: string data: { sessionID: string - callID: string - output: string + shell: Shell + output: { + output: string + cursor: number + size: number + truncated: boolean + } } } } -export type SyncEventStepStarted = { +export type SyncEventSessionStepStarted = { type: "sync" id: string syncEvent: { - type: "step.started.1" + type: "session.step.started.1" id: string seq: number aggregateID: string @@ -3898,11 +3824,11 @@ export type SyncEventStepStarted = { } } -export type SyncEventStepEnded = { +export type SyncEventSessionStepEnded = { type: "sync" id: string syncEvent: { - type: "step.ended.1" + type: "session.step.ended.1" id: string seq: number aggregateID: string @@ -3926,11 +3852,11 @@ export type SyncEventStepEnded = { } } -export type SyncEventStepFailed = { +export type SyncEventSessionStepFailed = { type: "sync" id: string syncEvent: { - type: "step.failed.1" + type: "session.step.failed.1" id: string seq: number aggregateID: string @@ -3942,11 +3868,11 @@ export type SyncEventStepFailed = { } } -export type SyncEventTextStarted = { +export type SyncEventSessionTextStarted = { type: "sync" id: string syncEvent: { - type: "text.started.1" + type: "session.text.started.1" id: string seq: number aggregateID: string @@ -3958,11 +3884,11 @@ export type SyncEventTextStarted = { } } -export type SyncEventTextEnded = { +export type SyncEventSessionTextEnded = { type: "sync" id: string syncEvent: { - type: "text.ended.1" + type: "session.text.ended.1" id: string seq: number aggregateID: string @@ -3975,11 +3901,11 @@ export type SyncEventTextEnded = { } } -export type SyncEventReasoningStarted = { +export type SyncEventSessionReasoningStarted = { type: "sync" id: string syncEvent: { - type: "reasoning.started.1" + type: "session.reasoning.started.1" id: string seq: number aggregateID: string @@ -3992,11 +3918,11 @@ export type SyncEventReasoningStarted = { } } -export type SyncEventReasoningEnded = { +export type SyncEventSessionReasoningEnded = { type: "sync" id: string syncEvent: { - type: "reasoning.ended.1" + type: "session.reasoning.ended.1" id: string seq: number aggregateID: string @@ -4010,11 +3936,11 @@ export type SyncEventReasoningEnded = { } } -export type SyncEventToolInputStarted = { +export type SyncEventSessionToolInputStarted = { type: "sync" id: string syncEvent: { - type: "tool.input.started.1" + type: "session.tool.input.started.1" id: string seq: number aggregateID: string @@ -4027,11 +3953,11 @@ export type SyncEventToolInputStarted = { } } -export type SyncEventToolInputEnded = { +export type SyncEventSessionToolInputEnded = { type: "sync" id: string syncEvent: { - type: "tool.input.ended.1" + type: "session.tool.input.ended.1" id: string seq: number aggregateID: string @@ -4044,11 +3970,11 @@ export type SyncEventToolInputEnded = { } } -export type SyncEventToolCalled = { +export type SyncEventSessionToolCalled = { type: "sync" id: string syncEvent: { - type: "tool.called.1" + type: "session.tool.called.1" id: string seq: number aggregateID: string @@ -4068,11 +3994,11 @@ export type SyncEventToolCalled = { } } -export type SyncEventToolProgress = { +export type SyncEventSessionToolProgress = { type: "sync" id: string syncEvent: { - type: "tool.progress.1" + type: "session.tool.progress.1" id: string seq: number aggregateID: string @@ -4088,11 +4014,11 @@ export type SyncEventToolProgress = { } } -export type SyncEventToolSuccess = { +export type SyncEventSessionToolSuccess = { type: "sync" id: string syncEvent: { - type: "tool.success.1" + type: "session.tool.success.1" id: string seq: number aggregateID: string @@ -4114,11 +4040,11 @@ export type SyncEventToolSuccess = { } } -export type SyncEventToolFailed = { +export type SyncEventSessionToolFailed = { type: "sync" id: string syncEvent: { - type: "tool.failed.1" + type: "session.tool.failed.1" id: string seq: number aggregateID: string @@ -4136,11 +4062,11 @@ export type SyncEventToolFailed = { } } -export type SyncEventRetried = { +export type SyncEventSessionRetried = { type: "sync" id: string syncEvent: { - type: "retried.1" + type: "session.retried.1" id: string seq: number aggregateID: string @@ -4152,11 +4078,11 @@ export type SyncEventRetried = { } } -export type SyncEventCompactionStarted = { +export type SyncEventSessionCompactionStarted = { type: "sync" id: string syncEvent: { - type: "compaction.started.1" + type: "session.compaction.started.1" id: string seq: number aggregateID: string @@ -4167,11 +4093,11 @@ export type SyncEventCompactionStarted = { } } -export type SyncEventCompactionEnded = { +export type SyncEventSessionCompactionEnded = { type: "sync" id: string syncEvent: { - type: "compaction.ended.1" + type: "session.compaction.ended.1" id: string seq: number aggregateID: string @@ -4184,11 +4110,11 @@ export type SyncEventCompactionEnded = { } } -export type SyncEventRevertStaged = { +export type SyncEventSessionRevertStaged = { type: "sync" id: string syncEvent: { - type: "revert.staged.1" + type: "session.revert.staged.1" id: string seq: number aggregateID: string @@ -4199,11 +4125,11 @@ export type SyncEventRevertStaged = { } } -export type SyncEventRevertCleared = { +export type SyncEventSessionRevertCleared = { type: "sync" id: string syncEvent: { - type: "revert.cleared.1" + type: "session.revert.cleared.1" id: string seq: number aggregateID: string @@ -4213,11 +4139,11 @@ export type SyncEventRevertCleared = { } } -export type SyncEventRevertCommitted = { +export type SyncEventSessionRevertCommitted = { type: "sync" id: string syncEvent: { - type: "revert.committed.1" + type: "session.revert.committed.1" id: string seq: number aggregateID: string @@ -4449,9 +4375,13 @@ export type SessionMessageShell = { completed?: number } type: "shell" - callID: string - command: string - output: string + shell: Shell + output?: { + output: string + cursor: number + size: number + truncated: boolean + } } export type SessionMessageAssistantText = { @@ -4600,13 +4530,13 @@ export type SessionContextEntryInfo = { value: unknown } -export type AgentSelected = { +export type SessionAgentSelected = { id: string created: number metadata?: { [key: string]: unknown } - type: "agent.selected" + type: "session.agent.selected" durable: { aggregateID: string seq: number @@ -4619,13 +4549,13 @@ export type AgentSelected = { } } -export type ModelSelected = { +export type SessionModelSelected = { id: string created: number metadata?: { [key: string]: unknown } - type: "model.selected" + type: "session.model.selected" durable: { aggregateID: string seq: number @@ -4658,13 +4588,52 @@ export type SessionMoved = { } } -export type PromptPromoted = { +export type SessionRenamed = { id: string created: number metadata?: { [key: string]: unknown } - type: "prompt.promoted" + type: "session.renamed" + durable: { + aggregateID: string + seq: number + version: number + } + location?: LocationRef + data: { + sessionID: string + title: string + } +} + +export type SessionForked = { + id: string + created: number + metadata?: { + [key: string]: unknown + } + type: "session.forked" + durable: { + aggregateID: string + seq: number + version: number + } + location?: LocationRef + data: { + sessionID: string + parentID: string + from?: string + } +} + +export type SessionPromptPromoted = { + id: string + created: number + metadata?: { + [key: string]: unknown + } + type: "session.prompt.promoted" durable: { aggregateID: string seq: number @@ -4677,13 +4646,13 @@ export type PromptPromoted = { } } -export type PromptAdmitted = { +export type SessionPromptAdmitted = { id: string created: number metadata?: { [key: string]: unknown } - type: "prompt.admitted" + type: "session.prompt.admitted" durable: { aggregateID: string seq: number @@ -4717,13 +4686,36 @@ export type SessionContextUpdated = { } } -export type SkillActivated = { +export type SessionSynthetic = { id: string created: number metadata?: { [key: string]: unknown } - type: "skill.activated" + type: "session.synthetic" + durable: { + aggregateID: string + seq: number + version: number + } + location?: LocationRef + data: { + sessionID: string + text: string + description?: string + metadata?: { + [key: string]: unknown + } + } +} + +export type SessionSkillActivated = { + id: string + created: number + metadata?: { + [key: string]: unknown + } + type: "session.skill.activated" durable: { aggregateID: string seq: number @@ -4737,13 +4729,13 @@ export type SkillActivated = { } } -export type ShellStarted = { +export type SessionShellStarted = { id: string created: number metadata?: { [key: string]: unknown } - type: "shell.started" + type: "session.shell.started" durable: { aggregateID: string seq: number @@ -4752,18 +4744,17 @@ export type ShellStarted = { location?: LocationRef data: { sessionID: string - callID: string - command: string + shell: Shell1 } } -export type ShellEnded = { +export type SessionShellEnded = { id: string created: number metadata?: { [key: string]: unknown } - type: "shell.ended" + type: "session.shell.ended" durable: { aggregateID: string seq: number @@ -4772,18 +4763,23 @@ export type ShellEnded = { location?: LocationRef data: { sessionID: string - callID: string - output: string + shell: Shell1 + output: { + output: string + cursor: number + size: number + truncated: boolean + } } } -export type StepStarted = { +export type SessionStepStarted = { id: string created: number metadata?: { [key: string]: unknown } - type: "step.started" + type: "session.step.started" durable: { aggregateID: string seq: number @@ -4799,13 +4795,13 @@ export type StepStarted = { } } -export type StepEnded = { +export type SessionStepEnded = { id: string created: number metadata?: { [key: string]: unknown } - type: "step.ended" + type: "session.step.ended" durable: { aggregateID: string seq: number @@ -4831,13 +4827,13 @@ export type StepEnded = { } } -export type StepFailed = { +export type SessionStepFailed = { id: string created: number metadata?: { [key: string]: unknown } - type: "step.failed" + type: "session.step.failed" durable: { aggregateID: string seq: number @@ -4851,13 +4847,13 @@ export type StepFailed = { } } -export type TextStarted = { +export type SessionTextStarted = { id: string created: number metadata?: { [key: string]: unknown } - type: "text.started" + type: "session.text.started" durable: { aggregateID: string seq: number @@ -4871,13 +4867,13 @@ export type TextStarted = { } } -export type TextEnded = { +export type SessionTextEnded = { id: string created: number metadata?: { [key: string]: unknown } - type: "text.ended" + type: "session.text.ended" durable: { aggregateID: string seq: number @@ -4892,13 +4888,13 @@ export type TextEnded = { } } -export type ReasoningStarted = { +export type SessionReasoningStarted = { id: string created: number metadata?: { [key: string]: unknown } - type: "reasoning.started" + type: "session.reasoning.started" durable: { aggregateID: string seq: number @@ -4913,13 +4909,13 @@ export type ReasoningStarted = { } } -export type ReasoningEnded = { +export type SessionReasoningEnded = { id: string created: number metadata?: { [key: string]: unknown } - type: "reasoning.ended" + type: "session.reasoning.ended" durable: { aggregateID: string seq: number @@ -4935,13 +4931,13 @@ export type ReasoningEnded = { } } -export type ToolInputStarted = { +export type SessionToolInputStarted = { id: string created: number metadata?: { [key: string]: unknown } - type: "tool.input.started" + type: "session.tool.input.started" durable: { aggregateID: string seq: number @@ -4956,13 +4952,13 @@ export type ToolInputStarted = { } } -export type ToolInputEnded = { +export type SessionToolInputEnded = { id: string created: number metadata?: { [key: string]: unknown } - type: "tool.input.ended" + type: "session.tool.input.ended" durable: { aggregateID: string seq: number @@ -4977,13 +4973,13 @@ export type ToolInputEnded = { } } -export type ToolCalled = { +export type SessionToolCalled = { id: string created: number metadata?: { [key: string]: unknown } - type: "tool.called" + type: "session.tool.called" durable: { aggregateID: string seq: number @@ -5005,13 +5001,13 @@ export type ToolCalled = { } } -export type ToolProgress = { +export type SessionToolProgress = { id: string created: number metadata?: { [key: string]: unknown } - type: "tool.progress" + type: "session.tool.progress" durable: { aggregateID: string seq: number @@ -5029,13 +5025,13 @@ export type ToolProgress = { } } -export type ToolSuccess = { +export type SessionToolSuccess = { id: string created: number metadata?: { [key: string]: unknown } - type: "tool.success" + type: "session.tool.success" durable: { aggregateID: string seq: number @@ -5059,13 +5055,13 @@ export type ToolSuccess = { } } -export type ToolFailed = { +export type SessionToolFailed = { id: string created: number metadata?: { [key: string]: unknown } - type: "tool.failed" + type: "session.tool.failed" durable: { aggregateID: string seq: number @@ -5085,13 +5081,33 @@ export type ToolFailed = { } } -export type CompactionStarted = { +export type SessionRetried = { id: string created: number metadata?: { [key: string]: unknown } - type: "compaction.started" + type: "session.retried" + durable: { + aggregateID: string + seq: number + version: number + } + location?: LocationRef + data: { + sessionID: string + attempt: number + error: SessionRetryError + } +} + +export type SessionCompactionStarted = { + id: string + created: number + metadata?: { + [key: string]: unknown + } + type: "session.compaction.started" durable: { aggregateID: string seq: number @@ -5104,13 +5120,13 @@ export type CompactionStarted = { } } -export type CompactionEnded = { +export type SessionCompactionEnded = { id: string created: number metadata?: { [key: string]: unknown } - type: "compaction.ended" + type: "session.compaction.ended" durable: { aggregateID: string seq: number @@ -5125,13 +5141,13 @@ export type CompactionEnded = { } } -export type RevertStaged = { +export type SessionRevertStaged = { id: string created: number metadata?: { [key: string]: unknown } - type: "revert.staged" + type: "session.revert.staged" durable: { aggregateID: string seq: number @@ -5144,13 +5160,13 @@ export type RevertStaged = { } } -export type RevertCleared = { +export type SessionRevertCleared = { id: string created: number metadata?: { [key: string]: unknown } - type: "revert.cleared" + type: "session.revert.cleared" durable: { aggregateID: string seq: number @@ -5162,13 +5178,13 @@ export type RevertCleared = { } } -export type RevertCommitted = { +export type SessionRevertCommitted = { id: string created: number metadata?: { [key: string]: unknown } - type: "revert.committed" + type: "session.revert.committed" durable: { aggregateID: string seq: number @@ -5708,13 +5724,13 @@ export type MessagePartRemoved = { } } -export type ExecutionSettled = { +export type SessionExecutionSettled = { id: string created: number metadata?: { [key: string]: unknown } - type: "execution.settled" + type: "session.execution.settled" location?: LocationRef data: { sessionID: string @@ -5723,13 +5739,13 @@ export type ExecutionSettled = { } } -export type TextDelta = { +export type SessionTextDelta = { id: string created: number metadata?: { [key: string]: unknown } - type: "text.delta" + type: "session.text.delta" location?: LocationRef data: { sessionID: string @@ -5739,13 +5755,13 @@ export type TextDelta = { } } -export type ReasoningDelta = { +export type SessionReasoningDelta = { id: string created: number metadata?: { [key: string]: unknown } - type: "reasoning.delta" + type: "session.reasoning.delta" location?: LocationRef data: { sessionID: string @@ -5755,13 +5771,13 @@ export type ReasoningDelta = { } } -export type ToolInputDelta = { +export type SessionToolInputDelta = { id: string created: number metadata?: { [key: string]: unknown } - type: "tool.input.delta" + type: "session.tool.input.delta" location?: LocationRef data: { sessionID: string @@ -5771,13 +5787,13 @@ export type ToolInputDelta = { } } -export type CompactionDelta = { +export type SessionCompactionDelta = { id: string created: number metadata?: { [key: string]: unknown } - type: "compaction.delta" + type: "session.compaction.delta" location?: LocationRef data: { sessionID: string @@ -6730,18 +6746,18 @@ export type EventMessagePartRemoved = { } } -export type EventAgentSelected = { +export type EventSessionAgentSelected = { id: string - type: "agent.selected" + type: "session.agent.selected" properties: { sessionID: string agent: string } } -export type EventModelSelected = { +export type EventSessionModelSelected = { id: string - type: "model.selected" + type: "session.model.selected" properties: { sessionID: string model: ModelRef @@ -6758,18 +6774,18 @@ export type EventSessionMoved = { } } -export type EventRenamed = { +export type EventSessionRenamed = { id: string - type: "renamed" + type: "session.renamed" properties: { sessionID: string title: string } } -export type EventForked = { +export type EventSessionForked = { id: string - type: "forked" + type: "session.forked" properties: { sessionID: string parentID: string @@ -6777,18 +6793,18 @@ export type EventForked = { } } -export type EventPromptPromoted = { +export type EventSessionPromptPromoted = { id: string - type: "prompt.promoted" + type: "session.prompt.promoted" properties: { sessionID: string inputID: string } } -export type EventPromptAdmitted = { +export type EventSessionPromptAdmitted = { id: string - type: "prompt.admitted" + type: "session.prompt.admitted" properties: { sessionID: string inputID: string @@ -6797,9 +6813,9 @@ export type EventPromptAdmitted = { } } -export type EventExecutionSettled = { +export type EventSessionExecutionSettled = { id: string - type: "execution.settled" + type: "session.execution.settled" properties: { sessionID: string outcome: "success" | "failure" | "interrupted" @@ -6816,9 +6832,9 @@ export type EventSessionContextUpdated = { } } -export type EventSynthetic = { +export type EventSessionSynthetic = { id: string - type: "synthetic" + type: "session.synthetic" properties: { sessionID: string text: string @@ -6829,9 +6845,9 @@ export type EventSynthetic = { } } -export type EventSkillActivated = { +export type EventSessionSkillActivated = { id: string - type: "skill.activated" + type: "session.skill.activated" properties: { sessionID: string name: string @@ -6839,29 +6855,33 @@ export type EventSkillActivated = { } } -export type EventShellStarted = { +export type EventSessionShellStarted = { id: string - type: "shell.started" + type: "session.shell.started" properties: { sessionID: string - callID: string - command: string + shell: Shell2 } } -export type EventShellEnded = { +export type EventSessionShellEnded = { id: string - type: "shell.ended" + type: "session.shell.ended" properties: { sessionID: string - callID: string - output: string + shell: Shell2 + output: { + output: string + cursor: number + size: number + truncated: boolean + } } } -export type EventStepStarted = { +export type EventSessionStepStarted = { id: string - type: "step.started" + type: "session.step.started" properties: { sessionID: string assistantMessageID: string @@ -6871,9 +6891,9 @@ export type EventStepStarted = { } } -export type EventStepEnded = { +export type EventSessionStepEnded = { id: string - type: "step.ended" + type: "session.step.ended" properties: { sessionID: string assistantMessageID: string @@ -6893,9 +6913,9 @@ export type EventStepEnded = { } } -export type EventStepFailed = { +export type EventSessionStepFailed = { id: string - type: "step.failed" + type: "session.step.failed" properties: { sessionID: string assistantMessageID: string @@ -6903,9 +6923,9 @@ export type EventStepFailed = { } } -export type EventTextStarted = { +export type EventSessionTextStarted = { id: string - type: "text.started" + type: "session.text.started" properties: { sessionID: string assistantMessageID: string @@ -6913,9 +6933,9 @@ export type EventTextStarted = { } } -export type EventTextDelta = { +export type EventSessionTextDelta = { id: string - type: "text.delta" + type: "session.text.delta" properties: { sessionID: string assistantMessageID: string @@ -6924,9 +6944,9 @@ export type EventTextDelta = { } } -export type EventTextEnded = { +export type EventSessionTextEnded = { id: string - type: "text.ended" + type: "session.text.ended" properties: { sessionID: string assistantMessageID: string @@ -6935,9 +6955,9 @@ export type EventTextEnded = { } } -export type EventReasoningStarted = { +export type EventSessionReasoningStarted = { id: string - type: "reasoning.started" + type: "session.reasoning.started" properties: { sessionID: string assistantMessageID: string @@ -6946,9 +6966,9 @@ export type EventReasoningStarted = { } } -export type EventReasoningDelta = { +export type EventSessionReasoningDelta = { id: string - type: "reasoning.delta" + type: "session.reasoning.delta" properties: { sessionID: string assistantMessageID: string @@ -6957,9 +6977,9 @@ export type EventReasoningDelta = { } } -export type EventReasoningEnded = { +export type EventSessionReasoningEnded = { id: string - type: "reasoning.ended" + type: "session.reasoning.ended" properties: { sessionID: string assistantMessageID: string @@ -6969,9 +6989,9 @@ export type EventReasoningEnded = { } } -export type EventToolInputStarted = { +export type EventSessionToolInputStarted = { id: string - type: "tool.input.started" + type: "session.tool.input.started" properties: { sessionID: string assistantMessageID: string @@ -6980,9 +7000,9 @@ export type EventToolInputStarted = { } } -export type EventToolInputDelta = { +export type EventSessionToolInputDelta = { id: string - type: "tool.input.delta" + type: "session.tool.input.delta" properties: { sessionID: string assistantMessageID: string @@ -6991,9 +7011,9 @@ export type EventToolInputDelta = { } } -export type EventToolInputEnded = { +export type EventSessionToolInputEnded = { id: string - type: "tool.input.ended" + type: "session.tool.input.ended" properties: { sessionID: string assistantMessageID: string @@ -7002,9 +7022,9 @@ export type EventToolInputEnded = { } } -export type EventToolCalled = { +export type EventSessionToolCalled = { id: string - type: "tool.called" + type: "session.tool.called" properties: { sessionID: string assistantMessageID: string @@ -7020,9 +7040,9 @@ export type EventToolCalled = { } } -export type EventToolProgress = { +export type EventSessionToolProgress = { id: string - type: "tool.progress" + type: "session.tool.progress" properties: { sessionID: string assistantMessageID: string @@ -7034,9 +7054,9 @@ export type EventToolProgress = { } } -export type EventToolSuccess = { +export type EventSessionToolSuccess = { id: string - type: "tool.success" + type: "session.tool.success" properties: { sessionID: string assistantMessageID: string @@ -7054,9 +7074,9 @@ export type EventToolSuccess = { } } -export type EventToolFailed = { +export type EventSessionToolFailed = { id: string - type: "tool.failed" + type: "session.tool.failed" properties: { sessionID: string assistantMessageID: string @@ -7070,9 +7090,9 @@ export type EventToolFailed = { } } -export type EventRetried = { +export type EventSessionRetried = { id: string - type: "retried" + type: "session.retried" properties: { sessionID: string attempt: number @@ -7080,27 +7100,27 @@ export type EventRetried = { } } -export type EventCompactionStarted = { +export type EventSessionCompactionStarted = { id: string - type: "compaction.started" + type: "session.compaction.started" properties: { sessionID: string reason: "auto" | "manual" } } -export type EventCompactionDelta = { +export type EventSessionCompactionDelta = { id: string - type: "compaction.delta" + type: "session.compaction.delta" properties: { sessionID: string text: string } } -export type EventCompactionEnded = { +export type EventSessionCompactionEnded = { id: string - type: "compaction.ended" + type: "session.compaction.ended" properties: { sessionID: string reason: "auto" | "manual" @@ -7109,26 +7129,26 @@ export type EventCompactionEnded = { } } -export type EventRevertStaged = { +export type EventSessionRevertStaged = { id: string - type: "revert.staged" + type: "session.revert.staged" properties: { sessionID: string revert: RevertState } } -export type EventRevertCleared = { +export type EventSessionRevertCleared = { id: string - type: "revert.cleared" + type: "session.revert.cleared" properties: { sessionID: string } } -export type EventRevertCommitted = { +export type EventSessionRevertCommitted = { id: string - type: "revert.committed" + type: "session.revert.committed" properties: { sessionID: string messageID: string @@ -7999,6 +8019,24 @@ export type SessionMessageSkill2 = { text: string } +export type ShellV2 = { + id: string + status: "running" | "exited" | "timeout" | "killed" + command: string + cwd: string + shell: string + file: string + pid?: number + exit?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" + metadata: { + [key: string]: unknown + } + time: { + started: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" + completed?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" + } +} + export type SessionMessageShell2 = { id: string metadata?: { @@ -8009,9 +8047,13 @@ export type SessionMessageShell2 = { completed?: number } type: "shell" - callID: string - command: string - output: string + shell: ShellV2 + output?: { + output: string + cursor: number + size: number + truncated: boolean + } } export type SessionMessageAssistantText2 = { @@ -8188,13 +8230,13 @@ export type SessionContextEntryInfo2 = { value: unknown } -export type AgentSelected2 = { +export type SessionAgentSelected2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "agent.selected" + type: "session.agent.selected" durable: { aggregateID: string seq: number @@ -8207,13 +8249,13 @@ export type AgentSelected2 = { } } -export type ModelSelected2 = { +export type SessionModelSelected2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "model.selected" + type: "session.model.selected" durable: { aggregateID: string seq: number @@ -8246,13 +8288,13 @@ export type SessionMoved2 = { } } -export type RenamedV2 = { +export type SessionRenamed2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "renamed" + type: "session.renamed" durable: { aggregateID: string seq: number @@ -8265,13 +8307,13 @@ export type RenamedV2 = { } } -export type ForkedV2 = { +export type SessionForked2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "forked" + type: "session.forked" durable: { aggregateID: string seq: number @@ -8285,13 +8327,13 @@ export type ForkedV2 = { } } -export type PromptPromoted2 = { +export type SessionPromptPromoted2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "prompt.promoted" + type: "session.prompt.promoted" durable: { aggregateID: string seq: number @@ -8304,13 +8346,13 @@ export type PromptPromoted2 = { } } -export type PromptAdmitted2 = { +export type SessionPromptAdmitted2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "prompt.admitted" + type: "session.prompt.admitted" durable: { aggregateID: string seq: number @@ -8344,13 +8386,13 @@ export type SessionContextUpdated2 = { } } -export type SyntheticV2 = { +export type SessionSynthetic2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "synthetic" + type: "session.synthetic" durable: { aggregateID: string seq: number @@ -8367,13 +8409,13 @@ export type SyntheticV2 = { } } -export type SkillActivated2 = { +export type SessionSkillActivated2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "skill.activated" + type: "session.skill.activated" durable: { aggregateID: string seq: number @@ -8387,13 +8429,31 @@ export type SkillActivated2 = { } } -export type ShellStarted2 = { +export type Shell1V2 = { + id: string + status: "running" | "exited" | "timeout" | "killed" + command: string + cwd: string + shell: string + file: string + pid?: number + exit?: number | "NaN" | "Infinity" | "-Infinity" + metadata: { + [key: string]: unknown + } + time: { + started: number | "NaN" | "Infinity" | "-Infinity" + completed?: number | "NaN" | "Infinity" | "-Infinity" + } +} + +export type SessionShellStarted2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "shell.started" + type: "session.shell.started" durable: { aggregateID: string seq: number @@ -8402,18 +8462,17 @@ export type ShellStarted2 = { location?: LocationRef2 data: { sessionID: string - callID: string - command: string + shell: Shell1V2 } } -export type ShellEnded2 = { +export type SessionShellEnded2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "shell.ended" + type: "session.shell.ended" durable: { aggregateID: string seq: number @@ -8422,18 +8481,23 @@ export type ShellEnded2 = { location?: LocationRef2 data: { sessionID: string - callID: string - output: string + shell: Shell1V2 + output: { + output: string + cursor: number + size: number + truncated: boolean + } } } -export type StepStarted2 = { +export type SessionStepStarted2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "step.started" + type: "session.step.started" durable: { aggregateID: string seq: number @@ -8449,13 +8513,13 @@ export type StepStarted2 = { } } -export type StepEnded2 = { +export type SessionStepEnded2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "step.ended" + type: "session.step.ended" durable: { aggregateID: string seq: number @@ -8481,13 +8545,13 @@ export type StepEnded2 = { } } -export type StepFailed2 = { +export type SessionStepFailed2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "step.failed" + type: "session.step.failed" durable: { aggregateID: string seq: number @@ -8501,13 +8565,13 @@ export type StepFailed2 = { } } -export type TextStarted2 = { +export type SessionTextStarted2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "text.started" + type: "session.text.started" durable: { aggregateID: string seq: number @@ -8521,13 +8585,13 @@ export type TextStarted2 = { } } -export type TextEnded2 = { +export type SessionTextEnded2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "text.ended" + type: "session.text.ended" durable: { aggregateID: string seq: number @@ -8548,13 +8612,13 @@ export type LlmProviderMetadata3 = { } } -export type ReasoningStarted2 = { +export type SessionReasoningStarted2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "reasoning.started" + type: "session.reasoning.started" durable: { aggregateID: string seq: number @@ -8575,13 +8639,13 @@ export type LlmProviderMetadata4 = { } } -export type ReasoningEnded2 = { +export type SessionReasoningEnded2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "reasoning.ended" + type: "session.reasoning.ended" durable: { aggregateID: string seq: number @@ -8597,13 +8661,13 @@ export type ReasoningEnded2 = { } } -export type ToolInputStarted2 = { +export type SessionToolInputStarted2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "tool.input.started" + type: "session.tool.input.started" durable: { aggregateID: string seq: number @@ -8618,13 +8682,13 @@ export type ToolInputStarted2 = { } } -export type ToolInputEnded2 = { +export type SessionToolInputEnded2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "tool.input.ended" + type: "session.tool.input.ended" durable: { aggregateID: string seq: number @@ -8645,13 +8709,13 @@ export type LlmProviderMetadata5 = { } } -export type ToolCalled2 = { +export type SessionToolCalled2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "tool.called" + type: "session.tool.called" durable: { aggregateID: string seq: number @@ -8673,13 +8737,13 @@ export type ToolCalled2 = { } } -export type ToolProgress2 = { +export type SessionToolProgress2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "tool.progress" + type: "session.tool.progress" durable: { aggregateID: string seq: number @@ -8703,13 +8767,13 @@ export type LlmProviderMetadata6 = { } } -export type ToolSuccess2 = { +export type SessionToolSuccess2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "tool.success" + type: "session.tool.success" durable: { aggregateID: string seq: number @@ -8739,13 +8803,13 @@ export type LlmProviderMetadata7 = { } } -export type ToolFailed2 = { +export type SessionToolFailed2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "tool.failed" + type: "session.tool.failed" durable: { aggregateID: string seq: number @@ -8778,13 +8842,13 @@ export type SessionRetryError2 = { } } -export type RetriedV2 = { +export type SessionRetried2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "retried" + type: "session.retried" durable: { aggregateID: string seq: number @@ -8798,13 +8862,13 @@ export type RetriedV2 = { } } -export type CompactionStarted2 = { +export type SessionCompactionStarted2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "compaction.started" + type: "session.compaction.started" durable: { aggregateID: string seq: number @@ -8817,13 +8881,13 @@ export type CompactionStarted2 = { } } -export type CompactionEnded2 = { +export type SessionCompactionEnded2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "compaction.ended" + type: "session.compaction.ended" durable: { aggregateID: string seq: number @@ -8838,13 +8902,13 @@ export type CompactionEnded2 = { } } -export type RevertStaged2 = { +export type SessionRevertStaged2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "revert.staged" + type: "session.revert.staged" durable: { aggregateID: string seq: number @@ -8857,13 +8921,13 @@ export type RevertStaged2 = { } } -export type RevertCleared2 = { +export type SessionRevertCleared2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "revert.cleared" + type: "session.revert.cleared" durable: { aggregateID: string seq: number @@ -8875,13 +8939,13 @@ export type RevertCleared2 = { } } -export type RevertCommitted2 = { +export type SessionRevertCommitted2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "revert.committed" + type: "session.revert.committed" durable: { aggregateID: string seq: number @@ -8895,37 +8959,37 @@ export type RevertCommitted2 = { } export type SessionDurableEventV2 = - | AgentSelected2 - | ModelSelected2 + | SessionAgentSelected2 + | SessionModelSelected2 | SessionMoved2 - | RenamedV2 - | ForkedV2 - | PromptPromoted2 - | PromptAdmitted2 + | SessionRenamed2 + | SessionForked2 + | SessionPromptPromoted2 + | SessionPromptAdmitted2 | SessionContextUpdated2 - | SyntheticV2 - | SkillActivated2 - | ShellStarted2 - | ShellEnded2 - | StepStarted2 - | StepEnded2 - | StepFailed2 - | TextStarted2 - | TextEnded2 - | ReasoningStarted2 - | ReasoningEnded2 - | ToolInputStarted2 - | ToolInputEnded2 - | ToolCalled2 - | ToolProgress2 - | ToolSuccess2 - | ToolFailed2 - | RetriedV2 - | CompactionStarted2 - | CompactionEnded2 - | RevertStaged2 - | RevertCleared2 - | RevertCommitted2 + | SessionSynthetic2 + | SessionSkillActivated2 + | SessionShellStarted2 + | SessionShellEnded2 + | SessionStepStarted2 + | SessionStepEnded2 + | SessionStepFailed2 + | SessionTextStarted2 + | SessionTextEnded2 + | SessionReasoningStarted2 + | SessionReasoningEnded2 + | SessionToolInputStarted2 + | SessionToolInputEnded2 + | SessionToolCalled2 + | SessionToolProgress2 + | SessionToolSuccess2 + | SessionToolFailed2 + | SessionRetried2 + | SessionCompactionStarted2 + | SessionCompactionEnded2 + | SessionRevertStaged2 + | SessionRevertCleared2 + | SessionRevertCommitted2 /** * Marker emitted once when a log read reaches its captured watermark. The reader holds every event committed at or below seq. @@ -10138,13 +10202,13 @@ export type MessagePartRemoved2 = { } } -export type ExecutionSettled2 = { +export type SessionExecutionSettled2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "execution.settled" + type: "session.execution.settled" location?: LocationRef2 data: { sessionID: string @@ -10153,13 +10217,13 @@ export type ExecutionSettled2 = { } } -export type TextDelta2 = { +export type SessionTextDelta2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "text.delta" + type: "session.text.delta" location?: LocationRef2 data: { sessionID: string @@ -10169,13 +10233,13 @@ export type TextDelta2 = { } } -export type ReasoningDelta2 = { +export type SessionReasoningDelta2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "reasoning.delta" + type: "session.reasoning.delta" location?: LocationRef2 data: { sessionID: string @@ -10185,13 +10249,13 @@ export type ReasoningDelta2 = { } } -export type ToolInputDelta2 = { +export type SessionToolInputDelta2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "tool.input.delta" + type: "session.tool.input.delta" location?: LocationRef2 data: { sessionID: string @@ -10201,13 +10265,13 @@ export type ToolInputDelta2 = { } } -export type CompactionDelta2 = { +export type SessionCompactionDelta2 = { id: string created: number metadata?: { [key: string]: unknown } - type: "compaction.delta" + type: "session.compaction.delta" location?: LocationRef2 data: { sessionID: string @@ -10413,24 +10477,6 @@ export type PtyDeleted2 = { } } -export type ShellV2 = { - id: string - status: "running" | "exited" | "timeout" | "killed" - command: string - cwd: string - shell: string - file: string - pid?: number - exit?: number | "NaN" | "Infinity" | "-Infinity" - metadata: { - [key: string]: unknown - } - time: { - started: number | "NaN" | "Infinity" | "-Infinity" - completed?: number | "NaN" | "Infinity" | "-Infinity" - } -} - export type ShellCreated2 = { id: string created: number @@ -10440,7 +10486,7 @@ export type ShellCreated2 = { type: "shell.created" location?: LocationRef2 data: { - info: ShellV2 + info: Shell1V2 } } @@ -11080,42 +11126,42 @@ export type V2EventV2 = | MessageRemoved2 | MessagePartUpdated2 | MessagePartRemoved2 - | AgentSelected2 - | ModelSelected2 + | SessionAgentSelected2 + | SessionModelSelected2 | SessionMoved2 - | RenamedV2 - | ForkedV2 - | PromptPromoted2 - | PromptAdmitted2 - | ExecutionSettled2 + | SessionRenamed2 + | SessionForked2 + | SessionPromptPromoted2 + | SessionPromptAdmitted2 + | SessionExecutionSettled2 | SessionContextUpdated2 - | SyntheticV2 - | SkillActivated2 - | ShellStarted2 - | ShellEnded2 - | StepStarted2 - | StepEnded2 - | StepFailed2 - | TextStarted2 - | TextDelta2 - | TextEnded2 - | ReasoningStarted2 - | ReasoningDelta2 - | ReasoningEnded2 - | ToolInputStarted2 - | ToolInputDelta2 - | ToolInputEnded2 - | ToolCalled2 - | ToolProgress2 - | ToolSuccess2 - | ToolFailed2 - | RetriedV2 - | CompactionStarted2 - | CompactionDelta2 - | CompactionEnded2 - | RevertStaged2 - | RevertCleared2 - | RevertCommitted2 + | SessionSynthetic2 + | SessionSkillActivated2 + | SessionShellStarted2 + | SessionShellEnded2 + | SessionStepStarted2 + | SessionStepEnded2 + | SessionStepFailed2 + | SessionTextStarted2 + | SessionTextDelta2 + | SessionTextEnded2 + | SessionReasoningStarted2 + | SessionReasoningDelta2 + | SessionReasoningEnded2 + | SessionToolInputStarted2 + | SessionToolInputDelta2 + | SessionToolInputEnded2 + | SessionToolCalled2 + | SessionToolProgress2 + | SessionToolSuccess2 + | SessionToolFailed2 + | SessionRetried2 + | SessionCompactionStarted2 + | SessionCompactionDelta2 + | SessionCompactionEnded2 + | SessionRevertStaged2 + | SessionRevertCleared2 + | SessionRevertCommitted2 | FileEdited2 | ReferenceUpdated2 | PermissionV2Asked2 @@ -11195,24 +11241,6 @@ export type ForbiddenErrorV2 = { message: string } -export type Shell1V2 = { - id: string - status: "running" | "exited" | "timeout" | "killed" - command: string - cwd: string - shell: string - file: string - pid?: number - exit?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" - metadata: { - [key: string]: unknown - } - time: { - started: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" - completed?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" - } -} - export type ShellNotFoundErrorV2 = { _tag: "ShellNotFoundError" id: string @@ -18444,7 +18472,7 @@ export type V2ShellListResponses = { */ 200: { location: LocationInfo2 - data: Array + data: Array } } @@ -18488,7 +18516,7 @@ export type V2ShellCreateResponses = { */ 200: { location: LocationInfo2 - data: Shell1V2 + data: ShellV2 } } @@ -18571,7 +18599,7 @@ export type V2ShellGetResponses = { */ 200: { location: LocationInfo2 - data: Shell1V2 + data: ShellV2 } } diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index b30c3beb35..e136ef6836 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -16410,7 +16410,7 @@ "text": { "type": "string" }, - "synthetic": { + "session.synthetic": { "type": "boolean" }, "ignored": { @@ -23071,7 +23071,7 @@ "text": { "type": "string" }, - "synthetic": { + "session.synthetic": { "type": "boolean" }, "ignored": { @@ -27479,7 +27479,7 @@ }, "type": { "type": "string", - "enum": ["synthetic"] + "enum": ["session.synthetic"] } }, "required": ["id", "time", "sessionID", "text", "type"], diff --git a/packages/tui/src/context/data.tsx b/packages/tui/src/context/data.tsx index cc9378dbac..0ed464e561 100644 --- a/packages/tui/src/context/data.tsx +++ b/packages/tui/src/context/data.tsx @@ -126,8 +126,8 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ const item = position === undefined ? undefined : messages[position] return item?.type === "assistant" ? item : undefined }, - activeShell(messages: SessionMessage[], callID: string) { - const item = messages.findLast((item) => item.type === "shell" && item.callID === callID) + shell(messages: SessionMessage[], shellID: string) { + const item = messages.findLast((item) => item.type === "shell" && item.shell.id === shellID) return item?.type === "shell" ? item : undefined }, latestTool(assistant: SessionMessageAssistant | undefined, callID?: string) { @@ -220,7 +220,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ case "skill.updated": void result.location.skill.refresh(event.location) break - case "agent.selected": + case "session.agent.selected": if (store.session.info[event.data.sessionID]) setStore("session", "info", event.data.sessionID, "agent", event.data.agent) message.update(event.data.sessionID, (draft, index) => { @@ -232,7 +232,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ }) }) break - case "model.selected": + case "session.model.selected": if (store.session.info[event.data.sessionID]) setStore("session", "info", event.data.sessionID, "model", event.data.model) message.update(event.data.sessionID, (draft, index) => { @@ -244,11 +244,11 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ }) }) break - case "renamed": + case "session.renamed": if (store.session.info[event.data.sessionID]) setStore("session", "info", event.data.sessionID, "title", event.data.title) break - case "prompt.promoted": { + case "session.prompt.promoted": { setStore("session", "status", event.data.sessionID, "running") message.update(event.data.sessionID, (draft, index) => { const position = index.get(event.data.inputID) @@ -264,7 +264,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ }) break } - case "prompt.admitted": + case "session.prompt.admitted": message.update(event.data.sessionID, (draft, index) => { message.append(draft, index, { id: event.data.inputID, @@ -287,7 +287,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ }) }) break - case "synthetic": + case "session.synthetic": message.update(event.data.sessionID, (draft, index) => { message.append(draft, index, { id: messageIDFromEvent(event.id), @@ -299,29 +299,28 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ }) }) break - case "shell.started": + case "session.shell.started": setStore("session", "status", event.data.sessionID, "running") message.update(event.data.sessionID, (draft, index) => { message.append(draft, index, { id: messageIDFromEvent(event.id), type: "shell", - callID: event.data.callID, - command: event.data.command, - output: "", + shell: event.data.shell, time: { created: event.created }, }) }) break - case "shell.ended": + case "session.shell.ended": setStore("session", "status", event.data.sessionID, "idle") - message.update(event.data.sessionID, (draft, index) => { - const match = message.activeShell(draft, event.data.callID) + message.update(event.data.sessionID, (draft) => { + const match = message.shell(draft, event.data.shell.id) if (!match) return + match.shell = event.data.shell match.output = event.data.output match.time.completed = event.created }) break - case "step.started": + case "session.step.started": setStore("session", "status", event.data.sessionID, "running") message.update(event.data.sessionID, (draft, index) => { if (index.has(event.data.assistantMessageID)) return @@ -338,7 +337,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ }) }) break - case "step.ended": + case "session.step.ended": setStore("session", "status", event.data.sessionID, "running") message.update(event.data.sessionID, (draft, index) => { const currentAssistant = message.assistant(draft, index, event.data.assistantMessageID) @@ -351,7 +350,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ currentAssistant.snapshot = { ...currentAssistant.snapshot, end: event.data.snapshot } }) break - case "step.failed": + case "session.step.failed": message.update(event.data.sessionID, (draft, index) => { const currentAssistant = message.assistant(draft, index, event.data.assistantMessageID) if (!currentAssistant) return @@ -360,7 +359,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ currentAssistant.error = event.data.error }) break - case "text.started": + case "session.text.started": message.update(event.data.sessionID, (draft, index) => { message.assistant(draft, index, event.data.assistantMessageID)?.content.push({ type: "text", @@ -369,7 +368,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ }) }) break - case "text.delta": + case "session.text.delta": message.update(event.data.sessionID, (draft, index) => { const match = message.latestText( message.assistant(draft, index, event.data.assistantMessageID), @@ -378,7 +377,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ if (match) match.text += event.data.delta }) break - case "text.ended": + case "session.text.ended": message.update(event.data.sessionID, (draft, index) => { const match = message.latestText( message.assistant(draft, index, event.data.assistantMessageID), @@ -387,7 +386,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ if (match) match.text = event.data.text }) break - case "tool.input.started": + case "session.tool.input.started": message.update(event.data.sessionID, (draft, index) => { message.assistant(draft, index, event.data.assistantMessageID)?.content.push({ type: "tool", @@ -398,7 +397,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ }) }) break - case "tool.input.delta": + case "session.tool.input.delta": message.update(event.data.sessionID, (draft, index) => { const match = message.latestTool( message.assistant(draft, index, event.data.assistantMessageID), @@ -407,7 +406,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ if (match?.state.status === "pending") match.state.input += event.data.delta }) break - case "tool.input.ended": + case "session.tool.input.ended": message.update(event.data.sessionID, (draft, index) => { const match = message.latestTool( message.assistant(draft, index, event.data.assistantMessageID), @@ -416,7 +415,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ if (match?.state.status === "pending") match.state.input = event.data.text }) break - case "tool.called": + case "session.tool.called": message.update(event.data.sessionID, (draft, index) => { const match = message.latestTool( message.assistant(draft, index, event.data.assistantMessageID), @@ -428,7 +427,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ match.state = { status: "running", input: event.data.input, structured: {}, content: [] } }) break - case "tool.progress": + case "session.tool.progress": message.update(event.data.sessionID, (draft, index) => { const match = message.latestTool( message.assistant(draft, index, event.data.assistantMessageID), @@ -439,7 +438,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ match.state.content = [...event.data.content] }) break - case "tool.success": + case "session.tool.success": message.update(event.data.sessionID, (draft, index) => { const match = message.latestTool( message.assistant(draft, index, event.data.assistantMessageID), @@ -461,7 +460,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ match.time.completed = event.created }) break - case "tool.failed": + case "session.tool.failed": message.update(event.data.sessionID, (draft, index) => { const match = message.latestTool( message.assistant(draft, index, event.data.assistantMessageID), @@ -484,7 +483,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ match.time.completed = event.created }) break - case "reasoning.started": + case "session.reasoning.started": message.update(event.data.sessionID, (draft, index) => { message.assistant(draft, index, event.data.assistantMessageID)?.content.push({ type: "reasoning", @@ -495,7 +494,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ }) }) break - case "reasoning.delta": + case "session.reasoning.delta": message.update(event.data.sessionID, (draft, index) => { const match = message.latestReasoning( message.assistant(draft, index, event.data.assistantMessageID), @@ -504,7 +503,7 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ if (match) match.text += event.data.delta }) break - case "reasoning.ended": + case "session.reasoning.ended": message.update(event.data.sessionID, (draft, index) => { const match = message.latestReasoning( message.assistant(draft, index, event.data.assistantMessageID), @@ -517,25 +516,25 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ } }) break - case "retried": - case "compaction.started": + case "session.retried": + case "session.compaction.started": setStore("session", "status", event.data.sessionID, "running") break - case "execution.settled": + case "session.execution.settled": setStore("session", "status", event.data.sessionID, "idle") break - case "revert.staged": + case "session.revert.staged": if (store.session.info[event.data.sessionID]) setStore("session", "info", event.data.sessionID, "revert", event.data.revert) break - case "revert.cleared": - case "revert.committed": + case "session.revert.cleared": + case "session.revert.committed": if (store.session.info[event.data.sessionID]) setStore("session", "info", event.data.sessionID, "revert", undefined) break - case "compaction.delta": + case "session.compaction.delta": break - case "compaction.ended": + case "session.compaction.ended": message.update(event.data.sessionID, (draft, index) => { message.append(draft, index, { id: messageIDFromEvent(event.id), diff --git a/packages/tui/src/feature-plugins/system/notifications.ts b/packages/tui/src/feature-plugins/system/notifications.ts index aa8dcace19..416ba8c466 100644 --- a/packages/tui/src/feature-plugins/system/notifications.ts +++ b/packages/tui/src/feature-plugins/system/notifications.ts @@ -74,17 +74,17 @@ const tui: TuiPlugin = async (api) => { notify(api, sessionID, "Session done", session?.parentID ? "subagent_done" : "done") } - api.event.on("prompt.promoted", (event) => started(event.data.sessionID)) - api.event.on("shell.started", (event) => started(event.data.sessionID)) - api.event.on("step.started", (event) => started(event.data.sessionID)) - api.event.on("retried", (event) => started(event.data.sessionID)) - api.event.on("compaction.started", (event) => started(event.data.sessionID)) - api.event.on("shell.ended", (event) => ended(event.data.sessionID)) - api.event.on("step.ended", (event) => { + api.event.on("session.prompt.promoted", (event) => started(event.data.sessionID)) + api.event.on("session.shell.started", (event) => started(event.data.sessionID)) + api.event.on("session.step.started", (event) => started(event.data.sessionID)) + api.event.on("session.retried", (event) => started(event.data.sessionID)) + api.event.on("session.compaction.started", (event) => started(event.data.sessionID)) + api.event.on("session.shell.ended", (event) => ended(event.data.sessionID)) + api.event.on("session.step.ended", (event) => { if (event.data.finish === "tool-calls") return ended(event.data.sessionID) }) - api.event.on("step.failed", (event) => { + api.event.on("session.step.failed", (event) => { const sessionID = event.data.sessionID if (!active.has(sessionID)) return errored.add(sessionID) diff --git a/packages/tui/src/routes/session/index.tsx b/packages/tui/src/routes/session/index.tsx index b0f337c2d4..b968f13cd3 100644 --- a/packages/tui/src/routes/session/index.tsx +++ b/packages/tui/src/routes/session/index.tsx @@ -1346,7 +1346,7 @@ function RevertMessage(props: { function ShellMessage(props: { message: Extract }) { const { theme } = useTheme() - const output = createMemo(() => stripAnsi(props.message.output.trim())) + const output = createMemo(() => stripAnsi(props.message.output?.output.trim() ?? "")) return ( - $ {props.message.command} + $ {props.message.shell.command} {output()} @@ -1408,13 +1408,7 @@ function UserMessage(props: { message: SessionMessageUser }) { > {props.message.text} - + {(file) => { const directory = file.mime === "application/x-directory" @@ -1744,7 +1738,8 @@ function ToolPart(props: { part: SessionMessageAssistantTool }) { return Boolean(shellID && data.shell.get(shellID)) } if (display() === "subagent") { - const sessionID = stringValue(props.part.state.structured.sessionID) ?? stringValue(props.part.state.structured.sessionId) + const sessionID = + stringValue(props.part.state.structured.sessionID) ?? stringValue(props.part.state.structured.sessionId) return Boolean(sessionID && data.session.status(sessionID) === "running") } return false @@ -2660,7 +2655,8 @@ function formatSessionTranscript( ) { const body = messages.flatMap((message) => { if (message.type === "user") return [`## User\n\n${message.text}`] - if (message.type === "shell") return [`## Shell\n\n\`\`\`\n$ ${message.command}\n${message.output}\n\`\`\``] + if (message.type === "shell") + return [`## Shell\n\n\`\`\`\n$ ${message.shell.command}\n${message.output?.output ?? ""}\n\`\`\``] if (message.type !== "assistant") return [] const content = message.content.flatMap((item) => { if (item.type === "text") return [item.text] diff --git a/packages/tui/src/routes/session/rows.ts b/packages/tui/src/routes/session/rows.ts index 23b43c3b17..783b2805f4 100644 --- a/packages/tui/src/routes/session/rows.ts +++ b/packages/tui/src/routes/session/rows.ts @@ -133,42 +133,42 @@ export function createSessionRows(sessionID: Accessor) { if (event.data.sessionID === sessionID()) appendMessage(event.data.inputID) } const subscriptions = [ - data.on("prompt.admitted", input), - data.on("prompt.promoted", input), + data.on("session.prompt.admitted", input), + data.on("session.prompt.promoted", input), data.on("session.context.updated", message), - data.on("synthetic", (event) => { + data.on("session.synthetic", (event) => { if (event.data.sessionID === sessionID() && event.data.description?.trim()) appendMessage(event.id.replace(/^evt_/, "msg_")) }), - data.on("shell.started", message), - data.on("agent.selected", message), - data.on("model.selected", message), - data.on("compaction.ended", message), - data.on("text.delta", (event) => { + data.on("session.shell.started", message), + data.on("session.agent.selected", message), + data.on("session.model.selected", message), + data.on("session.compaction.ended", message), + data.on("session.text.delta", (event) => { if (event.data.sessionID === sessionID()) appendPart({ messageID: event.data.assistantMessageID, partID: event.data.textID }) }), - data.on("text.ended", (event) => { + data.on("session.text.ended", (event) => { if (event.data.sessionID === sessionID() && event.data.text.trim()) appendPart({ messageID: event.data.assistantMessageID, partID: event.data.textID }) }), - data.on("reasoning.delta", (event) => { + data.on("session.reasoning.delta", (event) => { if (event.data.sessionID === sessionID()) appendPart({ messageID: event.data.assistantMessageID, partID: event.data.reasoningID }) }), - data.on("reasoning.ended", (event) => { + data.on("session.reasoning.ended", (event) => { if (event.data.sessionID === sessionID() && event.data.text.trim()) appendPart({ messageID: event.data.assistantMessageID, partID: event.data.reasoningID }) }), - data.on("tool.input.started", (event) => { + data.on("session.tool.input.started", (event) => { if (event.data.sessionID === sessionID()) appendPart({ messageID: event.data.assistantMessageID, partID: event.data.callID }, event.data.name) }), - data.on("step.ended", (event) => { + data.on("session.step.ended", (event) => { if (event.data.sessionID !== sessionID() || ["tool-calls", "unknown"].includes(event.data.finish)) return appendFooter(event.data.assistantMessageID) }), - data.on("step.failed", (event) => { + data.on("session.step.failed", (event) => { if (event.data.sessionID === sessionID()) appendFooter(event.data.assistantMessageID) }), ] diff --git a/packages/tui/test/cli/cmd/tui/notifications.test.ts b/packages/tui/test/cli/cmd/tui/notifications.test.ts index 5f1c6355b3..44cd98b133 100644 --- a/packages/tui/test/cli/cmd/tui/notifications.test.ts +++ b/packages/tui/test/cli/cmd/tui/notifications.test.ts @@ -91,7 +91,7 @@ function stepStarted(id: string, sessionID = "session"): V2Event { return { id, created: 0, - type: "step.started", + type: "session.step.started", durable: durable(sessionID), data: { sessionID, @@ -106,7 +106,7 @@ function stepEnded(id: string, sessionID = "session", finish = "stop"): V2Event return { id, created: 0, - type: "step.ended", + type: "session.step.ended", durable: durable(sessionID), data: { sessionID, @@ -122,7 +122,7 @@ function stepFailed(id: string, sessionID = "session"): V2Event { return { id, created: 0, - type: "step.failed", + type: "session.step.failed", durable: durable(sessionID), data: { sessionID, diff --git a/packages/tui/test/cli/tui/data.test.tsx b/packages/tui/test/cli/tui/data.test.tsx index a71bdc47d8..0587662dc3 100644 --- a/packages/tui/test/cli/tui/data.test.tsx +++ b/packages/tui/test/cli/tui/data.test.tsx @@ -269,7 +269,7 @@ test("tracks session status from active sessions and execution events", async () emitEvent(events, { id: "evt_step_started", created: 0, - type: "step.started", + type: "session.step.started", durable: durable("session-live"), data: { sessionID: "session-live", @@ -283,7 +283,7 @@ test("tracks session status from active sessions and execution events", async () emitEvent(events, { id: "evt_step_ended", created: 0, - type: "step.ended", + type: "session.step.ended", durable: durable("session-live", 1, 2), data: { sessionID: "session-live", @@ -302,7 +302,7 @@ test("tracks session status from active sessions and execution events", async () emitEvent(events, { id: "evt_execution_settled", created: 0, - type: "execution.settled", + type: "session.execution.settled", data: { sessionID: "session-live", outcome: "success", @@ -313,7 +313,7 @@ test("tracks session status from active sessions and execution events", async () emitEvent(events, { id: "evt_failed_step_started", created: 0, - type: "step.started", + type: "session.step.started", durable: durable("session-failed"), data: { sessionID: "session-failed", @@ -327,7 +327,7 @@ test("tracks session status from active sessions and execution events", async () emitEvent(events, { id: "evt_step_failed", created: 0, - type: "step.failed", + type: "session.step.failed", durable: durable("session-failed", 1, 2), data: { sessionID: "session-failed", @@ -344,7 +344,7 @@ test("tracks session status from active sessions and execution events", async () emitEvent(events, { id: "evt_failed_execution_settled", created: 0, - type: "execution.settled", + type: "session.execution.settled", data: { sessionID: "session-failed", outcome: "failure", @@ -797,14 +797,14 @@ test("settles pending tools when a live failure arrives", async () => { emitEvent(events, { id: "evt_agent_1", created: 0, - type: "agent.selected", + type: "session.agent.selected", durable: durable("session-1"), data: { sessionID: "session-1", agent: "build" }, }) emitEvent(events, { id: "evt_model_1", created: 0, - type: "model.selected", + type: "session.model.selected", durable: durable("session-1", 1), data: { sessionID: "session-1", @@ -814,7 +814,7 @@ test("settles pending tools when a live failure arrives", async () => { emitEvent(events, { id: "evt_step_started_1", created: 0, - type: "step.started", + type: "session.step.started", durable: durable("session-1", 2), data: { sessionID: "session-1", @@ -826,7 +826,7 @@ test("settles pending tools when a live failure arrives", async () => { emitEvent(events, { id: "evt_input_1", created: 0, - type: "tool.input.started", + type: "session.tool.input.started", durable: durable("session-1", 3), data: { sessionID: "session-1", @@ -838,7 +838,7 @@ test("settles pending tools when a live failure arrives", async () => { emitEvent(events, { id: "evt_called_1", created: 0, - type: "tool.called", + type: "session.tool.called", durable: durable("session-1", 4), data: { sessionID: "session-1", @@ -852,7 +852,7 @@ test("settles pending tools when a live failure arrives", async () => { emitEvent(events, { id: "evt_failed_1", created: 0, - type: "tool.failed", + type: "session.tool.failed", durable: durable("session-1", 5), data: { sessionID: "session-1", @@ -942,7 +942,7 @@ test("renders admitted prompts immediately with queued marker and clears when pr emitEvent(events, { id: "evt_admitted_1", created: 0, - type: "prompt.admitted", + type: "session.prompt.admitted", durable: durable(sessionID), data: { sessionID, @@ -961,7 +961,7 @@ test("renders admitted prompts immediately with queued marker and clears when pr emitEvent(events, { id: "evt_prompted_1", created: 0, - type: "prompt.promoted", + type: "session.prompt.promoted", durable: durable(sessionID, 1), data: { sessionID, @@ -969,8 +969,8 @@ test("renders admitted prompts immediately with queued marker and clears when pr }, }) - await wait(() => received.at(-1) === "prompt.promoted") - expect(received.slice(-2)).toEqual(["prompt.admitted", "prompt.promoted"]) + await wait(() => received.at(-1) === "session.prompt.promoted") + expect(received.slice(-2)).toEqual(["session.prompt.admitted", "session.prompt.promoted"]) unsubscribe() const message = sync.session.message.list(sessionID)?.[0] expect(message?.type).toBe("user") diff --git a/packages/ui/src/components/provider-icon.tsx b/packages/ui/src/components/provider-icon.tsx index 7c0eb3d047..46fb7fb6f2 100644 --- a/packages/ui/src/components/provider-icon.tsx +++ b/packages/ui/src/components/provider-icon.tsx @@ -9,7 +9,7 @@ export type ProviderIconProps = JSX.SVGElementTags["svg"] & { export const ProviderIcon: Component = (props) => { const [local, rest] = splitProps(props, ["id", "class", "classList"]) - const resolved = createMemo(() => (iconNames.includes(local.id as IconName) ? local.id : "synthetic")) + const resolved = createMemo(() => (iconNames.includes(local.id as IconName) ? local.id : "session.synthetic")) return (