fix(opencode): restore global sync event compatibility

This commit is contained in:
Dax Raad 2026-06-03 19:52:49 -04:00
commit 5e3026b5ce
9 changed files with 766 additions and 303 deletions

View file

@ -30,6 +30,7 @@ export type Payload<D extends Definition = Definition> = {
readonly type: D["type"] readonly type: D["type"]
readonly data: Data<D> readonly data: Data<D>
readonly version?: number readonly version?: number
readonly sync?: SyncMetadata
readonly location?: Location.Info readonly location?: Location.Info
readonly metadata?: Record<string, unknown> readonly metadata?: Record<string, unknown>
} }
@ -48,6 +49,11 @@ export type SerializedEvent = {
readonly data: Record<string, unknown> readonly data: Record<string, unknown>
} }
export type SyncMetadata = {
readonly seq: number
readonly aggregateID: string
}
export class InvalidSyncEventError extends Schema.TaggedErrorClass<InvalidSyncEventError>()( export class InvalidSyncEventError extends Schema.TaggedErrorClass<InvalidSyncEventError>()(
"EventV2.InvalidSyncEvent", "EventV2.InvalidSyncEvent",
{ {
@ -77,6 +83,12 @@ export function define<const Type extends string, Fields extends Schema.Struct.F
metadata: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)), metadata: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)),
type: Schema.Literal(input.type), type: Schema.Literal(input.type),
version: Schema.optional(Schema.Number), version: Schema.optional(Schema.Number),
sync: Schema.optional(
Schema.Struct({
seq: Schema.Finite,
aggregateID: Schema.String,
}),
),
location: Schema.optional(Location.Info), location: Schema.optional(Location.Info),
data: Data, data: Data,
}).annotate({ identifier: input.type }) }).annotate({ identifier: input.type })
@ -186,7 +198,7 @@ export const layer = Layer.effect(
) )
} else { } else {
const list = projectors.get(event.type) ?? [] const list = projectors.get(event.type) ?? []
yield* db return yield* db
.transaction( .transaction(
() => () =>
Effect.gen(function* () { Effect.gen(function* () {
@ -208,8 +220,12 @@ export const layer = Layer.effect(
}), }),
) )
} }
const serialized = {
seq,
aggregateID,
}
for (const projector of list) { for (const projector of list) {
yield* projector(event as Payload) yield* projector({ ...event, sync: serialized })
} }
yield* db yield* db
.insert(EventSequenceTable) .insert(EventSequenceTable)
@ -233,6 +249,7 @@ export const layer = Layer.effect(
]) ])
.run() .run()
.pipe(Effect.orDie) .pipe(Effect.orDie)
return serialized
}), }),
{ behavior: "immediate" }, { behavior: "immediate" },
) )
@ -247,14 +264,15 @@ export const layer = Layer.effect(
for (const sync of syncHandlers) { for (const sync of syncHandlers) {
yield* sync(event as Payload) yield* sync(event as Payload)
} }
yield* commitSyncEvent(event as Payload) const sync = yield* commitSyncEvent(event as Payload)
const payload = sync ? { ...event, sync } : event
for (const listener of listeners) { for (const listener of listeners) {
yield* listener(event as Payload) yield* listener(payload as Payload)
} }
const pubsub = typed.get(event.type) const pubsub = typed.get(event.type)
if (pubsub) yield* PubSub.publish(pubsub, event as Payload) if (pubsub) yield* PubSub.publish(pubsub, payload as Payload)
yield* PubSub.publish(all, event as Payload) yield* PubSub.publish(all, payload as Payload)
return event return payload
}) })
} }

View file

@ -109,6 +109,19 @@ describe("EventV2", () => {
}), }),
) )
it.effect("publishes sync metadata", () =>
Effect.gen(function* () {
const events = yield* EventV2.Service
const aggregateID = EventV2.ID.create()
const event = yield* events.publish(SyncMessage, { id: aggregateID, text: "hello" })
expect(event.sync).toEqual({
seq: 0,
aggregateID,
})
}),
)
it.effect("stores definitions in the exported registry", () => it.effect("stores definitions in the exported registry", () =>
Effect.sync(() => { Effect.sync(() => {
expect(EventV2.registry.get(Message.type)).toBe(Message) expect(EventV2.registry.get(Message.type)).toBe(Message)

View file

@ -291,7 +291,7 @@ export const { use: useSyncV2, provider: SyncProviderV2 } = createSimpleContext(
message: { message: {
async sync(sessionID: string) { async sync(sessionID: string) {
const response = await sdk.client.v2.session.messages({ sessionID }) const response = await sdk.client.v2.session.messages({ sessionID })
setStore("messages", sessionID, reconcile(response.data?.items ?? [])) setStore("messages", sessionID, reconcile(response.data?.data.items ?? []))
}, },
fromSession(sessionID: string) { fromSession(sessionID: string) {
const messages = store.messages[sessionID] const messages = store.messages[sessionID]

View file

@ -44,6 +44,21 @@ export const layer = Layer.effect(
workspace: workspaceID, workspace: workspaceID,
payload: { id: event.id, type: event.type, properties: event.data }, payload: { id: event.id, type: event.type, properties: event.data },
}) })
if (!event.sync || event.version === undefined) return
GlobalBus.emit("event", {
directory: event.location?.directory ?? ctx?.directory,
project: ctx?.project.id,
workspace: workspaceID,
payload: {
type: "sync",
syncEvent: {
id: event.id,
type: EventV2.versionedType(event.type, event.version),
...event.sync,
data: event.data,
},
},
})
}), }),
) )
yield* Effect.addFinalizer(() => unsubscribe) yield* Effect.addFinalizer(() => unsubscribe)

View file

@ -20,11 +20,14 @@ const SyncEventSchemas = EventV2.registry
return [ return [
Schema.Struct({ Schema.Struct({
type: Schema.Literal("sync"), type: Schema.Literal("sync"),
name: Schema.Literal(EventV2.versionedType(definition.type, definition.sync.version)), id: Schema.String,
syncEvent: Schema.Struct({
type: Schema.Literal(EventV2.versionedType(definition.type, definition.sync.version)),
id: Schema.String, id: Schema.String,
seq: Schema.Finite, seq: Schema.Finite,
aggregateID: Schema.Literal(definition.sync.aggregate), aggregateID: Schema.String,
data: definition.data, data: definition.data,
}),
}).annotate({ identifier: `SyncEvent.${definition.type}` }), }).annotate({ identifier: `SyncEvent.${definition.type}` }),
] ]
}) })

View file

@ -3,7 +3,13 @@ import { OpenApi } from "effect/unstable/httpapi"
import { PublicApi } from "../../src/server/routes/instance/httpapi/public" import { PublicApi } from "../../src/server/routes/instance/httpapi/public"
type Method = "get" | "post" | "put" | "delete" | "patch" type Method = "get" | "post" | "put" | "delete" | "patch"
type OpenApiSchema = { readonly $ref?: string } type OpenApiSchema = {
readonly $ref?: string
readonly type?: string
readonly enum?: readonly unknown[]
readonly properties?: Record<string, OpenApiSchema>
readonly required?: readonly string[]
}
type OpenApiResponse = { type OpenApiResponse = {
readonly description?: string readonly description?: string
readonly content?: Record<string, { readonly schema?: OpenApiSchema }> readonly content?: Record<string, { readonly schema?: OpenApiSchema }>
@ -19,7 +25,10 @@ type OpenApiOperation = {
readonly security?: unknown readonly security?: unknown
} }
type OpenApiPathItem = Partial<Record<Method, OpenApiOperation>> type OpenApiPathItem = Partial<Record<Method, OpenApiOperation>>
type OpenApiSpec = { readonly paths: Record<string, OpenApiPathItem> } type OpenApiSpec = {
readonly paths: Record<string, OpenApiPathItem>
readonly components: { readonly schemas: Record<string, OpenApiSchema> }
}
const methods = ["get", "post", "put", "delete", "patch"] as const const methods = ["get", "post", "put", "delete", "patch"] as const
@ -49,6 +58,23 @@ function isBuiltInEndpointError(name: string) {
} }
describe("PublicApi OpenAPI v2 errors", () => { describe("PublicApi OpenAPI v2 errors", () => {
test("documents nested legacy global sync events", () => {
const spec = OpenApi.fromApi(PublicApi) as OpenApiSpec
const schema = spec.components.schemas.SyncEventSessionCreated
expect(schema?.required).toEqual(["type", "id", "syncEvent"])
expect(schema?.properties?.type?.enum).toEqual(["sync"])
expect(schema?.properties?.syncEvent).toMatchObject({
required: ["type", "id", "seq", "aggregateID", "data"],
properties: {
type: { enum: ["session.created.1"] },
id: { type: "string" },
seq: { type: "number" },
aggregateID: { type: "string" },
},
})
})
test("preserves /api auth responses", () => { test("preserves /api auth responses", () => {
const spec = OpenApi.fromApi(PublicApi) as OpenApiSpec const spec = OpenApi.fromApi(PublicApi) as OpenApiSpec

View file

@ -1,6 +1,7 @@
import { describe, expect } from "bun:test" import { describe, expect } from "bun:test"
import { SessionV1 } from "@opencode-ai/core/v1/session" import { SessionV1 } from "@opencode-ai/core/v1/session"
import { Database } from "@opencode-ai/core/database/database" import { Database } from "@opencode-ai/core/database/database"
import { EventV2 } from "@opencode-ai/core/event"
import { SessionProjector } from "@opencode-ai/core/session/projector" import { SessionProjector } from "@opencode-ai/core/session/projector"
import { Deferred, Effect, Exit, Layer } from "effect" import { Deferred, Effect, Exit, Layer } from "effect"
import { Session as SessionNs } from "@/session/session" import { Session as SessionNs } from "@/session/session"
@ -14,6 +15,7 @@ import { Storage } from "@/storage/storage"
import { RuntimeFlags } from "@/effect/runtime-flags" import { RuntimeFlags } from "@/effect/runtime-flags"
import { BackgroundJob } from "@/background/job" import { BackgroundJob } from "@/background/job"
import { EventV2Bridge } from "@/event-v2-bridge" import { EventV2Bridge } from "@/event-v2-bridge"
import { GlobalBus } from "@/bus/global"
void Log.init({ print: false }) void Log.init({ print: false })
@ -101,6 +103,31 @@ describe("session.created event", () => {
yield* session.remove(info.id) yield* session.remove(info.id)
}), }),
) )
it.instance("emits legacy global sync payload", () =>
Effect.gen(function* () {
const session = yield* SessionNs.Service
const received = yield* Deferred.make<{ syncEvent: EventV2.SerializedEvent }>()
const listener = (event: { payload: { type?: string; syncEvent?: EventV2.SerializedEvent } }) => {
if (event.payload.type === "sync" && event.payload.syncEvent)
Deferred.doneUnsafe(received, Effect.succeed({ syncEvent: event.payload.syncEvent }))
}
GlobalBus.on("event", listener)
yield* Effect.addFinalizer(() => Effect.sync(() => GlobalBus.off("event", listener)))
const info = yield* session.create({})
const event = yield* awaitDeferred(received, "timed out waiting for legacy global sync event")
expect(event.syncEvent).toMatchObject({
type: EventV2.versionedType(SessionNs.Event.Created.type, 1),
seq: 0,
aggregateID: info.id,
data: { sessionID: info.id },
})
yield* session.remove(info.id)
}),
)
}) })
describe("step-finish token propagation via event", () => { describe("step-finish token propagation via event", () => {

View file

@ -255,6 +255,10 @@ import type {
TuiShowToastResponses, TuiShowToastResponses,
TuiSubmitPromptErrors, TuiSubmitPromptErrors,
TuiSubmitPromptResponses, TuiSubmitPromptResponses,
V2CommandListErrors,
V2CommandListResponses,
V2EventSubscribeErrors,
V2EventSubscribeResponses,
V2FsListErrors, V2FsListErrors,
V2FsListResponses, V2FsListResponses,
V2FsReadErrors, V2FsReadErrors,
@ -287,6 +291,8 @@ import type {
V2SessionPromptResponses, V2SessionPromptResponses,
V2SessionWaitErrors, V2SessionWaitErrors,
V2SessionWaitResponses, V2SessionWaitResponses,
V2SkillListErrors,
V2SkillListResponses,
VcsApplyErrors, VcsApplyErrors,
VcsApplyResponses, VcsApplyResponses,
VcsDiffErrors, VcsDiffErrors,
@ -4990,6 +4996,78 @@ export class Fs extends HeyApiClient {
} }
} }
export class Command2 extends HeyApiClient {
/**
* List v2 commands
*
* Retrieve currently registered v2 commands.
*/
public list<ThrowOnError extends boolean = false>(
parameters?: {
location?: {
directory?: string
workspace?: string
}
},
options?: Options<never, ThrowOnError>,
) {
const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "location" }] }])
return (options?.client ?? this.client).get<V2CommandListResponses, V2CommandListErrors, ThrowOnError>({
url: "/api/command",
...options,
...params,
})
}
}
export class Skill extends HeyApiClient {
/**
* List v2 skills
*
* Retrieve currently registered v2 skills.
*/
public list<ThrowOnError extends boolean = false>(
parameters?: {
location?: {
directory?: string
workspace?: string
}
},
options?: Options<never, ThrowOnError>,
) {
const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "location" }] }])
return (options?.client ?? this.client).get<V2SkillListResponses, V2SkillListErrors, ThrowOnError>({
url: "/api/skill",
...options,
...params,
})
}
}
export class Event2 extends HeyApiClient {
/**
* Subscribe to v2 events
*
* Subscribe to native EventV2 payloads for a location.
*/
public subscribe<ThrowOnError extends boolean = false>(
parameters?: {
location?: {
directory?: string
workspace?: string
}
},
options?: Options<never, ThrowOnError>,
) {
const params = buildClientParams([parameters], [{ args: [{ in: "query", key: "location" }] }])
return (options?.client ?? this.client).sse.get<V2EventSubscribeResponses, V2EventSubscribeErrors, ThrowOnError>({
url: "/api/event",
...options,
...params,
})
}
}
export class V2 extends HeyApiClient { export class V2 extends HeyApiClient {
private _session?: Session3 private _session?: Session3
get session(): Session3 { get session(): Session3 {
@ -5015,6 +5093,21 @@ export class V2 extends HeyApiClient {
get fs(): Fs { get fs(): Fs {
return (this._fs ??= new Fs({ client: this.client })) return (this._fs ??= new Fs({ client: this.client }))
} }
private _command?: Command2
get command(): Command2 {
return (this._command ??= new Command2({ client: this.client }))
}
private _skill?: Skill
get skill(): Skill {
return (this._skill ??= new Skill({ client: this.client }))
}
private _event?: Event2
get event(): Event2 {
return (this._event ??= new Event2({ client: this.client }))
}
} }
export class Control extends HeyApiClient { export class Control extends HeyApiClient {

View file

@ -1789,6 +1789,7 @@ export type Config = {
description?: string description?: string
agent?: string agent?: string
model?: string model?: string
variant?: string
subtask?: boolean subtask?: boolean
} }
} }
@ -2856,109 +2857,135 @@ export type EventServerInstanceDisposed = {
export type SyncEventSessionCreated = { export type SyncEventSessionCreated = {
type: "sync" type: "sync"
name: "session.created.1" id: string
syncEvent: {
type: "session.created.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
sessionID: string sessionID: string
info: Session info: Session
} }
} }
}
export type SyncEventSessionUpdated = { export type SyncEventSessionUpdated = {
type: "sync" type: "sync"
name: "session.updated.1" id: string
syncEvent: {
type: "session.updated.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
sessionID: string sessionID: string
info: Session info: Session
} }
} }
}
export type SyncEventSessionDeleted = { export type SyncEventSessionDeleted = {
type: "sync" type: "sync"
name: "session.deleted.1" id: string
syncEvent: {
type: "session.deleted.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
sessionID: string sessionID: string
info: Session info: Session
} }
} }
}
export type SyncEventMessageUpdated = { export type SyncEventMessageUpdated = {
type: "sync" type: "sync"
name: "message.updated.1" id: string
syncEvent: {
type: "message.updated.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
sessionID: string sessionID: string
info: Message info: Message
} }
} }
}
export type SyncEventMessageRemoved = { export type SyncEventMessageRemoved = {
type: "sync" type: "sync"
name: "message.removed.1" id: string
syncEvent: {
type: "message.removed.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
sessionID: string sessionID: string
messageID: string messageID: string
} }
} }
}
export type SyncEventMessagePartUpdated = { export type SyncEventMessagePartUpdated = {
type: "sync" type: "sync"
name: "message.part.updated.1" id: string
syncEvent: {
type: "message.part.updated.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
sessionID: string sessionID: string
part: Part part: Part
time: number time: number
} }
} }
}
export type SyncEventMessagePartRemoved = { export type SyncEventMessagePartRemoved = {
type: "sync" type: "sync"
name: "message.part.removed.1" id: string
syncEvent: {
type: "message.part.removed.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
sessionID: string sessionID: string
messageID: string messageID: string
partID: string partID: string
} }
} }
}
export type SyncEventSessionNextAgentSwitched = { export type SyncEventSessionNextAgentSwitched = {
type: "sync" type: "sync"
name: "session.next.agent.switched.1" id: string
syncEvent: {
type: "session.next.agent.switched.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
agent: string agent: string
} }
} }
}
export type SyncEventSessionNextModelSwitched = { export type SyncEventSessionNextModelSwitched = {
type: "sync" type: "sync"
name: "session.next.model.switched.1" id: string
syncEvent: {
type: "session.next.model.switched.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
@ -2969,39 +2996,48 @@ export type SyncEventSessionNextModelSwitched = {
} }
} }
} }
}
export type SyncEventSessionNextPrompted = { export type SyncEventSessionNextPrompted = {
type: "sync" type: "sync"
name: "session.next.prompted.1" id: string
syncEvent: {
type: "session.next.prompted.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
prompt: Prompt prompt: Prompt
} }
} }
}
export type SyncEventSessionNextSynthetic = { export type SyncEventSessionNextSynthetic = {
type: "sync" type: "sync"
name: "session.next.synthetic.1" id: string
syncEvent: {
type: "session.next.synthetic.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
text: string text: string
} }
} }
}
export type SyncEventSessionNextShellStarted = { export type SyncEventSessionNextShellStarted = {
type: "sync" type: "sync"
name: "session.next.shell.started.1" id: string
syncEvent: {
type: "session.next.shell.started.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
@ -3009,13 +3045,16 @@ export type SyncEventSessionNextShellStarted = {
command: string command: string
} }
} }
}
export type SyncEventSessionNextShellEnded = { export type SyncEventSessionNextShellEnded = {
type: "sync" type: "sync"
name: "session.next.shell.ended.1" id: string
syncEvent: {
type: "session.next.shell.ended.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
@ -3023,13 +3062,16 @@ export type SyncEventSessionNextShellEnded = {
output: string output: string
} }
} }
}
export type SyncEventSessionNextStepStarted = { export type SyncEventSessionNextStepStarted = {
type: "sync" type: "sync"
name: "session.next.step.started.1" id: string
syncEvent: {
type: "session.next.step.started.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
@ -3042,13 +3084,16 @@ export type SyncEventSessionNextStepStarted = {
snapshot?: string snapshot?: string
} }
} }
}
export type SyncEventSessionNextStepEnded = { export type SyncEventSessionNextStepEnded = {
type: "sync" type: "sync"
name: "session.next.step.ended.1" id: string
syncEvent: {
type: "session.next.step.ended.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
@ -3066,77 +3111,95 @@ export type SyncEventSessionNextStepEnded = {
snapshot?: string snapshot?: string
} }
} }
}
export type SyncEventSessionNextStepFailed = { export type SyncEventSessionNextStepFailed = {
type: "sync" type: "sync"
name: "session.next.step.failed.1" id: string
syncEvent: {
type: "session.next.step.failed.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
error: SessionErrorUnknown error: SessionErrorUnknown
} }
} }
}
export type SyncEventSessionNextTextStarted = { export type SyncEventSessionNextTextStarted = {
type: "sync" type: "sync"
name: "session.next.text.started.1" id: string
syncEvent: {
type: "session.next.text.started.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
} }
} }
}
export type SyncEventSessionNextTextDelta = { export type SyncEventSessionNextTextDelta = {
type: "sync" type: "sync"
name: "session.next.text.delta.1" id: string
syncEvent: {
type: "session.next.text.delta.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
delta: string delta: string
} }
} }
}
export type SyncEventSessionNextTextEnded = { export type SyncEventSessionNextTextEnded = {
type: "sync" type: "sync"
name: "session.next.text.ended.1" id: string
syncEvent: {
type: "session.next.text.ended.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
text: string text: string
} }
} }
}
export type SyncEventSessionNextReasoningStarted = { export type SyncEventSessionNextReasoningStarted = {
type: "sync" type: "sync"
name: "session.next.reasoning.started.1" id: string
syncEvent: {
type: "session.next.reasoning.started.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
reasoningID: string reasoningID: string
} }
} }
}
export type SyncEventSessionNextReasoningDelta = { export type SyncEventSessionNextReasoningDelta = {
type: "sync" type: "sync"
name: "session.next.reasoning.delta.1" id: string
syncEvent: {
type: "session.next.reasoning.delta.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
@ -3144,13 +3207,16 @@ export type SyncEventSessionNextReasoningDelta = {
delta: string delta: string
} }
} }
}
export type SyncEventSessionNextReasoningEnded = { export type SyncEventSessionNextReasoningEnded = {
type: "sync" type: "sync"
name: "session.next.reasoning.ended.1" id: string
syncEvent: {
type: "session.next.reasoning.ended.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
@ -3158,13 +3224,16 @@ export type SyncEventSessionNextReasoningEnded = {
text: string text: string
} }
} }
}
export type SyncEventSessionNextToolInputStarted = { export type SyncEventSessionNextToolInputStarted = {
type: "sync" type: "sync"
name: "session.next.tool.input.started.1" id: string
syncEvent: {
type: "session.next.tool.input.started.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
@ -3172,13 +3241,16 @@ export type SyncEventSessionNextToolInputStarted = {
name: string name: string
} }
} }
}
export type SyncEventSessionNextToolInputDelta = { export type SyncEventSessionNextToolInputDelta = {
type: "sync" type: "sync"
name: "session.next.tool.input.delta.1" id: string
syncEvent: {
type: "session.next.tool.input.delta.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
@ -3186,13 +3258,16 @@ export type SyncEventSessionNextToolInputDelta = {
delta: string delta: string
} }
} }
}
export type SyncEventSessionNextToolInputEnded = { export type SyncEventSessionNextToolInputEnded = {
type: "sync" type: "sync"
name: "session.next.tool.input.ended.1" id: string
syncEvent: {
type: "session.next.tool.input.ended.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
@ -3200,13 +3275,16 @@ export type SyncEventSessionNextToolInputEnded = {
text: string text: string
} }
} }
}
export type SyncEventSessionNextToolCalled = { export type SyncEventSessionNextToolCalled = {
type: "sync" type: "sync"
name: "session.next.tool.called.1" id: string
syncEvent: {
type: "session.next.tool.called.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
@ -3223,13 +3301,16 @@ export type SyncEventSessionNextToolCalled = {
} }
} }
} }
}
export type SyncEventSessionNextToolProgress = { export type SyncEventSessionNextToolProgress = {
type: "sync" type: "sync"
name: "session.next.tool.progress.1" id: string
syncEvent: {
type: "session.next.tool.progress.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
@ -3240,13 +3321,16 @@ export type SyncEventSessionNextToolProgress = {
content: Array<ToolTextContent | ToolFileContent> content: Array<ToolTextContent | ToolFileContent>
} }
} }
}
export type SyncEventSessionNextToolSuccess = { export type SyncEventSessionNextToolSuccess = {
type: "sync" type: "sync"
name: "session.next.tool.success.1" id: string
syncEvent: {
type: "session.next.tool.success.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
@ -3263,13 +3347,16 @@ export type SyncEventSessionNextToolSuccess = {
} }
} }
} }
}
export type SyncEventSessionNextToolFailed = { export type SyncEventSessionNextToolFailed = {
type: "sync" type: "sync"
name: "session.next.tool.failed.1" id: string
syncEvent: {
type: "session.next.tool.failed.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
@ -3283,13 +3370,16 @@ export type SyncEventSessionNextToolFailed = {
} }
} }
} }
}
export type SyncEventSessionNextRetried = { export type SyncEventSessionNextRetried = {
type: "sync" type: "sync"
name: "session.next.retried.1" id: string
syncEvent: {
type: "session.next.retried.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
@ -3297,39 +3387,48 @@ export type SyncEventSessionNextRetried = {
error: SessionNextRetryError error: SessionNextRetryError
} }
} }
}
export type SyncEventSessionNextCompactionStarted = { export type SyncEventSessionNextCompactionStarted = {
type: "sync" type: "sync"
name: "session.next.compaction.started.1" id: string
syncEvent: {
type: "session.next.compaction.started.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
reason: "auto" | "manual" reason: "auto" | "manual"
} }
} }
}
export type SyncEventSessionNextCompactionDelta = { export type SyncEventSessionNextCompactionDelta = {
type: "sync" type: "sync"
name: "session.next.compaction.delta.1" id: string
syncEvent: {
type: "session.next.compaction.delta.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
text: string text: string
} }
} }
}
export type SyncEventSessionNextCompactionEnded = { export type SyncEventSessionNextCompactionEnded = {
type: "sync" type: "sync"
name: "session.next.compaction.ended.1" id: string
syncEvent: {
type: "session.next.compaction.ended.1"
id: string id: string
seq: number seq: number
aggregateID: "sessionID" aggregateID: string
data: { data: {
timestamp: number timestamp: number
sessionID: string sessionID: string
@ -3337,6 +3436,7 @@ export type SyncEventSessionNextCompactionEnded = {
include?: string include?: string
} }
} }
}
export type PolicyEffect = "allow" | "deny" export type PolicyEffect = "allow" | "deny"
@ -3592,6 +3692,15 @@ export type SessionMessage =
| SessionMessageAssistant | SessionMessageAssistant
| SessionMessageCompaction | SessionMessageCompaction
export type LocationInfo = {
directory: string
workspaceID?: string
project: {
id: string
directory: string
}
}
export type ProviderV2Info = { export type ProviderV2Info = {
id: string id: string
name: string name: string
@ -3677,6 +3786,27 @@ export type LocationFileSystemEntry = {
mime: string mime: string
} }
export type CommandV2Info = {
name: string
template: string
description?: string
agent?: string
model?: {
id: string
providerID: string
variant?: string
}
subtask?: boolean
}
export type SkillV2Info = {
name: string
description?: string
slash?: boolean
location: string
content: string
}
export type EventModelsDevRefreshed = { export type EventModelsDevRefreshed = {
id: string id: string
type: "models-dev.refreshed" type: "models-dev.refreshed"
@ -8092,9 +8222,11 @@ export type V2SessionListError = V2SessionListErrors[keyof V2SessionListErrors]
export type V2SessionListResponses = { export type V2SessionListResponses = {
/** /**
* V2SessionsResponse * Success
*/ */
200: V2SessionsResponse 200: {
data: V2SessionsResponse
}
} }
export type V2SessionListResponse = V2SessionListResponses[keyof V2SessionListResponses] export type V2SessionListResponse = V2SessionListResponses[keyof V2SessionListResponses]
@ -8137,9 +8269,11 @@ export type V2SessionPromptError = V2SessionPromptErrors[keyof V2SessionPromptEr
export type V2SessionPromptResponses = { export type V2SessionPromptResponses = {
/** /**
* Session.Message * Success
*/ */
200: SessionMessage 200: {
data: SessionMessage
}
} }
export type V2SessionPromptResponse = V2SessionPromptResponses[keyof V2SessionPromptResponses] export type V2SessionPromptResponse = V2SessionPromptResponses[keyof V2SessionPromptResponses]
@ -8265,7 +8399,9 @@ export type V2SessionContextResponses = {
/** /**
* Success * Success
*/ */
200: Array<SessionMessage> 200: {
data: Array<SessionMessage>
}
} }
export type V2SessionContextResponse = V2SessionContextResponses[keyof V2SessionContextResponses] export type V2SessionContextResponse = V2SessionContextResponses[keyof V2SessionContextResponses]
@ -8311,9 +8447,11 @@ export type V2SessionMessagesError = V2SessionMessagesErrors[keyof V2SessionMess
export type V2SessionMessagesResponses = { export type V2SessionMessagesResponses = {
/** /**
* V2SessionMessagesResponse * Success
*/ */
200: V2SessionMessagesResponse 200: {
data: V2SessionMessagesResponse
}
} }
export type V2SessionMessagesResponse2 = V2SessionMessagesResponses[keyof V2SessionMessagesResponses] export type V2SessionMessagesResponse2 = V2SessionMessagesResponses[keyof V2SessionMessagesResponses]
@ -8351,7 +8489,10 @@ export type V2ModelListResponses = {
/** /**
* Success * Success
*/ */
200: Array<ModelV2Info> 200: {
location: LocationInfo
data: Array<ModelV2Info>
}
} }
export type V2ModelListResponse = V2ModelListResponses[keyof V2ModelListResponses] export type V2ModelListResponse = V2ModelListResponses[keyof V2ModelListResponses]
@ -8389,7 +8530,10 @@ export type V2ProviderListResponses = {
/** /**
* Success * Success
*/ */
200: Array<ProviderV2Info> 200: {
location: LocationInfo
data: Array<ProviderV2Info>
}
} }
export type V2ProviderListResponse = V2ProviderListResponses[keyof V2ProviderListResponses] export type V2ProviderListResponse = V2ProviderListResponses[keyof V2ProviderListResponses]
@ -8431,9 +8575,12 @@ export type V2ProviderGetError = V2ProviderGetErrors[keyof V2ProviderGetErrors]
export type V2ProviderGetResponses = { export type V2ProviderGetResponses = {
/** /**
* ProviderV2.Info * Success
*/ */
200: ProviderV2Info 200: {
location: LocationInfo
data: ProviderV2Info
}
} }
export type V2ProviderGetResponse = V2ProviderGetResponses[keyof V2ProviderGetResponses] export type V2ProviderGetResponse = V2ProviderGetResponses[keyof V2ProviderGetResponses]
@ -8467,7 +8614,10 @@ export type V2PermissionRequestListResponses = {
/** /**
* Success * Success
*/ */
200: Array<PermissionV2Request> 200: {
location: LocationInfo
data: Array<PermissionV2Request>
}
} }
export type V2PermissionRequestListResponse = V2PermissionRequestListResponses[keyof V2PermissionRequestListResponses] export type V2PermissionRequestListResponse = V2PermissionRequestListResponses[keyof V2PermissionRequestListResponses]
@ -8502,7 +8652,9 @@ export type V2SessionPermissionListResponses = {
/** /**
* Success * Success
*/ */
200: Array<PermissionV2Request> 200: {
data: Array<PermissionV2Request>
}
} }
export type V2SessionPermissionListResponse = V2SessionPermissionListResponses[keyof V2SessionPermissionListResponses] export type V2SessionPermissionListResponse = V2SessionPermissionListResponses[keyof V2SessionPermissionListResponses]
@ -8573,7 +8725,9 @@ export type V2PermissionSavedListResponses = {
/** /**
* Success * Success
*/ */
200: Array<PermissionSavedInfo> 200: {
data: Array<PermissionSavedInfo>
}
} }
export type V2PermissionSavedListResponse = V2PermissionSavedListResponses[keyof V2PermissionSavedListResponses] export type V2PermissionSavedListResponse = V2PermissionSavedListResponses[keyof V2PermissionSavedListResponses]
@ -8640,7 +8794,10 @@ export type V2FsReadResponses = {
/** /**
* Success * Success
*/ */
200: LocationFileSystemTextContent | LocationFileSystemBinaryContent 200: {
location: LocationInfo
data: LocationFileSystemTextContent | LocationFileSystemBinaryContent
}
} }
export type V2FsReadResponse = V2FsReadResponses[keyof V2FsReadResponses] export type V2FsReadResponse = V2FsReadResponses[keyof V2FsReadResponses]
@ -8676,11 +8833,122 @@ export type V2FsListResponses = {
/** /**
* Success * Success
*/ */
200: Array<LocationFileSystemEntry> 200: {
location: LocationInfo
data: Array<LocationFileSystemEntry>
}
} }
export type V2FsListResponse = V2FsListResponses[keyof V2FsListResponses] export type V2FsListResponse = V2FsListResponses[keyof V2FsListResponses]
export type V2CommandListData = {
body?: never
path?: never
query?: {
location?: {
directory?: string
workspace?: string
}
}
url: "/api/command"
}
export type V2CommandListErrors = {
/**
* InvalidRequestError
*/
400: InvalidRequestError
/**
* UnauthorizedError
*/
401: UnauthorizedError
}
export type V2CommandListError = V2CommandListErrors[keyof V2CommandListErrors]
export type V2CommandListResponses = {
/**
* Success
*/
200: {
location: LocationInfo
data: Array<CommandV2Info>
}
}
export type V2CommandListResponse = V2CommandListResponses[keyof V2CommandListResponses]
export type V2SkillListData = {
body?: never
path?: never
query?: {
location?: {
directory?: string
workspace?: string
}
}
url: "/api/skill"
}
export type V2SkillListErrors = {
/**
* InvalidRequestError
*/
400: InvalidRequestError
/**
* UnauthorizedError
*/
401: UnauthorizedError
}
export type V2SkillListError = V2SkillListErrors[keyof V2SkillListErrors]
export type V2SkillListResponses = {
/**
* Success
*/
200: {
location: LocationInfo
data: Array<SkillV2Info>
}
}
export type V2SkillListResponse = V2SkillListResponses[keyof V2SkillListResponses]
export type V2EventSubscribeData = {
body?: never
path?: never
query?: {
location?: {
directory?: string
workspace?: string
}
}
url: "/api/event"
}
export type V2EventSubscribeErrors = {
/**
* InvalidRequestError
*/
400: InvalidRequestError
/**
* UnauthorizedError
*/
401: UnauthorizedError
}
export type V2EventSubscribeError = V2EventSubscribeErrors[keyof V2EventSubscribeErrors]
export type V2EventSubscribeResponses = {
/**
* Success
*/
200: string
}
export type V2EventSubscribeResponse = V2EventSubscribeResponses[keyof V2EventSubscribeResponses]
export type TuiAppendPromptData = { export type TuiAppendPromptData = {
body?: { body?: {
text: string text: string