diff --git a/packages/client/src/generated/types.ts b/packages/client/src/generated/types.ts index ac888719f48..f51e7427987 100644 --- a/packages/client/src/generated/types.ts +++ b/packages/client/src/generated/types.ts @@ -152,8 +152,8 @@ export type SessionsListOutput = { readonly id: string readonly parentID?: string readonly projectID: string - readonly agent?: string | null - readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string | null } | null + readonly agent?: string + readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string } readonly cost: number readonly tokens: { readonly input: number @@ -161,23 +161,23 @@ export type SessionsListOutput = { readonly reasoning: number readonly cache: { readonly read: number; readonly write: number } } - readonly time: { readonly created: number; readonly updated: number; readonly archived?: number | null } + readonly time: { readonly created: number; readonly updated: number; readonly archived?: number } readonly title: string - readonly location: { readonly directory: string; readonly workspaceID?: string | null | null } - readonly subpath?: string | null + readonly location: { readonly directory: string; readonly workspaceID?: string } + readonly subpath?: string readonly revert?: { readonly messageID: string - readonly partID?: string | null - readonly snapshot?: string | null - readonly diff?: string | null + readonly partID?: string + readonly snapshot?: string + readonly diff?: string readonly files?: ReadonlyArray<{ readonly path: string readonly status: "added" | "modified" | "deleted" readonly additions: number readonly deletions: number readonly patch: string - }> | null - } | null + }> + } }> readonly cursor: { readonly previous?: string | null; readonly next?: string | null } } @@ -186,26 +186,26 @@ export type SessionsCreateInput = { readonly id?: { readonly id?: string | null readonly agent?: string | null - readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string | null } | null - readonly location?: { readonly directory: string; readonly workspaceID?: string | null | null } | null + readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string } | null + readonly location?: { readonly directory: string; readonly workspaceID?: string } | null }["id"] readonly agent?: { readonly id?: string | null readonly agent?: string | null - readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string | null } | null - readonly location?: { readonly directory: string; readonly workspaceID?: string | null | null } | null + readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string } | null + readonly location?: { readonly directory: string; readonly workspaceID?: string } | null }["agent"] readonly model?: { readonly id?: string | null readonly agent?: string | null - readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string | null } | null - readonly location?: { readonly directory: string; readonly workspaceID?: string | null | null } | null + readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string } | null + readonly location?: { readonly directory: string; readonly workspaceID?: string } | null }["model"] readonly location?: { readonly id?: string | null readonly agent?: string | null - readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string | null } | null - readonly location?: { readonly directory: string; readonly workspaceID?: string | null | null } | null + readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string } | null + readonly location?: { readonly directory: string; readonly workspaceID?: string } | null }["location"] } @@ -214,8 +214,8 @@ export type SessionsCreateOutput = { readonly id: string readonly parentID?: string readonly projectID: string - readonly agent?: string | null - readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string | null } | null + readonly agent?: string + readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string } readonly cost: number readonly tokens: { readonly input: number @@ -223,23 +223,23 @@ export type SessionsCreateOutput = { readonly reasoning: number readonly cache: { readonly read: number; readonly write: number } } - readonly time: { readonly created: number; readonly updated: number; readonly archived?: number | null } + readonly time: { readonly created: number; readonly updated: number; readonly archived?: number } readonly title: string - readonly location: { readonly directory: string; readonly workspaceID?: string | null | null } - readonly subpath?: string | null + readonly location: { readonly directory: string; readonly workspaceID?: string } + readonly subpath?: string readonly revert?: { readonly messageID: string - readonly partID?: string | null - readonly snapshot?: string | null - readonly diff?: string | null + readonly partID?: string + readonly snapshot?: string + readonly diff?: string readonly files?: ReadonlyArray<{ readonly path: string readonly status: "added" | "modified" | "deleted" readonly additions: number readonly deletions: number readonly patch: string - }> | null - } | null + }> + } } }["data"] @@ -250,8 +250,8 @@ export type SessionsGetOutput = { readonly id: string readonly parentID?: string readonly projectID: string - readonly agent?: string | null - readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string | null } | null + readonly agent?: string + readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string } readonly cost: number readonly tokens: { readonly input: number @@ -259,23 +259,23 @@ export type SessionsGetOutput = { readonly reasoning: number readonly cache: { readonly read: number; readonly write: number } } - readonly time: { readonly created: number; readonly updated: number; readonly archived?: number | null } + readonly time: { readonly created: number; readonly updated: number; readonly archived?: number } readonly title: string - readonly location: { readonly directory: string; readonly workspaceID?: string | null | null } - readonly subpath?: string | null + readonly location: { readonly directory: string; readonly workspaceID?: string } + readonly subpath?: string readonly revert?: { readonly messageID: string - readonly partID?: string | null - readonly snapshot?: string | null - readonly diff?: string | null + readonly partID?: string + readonly snapshot?: string + readonly diff?: string readonly files?: ReadonlyArray<{ readonly path: string readonly status: "added" | "modified" | "deleted" readonly additions: number readonly deletions: number readonly patch: string - }> | null - } | null + }> + } } }["data"] @@ -289,7 +289,7 @@ export type SessionsSwitchAgentOutput = void export type SessionsSwitchModelInput = { readonly sessionID: { readonly sessionID: string }["sessionID"] readonly model: { - readonly model: { readonly id: string; readonly providerID: string; readonly variant?: string | undefined } + readonly model: { readonly id: string; readonly providerID: string; readonly variant?: string } }["model"] } @@ -298,96 +298,80 @@ export type SessionsSwitchModelOutput = void export type SessionsPromptInput = { readonly sessionID: { readonly sessionID: string }["sessionID"] readonly id?: { - readonly id?: string | undefined + readonly id?: string | null readonly prompt: { readonly text: string - readonly files?: - | ReadonlyArray<{ - readonly uri: string - readonly mime: string - readonly name?: string | undefined - readonly description?: string | undefined - readonly source?: { readonly start: number; readonly end: number; readonly text: string } | undefined - }> - | undefined - readonly agents?: - | ReadonlyArray<{ - readonly name: string - readonly source?: { readonly start: number; readonly end: number; readonly text: string } | undefined - }> - | undefined + readonly files?: ReadonlyArray<{ + readonly uri: string + readonly mime: string + readonly name?: string + readonly description?: string + readonly source?: { readonly start: number; readonly end: number; readonly text: string } + }> + readonly agents?: ReadonlyArray<{ + readonly name: string + readonly source?: { readonly start: number; readonly end: number; readonly text: string } + }> } - readonly delivery?: "steer" | "queue" | undefined - readonly resume?: boolean | undefined + readonly delivery?: "steer" | "queue" | null + readonly resume?: boolean | null }["id"] readonly prompt: { - readonly id?: string | undefined + readonly id?: string | null readonly prompt: { readonly text: string - readonly files?: - | ReadonlyArray<{ - readonly uri: string - readonly mime: string - readonly name?: string | undefined - readonly description?: string | undefined - readonly source?: { readonly start: number; readonly end: number; readonly text: string } | undefined - }> - | undefined - readonly agents?: - | ReadonlyArray<{ - readonly name: string - readonly source?: { readonly start: number; readonly end: number; readonly text: string } | undefined - }> - | undefined + readonly files?: ReadonlyArray<{ + readonly uri: string + readonly mime: string + readonly name?: string + readonly description?: string + readonly source?: { readonly start: number; readonly end: number; readonly text: string } + }> + readonly agents?: ReadonlyArray<{ + readonly name: string + readonly source?: { readonly start: number; readonly end: number; readonly text: string } + }> } - readonly delivery?: "steer" | "queue" | undefined - readonly resume?: boolean | undefined + readonly delivery?: "steer" | "queue" | null + readonly resume?: boolean | null }["prompt"] readonly delivery?: { - readonly id?: string | undefined + readonly id?: string | null readonly prompt: { readonly text: string - readonly files?: - | ReadonlyArray<{ - readonly uri: string - readonly mime: string - readonly name?: string | undefined - readonly description?: string | undefined - readonly source?: { readonly start: number; readonly end: number; readonly text: string } | undefined - }> - | undefined - readonly agents?: - | ReadonlyArray<{ - readonly name: string - readonly source?: { readonly start: number; readonly end: number; readonly text: string } | undefined - }> - | undefined + readonly files?: ReadonlyArray<{ + readonly uri: string + readonly mime: string + readonly name?: string + readonly description?: string + readonly source?: { readonly start: number; readonly end: number; readonly text: string } + }> + readonly agents?: ReadonlyArray<{ + readonly name: string + readonly source?: { readonly start: number; readonly end: number; readonly text: string } + }> } - readonly delivery?: "steer" | "queue" | undefined - readonly resume?: boolean | undefined + readonly delivery?: "steer" | "queue" | null + readonly resume?: boolean | null }["delivery"] readonly resume?: { - readonly id?: string | undefined + readonly id?: string | null readonly prompt: { readonly text: string - readonly files?: - | ReadonlyArray<{ - readonly uri: string - readonly mime: string - readonly name?: string | undefined - readonly description?: string | undefined - readonly source?: { readonly start: number; readonly end: number; readonly text: string } | undefined - }> - | undefined - readonly agents?: - | ReadonlyArray<{ - readonly name: string - readonly source?: { readonly start: number; readonly end: number; readonly text: string } | undefined - }> - | undefined + readonly files?: ReadonlyArray<{ + readonly uri: string + readonly mime: string + readonly name?: string + readonly description?: string + readonly source?: { readonly start: number; readonly end: number; readonly text: string } + }> + readonly agents?: ReadonlyArray<{ + readonly name: string + readonly source?: { readonly start: number; readonly end: number; readonly text: string } + }> } - readonly delivery?: "steer" | "queue" | undefined - readonly resume?: boolean | undefined + readonly delivery?: "steer" | "queue" | null + readonly resume?: boolean | null }["resume"] } @@ -401,18 +385,18 @@ export type SessionsPromptOutput = { readonly files?: ReadonlyArray<{ readonly uri: string readonly mime: string - readonly name?: string | null - readonly description?: string | null - readonly source?: { readonly start: number; readonly end: number; readonly text: string } | null - }> | null + readonly name?: string + readonly description?: string + readonly source?: { readonly start: number; readonly end: number; readonly text: string } + }> readonly agents?: ReadonlyArray<{ readonly name: string - readonly source?: { readonly start: number; readonly end: number; readonly text: string } | null - }> | null + readonly source?: { readonly start: number; readonly end: number; readonly text: string } + }> } readonly delivery: "steer" | "queue" readonly timeCreated: number - readonly promotedSeq?: number | null + readonly promotedSeq?: number } }["data"] @@ -433,18 +417,16 @@ export type SessionsStageInput = { export type SessionsStageOutput = { readonly data: { readonly messageID: string - readonly partID?: string | undefined - readonly snapshot?: string | undefined - readonly diff?: string | undefined - readonly files?: - | ReadonlyArray<{ - readonly path: string - readonly status: "added" | "modified" | "deleted" - readonly additions: number - readonly deletions: number - readonly patch: string - }> - | undefined + readonly partID?: string + readonly snapshot?: string + readonly diff?: string + readonly files?: ReadonlyArray<{ + readonly path: string + readonly status: "added" | "modified" | "deleted" + readonly additions: number + readonly deletions: number + readonly patch: string + }> } }["data"] @@ -462,39 +444,39 @@ export type SessionsContextOutput = { readonly data: ReadonlyArray< | { readonly id: string - readonly metadata?: { readonly [x: string]: JsonValue } | null + readonly metadata?: { readonly [x: string]: JsonValue } readonly time: { readonly created: number } readonly type: "agent-switched" readonly agent: string } | { readonly id: string - readonly metadata?: { readonly [x: string]: JsonValue } | null + readonly metadata?: { readonly [x: string]: JsonValue } readonly time: { readonly created: number } readonly type: "model-switched" - readonly model: { readonly id: string; readonly providerID: string; readonly variant?: string | null } + readonly model: { readonly id: string; readonly providerID: string; readonly variant?: string } } | { readonly id: string - readonly metadata?: { readonly [x: string]: JsonValue } | null + readonly metadata?: { readonly [x: string]: JsonValue } readonly time: { readonly created: number } readonly text: string readonly files?: ReadonlyArray<{ readonly uri: string readonly mime: string - readonly name?: string | null - readonly description?: string | null - readonly source?: { readonly start: number; readonly end: number; readonly text: string } | null - }> | null + readonly name?: string + readonly description?: string + readonly source?: { readonly start: number; readonly end: number; readonly text: string } + }> readonly agents?: ReadonlyArray<{ readonly name: string - readonly source?: { readonly start: number; readonly end: number; readonly text: string } | null - }> | null + readonly source?: { readonly start: number; readonly end: number; readonly text: string } + }> readonly type: "user" } | { readonly id: string - readonly metadata?: { readonly [x: string]: JsonValue } | null + readonly metadata?: { readonly [x: string]: JsonValue } readonly time: { readonly created: number } readonly sessionID: string readonly text: string @@ -502,15 +484,15 @@ export type SessionsContextOutput = { } | { readonly id: string - readonly metadata?: { readonly [x: string]: JsonValue } | null + readonly metadata?: { readonly [x: string]: JsonValue } readonly time: { readonly created: number } readonly type: "system" readonly text: string } | { readonly id: string - readonly metadata?: { readonly [x: string]: JsonValue } | null - readonly time: { readonly created: number; readonly completed?: number | null } + readonly metadata?: { readonly [x: string]: JsonValue } + readonly time: { readonly created: number; readonly completed?: number } readonly type: "shell" readonly callID: string readonly command: string @@ -518,18 +500,18 @@ export type SessionsContextOutput = { } | { readonly id: string - readonly metadata?: { readonly [x: string]: JsonValue } | null - readonly time: { readonly created: number; readonly completed?: number | null } + readonly metadata?: { readonly [x: string]: JsonValue } + readonly time: { readonly created: number; readonly completed?: number } readonly type: "assistant" readonly agent: string - readonly model: { readonly id: string; readonly providerID: string; readonly variant?: string | null } + readonly model: { readonly id: string; readonly providerID: string; readonly variant?: string } readonly content: ReadonlyArray< | { readonly type: "text"; readonly id: string; readonly text: string } | { readonly type: "reasoning" readonly id: string readonly text: string - readonly providerMetadata?: { readonly [x: string]: { readonly [x: string]: JsonValue } } | null + readonly providerMetadata?: { readonly [x: string]: { readonly [x: string]: JsonValue } } } | { readonly type: "tool" @@ -537,23 +519,18 @@ export type SessionsContextOutput = { readonly name: string readonly provider?: { readonly executed: boolean - readonly metadata?: { readonly [x: string]: { readonly [x: string]: JsonValue } } | null - readonly resultMetadata?: { readonly [x: string]: { readonly [x: string]: JsonValue } } | null - } | null + readonly metadata?: { readonly [x: string]: { readonly [x: string]: JsonValue } } + readonly resultMetadata?: { readonly [x: string]: { readonly [x: string]: JsonValue } } + } readonly state: | { readonly status: "pending"; readonly input: string } | { readonly status: "running" readonly input: { readonly [x: string]: JsonValue } - readonly structured: { readonly [x: string]: any } + readonly structured: { readonly [x: string]: JsonValue } readonly content: ReadonlyArray< | { readonly type: "text"; readonly text: string } - | { - readonly type: "file" - readonly uri: string - readonly mime: string - readonly name?: string | null - } + | { readonly type: "file"; readonly uri: string; readonly mime: string; readonly name?: string } > } | { @@ -562,61 +539,47 @@ export type SessionsContextOutput = { readonly attachments?: ReadonlyArray<{ readonly uri: string readonly mime: string - readonly name?: string | null - readonly description?: string | null - readonly source?: { readonly start: number; readonly end: number; readonly text: string } | null - }> | null + readonly name?: string + readonly description?: string + readonly source?: { readonly start: number; readonly end: number; readonly text: string } + }> readonly content: ReadonlyArray< | { readonly type: "text"; readonly text: string } - | { - readonly type: "file" - readonly uri: string - readonly mime: string - readonly name?: string | null - } + | { readonly type: "file"; readonly uri: string; readonly mime: string; readonly name?: string } > - readonly outputPaths?: ReadonlyArray | null - readonly structured: { readonly [x: string]: any } - readonly result?: JsonValue | null + readonly outputPaths?: ReadonlyArray + readonly structured: { readonly [x: string]: JsonValue } + readonly result?: JsonValue } | { readonly status: "error" readonly input: { readonly [x: string]: JsonValue } readonly content: ReadonlyArray< | { readonly type: "text"; readonly text: string } - | { - readonly type: "file" - readonly uri: string - readonly mime: string - readonly name?: string | null - } + | { readonly type: "file"; readonly uri: string; readonly mime: string; readonly name?: string } > - readonly structured: { readonly [x: string]: any } + readonly structured: { readonly [x: string]: JsonValue } readonly error: { readonly type: "unknown"; readonly message: string } - readonly result?: JsonValue | null + readonly result?: JsonValue } readonly time: { readonly created: number - readonly ran?: number | null - readonly completed?: number | null - readonly pruned?: number | null + readonly ran?: number + readonly completed?: number + readonly pruned?: number } } > - readonly snapshot?: { - readonly start?: string | null - readonly end?: string | null - readonly files?: ReadonlyArray | null - } | null - readonly finish?: string | null - readonly cost?: number | null + readonly snapshot?: { readonly start?: string; readonly end?: string; readonly files?: ReadonlyArray } + readonly finish?: string + readonly cost?: number readonly tokens?: { readonly input: number readonly output: number readonly reasoning: number readonly cache: { readonly read: number; readonly write: number } - } | null - readonly error?: { readonly type: "unknown"; readonly message: string } | null + } + readonly error?: { readonly type: "unknown"; readonly message: string } } | { readonly type: "compaction" @@ -624,7 +587,7 @@ export type SessionsContextOutput = { readonly summary: string readonly recent: string readonly id: string - readonly metadata?: { readonly [x: string]: JsonValue } | null + readonly metadata?: { readonly [x: string]: JsonValue } readonly time: { readonly created: number } } > diff --git a/packages/core/src/config/plugin/reference.ts b/packages/core/src/config/plugin/reference.ts index 0e7b95ac087..d5fa53c4112 100644 --- a/packages/core/src/config/plugin/reference.ts +++ b/packages/core/src/config/plugin/reference.ts @@ -25,6 +25,8 @@ export const Plugin = define({ const directory = doc.path ? path.dirname(doc.path) : location.directory for (const [name, entry] of Object.entries(doc.info.references ?? {})) { if (!validAlias(name)) continue + const description = typeof entry === "string" ? undefined : entry.description + const hidden = typeof entry === "string" ? undefined : entry.hidden entries.set( name, local(entry) @@ -33,15 +35,15 @@ export const Plugin = define({ path: AbsolutePath.make( localPath(directory, global.home, typeof entry === "string" ? entry : entry.path), ), - description: typeof entry === "string" ? undefined : entry.description, - hidden: typeof entry === "string" ? undefined : entry.hidden, + ...(description === undefined ? {} : { description }), + ...(hidden === undefined ? {} : { hidden }), }) : Reference.GitSource.make({ type: "git", repository: typeof entry === "string" ? entry : entry.repository, - branch: typeof entry === "string" ? undefined : entry.branch, - description: typeof entry === "string" ? undefined : entry.description, - hidden: typeof entry === "string" ? undefined : entry.hidden, + ...(entry.branch === undefined ? {} : { branch: entry.branch }), + ...(description === undefined ? {} : { description }), + ...(hidden === undefined ? {} : { hidden }), }), ) } diff --git a/packages/core/src/plugin/host.ts b/packages/core/src/plugin/host.ts index 8c35d0f19a7..a9d084709ef 100644 --- a/packages/core/src/plugin/host.ts +++ b/packages/core/src/plugin/host.ts @@ -12,8 +12,11 @@ import { ModelV2 } from "../model" import { PluginV2 } from "../plugin" import { ProviderV2 } from "../provider" import { Reference } from "../reference" +import type { DeepMutable } from "../schema" import { SkillV2 } from "../skill" +const mutable = (value: T) => value as DeepMutable + export const make = Effect.fn("PluginHost.make")(function* (plugin: PluginV2.Interface) { const agents = yield* AgentV2.Service const aisdk = yield* AISDK.Service @@ -30,8 +33,8 @@ export const make = Effect.fn("PluginHost.make")(function* (plugin: PluginV2.Int transform: (callback) => agents.transform((draft) => callback({ - list: draft.list, - get: (id) => draft.get(AgentV2.ID.make(id)), + list: () => mutable(draft.list()), + get: (id) => mutable(draft.get(AgentV2.ID.make(id))), default: (id) => draft.default(id === undefined ? undefined : AgentV2.ID.make(id)), update: (id, update) => draft.update(AgentV2.ID.make(id), update), remove: (id) => draft.remove(AgentV2.ID.make(id)), @@ -42,7 +45,7 @@ export const make = Effect.fn("PluginHost.make")(function* (plugin: PluginV2.Int sdk: (callback) => aisdk.hook.sdk((event) => { const output = { - model: event.model, + model: mutable(event.model), package: event.package, options: event.options, sdk: event.sdk, @@ -55,7 +58,7 @@ export const make = Effect.fn("PluginHost.make")(function* (plugin: PluginV2.Int language: (callback) => aisdk.hook.language((event) => { const output = { - model: event.model, + model: mutable(event.model), sdk: event.sdk, options: event.options, language: event.language, @@ -72,13 +75,14 @@ export const make = Effect.fn("PluginHost.make")(function* (plugin: PluginV2.Int catalog.transform((draft) => callback({ provider: { - list: draft.provider.list, - get: (id) => draft.provider.get(ProviderV2.ID.make(id)), + list: () => mutable(draft.provider.list()), + get: (id) => mutable(draft.provider.get(ProviderV2.ID.make(id))), update: (id, update) => draft.provider.update(ProviderV2.ID.make(id), update), remove: (id) => draft.provider.remove(ProviderV2.ID.make(id)), }, model: { - get: (providerID, modelID) => draft.model.get(ProviderV2.ID.make(providerID), ModelV2.ID.make(modelID)), + get: (providerID, modelID) => + mutable(draft.model.get(ProviderV2.ID.make(providerID), ModelV2.ID.make(modelID))), update: (providerID, modelID, update) => draft.model.update(ProviderV2.ID.make(providerID), ModelV2.ID.make(modelID), update), remove: (providerID, modelID) => @@ -108,12 +112,12 @@ export const make = Effect.fn("PluginHost.make")(function* (plugin: PluginV2.Int transform: (callback) => integration.transform((draft) => callback({ - list: draft.list, - get: (id) => draft.get(Integration.ID.make(id)), + list: () => mutable(draft.list()), + get: (id) => mutable(draft.get(Integration.ID.make(id))), update: (id, update) => draft.update(Integration.ID.make(id), update), remove: (id) => draft.remove(Integration.ID.make(id)), method: { - list: (id) => draft.method.list(Integration.ID.make(id)), + list: (id) => mutable(draft.method.list(Integration.ID.make(id))), update: (input) => { if ("authorize" in input) { const methodID = Integration.MethodID.make(input.method.id) diff --git a/packages/core/src/reference.ts b/packages/core/src/reference.ts index 04907ede75e..31c23a2161a 100644 --- a/packages/core/src/reference.ts +++ b/packages/core/src/reference.ts @@ -65,8 +65,8 @@ export const layer = Layer.effect( new Info({ name, path: source.path, - description: source.description, - hidden: source.hidden, + ...(source.description === undefined ? {} : { description: source.description }), + ...(source.hidden === undefined ? {} : { hidden: source.hidden }), source, }), ) @@ -86,13 +86,13 @@ export const layer = Layer.effect( seen.set(target, source.branch) materialized.set( name, - new Info({ - name, - path: AbsolutePath.make(target), - description: source.description, - hidden: source.hidden, - source, - }), + new Info({ + name, + path: AbsolutePath.make(target), + ...(source.description === undefined ? {} : { description: source.description }), + ...(source.hidden === undefined ? {} : { hidden: source.hidden }), + source, + }), ) yield* cache.ensure({ reference: repository, branch: source.branch, refresh: true }).pipe( Effect.catchCause((cause) => diff --git a/packages/core/src/v1/config/migrate.ts b/packages/core/src/v1/config/migrate.ts index 1583c6c1d51..d0cc465e576 100644 --- a/packages/core/src/v1/config/migrate.ts +++ b/packages/core/src/v1/config/migrate.ts @@ -170,6 +170,7 @@ function providers(info?: Readonly>) { function migrateProvider(info: ConfigProviderV1.Info) { const lowerer = ConfigProviderOptionsV1.get(info.npm) const options = lowerer.provider(info.options ?? {}) + const url = info.api ?? options.url return { name: info.name, env: info.env, @@ -177,7 +178,7 @@ function migrateProvider(info: ConfigProviderV1.Info) { ? { type: "aisdk" as const, package: info.npm, - url: info.api ?? options.url, + ...(url === undefined ? {} : { url }), settings: options.settings ?? {}, } : undefined, @@ -221,7 +222,7 @@ function migrateModel(info: typeof ConfigProviderV1.Model.Type, packageName?: st ...(info.id === undefined ? {} : { id: info.id }), type: "aisdk" as const, package: info.provider.npm, - url: info.provider.api, + ...(info.provider.api === undefined ? {} : { url: info.provider.api }), settings: {}, } : info.id === undefined diff --git a/packages/core/test/config/config.test.ts b/packages/core/test/config/config.test.ts index b092bb55829..4b31835726c 100644 --- a/packages/core/test/config/config.test.ts +++ b/packages/core/test/config/config.test.ts @@ -106,7 +106,6 @@ describe("Config", () => { expect(migrated.providers?.bedrock?.api).toEqual({ type: "aisdk", package: "@ai-sdk/amazon-bedrock", - url: undefined, settings: { region: "us-east-1", profile: "dev" }, }) expect(migrated.providers?.bedrock?.request).toEqual({ diff --git a/packages/core/test/tool-todowrite.test.ts b/packages/core/test/tool-todowrite.test.ts index 38ba1900aaf..174d6139c80 100644 --- a/packages/core/test/tool-todowrite.test.ts +++ b/packages/core/test/tool-todowrite.test.ts @@ -77,7 +77,9 @@ describe("TodoWriteTool", () => { yield* setup const registry = yield* ToolRegistry.Service const service = yield* SessionTodo.Service - const todoList = [{ content: "Implement slice", status: "in_progress", priority: "high" }] + const todoList: ReadonlyArray = [ + { content: "Implement slice", status: "in_progress", priority: "high" }, + ] expect((yield* toolDefinitions(registry)).map((tool) => tool.name)).toEqual([TodoWriteTool.name]) expect(yield* settleTool(registry, call(todoList))).toEqual({ diff --git a/packages/opencode/src/session/todo.ts b/packages/opencode/src/session/todo.ts index 462613522dc..d8cc825dfc8 100644 --- a/packages/opencode/src/session/todo.ts +++ b/packages/opencode/src/session/todo.ts @@ -14,7 +14,7 @@ export type Info = SessionTodo.Info export const Event = SessionTodo.Event export interface Interface { - readonly update: (input: { sessionID: SessionID; todos: Info[] }) => Effect.Effect + readonly update: (input: { sessionID: SessionID; todos: ReadonlyArray }) => Effect.Effect readonly get: (sessionID: SessionID) => Effect.Effect } @@ -26,7 +26,7 @@ export const layer = Layer.effect( const events = yield* EventV2Bridge.Service const { db } = yield* Database.Service - const update = Effect.fn("Todo.update")(function* (input: { sessionID: SessionID; todos: Info[] }) { + const update = Effect.fn("Todo.update")(function* (input: { sessionID: SessionID; todos: ReadonlyArray }) { yield* db .transaction((tx) => Effect.gen(function* () { diff --git a/packages/opencode/src/tool/todo.ts b/packages/opencode/src/tool/todo.ts index 18d21cf61e0..69fb0550e8c 100644 --- a/packages/opencode/src/tool/todo.ts +++ b/packages/opencode/src/tool/todo.ts @@ -3,19 +3,8 @@ import * as Tool from "./tool" import DESCRIPTION_WRITE from "./todowrite.txt" import { Todo } from "../session/todo" -// Todo.Info is still a zod schema (session/todo.ts). Inline the field shape -// here rather than referencing its `.shape` — the LLM-visible JSON Schema is -// identical, and it removes the last zod dependency from this tool. -const TodoItem = Schema.Struct({ - content: Schema.String.annotate({ description: "Brief description of the task" }), - status: Schema.String.annotate({ - description: "Current status of the task: pending, in_progress, completed, cancelled", - }), - priority: Schema.String.annotate({ description: "Priority level of the task: high, medium, low" }), -}) - export const Parameters = Schema.Struct({ - todos: Schema.mutable(Schema.Array(TodoItem)).annotate({ description: "The updated todo list" }), + todos: Schema.mutable(Schema.Array(Todo.Info)).annotate({ description: "The updated todo list" }), }) type Metadata = { diff --git a/packages/opencode/test/server/httpapi-exercise/index.ts b/packages/opencode/test/server/httpapi-exercise/index.ts index ea5f5da94a6..d0ffe7f8f16 100644 --- a/packages/opencode/test/server/httpapi-exercise/index.ts +++ b/packages/opencode/test/server/httpapi-exercise/index.ts @@ -1195,7 +1195,7 @@ const scenarios: Scenario[] = [ .seeded((ctx) => Effect.gen(function* () { const session = yield* ctx.session({ title: "Todo session" }) - const todos = [{ content: "cover session todo", status: "pending", priority: "high" }] + const todos = [{ content: "cover session todo", status: "pending" as const, priority: "high" as const }] yield* ctx.todos(session.id, todos) return { session, todos } }), diff --git a/packages/opencode/test/server/httpapi-exercise/types.ts b/packages/opencode/test/server/httpapi-exercise/types.ts index 0b36946993f..acc1898e328 100644 --- a/packages/opencode/test/server/httpapi-exercise/types.ts +++ b/packages/opencode/test/server/httpapi-exercise/types.ts @@ -119,5 +119,9 @@ export type Result = | { status: "skip"; scenario: TodoScenario } export type SessionInfo = { id: SessionID; title: string; parentID?: SessionID } -export type TodoInfo = { content: string; status: string; priority: string } +export type TodoInfo = { + content: string + status: "pending" | "in_progress" | "completed" | "cancelled" + priority: "high" | "medium" | "low" +} export type MessageSeed = { info: SessionV1.User; part: SessionV1.TextPart } diff --git a/packages/opencode/test/server/httpapi-reference.test.ts b/packages/opencode/test/server/httpapi-reference.test.ts index bf615126816..9354d527da0 100644 --- a/packages/opencode/test/server/httpapi-reference.test.ts +++ b/packages/opencode/test/server/httpapi-reference.test.ts @@ -44,26 +44,18 @@ describe("reference HttpApi", () => { { name: "docs", path: path.join(tmp.path, "docs"), - description: null, - hidden: null, source: { type: "local", path: path.join(tmp.path, "docs"), - description: null, - hidden: null, }, }, { name: "effect", path: path.join(Global.Path.repos, "github.com", "Effect-TS", "effect"), - description: null, - hidden: null, source: { type: "git", repository: "Effect-TS/effect", branch: "main", - description: null, - hidden: null, }, }, ]) diff --git a/packages/opencode/test/session/schema-decoding.test.ts b/packages/opencode/test/session/schema-decoding.test.ts index 1323c2aba61..3bcbd55d4b6 100644 --- a/packages/opencode/test/session/schema-decoding.test.ts +++ b/packages/opencode/test/session/schema-decoding.test.ts @@ -256,7 +256,7 @@ describe("Todo.Info", () => { const decode = decodeUnknown(Todo.Info) test("three-field round-trip", () => { - const input = { content: "do a thing", status: "pending", priority: "high" } + const input = Todo.Info.make({ content: "do a thing", status: "pending", priority: "high" }) expect(decode(input)).toEqual(input) }) }) diff --git a/packages/schema/src/agent.ts b/packages/schema/src/agent.ts index 65dbb043776..adf7aec2823 100644 --- a/packages/schema/src/agent.ts +++ b/packages/schema/src/agent.ts @@ -1,6 +1,7 @@ export * as Agent from "./agent" import { Schema } from "effect" +import { optional } from "./schema" import { Model } from "./model" import { Permission } from "./permission" import { Provider } from "./provider" @@ -12,20 +13,20 @@ export type ID = typeof ID.Type export const Color = Schema.Union([ Schema.String.check(Schema.isPattern(/^#[0-9a-fA-F]{6}$/)), Schema.Literals(["primary", "secondary", "accent", "success", "warning", "error", "info"]), -]) +]).annotate({ identifier: "Agent.Color" }) export type Color = typeof Color.Type export interface Info extends Schema.Schema.Type {} export const Info = Schema.Struct({ id: ID, - model: Model.Ref.pipe(Schema.optional), + model: Model.Ref.pipe(optional), request: Provider.Request, - system: Schema.String.pipe(Schema.optional), - description: Schema.String.pipe(Schema.optional), + system: Schema.String.pipe(optional), + description: Schema.String.pipe(optional), mode: Schema.Literals(["subagent", "primary", "all"]), hidden: Schema.Boolean, - color: Color.pipe(Schema.optional), - steps: PositiveInt.pipe(Schema.optional), + color: Color.pipe(optional), + steps: PositiveInt.pipe(optional), permissions: Permission.Ruleset, }) .annotate({ identifier: "AgentV2.Info" }) diff --git a/packages/schema/src/command.ts b/packages/schema/src/command.ts index a038f1e166f..2bdf3a95c50 100644 --- a/packages/schema/src/command.ts +++ b/packages/schema/src/command.ts @@ -1,14 +1,15 @@ export * as Command from "./command" import { Schema } from "effect" +import { optional } from "./schema" import { Model } from "./model" export interface Info extends Schema.Schema.Type {} export const Info = Schema.Struct({ name: Schema.String, template: Schema.String, - description: Schema.String.pipe(Schema.optional), - agent: Schema.String.pipe(Schema.optional), - model: Model.Ref.pipe(Schema.optional), - subtask: Schema.Boolean.pipe(Schema.optional), + description: Schema.String.pipe(optional), + agent: Schema.String.pipe(optional), + model: Model.Ref.pipe(optional), + subtask: Schema.Boolean.pipe(optional), }).annotate({ identifier: "CommandV2.Info" }) diff --git a/packages/schema/src/credential.ts b/packages/schema/src/credential.ts index 6bfa6276d83..e54e2f680b7 100644 --- a/packages/schema/src/credential.ts +++ b/packages/schema/src/credential.ts @@ -1,6 +1,7 @@ export * as Credential from "./credential" import { Schema } from "effect" +import { optional } from "./schema" import { IntegrationMethodID } from "./integration-id" import { ascending } from "./identifier" import { NonNegativeInt, statics } from "./schema" @@ -18,14 +19,14 @@ export const OAuth = Schema.Struct({ refresh: Schema.String, access: Schema.String, expires: NonNegativeInt, - metadata: Schema.optional(Schema.Record(Schema.String, Schema.Any)), + metadata: optional(Schema.Record(Schema.String, Schema.Unknown)), }).annotate({ identifier: "Credential.OAuth" }) export interface Key extends Schema.Schema.Type {} export const Key = Schema.Struct({ type: Schema.Literal("key"), key: Schema.String, - metadata: Schema.optional(Schema.Record(Schema.String, Schema.Any)), + metadata: optional(Schema.Record(Schema.String, Schema.Unknown)), }).annotate({ identifier: "Credential.Key" }) export const Value = Schema.Union([OAuth, Key]) diff --git a/packages/schema/src/event.ts b/packages/schema/src/event.ts index 849ffb89026..da1cadfa7b6 100644 --- a/packages/schema/src/event.ts +++ b/packages/schema/src/event.ts @@ -1,6 +1,7 @@ export * as Event from "./event" import { Schema } from "effect" +import { optional } from "./schema" import { ascending } from "./identifier" import { Location } from "./location" import { statics } from "./schema" @@ -53,12 +54,10 @@ export function define< return Object.assign( Schema.Struct({ id: ID, - metadata: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)), + metadata: optional(Schema.Record(Schema.String, Schema.Unknown)), type: Schema.Literal(input.type), - durable: Schema.optional( - Schema.Struct({ aggregateID: Schema.String, seq: Schema.Number, version: Schema.Number }), - ), - location: Schema.optional(Location.Ref), + durable: optional(Schema.Struct({ aggregateID: Schema.String, seq: Schema.Number, version: Schema.Number })), + location: optional(Location.Ref), data, }).annotate({ identifier: input.type }), { diff --git a/packages/schema/src/file-diff.ts b/packages/schema/src/file-diff.ts index 26bfd4155b4..45226df28ee 100644 --- a/packages/schema/src/file-diff.ts +++ b/packages/schema/src/file-diff.ts @@ -1,12 +1,13 @@ export * as FileDiff from "./file-diff" import { Schema } from "effect" +import { optional } from "./schema" export const Info = Schema.Struct({ - file: Schema.optional(Schema.String), - patch: Schema.optional(Schema.String), + file: optional(Schema.String), + patch: optional(Schema.String), additions: Schema.Finite, deletions: Schema.Finite, - status: Schema.optional(Schema.Literals(["added", "deleted", "modified"])), + status: optional(Schema.Literals(["added", "deleted", "modified"])), }).annotate({ identifier: "SnapshotFileDiff" }) -export type Info = typeof Info.Type +export interface Info extends Schema.Schema.Type {} diff --git a/packages/schema/src/filesystem.ts b/packages/schema/src/filesystem.ts index 7c8a96d8673..1998c1b9fd6 100644 --- a/packages/schema/src/filesystem.ts +++ b/packages/schema/src/filesystem.ts @@ -1,6 +1,7 @@ export * as FileSystem from "./filesystem" import { Schema } from "effect" +import { optional } from "./schema" import { define, inventory } from "./event" import { NonNegativeInt, PositiveInt, RelativePath } from "./schema" @@ -21,7 +22,7 @@ export const Submatch = Schema.Struct({ text: Schema.String, start: NonNegativeInt, end: NonNegativeInt, -}) +}).annotate({ identifier: "FileSystem.Submatch" }) export interface Match extends Schema.Schema.Type {} export const Match = Schema.Struct({ @@ -34,6 +35,6 @@ export const Match = Schema.Struct({ export class FindInput extends Schema.Class("FileSystem.FindInput")({ query: Schema.String, - type: Schema.Literals(["file", "directory"]).pipe(Schema.optional), - limit: PositiveInt.pipe(Schema.optional), + type: Schema.Literals(["file", "directory"]).pipe(optional), + limit: PositiveInt.pipe(optional), }) {} diff --git a/packages/schema/src/integration.ts b/packages/schema/src/integration.ts index a948422ac07..1345318da18 100644 --- a/packages/schema/src/integration.ts +++ b/packages/schema/src/integration.ts @@ -1,6 +1,7 @@ export * as Integration from "./integration" import { Schema } from "effect" +import { optional } from "./schema" import { define, inventory } from "./event" import { Connection } from "./connection" import { ascending } from "./identifier" @@ -25,8 +26,8 @@ export const TextPrompt = Schema.Struct({ type: Schema.Literal("text"), key: Schema.String, message: Schema.String, - placeholder: Schema.optional(Schema.String), - when: Schema.optional(When), + placeholder: optional(Schema.String), + when: optional(When), }).annotate({ identifier: "Integration.TextPrompt" }) export interface SelectPrompt extends Schema.Schema.Type {} @@ -34,16 +35,14 @@ export const SelectPrompt = Schema.Struct({ type: Schema.Literal("select"), key: Schema.String, message: Schema.String, - options: Schema.mutable( - Schema.Array( - Schema.Struct({ - label: Schema.String, - value: Schema.String, - hint: Schema.optional(Schema.String), - }), - ), + options: Schema.Array( + Schema.Struct({ + label: Schema.String, + value: Schema.String, + hint: optional(Schema.String), + }), ), - when: Schema.optional(When), + when: optional(When), }).annotate({ identifier: "Integration.SelectPrompt" }) export const Prompt = Schema.Union([TextPrompt, SelectPrompt]).pipe(Schema.toTaggedUnion("type")) @@ -54,19 +53,19 @@ export const OAuthMethod = Schema.Struct({ id: MethodID, type: Schema.Literal("oauth"), label: Schema.String, - prompts: Schema.optional(Schema.mutable(Schema.Array(Prompt))), + prompts: optional(Schema.Array(Prompt)), }).annotate({ identifier: "Integration.OAuthMethod" }) export interface KeyMethod extends Schema.Schema.Type {} export const KeyMethod = Schema.Struct({ type: Schema.Literal("key"), - label: Schema.optional(Schema.String), + label: optional(Schema.String), }).annotate({ identifier: "Integration.KeyMethod" }) export interface EnvMethod extends Schema.Schema.Type {} export const EnvMethod = Schema.Struct({ type: Schema.Literal("env"), - names: Schema.mutable(Schema.Array(Schema.String)), + names: Schema.Array(Schema.String), }).annotate({ identifier: "Integration.EnvMethod" }) export const Method = Schema.Union([OAuthMethod, KeyMethod, EnvMethod]) @@ -96,8 +95,8 @@ export const Ref = Schema.Struct({ export class Info extends Schema.Class("Integration.Info")({ id: ID, name: Schema.String, - methods: Schema.mutable(Schema.Array(Method)), - connections: Schema.mutable(Schema.Array(Connection.Info)), + methods: Schema.Array(Method), + connections: Schema.Array(Connection.Info), }) {} export const AttemptID = Schema.String.pipe( @@ -124,5 +123,7 @@ export const AttemptStatus = Schema.Union([ Schema.Struct({ status: Schema.Literal("complete"), time: AttemptTime }), Schema.Struct({ status: Schema.Literal("failed"), message: Schema.String, time: AttemptTime }), Schema.Struct({ status: Schema.Literal("expired"), time: AttemptTime }), -]).pipe(Schema.toTaggedUnion("status")) +]) + .pipe(Schema.toTaggedUnion("status")) + .annotate({ identifier: "Integration.AttemptStatus" }) export type AttemptStatus = typeof AttemptStatus.Type diff --git a/packages/schema/src/llm.ts b/packages/schema/src/llm.ts index 545d7dbb51f..44101dd8767 100644 --- a/packages/schema/src/llm.ts +++ b/packages/schema/src/llm.ts @@ -1,8 +1,11 @@ export * as LLM from "./llm" import { Schema } from "effect" +import { optional } from "./schema" -export const ProviderMetadata = Schema.Record(Schema.String, Schema.Record(Schema.String, Schema.Unknown)) +export const ProviderMetadata = Schema.Record(Schema.String, Schema.Record(Schema.String, Schema.Unknown)).annotate({ + identifier: "LLM.ProviderMetadata", +}) export type ProviderMetadata = Schema.Schema.Type export interface ToolTextContent extends Schema.Schema.Type {} @@ -16,8 +19,10 @@ export const ToolFileContent = Schema.Struct({ type: Schema.Literal("file"), uri: Schema.String, mime: Schema.String, - name: Schema.optional(Schema.String), + name: optional(Schema.String), }).annotate({ identifier: "Tool.FileContent" }) -export const ToolContent = Schema.Union([ToolTextContent, ToolFileContent]).pipe(Schema.toTaggedUnion("type")) +export const ToolContent = Schema.Union([ToolTextContent, ToolFileContent]) + .pipe(Schema.toTaggedUnion("type")) + .annotate({ identifier: "LLM.ToolContent" }) export type ToolContent = Schema.Schema.Type diff --git a/packages/schema/src/location.ts b/packages/schema/src/location.ts index b9421bfd556..c01ce36372a 100644 --- a/packages/schema/src/location.ts +++ b/packages/schema/src/location.ts @@ -1,6 +1,6 @@ export * as Location from "./location" -import { Effect, Schema } from "effect" +import { Schema } from "effect" import { AbsolutePath, optional } from "./schema" import { ProjectID } from "./project-id" import { WorkspaceID } from "./workspace-id" @@ -8,10 +8,7 @@ import { WorkspaceID } from "./workspace-id" export interface Ref extends Schema.Schema.Type {} export const Ref = Schema.Struct({ directory: AbsolutePath, - workspaceID: Schema.optional(WorkspaceID).pipe( - Schema.withDecodingDefault(Effect.succeed(undefined)), - Schema.withConstructorDefault(Effect.succeed(undefined)), - ), + workspaceID: optional(WorkspaceID), }).annotate({ identifier: "Location.Ref" }) export class Info extends Schema.Class("Location.Info")({ diff --git a/packages/schema/src/model.ts b/packages/schema/src/model.ts index e6b5823cbc9..10fa175e247 100644 --- a/packages/schema/src/model.ts +++ b/packages/schema/src/model.ts @@ -1,6 +1,7 @@ export * as Model from "./model" import { Schema } from "effect" +import { optional } from "./schema" import { Provider } from "./provider" import { statics } from "./schema" @@ -13,9 +14,9 @@ export type VariantID = typeof VariantID.Type export const Ref = Schema.Struct({ id: ID, providerID: Provider.ID, - variant: VariantID.pipe(Schema.optional), -}) -export type Ref = typeof Ref.Type + variant: VariantID.pipe(optional), +}).annotate({ identifier: "Model.Ref" }) +export interface Ref extends Schema.Schema.Type {} export const Family = Schema.String.pipe(Schema.brand("Family")) export type Family = typeof Family.Type @@ -23,23 +24,23 @@ export type Family = typeof Family.Type export interface Capabilities extends Schema.Schema.Type {} export const Capabilities = Schema.Struct({ tools: Schema.Boolean, - input: Schema.String.pipe(Schema.Array, Schema.mutable), - output: Schema.String.pipe(Schema.Array, Schema.mutable), -}) + input: Schema.Array(Schema.String), + output: Schema.Array(Schema.String), +}).annotate({ identifier: "Model.Capabilities" }) export interface Cost extends Schema.Schema.Type {} export const Cost = Schema.Struct({ tier: Schema.Struct({ type: Schema.Literal("context"), size: Schema.Int, - }).pipe(Schema.optional), + }).pipe(optional), input: Schema.Finite, output: Schema.Finite, cache: Schema.Struct({ read: Schema.Finite, write: Schema.Finite, }), -}) +}).annotate({ identifier: "Model.Cost" }) export const Api = Schema.Union([ Schema.Struct({ @@ -50,34 +51,36 @@ export const Api = Schema.Union([ id: ID, ...Provider.Native.fields, }), -]).pipe(Schema.toTaggedUnion("type")) +]) + .pipe(Schema.toTaggedUnion("type")) + .annotate({ identifier: "Model.Api" }) export type Api = typeof Api.Type export interface Info extends Schema.Schema.Type {} export const Info = Schema.Struct({ id: ID, providerID: Provider.ID, - family: Family.pipe(Schema.optional), + family: Family.pipe(optional), name: Schema.String, api: Api, capabilities: Capabilities, request: Schema.Struct({ ...Provider.Request.fields, - variant: Schema.String.pipe(Schema.optional), + variant: Schema.String.pipe(optional), }), variants: Schema.Struct({ id: VariantID, ...Provider.Request.fields, - }).pipe(Schema.Array, Schema.mutable), + }).pipe(Schema.Array), time: Schema.Struct({ released: Schema.Finite, }), - cost: Cost.pipe(Schema.Array, Schema.mutable), + cost: Schema.Array(Cost), status: Schema.Literals(["alpha", "beta", "deprecated", "active"]), enabled: Schema.Boolean, limit: Schema.Struct({ context: Schema.Int, - input: Schema.Int.pipe(Schema.optional), + input: Schema.Int.pipe(optional), output: Schema.Int, }), }) diff --git a/packages/schema/src/permission-saved.ts b/packages/schema/src/permission-saved.ts index 2815d51f958..969a6dc25ca 100644 --- a/packages/schema/src/permission-saved.ts +++ b/packages/schema/src/permission-saved.ts @@ -17,4 +17,4 @@ export const Info = Schema.Struct({ action: Schema.String, resource: Schema.String, }).annotate({ identifier: "PermissionSaved.Info" }) -export type Info = typeof Info.Type +export interface Info extends Schema.Schema.Type {} diff --git a/packages/schema/src/permission.ts b/packages/schema/src/permission.ts index 733c1e0b9b1..25d776284fd 100644 --- a/packages/schema/src/permission.ts +++ b/packages/schema/src/permission.ts @@ -1,6 +1,7 @@ export * as Permission from "./permission" import { Schema } from "effect" +import { optional } from "./schema" import { define, inventory } from "./event" import { ascending } from "./identifier" import { SessionID } from "./session-id" @@ -25,16 +26,16 @@ const RequestFields = { sessionID: SessionID, action: Schema.String, resources: Schema.Array(Schema.String), - save: Schema.Array(Schema.String).pipe(Schema.optional), - metadata: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional), - source: Source.pipe(Schema.optional), + save: Schema.Array(Schema.String).pipe(optional), + metadata: Schema.Record(Schema.String, Schema.Unknown).pipe(optional), + source: Source.pipe(optional), } export const Request = Schema.Struct({ id: ID, ...RequestFields, }).annotate({ identifier: "PermissionV2.Request" }) -export type Request = typeof Request.Type +export interface Request extends Schema.Schema.Type {} export const Reply = Schema.Literals(["once", "always", "reject"]).annotate({ identifier: "PermissionV2.Reply" }) export type Reply = typeof Reply.Type @@ -60,5 +61,5 @@ export const Rule = Schema.Struct({ effect: Effect, }).annotate({ identifier: "PermissionV2.Rule" }) -export const Ruleset = Schema.mutable(Schema.Array(Rule)).annotate({ identifier: "PermissionV2.Ruleset" }) +export const Ruleset = Schema.Array(Rule).annotate({ identifier: "PermissionV2.Ruleset" }) export type Ruleset = typeof Ruleset.Type diff --git a/packages/schema/src/project-copy.ts b/packages/schema/src/project-copy.ts index d90c323d596..850b87bcb35 100644 --- a/packages/schema/src/project-copy.ts +++ b/packages/schema/src/project-copy.ts @@ -1,6 +1,7 @@ export * as ProjectCopy from "./project-copy" import { Schema } from "effect" +import { optional } from "./schema" import { ProjectID } from "./project-id" import { AbsolutePath } from "./schema" @@ -12,18 +13,18 @@ export const CreateInput = Schema.Struct({ strategy: StrategyID, sourceDirectory: AbsolutePath, directory: AbsolutePath, - name: Schema.optional(Schema.String), + name: optional(Schema.String), }).annotate({ identifier: "ProjectCopy.CreateInput" }) -export type CreateInput = typeof CreateInput.Type +export interface CreateInput extends Schema.Schema.Type {} export const RemoveInput = Schema.Struct({ projectID: ProjectID, directory: AbsolutePath, force: Schema.Boolean, }).annotate({ identifier: "ProjectCopy.RemoveInput" }) -export type RemoveInput = typeof RemoveInput.Type +export interface RemoveInput extends Schema.Schema.Type {} export const Copy = Schema.Struct({ directory: AbsolutePath, }).annotate({ identifier: "ProjectCopy.Copy" }) -export type Copy = typeof Copy.Type +export interface Copy extends Schema.Schema.Type {} diff --git a/packages/schema/src/project.ts b/packages/schema/src/project.ts index 6cee635c600..7e73530a6d5 100644 --- a/packages/schema/src/project.ts +++ b/packages/schema/src/project.ts @@ -8,22 +8,25 @@ import { ProjectID } from "./project-id" export const ID = ProjectID export type ID = typeof ID.Type -export const Vcs = Schema.Literal("git") +export const Vcs = Schema.Literal("git").annotate({ identifier: "Project.Vcs" }) export const Icon = Schema.Struct({ url: optional(Schema.String), override: optional(Schema.String), color: optional(Schema.String), -}) +}).annotate({ identifier: "Project.Icon" }) +export interface Icon extends Schema.Schema.Type {} export const Commands = Schema.Struct({ start: optional( Schema.String.annotate({ description: "Startup script to run when creating a new workspace (worktree)" }), ), -}) +}).annotate({ identifier: "Project.Commands" }) +export interface Commands extends Schema.Schema.Type {} export const Time = Schema.Struct({ created: NonNegativeInt, updated: NonNegativeInt, initialized: optional(NonNegativeInt), -}) +}).annotate({ identifier: "Project.Time" }) +export interface Time extends Schema.Schema.Type {} export const Info = Schema.Struct({ id: ID, @@ -35,7 +38,7 @@ export const Info = Schema.Struct({ time: Time, sandboxes: Schema.Array(Schema.String), }).annotate({ identifier: "Project" }) -export type Info = typeof Info.Type +export interface Info extends Schema.Schema.Type {} const Updated = define({ type: "project.updated", schema: Info.fields }) export const Event = { Updated, Definitions: inventory(Updated) } diff --git a/packages/schema/src/prompt.ts b/packages/schema/src/prompt.ts index 87441bc01e4..376700cc7a6 100644 --- a/packages/schema/src/prompt.ts +++ b/packages/schema/src/prompt.ts @@ -1,4 +1,5 @@ import { Schema } from "effect" +import { optional } from "./schema" import { statics } from "./schema" export interface Source extends Schema.Schema.Type {} @@ -12,9 +13,9 @@ export interface FileAttachment extends Schema.Schema.Type {} export const AgentAttachment = Schema.Struct({ name: Schema.String, - source: Source.pipe(Schema.optional), + source: Source.pipe(optional), }).annotate({ identifier: "Prompt.AgentAttachment" }) export interface Prompt extends Schema.Schema.Type {} export const Prompt = Schema.Struct({ text: Schema.String, - files: Schema.Array(FileAttachment).pipe(Schema.optional), - agents: Schema.Array(AgentAttachment).pipe(Schema.optional), + files: Schema.Array(FileAttachment).pipe(optional), + agents: Schema.Array(AgentAttachment).pipe(optional), }) .annotate({ identifier: "Prompt" }) .pipe( diff --git a/packages/schema/src/provider.ts b/packages/schema/src/provider.ts index a18800a4b14..51ff4b37913 100644 --- a/packages/schema/src/provider.ts +++ b/packages/schema/src/provider.ts @@ -1,6 +1,7 @@ export * as Provider from "./provider" import { Schema } from "effect" +import { optional } from "./schema" import { Integration } from "./integration" import { statics } from "./schema" @@ -26,32 +27,34 @@ export interface AISDK extends Schema.Schema.Type {} export const AISDK = Schema.Struct({ type: Schema.Literal("aisdk"), package: Schema.String, - url: Schema.String.pipe(Schema.optional), - settings: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional), -}) + url: Schema.String.pipe(optional), + settings: Schema.Record(Schema.String, Schema.Unknown).pipe(optional), +}).annotate({ identifier: "Provider.AISDK" }) export interface Native extends Schema.Schema.Type {} export const Native = Schema.Struct({ type: Schema.Literal("native"), - url: Schema.String.pipe(Schema.optional), + url: Schema.String.pipe(optional), settings: Schema.Record(Schema.String, Schema.Unknown), -}) +}).annotate({ identifier: "Provider.Native" }) -export const Api = Schema.Union([AISDK, Native]).pipe(Schema.toTaggedUnion("type")) +export const Api = Schema.Union([AISDK, Native]) + .pipe(Schema.toTaggedUnion("type")) + .annotate({ identifier: "Provider.Api" }) export type Api = typeof Api.Type export interface Request extends Schema.Schema.Type {} export const Request = Schema.Struct({ headers: Schema.Record(Schema.String, Schema.String), - body: Schema.Record(Schema.String, Schema.Any), -}) + body: Schema.Record(Schema.String, Schema.Json), +}).annotate({ identifier: "Provider.Request" }) export interface Info extends Schema.Schema.Type {} export const Info = Schema.Struct({ id: ID, - integrationID: Integration.ID.pipe(Schema.optional), + integrationID: Integration.ID.pipe(optional), name: Schema.String, - disabled: Schema.Boolean.pipe(Schema.optional), + disabled: Schema.Boolean.pipe(optional), api: Api, request: Request, }) diff --git a/packages/schema/src/pty-ticket.ts b/packages/schema/src/pty-ticket.ts index 4d1bdedfb8a..9b258575a90 100644 --- a/packages/schema/src/pty-ticket.ts +++ b/packages/schema/src/pty-ticket.ts @@ -6,4 +6,5 @@ import { PositiveInt } from "./schema" export const ConnectToken = Schema.Struct({ ticket: Schema.String, expires_in: PositiveInt, -}) +}).annotate({ identifier: "PtyTicket.ConnectToken" }) +export interface ConnectToken extends Schema.Schema.Type {} diff --git a/packages/schema/src/pty.ts b/packages/schema/src/pty.ts index 9d6120ccde4..1392ece55f5 100644 --- a/packages/schema/src/pty.ts +++ b/packages/schema/src/pty.ts @@ -1,6 +1,7 @@ export * as Pty from "./pty" import { Schema } from "effect" +import { optional } from "./schema" import { define, inventory } from "./event" import { ascending } from "./identifier" import { NonNegativeInt, PositiveInt, statics } from "./schema" @@ -8,9 +9,13 @@ import { NonNegativeInt, PositiveInt, statics } from "./schema" const IDSchema = Schema.String.check(Schema.isStartsWith("pty")).pipe(Schema.brand("PtyID")) export const ID = IDSchema.pipe( - statics((schema: typeof IDSchema) => ({ - ascending: (id?: string) => schema.make(id ?? "pty_" + ascending()), - })), + statics((schema: typeof IDSchema) => { + const create = () => schema.make("pty_" + ascending()) + return { + create, + ascending: (id?: string) => (id === undefined ? create() : schema.make(id)), + } + }), ) export type ID = typeof ID.Type @@ -22,8 +27,9 @@ export const Info = Schema.Struct({ cwd: Schema.String, status: Schema.Literals(["running", "exited"]), pid: NonNegativeInt, - exitCode: Schema.optional(NonNegativeInt), + exitCode: optional(NonNegativeInt), }).annotate({ identifier: "Pty" }) +export interface Info extends Schema.Schema.Type {} const Created = define({ type: "pty.created", schema: { info: Info } }) const Updated = define({ type: "pty.updated", schema: { info: Info } }) @@ -32,21 +38,21 @@ const Deleted = define({ type: "pty.deleted", schema: { id: ID } }) export const Event = { Created, Updated, Exited, Deleted, Definitions: inventory(Created, Updated, Exited, Deleted) } export const CreateInput = Schema.Struct({ - command: Schema.optional(Schema.String), - args: Schema.optional(Schema.Array(Schema.String)), - cwd: Schema.optional(Schema.String), - title: Schema.optional(Schema.String), - env: Schema.optional(Schema.Record(Schema.String, Schema.String)), + command: optional(Schema.String), + args: optional(Schema.Array(Schema.String)), + cwd: optional(Schema.String), + title: optional(Schema.String), + env: optional(Schema.Record(Schema.String, Schema.String)), }) -export type CreateInput = typeof CreateInput.Type +export interface CreateInput extends Schema.Schema.Type {} export const UpdateInput = Schema.Struct({ - title: Schema.optional(Schema.String), - size: Schema.optional( + title: optional(Schema.String), + size: optional( Schema.Struct({ rows: PositiveInt, cols: PositiveInt, }), ), }) -export type UpdateInput = typeof UpdateInput.Type +export interface UpdateInput extends Schema.Schema.Type {} diff --git a/packages/schema/src/question.ts b/packages/schema/src/question.ts index 0933c11ec12..aba5ebfbaf2 100644 --- a/packages/schema/src/question.ts +++ b/packages/schema/src/question.ts @@ -1,6 +1,7 @@ export * as Question from "./question" import { Schema } from "effect" +import { optional } from "./schema" import { define, inventory } from "./event" import { ascending } from "./identifier" import { SessionID } from "./session-id" @@ -8,7 +9,13 @@ import { statics } from "./schema" export const ID = Schema.String.check(Schema.isStartsWith("que")).pipe( Schema.brand("QuestionV2.ID"), - statics((schema) => ({ ascending: (id?: string) => schema.make(id ?? "que_" + ascending()) })), + statics((schema) => { + const create = () => schema.make("que_" + ascending()) + return { + create, + ascending: (id?: string) => (id === undefined ? create() : schema.make(id)), + } + }), ) export type ID = typeof ID.Type @@ -16,39 +23,39 @@ export const Option = Schema.Struct({ label: Schema.String.annotate({ description: "Display text (1-5 words, concise)" }), description: Schema.String.annotate({ description: "Explanation of choice" }), }).annotate({ identifier: "QuestionV2.Option" }) -export type Option = typeof Option.Type +export interface Option extends Schema.Schema.Type {} const base = { question: Schema.String.annotate({ description: "Complete question" }), header: Schema.String.annotate({ description: "Very short label (max 30 chars)" }), options: Schema.Array(Option).annotate({ description: "Available choices" }), - multiple: Schema.Boolean.pipe(Schema.optional).annotate({ description: "Allow selecting multiple choices" }), + multiple: Schema.Boolean.pipe(optional).annotate({ description: "Allow selecting multiple choices" }), } export const Info = Schema.Struct({ ...base, - custom: Schema.Boolean.pipe(Schema.optional).annotate({ + custom: Schema.Boolean.pipe(optional).annotate({ description: "Allow typing a custom answer (default: true)", }), }).annotate({ identifier: "QuestionV2.Info" }) -export type Info = typeof Info.Type +export interface Info extends Schema.Schema.Type {} export const Prompt = Schema.Struct(base).annotate({ identifier: "QuestionV2.Prompt" }) -export type Prompt = typeof Prompt.Type +export interface Prompt extends Schema.Schema.Type {} export const Tool = Schema.Struct({ messageID: Schema.String, callID: Schema.String, }).annotate({ identifier: "QuestionV2.Tool" }) -export type Tool = typeof Tool.Type +export interface Tool extends Schema.Schema.Type {} export const Request = Schema.Struct({ id: ID, sessionID: SessionID, questions: Schema.Array(Info).annotate({ description: "Questions to ask" }), - tool: Tool.pipe(Schema.optional), + tool: Tool.pipe(optional), }).annotate({ identifier: "QuestionV2.Request" }) -export type Request = typeof Request.Type +export interface Request extends Schema.Schema.Type {} export const Answer = Schema.Array(Schema.String).annotate({ identifier: "QuestionV2.Answer" }) export type Answer = typeof Answer.Type @@ -58,7 +65,7 @@ export const Reply = Schema.Struct({ description: "User answers in order of questions (each answer is an array of selected labels)", }), }).annotate({ identifier: "QuestionV2.Reply" }) -export type Reply = typeof Reply.Type +export interface Reply extends Schema.Schema.Type {} const Asked = define({ type: "question.v2.asked", schema: Request.fields }) const Replied = define({ diff --git a/packages/schema/src/reference.ts b/packages/schema/src/reference.ts index ca80ff33f09..84b623a2742 100644 --- a/packages/schema/src/reference.ts +++ b/packages/schema/src/reference.ts @@ -1,6 +1,7 @@ export * as Reference from "./reference" import { Schema } from "effect" +import { optional } from "./schema" import { define, inventory } from "./event" import { AbsolutePath } from "./schema" @@ -11,26 +12,28 @@ export interface LocalSource extends Schema.Schema.Type {} export const LocalSource = Schema.Struct({ type: Schema.Literal("local"), path: AbsolutePath, - description: Schema.String.pipe(Schema.optional), - hidden: Schema.Boolean.pipe(Schema.optional), + description: Schema.String.pipe(optional), + hidden: Schema.Boolean.pipe(optional), }).annotate({ identifier: "Reference.LocalSource" }) export interface GitSource extends Schema.Schema.Type {} export const GitSource = Schema.Struct({ type: Schema.Literal("git"), repository: Schema.String, - branch: Schema.String.pipe(Schema.optional), - description: Schema.String.pipe(Schema.optional), - hidden: Schema.Boolean.pipe(Schema.optional), + branch: Schema.String.pipe(optional), + description: Schema.String.pipe(optional), + hidden: Schema.Boolean.pipe(optional), }).annotate({ identifier: "Reference.GitSource" }) -export const Source = Schema.Union([LocalSource, GitSource]).pipe(Schema.toTaggedUnion("type")) +export const Source = Schema.Union([LocalSource, GitSource]) + .pipe(Schema.toTaggedUnion("type")) + .annotate({ identifier: "Reference.Source" }) export type Source = typeof Source.Type export class Info extends Schema.Class("Reference.Info")({ name: Schema.String, path: AbsolutePath, - description: Schema.String.pipe(Schema.optional), - hidden: Schema.Boolean.pipe(Schema.optional), + description: Schema.String.pipe(optional), + hidden: Schema.Boolean.pipe(optional), source: Source, }) {} diff --git a/packages/schema/src/revert.ts b/packages/schema/src/revert.ts index 4ac0977420d..05222d53981 100644 --- a/packages/schema/src/revert.ts +++ b/packages/schema/src/revert.ts @@ -1,6 +1,7 @@ export * as Revert from "./revert" import { Schema } from "effect" +import { optional } from "./schema" import { NonNegativeInt, RelativePath } from "./schema" import { SessionMessage } from "./session-message" @@ -11,13 +12,13 @@ export const FileDiff = Schema.Struct({ deletions: NonNegativeInt, patch: Schema.String, }).annotate({ identifier: "File.Diff" }) -export type FileDiff = typeof FileDiff.Type +export interface FileDiff extends Schema.Schema.Type {} export const State = Schema.Struct({ messageID: SessionMessage.ID, - partID: Schema.String.pipe(Schema.optional), - snapshot: Schema.String.pipe(Schema.optional), - diff: Schema.String.pipe(Schema.optional), - files: Schema.Array(FileDiff).pipe(Schema.optional), -}) -export type State = typeof State.Type + partID: Schema.String.pipe(optional), + snapshot: Schema.String.pipe(optional), + diff: Schema.String.pipe(optional), + files: Schema.Array(FileDiff).pipe(optional), +}).annotate({ identifier: "Revert.State" }) +export interface State extends Schema.Schema.Type {} diff --git a/packages/schema/src/schema.ts b/packages/schema/src/schema.ts index 1cadffdf604..d19a39b9708 100644 --- a/packages/schema/src/schema.ts +++ b/packages/schema/src/schema.ts @@ -11,7 +11,7 @@ export type AbsolutePath = typeof AbsolutePath.Type export const optional = (schema: S) => Schema.optionalKey(schema).pipe( - Schema.decodeTo(Schema.optional(schema), { + Schema.decodeTo(Schema.optional(Schema.toType(schema)), { decode: SchemaGetter.passthrough({ strict: false }), encode: SchemaGetter.transformOptional(Option.filter((value) => value !== undefined)), }), diff --git a/packages/schema/src/session-event.ts b/packages/schema/src/session-event.ts index e94cf94c5bc..f58c3dcce02 100644 --- a/packages/schema/src/session-event.ts +++ b/packages/schema/src/session-event.ts @@ -1,6 +1,7 @@ export * as SessionEvent from "./session-event" import { Schema } from "effect" +import { optional } from "./schema" import { Event } from "./event" import { ProviderMetadata, ToolContent } from "./llm" import { Delivery } from "./session-delivery" @@ -21,7 +22,7 @@ export const Source = Schema.Struct({ }).annotate({ identifier: "session.next.event.source", }) -export type Source = typeof Source.Type +export interface Source extends Schema.Schema.Type {} const Base = { timestamp: DateTimeUtcFromMillis, @@ -78,7 +79,7 @@ export const Moved = Event.define({ schema: { ...Base, location: Location.Ref, - subdirectory: RelativePath.pipe(Schema.optional), + subdirectory: RelativePath.pipe(optional), }, }) export type Moved = typeof Moved.Type @@ -153,7 +154,7 @@ export namespace Step { assistantMessageID: SessionMessage.ID, agent: Schema.String, model: Model.Ref, - snapshot: Schema.String.pipe(Schema.optional), + snapshot: Schema.String.pipe(optional), }, }) export type Started = typeof Started.Type @@ -175,8 +176,8 @@ export namespace Step { write: Schema.Finite, }), }), - snapshot: Schema.String.pipe(Schema.optional), - files: Schema.Array(RelativePath).pipe(Schema.optional), + snapshot: Schema.String.pipe(optional), + files: Schema.Array(RelativePath).pipe(optional), }, }) export type Ended = typeof Ended.Type @@ -238,7 +239,7 @@ export namespace Reasoning { ...Base, assistantMessageID: SessionMessage.ID, reasoningID: Schema.String, - providerMetadata: ProviderMetadata.pipe(Schema.optional), + providerMetadata: ProviderMetadata.pipe(optional), }, }) export type Started = typeof Started.Type @@ -263,7 +264,7 @@ export namespace Reasoning { assistantMessageID: SessionMessage.ID, reasoningID: Schema.String, text: Schema.String, - providerMetadata: ProviderMetadata.pipe(Schema.optional), + providerMetadata: ProviderMetadata.pipe(optional), }, }) export type Ended = typeof Ended.Type @@ -317,7 +318,7 @@ export namespace Tool { input: Schema.Record(Schema.String, Schema.Unknown), provider: Schema.Struct({ executed: Schema.Boolean, - metadata: ProviderMetadata.pipe(Schema.optional), + metadata: ProviderMetadata.pipe(optional), }), }, }) @@ -332,7 +333,7 @@ export namespace Tool { ...options, schema: { ...ToolBase, - structured: Schema.Record(Schema.String, Schema.Any), + structured: Schema.Record(Schema.String, Schema.Unknown), content: Schema.Array(ToolContent), }, }) @@ -343,13 +344,13 @@ export namespace Tool { ...options, schema: { ...ToolBase, - structured: Schema.Record(Schema.String, Schema.Any), + structured: Schema.Record(Schema.String, Schema.Unknown), content: Schema.Array(ToolContent), - outputPaths: Schema.Array(Schema.String).pipe(Schema.optional), - result: Schema.Unknown.pipe(Schema.optional), + outputPaths: Schema.Array(Schema.String).pipe(optional), + result: Schema.Unknown.pipe(optional), provider: Schema.Struct({ executed: Schema.Boolean, - metadata: ProviderMetadata.pipe(Schema.optional), + metadata: ProviderMetadata.pipe(optional), }), }, }) @@ -361,10 +362,10 @@ export namespace Tool { schema: { ...ToolBase, error: UnknownError, - result: Schema.Unknown.pipe(Schema.optional), + result: Schema.Unknown.pipe(optional), provider: Schema.Struct({ executed: Schema.Boolean, - metadata: ProviderMetadata.pipe(Schema.optional), + metadata: ProviderMetadata.pipe(optional), }), }, }) @@ -373,15 +374,15 @@ export namespace Tool { export const RetryError = Schema.Struct({ message: Schema.String, - statusCode: Schema.Finite.pipe(Schema.optional), + statusCode: Schema.Finite.pipe(optional), isRetryable: Schema.Boolean, - responseHeaders: Schema.Record(Schema.String, Schema.String).pipe(Schema.optional), - responseBody: Schema.String.pipe(Schema.optional), - metadata: Schema.Record(Schema.String, Schema.String).pipe(Schema.optional), + responseHeaders: Schema.Record(Schema.String, Schema.String).pipe(optional), + responseBody: Schema.String.pipe(optional), + metadata: Schema.Record(Schema.String, Schema.String).pipe(optional), }).annotate({ identifier: "session.next.retry_error", }) -export type RetryError = typeof RetryError.Type +export interface RetryError extends Schema.Schema.Type {} export const Retried = Event.define({ type: "session.next.retried", diff --git a/packages/schema/src/session-input.ts b/packages/schema/src/session-input.ts index 219dfa10ec2..40babac105f 100644 --- a/packages/schema/src/session-input.ts +++ b/packages/schema/src/session-input.ts @@ -1,6 +1,7 @@ export * as SessionInput from "./session-input" import { Schema } from "effect" +import { optional } from "./schema" import { Prompt } from "./prompt" import { DateTimeUtcFromMillis, NonNegativeInt } from "./schema" import { SessionDelivery } from "./session-delivery" @@ -18,5 +19,5 @@ export const Admitted = Schema.Struct({ prompt: Prompt, delivery: Delivery, timeCreated: DateTimeUtcFromMillis, - promotedSeq: NonNegativeInt.pipe(Schema.optional), + promotedSeq: NonNegativeInt.pipe(optional), }).annotate({ identifier: "SessionInput.Admitted" }) diff --git a/packages/schema/src/session-message.ts b/packages/schema/src/session-message.ts index c365e08ba6f..f32bb0582e6 100644 --- a/packages/schema/src/session-message.ts +++ b/packages/schema/src/session-message.ts @@ -1,6 +1,7 @@ export * as SessionMessage from "./session-message" import { Schema } from "effect" +import { optional } from "./schema" import { ProviderMetadata, ToolContent } from "./llm" import { Model } from "./model" import { FileAttachment, Prompt } from "./prompt" @@ -22,7 +23,7 @@ export const UnknownError = Schema.Struct({ const Base = { id: ID, - metadata: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional), + metadata: Schema.Record(Schema.String, Schema.Unknown).pipe(optional), time: Schema.Struct({ created: DateTimeUtcFromMillis }), } @@ -73,7 +74,7 @@ export const Shell = Schema.Struct({ output: Schema.String, time: Schema.Struct({ created: DateTimeUtcFromMillis, - completed: DateTimeUtcFromMillis.pipe(Schema.optional), + completed: DateTimeUtcFromMillis.pipe(optional), }), }).annotate({ identifier: "Session.Message.Shell" }) @@ -87,7 +88,7 @@ export interface ToolStateRunning extends Schema.Schema.Type {} @@ -107,9 +108,9 @@ export const ToolStateError = Schema.Struct({ status: Schema.Literal("error"), input: Schema.Record(Schema.String, Schema.Unknown), content: ToolContent.pipe(Schema.Array), - structured: Schema.Record(Schema.String, Schema.Any), + structured: Schema.Record(Schema.String, Schema.Unknown), error: UnknownError, - result: Schema.Unknown.pipe(Schema.optional), + result: Schema.Unknown.pipe(optional), }).annotate({ identifier: "Session.Message.ToolState.Error" }) export const ToolState = Schema.Union([ToolStatePending, ToolStateRunning, ToolStateCompleted, ToolStateError]).pipe( @@ -124,15 +125,15 @@ export const AssistantTool = Schema.Struct({ name: Schema.String, provider: Schema.Struct({ executed: Schema.Boolean, - metadata: ProviderMetadata.pipe(Schema.optional), - resultMetadata: ProviderMetadata.pipe(Schema.optional), - }).pipe(Schema.optional), + metadata: ProviderMetadata.pipe(optional), + resultMetadata: ProviderMetadata.pipe(optional), + }).pipe(optional), state: ToolState, time: Schema.Struct({ created: DateTimeUtcFromMillis, - ran: DateTimeUtcFromMillis.pipe(Schema.optional), - completed: DateTimeUtcFromMillis.pipe(Schema.optional), - pruned: DateTimeUtcFromMillis.pipe(Schema.optional), + ran: DateTimeUtcFromMillis.pipe(optional), + completed: DateTimeUtcFromMillis.pipe(optional), + pruned: DateTimeUtcFromMillis.pipe(optional), }), }).annotate({ identifier: "Session.Message.Assistant.Tool" }) @@ -148,7 +149,7 @@ export const AssistantReasoning = Schema.Struct({ type: Schema.Literal("reasoning"), id: Schema.String, text: Schema.String, - providerMetadata: ProviderMetadata.pipe(Schema.optional), + providerMetadata: ProviderMetadata.pipe(optional), }).annotate({ identifier: "Session.Message.Assistant.Reasoning" }) export const AssistantContent = Schema.Union([AssistantText, AssistantReasoning, AssistantTool]).pipe( @@ -164,22 +165,22 @@ export const Assistant = Schema.Struct({ model: Model.Ref, content: AssistantContent.pipe(Schema.Array), snapshot: Schema.Struct({ - start: Schema.String.pipe(Schema.optional), - end: Schema.String.pipe(Schema.optional), - files: Schema.Array(RelativePath).pipe(Schema.optional), - }).pipe(Schema.optional), - finish: Schema.String.pipe(Schema.optional), - cost: Schema.Finite.pipe(Schema.optional), + start: Schema.String.pipe(optional), + end: Schema.String.pipe(optional), + files: Schema.Array(RelativePath).pipe(optional), + }).pipe(optional), + finish: Schema.String.pipe(optional), + cost: Schema.Finite.pipe(optional), tokens: Schema.Struct({ input: Schema.Finite, output: Schema.Finite, reasoning: Schema.Finite, cache: Schema.Struct({ read: Schema.Finite, write: Schema.Finite }), - }).pipe(Schema.optional), - error: UnknownError.pipe(Schema.optional), + }).pipe(optional), + error: UnknownError.pipe(optional), time: Schema.Struct({ created: DateTimeUtcFromMillis, - completed: DateTimeUtcFromMillis.pipe(Schema.optional), + completed: DateTimeUtcFromMillis.pipe(optional), }), }).annotate({ identifier: "Session.Message.Assistant" }) diff --git a/packages/schema/src/session-status-event.ts b/packages/schema/src/session-status-event.ts index 5233f97edb0..f6a3022bcb1 100644 --- a/packages/schema/src/session-status-event.ts +++ b/packages/schema/src/session-status-event.ts @@ -1,6 +1,7 @@ export * as SessionStatusEvent from "./session-status-event" import { Schema } from "effect" +import { optional } from "./schema" import { Event } from "./event" import { NonNegativeInt } from "./schema" import { SessionID } from "./session-id" @@ -13,14 +14,14 @@ export const Info = Schema.Union([ type: Schema.Literal("retry"), attempt: NonNegativeInt, message: Schema.String, - action: Schema.optional( + action: optional( Schema.Struct({ reason: Schema.String, provider: Schema.String, title: Schema.String, message: Schema.String, label: Schema.String, - link: Schema.optional(Schema.String), + link: optional(Schema.String), }), ), next: NonNegativeInt, diff --git a/packages/schema/src/session-todo.ts b/packages/schema/src/session-todo.ts index 5a05d510961..7f6a72bf000 100644 --- a/packages/schema/src/session-todo.ts +++ b/packages/schema/src/session-todo.ts @@ -9,9 +9,11 @@ export const Info = Schema.Struct({ status: Schema.String.annotate({ description: "Current status of the task: pending, in_progress, completed, cancelled", }), - priority: Schema.String.annotate({ description: "Priority level of the task: high, medium, low" }), + priority: Schema.String.annotate({ + description: "Priority level of the task: high, medium, low", + }), }).annotate({ identifier: "Todo" }) -export type Info = typeof Info.Type +export interface Info extends Schema.Schema.Type {} const Updated = define({ type: "todo.updated", diff --git a/packages/schema/src/session.ts b/packages/schema/src/session.ts index 1db7dd7f7c1..937705eeb2f 100644 --- a/packages/schema/src/session.ts +++ b/packages/schema/src/session.ts @@ -20,8 +20,8 @@ export const Info = Schema.Struct({ id: ID, parentID: ID.pipe(optional), projectID: Project.ID, - agent: Agent.ID.pipe(Schema.optional), - model: Model.Ref.pipe(Schema.optional), + agent: Agent.ID.pipe(optional), + model: Model.Ref.pipe(optional), cost: Schema.Finite, tokens: Schema.Struct({ input: Schema.Finite, @@ -35,17 +35,17 @@ export const Info = Schema.Struct({ time: Schema.Struct({ created: DateTimeUtcFromMillis, updated: DateTimeUtcFromMillis, - archived: DateTimeUtcFromMillis.pipe(Schema.optional), + archived: DateTimeUtcFromMillis.pipe(optional), }), title: Schema.String, location: Location.Ref, - subpath: RelativePath.pipe(Schema.optional), - revert: Revert.State.pipe(Schema.optional), + subpath: RelativePath.pipe(optional), + revert: Revert.State.pipe(optional), }).annotate({ identifier: "SessionV2.Info" }) export const ListAnchor = Schema.Struct({ id: ID, time: Schema.Finite, direction: Schema.Literals(["previous", "next"]), -}) -export type ListAnchor = typeof ListAnchor.Type +}).annotate({ identifier: "Session.ListAnchor" }) +export interface ListAnchor extends Schema.Schema.Type {} diff --git a/packages/schema/src/skill.ts b/packages/schema/src/skill.ts index 3a39e3be6e4..ec299180ed0 100644 --- a/packages/schema/src/skill.ts +++ b/packages/schema/src/skill.ts @@ -1,6 +1,7 @@ export * as Skill from "./skill" import { Schema } from "effect" +import { optional } from "./schema" import { AbsolutePath } from "./schema" export interface DirectorySource extends Schema.Schema.Type {} @@ -18,8 +19,8 @@ export const UrlSource = Schema.Struct({ export interface Info extends Schema.Schema.Type {} export const Info = Schema.Struct({ name: Schema.String, - description: Schema.String.pipe(Schema.optional), - slash: Schema.Boolean.pipe(Schema.optional), + description: Schema.String.pipe(optional), + slash: Schema.Boolean.pipe(optional), location: AbsolutePath, content: Schema.String, }).annotate({ identifier: "SkillV2.Info" }) diff --git a/packages/schema/src/tui-event.ts b/packages/schema/src/tui-event.ts index 41fa4dbeb6c..800094e61e8 100644 --- a/packages/schema/src/tui-event.ts +++ b/packages/schema/src/tui-event.ts @@ -1,6 +1,7 @@ export * as TuiEvent from "./tui-event" import { Effect, Schema } from "effect" +import { optional } from "./schema" import { Event } from "./event" import { PositiveInt } from "./schema" import { SessionID } from "./session-id" @@ -39,7 +40,7 @@ export const CommandExecute = Event.define({ export const ToastShow = Event.define({ type: "tui.toast.show", schema: { - title: Schema.optional(Schema.String), + title: optional(Schema.String), message: Schema.String, variant: Schema.Literals(["info", "success", "warning", "error"]), duration: PositiveInt.pipe(Schema.withDecodingDefault(Effect.succeed(DEFAULT_TOAST_DURATION))).annotate({ diff --git a/packages/schema/src/vcs-event.ts b/packages/schema/src/vcs-event.ts index ac1f74b98be..1c0d720dc4b 100644 --- a/packages/schema/src/vcs-event.ts +++ b/packages/schema/src/vcs-event.ts @@ -1,12 +1,13 @@ export * as VcsEvent from "./vcs-event" import { Schema } from "effect" +import { optional } from "./schema" import { Event } from "./event" export const BranchUpdated = Event.define({ type: "vcs.branch.updated", schema: { - branch: Schema.optional(Schema.String), + branch: optional(Schema.String), }, }) diff --git a/packages/schema/src/workspace-event.ts b/packages/schema/src/workspace-event.ts index 687af2cc7cb..82e15e07719 100644 --- a/packages/schema/src/workspace-event.ts +++ b/packages/schema/src/workspace-event.ts @@ -7,8 +7,8 @@ import { WorkspaceID } from "./workspace-id" export const ConnectionStatus = Schema.Struct({ workspaceID: WorkspaceID, status: Schema.Literals(["connected", "connecting", "disconnected", "error"]), -}) -export type ConnectionStatus = typeof ConnectionStatus.Type +}).annotate({ identifier: "WorkspaceEvent.ConnectionStatus" }) +export interface ConnectionStatus extends Schema.Schema.Type {} export const Ready = Event.define({ type: "workspace.ready", diff --git a/packages/schema/src/worktree-event.ts b/packages/schema/src/worktree-event.ts index 809fe8d9fe3..c42ea5821e1 100644 --- a/packages/schema/src/worktree-event.ts +++ b/packages/schema/src/worktree-event.ts @@ -1,13 +1,14 @@ export * as WorktreeEvent from "./worktree-event" import { Schema } from "effect" +import { optional } from "./schema" import { Event } from "./event" export const Ready = Event.define({ type: "worktree.ready", schema: { name: Schema.String, - branch: Schema.optional(Schema.String), + branch: optional(Schema.String), }, }) diff --git a/packages/schema/test/contract-hygiene.test.ts b/packages/schema/test/contract-hygiene.test.ts new file mode 100644 index 00000000000..cf83dbb2889 --- /dev/null +++ b/packages/schema/test/contract-hygiene.test.ts @@ -0,0 +1,67 @@ +import { describe, expect, test } from "bun:test" +import { Schema } from "effect" +import { Agent } from "../src/agent" +import { FileSystem } from "../src/filesystem" +import { Model } from "../src/model" +import { Project } from "../src/project" +import { Pty } from "../src/pty" +import { Question } from "../src/question" +import { Session } from "../src/session" +import { SessionEvent } from "../src/session-event" +import { SessionTodo } from "../src/session-todo" +import { optional } from "../src/schema" + +describe("contract hygiene", () => { + test("optional properties preserve transformations and omit undefined while encoding", () => { + const Value = Schema.Struct({ value: optional(Schema.FiniteFromString) }) + expect(Schema.decodeUnknownSync(Value)({ value: "1" })).toEqual({ value: 1 }) + expect(Schema.encodeSync(Value)({ value: 1 })).toEqual({ value: "1" }) + expect(Schema.encodeSync(Value)({ value: undefined })).toEqual({}) + }) + + test("todo status and priority preserve arbitrary strings", () => { + const decode = Schema.decodeUnknownSync(SessionTodo.Info) + expect(decode({ content: "ship", status: "waiting", priority: "urgent" })).toEqual({ + content: "ship", + status: "waiting", + priority: "urgent", + }) + }) + + test("current ID constructors expose create", () => { + expect(Question.ID.create()).toStartWith("que_") + expect(Pty.ID.create()).toStartWith("pty_") + }) + + test("reusable public identifiers are stable and unique", () => { + const identifiers = [ + Agent.Color, + FileSystem.Submatch, + Model.Ref, + Model.Capabilities, + Model.Cost, + Model.Api, + Project.Icon, + Project.Commands, + Project.Time, + Project.Info, + Pty.Info, + Session.ListAnchor, + ].map((schema) => schema.ast.annotations?.identifier) + + expect(identifiers.every((identifier) => typeof identifier === "string")).toBe(true) + expect(new Set(identifiers).size).toBe(identifiers.length) + }) + + test("current source avoids Any and mutable contract wrappers", async () => { + const files = [...new Bun.Glob("*.ts").scanSync(new URL("../src", import.meta.url).pathname)].filter( + (file) => !file.endsWith("-v1.ts"), + ) + const source = await Promise.all( + files.map((file) => Bun.file(new URL(`../src/${file}`, import.meta.url)).text()), + ).then((values) => values.join("\n")) + + expect(source).not.toContain("Schema.Any") + expect(source).not.toContain("Schema.mutable") + }) +}) diff --git a/packages/sdk/js/src/v2/gen/sdk.gen.ts b/packages/sdk/js/src/v2/gen/sdk.gen.ts index 98a0be7b7c6..08e93f02a2b 100644 --- a/packages/sdk/js/src/v2/gen/sdk.gen.ts +++ b/packages/sdk/js/src/v2/gen/sdk.gen.ts @@ -111,6 +111,7 @@ import type { McpRemoteConfig, McpStatusErrors, McpStatusResponses, + ModelRef, MoveSessionDestination, OutputFormat, Part as Part2, @@ -129,10 +130,12 @@ import type { PermissionRuleset, PermissionV2Reply, PermissionV2Source, + ProjectCommands, ProjectCurrentErrors, ProjectCurrentResponses, ProjectDirectoriesErrors, ProjectDirectoriesResponses, + ProjectIcon, ProjectInitGitErrors, ProjectInitGitResponses, ProjectListErrors, @@ -2616,17 +2619,8 @@ export class Project extends HeyApiClient { directory?: string workspace?: string name?: string - icon?: { - url?: string - override?: string - color?: string - } - commands?: { - /** - * Startup script to run when creating a new workspace (worktree) - */ - start?: string - } + icon?: ProjectIcon + commands?: ProjectCommands }, options?: Options, ) { @@ -5471,11 +5465,7 @@ export class Session3 extends HeyApiClient { parameters?: { id?: string agent?: string - model?: { - id: string - providerID: string - variant?: string - } + model?: ModelRef location?: LocationRef }, options?: Options, @@ -5571,11 +5561,7 @@ export class Session3 extends HeyApiClient { public switchModel( parameters: { sessionID: string - model?: { - id: string - providerID: string - variant?: string - } + model?: ModelRef }, options?: Options, ) { diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 2f22dc9e7f0..cab35b9c272 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -835,11 +835,7 @@ export type GlobalEvent = { timestamp: number sessionID: string messageID: string - model: { - id: string - providerID: string - variant?: string - } + model: ModelRef } } | { @@ -923,11 +919,7 @@ export type GlobalEvent = { sessionID: string assistantMessageID: string agent: string - model: { - id: string - providerID: string - variant?: string - } + model: ModelRef snapshot?: string } } @@ -1003,11 +995,7 @@ export type GlobalEvent = { sessionID: string assistantMessageID: string reasoningID: string - providerMetadata?: { - [key: string]: { - [key: string]: unknown - } - } + providerMetadata?: LlmProviderMetadata } } | { @@ -1030,11 +1018,7 @@ export type GlobalEvent = { assistantMessageID: string reasoningID: string text: string - providerMetadata?: { - [key: string]: { - [key: string]: unknown - } - } + providerMetadata?: LlmProviderMetadata } } | { @@ -1084,11 +1068,7 @@ export type GlobalEvent = { } provider: { executed: boolean - metadata?: { - [key: string]: { - [key: string]: unknown - } - } + metadata?: LlmProviderMetadata } } } @@ -1103,7 +1083,7 @@ export type GlobalEvent = { structured: { [key: string]: unknown } - content: Array + content: Array } } | { @@ -1117,16 +1097,12 @@ export type GlobalEvent = { structured: { [key: string]: unknown } - content: Array + content: Array outputPaths?: Array result?: unknown provider: { executed: boolean - metadata?: { - [key: string]: { - [key: string]: unknown - } - } + metadata?: LlmProviderMetadata } } } @@ -1142,11 +1118,7 @@ export type GlobalEvent = { result?: unknown provider: { executed: boolean - metadata?: { - [key: string]: { - [key: string]: unknown - } - } + metadata?: LlmProviderMetadata } } } @@ -1198,13 +1170,7 @@ export type GlobalEvent = { properties: { timestamp: number sessionID: string - revert: { - messageID: string - partID?: string - snapshot?: string - diff?: string - files?: Array - } + revert: RevertState } } | { @@ -1516,24 +1482,11 @@ export type GlobalEvent = { properties: { id: string worktree: string - vcs?: "git" + vcs?: ProjectVcs name?: string - icon?: { - url?: string - override?: string - color?: string - } - commands?: { - /** - * Startup script to run when creating a new workspace (worktree) - */ - start?: string - } - time: { - created: number - updated: number - initialized?: number - } + icon?: ProjectIcon + commands?: ProjectCommands + time: ProjectTime sandboxes: Array } } @@ -2466,24 +2419,11 @@ export type McpServerNotFoundError = { export type Project = { id: string worktree: string - vcs?: "git" + vcs?: ProjectVcs name?: string - icon?: { - url?: string - override?: string - color?: string - } - commands?: { - /** - * Startup script to run when creating a new workspace (worktree) - */ - start?: string - } - time: { - created: number - updated: number - initialized?: number - } + icon?: ProjectIcon + commands?: ProjectCommands + time: ProjectTime sandboxes: Array } @@ -2976,6 +2916,12 @@ export type MoveSessionDestination = { directory: string } +export type ModelRef = { + id: string + providerID: string + variant?: string +} + export type LocationRef = { directory: string workspaceID?: string @@ -3005,6 +2951,12 @@ export type SessionErrorUnknown = { message: string } +export type LlmProviderMetadata = { + [key: string]: { + [key: string]: unknown + } +} + export type ToolTextContent = { type: "text" text: string @@ -3017,6 +2969,8 @@ export type ToolFileContent = { name?: string } +export type LlmToolContent = ToolTextContent | ToolFileContent + export type SessionNextRetryError = { message: string statusCode?: number @@ -3038,6 +2992,14 @@ export type FileDiff = { patch: string } +export type RevertState = { + messageID: string + partID?: string + snapshot?: string + diff?: string + files?: Array +} + export type PermissionV2Source = { type: "tool" messageID: string @@ -3081,6 +3043,27 @@ export type QuestionV2Tool = { export type QuestionV2Answer = Array +export type ProjectVcs = "git" + +export type ProjectIcon = { + url?: string + override?: string + color?: string +} + +export type ProjectCommands = { + /** + * Startup script to run when creating a new workspace (worktree) + */ + start?: string +} + +export type ProjectTime = { + created: number + updated: number + initialized?: number +} + export type EventServerInstanceDisposed = { id: string type: "server.instance.disposed" @@ -3225,11 +3208,7 @@ export type SyncEventSessionNextModelSwitched = { timestamp: number sessionID: string messageID: string - model: { - id: string - providerID: string - variant?: string - } + model: ModelRef } } } @@ -3369,11 +3348,7 @@ export type SyncEventSessionNextStepStarted = { sessionID: string assistantMessageID: string agent: string - model: { - id: string - providerID: string - variant?: string - } + model: ModelRef snapshot?: string } } @@ -3473,11 +3448,7 @@ export type SyncEventSessionNextReasoningStarted = { sessionID: string assistantMessageID: string reasoningID: string - providerMetadata?: { - [key: string]: { - [key: string]: unknown - } - } + providerMetadata?: LlmProviderMetadata } } } @@ -3496,11 +3467,7 @@ export type SyncEventSessionNextReasoningEnded = { assistantMessageID: string reasoningID: string text: string - providerMetadata?: { - [key: string]: { - [key: string]: unknown - } - } + providerMetadata?: LlmProviderMetadata } } } @@ -3560,11 +3527,7 @@ export type SyncEventSessionNextToolCalled = { } provider: { executed: boolean - metadata?: { - [key: string]: { - [key: string]: unknown - } - } + metadata?: LlmProviderMetadata } } } @@ -3586,7 +3549,7 @@ export type SyncEventSessionNextToolProgress = { structured: { [key: string]: unknown } - content: Array + content: Array } } } @@ -3607,16 +3570,12 @@ export type SyncEventSessionNextToolSuccess = { structured: { [key: string]: unknown } - content: Array + content: Array outputPaths?: Array result?: unknown provider: { executed: boolean - metadata?: { - [key: string]: { - [key: string]: unknown - } - } + metadata?: LlmProviderMetadata } } } @@ -3639,11 +3598,7 @@ export type SyncEventSessionNextToolFailed = { result?: unknown provider: { executed: boolean - metadata?: { - [key: string]: { - [key: string]: unknown - } - } + metadata?: LlmProviderMetadata } } } @@ -3713,13 +3668,7 @@ export type SyncEventSessionNextRevertStaged = { data: { timestamp: number sessionID: string - revert: { - messageID: string - partID?: string - snapshot?: string - diff?: string - files?: Array - } + revert: RevertState } } } @@ -3781,6 +3730,16 @@ export type ProjectDirectories = Array<{ strategy?: string }> +export type PtyTicketConnectToken = { + ticket: string + expires_in: number +} + +export type WorkspaceEventConnectionStatus = { + workspaceID: string + status: "connected" | "connecting" | "disconnected" | "error" +} + export type LocationInfo = { directory: string workspaceID?: string @@ -3790,6 +3749,17 @@ export type LocationInfo = { } } +export type ProviderRequest = { + headers: { + [key: string]: string + } + body: { + [key: string]: unknown + } +} + +export type AgentColor = string | "primary" | "secondary" | "accent" | "success" | "warning" | "error" | "info" + export type PermissionV2Effect = "allow" | "deny" | "ask" export type PermissionV2Rule = { @@ -3802,24 +3772,13 @@ export type PermissionV2Ruleset = Array export type AgentV2Info = { id: string - model?: { - id: string - providerID: string - variant?: string - } - request: { - headers: { - [key: string]: string - } - body: { - [key: string]: unknown - } - } + model?: ModelRef + request: ProviderRequest system?: string description?: string mode: "subagent" | "primary" | "all" hidden: boolean - color?: string | "primary" | "secondary" | "accent" | "success" | "warning" | "error" | "info" + color?: AgentColor steps?: number permissions: PermissionV2Ruleset } @@ -3829,11 +3788,7 @@ export type SessionV2Info = { parentID?: string projectID: string agent?: string - model?: { - id: string - providerID: string - variant?: string - } + model?: ModelRef cost: number tokens: { input: number @@ -3852,13 +3807,7 @@ export type SessionV2Info = { title: string location: LocationRef subpath?: string - revert?: { - messageID: string - partID?: string - snapshot?: string - diff?: string - files?: Array - } + revert?: RevertState } export type SessionInputAdmitted = { @@ -3892,11 +3841,7 @@ export type SessionMessageModelSwitched = { created: number } type: "model-switched" - model: { - id: string - providerID: string - variant?: string - } + model: ModelRef } export type SessionMessageUser = { @@ -3963,11 +3908,7 @@ export type SessionMessageAssistantReasoning = { type: "reasoning" id: string text: string - providerMetadata?: { - [key: string]: { - [key: string]: unknown - } - } + providerMetadata?: LlmProviderMetadata } export type SessionMessageToolStatePending = { @@ -3983,7 +3924,7 @@ export type SessionMessageToolStateRunning = { structured: { [key: string]: unknown } - content: Array + content: Array } export type SessionMessageToolStateCompleted = { @@ -3992,7 +3933,7 @@ export type SessionMessageToolStateCompleted = { [key: string]: unknown } attachments?: Array - content: Array + content: Array outputPaths?: Array structured: { [key: string]: unknown @@ -4005,7 +3946,7 @@ export type SessionMessageToolStateError = { input: { [key: string]: unknown } - content: Array + content: Array structured: { [key: string]: unknown } @@ -4019,16 +3960,8 @@ export type SessionMessageAssistantTool = { name: string provider?: { executed: boolean - metadata?: { - [key: string]: { - [key: string]: unknown - } - } - resultMetadata?: { - [key: string]: { - [key: string]: unknown - } - } + metadata?: LlmProviderMetadata + resultMetadata?: LlmProviderMetadata } state: | SessionMessageToolStatePending @@ -4054,11 +3987,7 @@ export type SessionMessageAssistant = { } type: "assistant" agent: string - model: { - id: string - providerID: string - variant?: string - } + model: ModelRef content: Array snapshot?: { start?: string @@ -4103,34 +4032,51 @@ export type SessionMessage = | SessionMessageAssistant | SessionMessageCompaction +export type ModelApi = + | { + id: string + type: "aisdk" + package: string + url?: string + settings?: { + [key: string]: unknown + } + } + | { + id: string + type: "native" + url?: string + settings: { + [key: string]: unknown + } + } + +export type ModelCapabilities = { + tools: boolean + input: Array + output: Array +} + +export type ModelCost = { + tier?: { + type: "context" + size: number + } + input: number + output: number + cache: { + read: number + write: number + } +} + export type ModelV2Info = { id: string providerID: string family?: string name: string - api: - | { - id: string - type: "aisdk" - package: string - url?: string - settings?: { - [key: string]: unknown - } - } - | { - id: string - type: "native" - url?: string - settings: { - [key: string]: unknown - } - } - capabilities: { - tools: boolean - input: Array - output: Array - } + api: ModelApi + capabilities: ModelCapabilities request: { headers: { [key: string]: string @@ -4152,18 +4098,7 @@ export type ModelV2Info = { time: { released: number } - cost: Array<{ - tier?: { - type: "context" - size: number - } - input: number - output: number - cache: { - read: number - write: number - } - }> + cost: Array status: "alpha" | "beta" | "deprecated" | "active" enabled: boolean limit: { @@ -4173,35 +4108,32 @@ export type ModelV2Info = { } } +export type ProviderAisdk = { + type: "aisdk" + package: string + url?: string + settings?: { + [key: string]: unknown + } +} + +export type ProviderNative = { + type: "native" + url?: string + settings: { + [key: string]: unknown + } +} + +export type ProviderApi = ProviderAisdk | ProviderNative + export type ProviderV2Info = { id: string integrationID?: string name: string disabled?: boolean - api: - | { - type: "aisdk" - package: string - url?: string - settings?: { - [key: string]: unknown - } - } - | { - type: "native" - url?: string - settings: { - [key: string]: unknown - } - } - request: { - headers: { - [key: string]: string - } - body: { - [key: string]: unknown - } - } + api: ProviderApi + request: ProviderRequest } export type IntegrationWhen = { @@ -4278,6 +4210,37 @@ export type IntegrationAttempt = { } } +export type IntegrationAttemptStatus = + | { + status: "pending" + time: { + created: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" + expires: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" + } + } + | { + status: "complete" + time: { + created: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" + expires: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" + } + } + | { + status: "failed" + message: string + time: { + created: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" + expires: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" + } + } + | { + status: "expired" + time: { + created: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" + expires: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" + } + } + export type PermissionV2Request = { id: string sessionID: string @@ -4307,11 +4270,7 @@ export type CommandV2Info = { template: string description?: string agent?: string - model?: { - id: string - providerID: string - variant?: string - } + model?: ModelRef subtask?: boolean } @@ -4555,11 +4514,7 @@ export type V2EventSessionNextModelSwitched = { timestamp: number sessionID: string messageID: string - model: { - id: string - providerID: string - variant?: string - } + model: ModelRef } } @@ -4723,11 +4678,7 @@ export type V2EventSessionNextStepStarted = { sessionID: string assistantMessageID: string agent: string - model: { - id: string - providerID: string - variant?: string - } + model: ModelRef snapshot?: string } } @@ -4863,11 +4814,7 @@ export type V2EventSessionNextReasoningStarted = { sessionID: string assistantMessageID: string reasoningID: string - providerMetadata?: { - [key: string]: { - [key: string]: unknown - } - } + providerMetadata?: LlmProviderMetadata } } @@ -4910,11 +4857,7 @@ export type V2EventSessionNextReasoningEnded = { assistantMessageID: string reasoningID: string text: string - providerMetadata?: { - [key: string]: { - [key: string]: unknown - } - } + providerMetadata?: LlmProviderMetadata } } @@ -5004,11 +4947,7 @@ export type V2EventSessionNextToolCalled = { } provider: { executed: boolean - metadata?: { - [key: string]: { - [key: string]: unknown - } - } + metadata?: LlmProviderMetadata } } } @@ -5033,7 +4972,7 @@ export type V2EventSessionNextToolProgress = { structured: { [key: string]: unknown } - content: Array + content: Array } } @@ -5057,16 +4996,12 @@ export type V2EventSessionNextToolSuccess = { structured: { [key: string]: unknown } - content: Array + content: Array outputPaths?: Array result?: unknown provider: { executed: boolean - metadata?: { - [key: string]: { - [key: string]: unknown - } - } + metadata?: LlmProviderMetadata } } } @@ -5092,11 +5027,7 @@ export type V2EventSessionNextToolFailed = { result?: unknown provider: { executed: boolean - metadata?: { - [key: string]: { - [key: string]: unknown - } - } + metadata?: LlmProviderMetadata } } } @@ -5198,13 +5129,7 @@ export type V2EventSessionNextRevertStaged = { data: { timestamp: number sessionID: string - revert: { - messageID: string - partID?: string - snapshot?: string - diff?: string - files?: Array - } + revert: RevertState } } @@ -5846,24 +5771,11 @@ export type V2EventProjectUpdated = { data: { id: string worktree: string - vcs?: "git" + vcs?: ProjectVcs name?: string - icon?: { - url?: string - override?: string - color?: string - } - commands?: { - /** - * Startup script to run when creating a new workspace (worktree) - */ - start?: string - } - time: { - created: number - updated: number - initialized?: number - } + icon?: ProjectIcon + commands?: ProjectCommands + time: ProjectTime sandboxes: Array } } @@ -6150,12 +6062,14 @@ export type ReferenceGitSource = { hidden?: boolean } +export type ReferenceSource = ReferenceLocalSource | ReferenceGitSource + export type ReferenceInfo = { name: string path: string description?: string hidden?: boolean - source: ReferenceLocalSource | ReferenceGitSource + source: ReferenceSource } export type ProjectCopyCopy = { @@ -6277,11 +6191,7 @@ export type EventSessionNextModelSwitched = { timestamp: number sessionID: string messageID: string - model: { - id: string - providerID: string - variant?: string - } + model: ModelRef } } @@ -6373,11 +6283,7 @@ export type EventSessionNextStepStarted = { sessionID: string assistantMessageID: string agent: string - model: { - id: string - providerID: string - variant?: string - } + model: ModelRef snapshot?: string } } @@ -6459,11 +6365,7 @@ export type EventSessionNextReasoningStarted = { sessionID: string assistantMessageID: string reasoningID: string - providerMetadata?: { - [key: string]: { - [key: string]: unknown - } - } + providerMetadata?: LlmProviderMetadata } } @@ -6488,11 +6390,7 @@ export type EventSessionNextReasoningEnded = { assistantMessageID: string reasoningID: string text: string - providerMetadata?: { - [key: string]: { - [key: string]: unknown - } - } + providerMetadata?: LlmProviderMetadata } } @@ -6546,11 +6444,7 @@ export type EventSessionNextToolCalled = { } provider: { executed: boolean - metadata?: { - [key: string]: { - [key: string]: unknown - } - } + metadata?: LlmProviderMetadata } } } @@ -6566,7 +6460,7 @@ export type EventSessionNextToolProgress = { structured: { [key: string]: unknown } - content: Array + content: Array } } @@ -6581,16 +6475,12 @@ export type EventSessionNextToolSuccess = { structured: { [key: string]: unknown } - content: Array + content: Array outputPaths?: Array result?: unknown provider: { executed: boolean - metadata?: { - [key: string]: { - [key: string]: unknown - } - } + metadata?: LlmProviderMetadata } } } @@ -6607,11 +6497,7 @@ export type EventSessionNextToolFailed = { result?: unknown provider: { executed: boolean - metadata?: { - [key: string]: { - [key: string]: unknown - } - } + metadata?: LlmProviderMetadata } } } @@ -6668,13 +6554,7 @@ export type EventSessionNextRevertStaged = { properties: { timestamp: number sessionID: string - revert: { - messageID: string - partID?: string - snapshot?: string - diff?: string - files?: Array - } + revert: RevertState } } @@ -6964,24 +6844,11 @@ export type EventProjectUpdated = { properties: { id: string worktree: string - vcs?: "git" + vcs?: ProjectVcs name?: string - icon?: { - url?: string - override?: string - color?: string - } - commands?: { - /** - * Startup script to run when creating a new workspace (worktree) - */ - start?: string - } - time: { - created: number - updated: number - initialized?: number - } + icon?: ProjectIcon + commands?: ProjectCommands + time: ProjectTime sandboxes: Array } } @@ -8847,17 +8714,8 @@ export type ProjectInitGitResponse = ProjectInitGitResponses[keyof ProjectInitGi export type ProjectUpdateData = { body?: { name?: string - icon?: { - url?: string - override?: string - color?: string - } - commands?: { - /** - * Startup script to run when creating a new workspace (worktree) - */ - start?: string - } + icon?: ProjectIcon + commands?: ProjectCommands } path: { projectID: string @@ -9194,10 +9052,7 @@ export type PtyConnectTokenResponses = { /** * WebSocket connect token */ - 200: { - ticket: string - expires_in: number - } + 200: PtyTicketConnectToken } export type PtyConnectTokenResponse = PtyConnectTokenResponses[keyof PtyConnectTokenResponses] @@ -11222,10 +11077,7 @@ export type ExperimentalWorkspaceStatusResponses = { /** * Workspace status */ - 200: Array<{ - workspaceID: string - status: "connected" | "connecting" | "disconnected" | "error" - }> + 200: Array } export type ExperimentalWorkspaceStatusResponse = @@ -11447,11 +11299,7 @@ export type V2SessionCreateData = { body: { id?: string agent?: string - model?: { - id: string - providerID: string - variant?: string - } + model?: ModelRef location?: LocationRef } path?: never @@ -11559,11 +11407,7 @@ export type V2SessionSwitchAgentResponse = V2SessionSwitchAgentResponses[keyof V export type V2SessionSwitchModelData = { body: { - model: { - id: string - providerID: string - variant?: string - } + model: ModelRef } path: { sessionID: string @@ -11760,13 +11604,7 @@ export type V2SessionRevertStageResponses = { * Success */ 200: { - data: { - messageID: string - partID?: string - snapshot?: string - diff?: string - files?: Array - } + data: RevertState } } @@ -12293,36 +12131,7 @@ export type V2IntegrationAttemptStatusResponses = { */ 200: { location: LocationInfo - data: - | { - status: "pending" - time: { - created: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" - expires: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" - } - } - | { - status: "complete" - time: { - created: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" - expires: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" - } - } - | { - status: "failed" - message: string - time: { - created: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" - expires: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" - } - } - | { - status: "expired" - time: { - created: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" - expires: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" - } - } + data: IntegrationAttemptStatus } } @@ -13180,10 +12989,7 @@ export type V2PtyConnectTokenResponses = { */ 200: { location: LocationInfo - data: { - ticket: string - expires_in: number - } + data: PtyTicketConnectToken } }