diff --git a/packages/core/src/plugin.ts b/packages/core/src/plugin.ts index af3559189c..95b6357571 100644 --- a/packages/core/src/plugin.ts +++ b/packages/core/src/plugin.ts @@ -1,8 +1,8 @@ export * as PluginV2 from "./plugin" import { Context, Deferred, Effect, Exit, Layer, Scope } from "effect" -import type { Plugin } from "@opencode-ai/plugin/v2/effect" -import { PluginEvent, PluginID } from "@opencode-ai/schema/plugin" +import type { Plugin as PluginRuntime } from "@opencode-ai/plugin/v2/effect" +import { Plugin } from "@opencode-ai/schema/plugin" import { AgentV2 } from "./agent" import { AISDK } from "./aisdk" import { Catalog } from "./catalog" @@ -15,13 +15,12 @@ import { Reference } from "./reference" import { SkillV2 } from "./skill" import { State } from "./state" -export const ID = PluginID +export const ID = Plugin.ID export type ID = typeof ID.Type - -export const Event = PluginEvent +export const Event = Plugin.Event export interface Interface { - readonly add: (id: ID, effect: Plugin["effect"]) => Effect.Effect + readonly add: (id: ID, effect: PluginRuntime["effect"]) => Effect.Effect readonly remove: (id: ID) => Effect.Effect readonly wait: (id: ID) => Effect.Effect } @@ -38,9 +37,9 @@ export const layer = Layer.effect( const loading = new Set() const waiters = new Map>>() const failures = new Map>() - let host: Parameters[0] + let host: Parameters[0] - const add = Effect.fn("Plugin.add")(function* (id: ID, effect: Plugin["effect"]) { + const add = Effect.fn("Plugin.add")(function* (id: ID, effect: PluginRuntime["effect"]) { if (loading.has(id)) return yield* Effect.die(`Plugin load cycle detected for ${id}`) yield* locks.withLock(id)( diff --git a/packages/core/src/project/copy.ts b/packages/core/src/project/copy.ts index 2a8000ada3..dbaf77f4a5 100644 --- a/packages/core/src/project/copy.ts +++ b/packages/core/src/project/copy.ts @@ -13,7 +13,7 @@ import { Slug } from "../util/slug" import { EventV2 } from "../event" import { Database } from "../database/database" import { Location } from "../location" -import { ProjectDirectoriesEvent } from "@opencode-ai/schema/project-directories" +import { Event } from "@opencode-ai/schema/project-directories" import { ProjectCopy } from "@opencode-ai/schema/project-copy" export const StrategyID = ProjectCopy.StrategyID @@ -96,7 +96,7 @@ export interface Strategy { readonly list: (directory: AbsolutePath) => Effect.Effect } -export const Event = ProjectDirectoriesEvent +export { Event } export interface Interface { readonly register: (strategy: Strategy) => Effect.Effect diff --git a/packages/core/src/project/directories.ts b/packages/core/src/project/directories.ts index 7c0522107a..46408bc5c7 100644 --- a/packages/core/src/project/directories.ts +++ b/packages/core/src/project/directories.ts @@ -4,7 +4,7 @@ import { and, asc, desc, eq, isNotNull, isNull, ne, or } from "drizzle-orm" import { Context, Effect, Layer, Schema } from "effect" import { Database } from "../database/database" import { LayerNode } from "../effect/layer-node" -import { AbsolutePath, optionalOmitUndefined } from "../schema" +import { AbsolutePath, optional } from "../schema" import { ProjectSchema } from "./schema" import { ProjectDirectoryTable } from "./sql" import type { EffectDrizzleSqlite } from "@opencode-ai/effect-drizzle-sqlite" @@ -39,7 +39,7 @@ export type ListInput = typeof ListInput.Type export const ListOutput = Schema.Array( Schema.Struct({ directory: AbsolutePath, - strategy: optionalOmitUndefined(Schema.String), + strategy: optional(Schema.String), }), ).annotate({ identifier: "Project.Directories" }) export type ListOutput = typeof ListOutput.Type diff --git a/packages/core/src/pty.ts b/packages/core/src/pty.ts index b0b2077264..9c5d2455a6 100644 --- a/packages/core/src/pty.ts +++ b/packages/core/src/pty.ts @@ -2,7 +2,7 @@ export * as Pty from "./pty" import type { Disp, Proc } from "#pty" import { Context, Effect, Layer, Schema, Types } from "effect" -import { PtyEvent, PtyInfo, Pty } from "@opencode-ai/schema/pty" +import { Pty } from "@opencode-ai/schema/pty" import { Config } from "./config" import { EventV2 } from "./event" import { Location } from "./location" @@ -35,8 +35,7 @@ type Active = { listeners: Disp[] } -export const Info = PtyInfo - +export const Info = Pty.Info export type Info = Types.DeepMutable export const CreateInput = Pty.CreateInput @@ -47,6 +46,8 @@ export const UpdateInput = Pty.UpdateInput export type UpdateInput = Types.DeepMutable +export const Event = Pty.Event + export type AttachInput = { // Absolute output cursor to replay from. -1 tails from the current end; omitted replays the full retained buffer. readonly cursor?: number @@ -75,8 +76,6 @@ export class ExitedError extends Schema.TaggedErrorClass()("Pty.Exi ptyID: PtyID, }) {} -export const Event = PtyEvent - export interface Interface { readonly list: () => Effect.Effect readonly get: (id: PtyID) => Effect.Effect diff --git a/packages/core/src/schema.ts b/packages/core/src/schema.ts index 0412c7df46..4420ec2639 100644 --- a/packages/core/src/schema.ts +++ b/packages/core/src/schema.ts @@ -3,20 +3,20 @@ import { AbsolutePath, DateTimeUtcFromMillis, NonNegativeInt, - optionalOmitUndefined, + optional, PositiveInt, RelativePath, - withStatics, + statics, } from "@opencode-ai/schema/schema" export { AbsolutePath, DateTimeUtcFromMillis, NonNegativeInt, - optionalOmitUndefined, + optional, PositiveInt, RelativePath, - withStatics, + statics, } /** diff --git a/packages/core/src/session/context-epoch.ts b/packages/core/src/session/context-epoch.ts index f06b69cd51..65b17a86a4 100644 --- a/packages/core/src/session/context-epoch.ts +++ b/packages/core/src/session/context-epoch.ts @@ -9,7 +9,7 @@ import { ContextSnapshotDecodeError } from "./error" import { SessionEvent } from "./event" import { SessionHistory } from "./history" import { SessionInput } from "./input" -import { SessionMessageID } from "./message-id" +import { SessionMessage } from "./message" import { SessionSchema } from "./schema" import { SessionContextEpochTable } from "./sql" @@ -71,7 +71,7 @@ const prepareOnce = Effect.fnUntraced(function* ( yield* events.publish( SessionEvent.ContextUpdated, - { sessionID, messageID: SessionMessageID.ID.create(), timestamp: yield* DateTime.now, text: result.text }, + { sessionID, messageID: SessionMessage.ID.create(), timestamp: yield* DateTime.now, text: result.text }, { commit: () => advance(db, sessionID, result.snapshot).pipe(Effect.orDie) }, ) return { baseline: stored.baseline, baselineSeq: stored.baseline_seq } diff --git a/packages/core/src/session/info.ts b/packages/core/src/session/info.ts index 087cc29ead..66832750fd 100644 --- a/packages/core/src/session/info.ts +++ b/packages/core/src/session/info.ts @@ -8,7 +8,7 @@ import { AbsolutePath, RelativePath } from "../schema" import { WorkspaceV2 } from "../workspace" import { SessionSchema } from "./schema" import { SessionTable } from "./sql" -import { SessionMessageID } from "./message-id" +import { SessionMessage } from "./message" import { Snapshot } from "../snapshot" export function fromRow(row: typeof SessionTable.$inferSelect): SessionSchema.Info { @@ -40,7 +40,7 @@ export function fromRow(row: typeof SessionTable.$inferSelect): SessionSchema.In workspaceID: row.workspace_id ? WorkspaceV2.ID.make(row.workspace_id) : undefined, }), subpath: row.path ? RelativePath.make(row.path) : undefined, - revert: row.revert ? { ...row.revert, messageID: SessionMessageID.ID.make(row.revert.messageID) } : undefined, + revert: row.revert ? { ...row.revert, messageID: SessionMessage.ID.make(row.revert.messageID) } : undefined, time: { created: DateTime.makeUnsafe(row.time_created), updated: DateTime.makeUnsafe(row.time_updated), diff --git a/packages/core/src/session/message-id.ts b/packages/core/src/session/message-id.ts deleted file mode 100644 index 75c871c0b3..0000000000 --- a/packages/core/src/session/message-id.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * as SessionMessageID from "./message-id" -export { ID } from "@opencode-ai/schema/session-message-id" diff --git a/packages/core/src/session/projector.ts b/packages/core/src/session/projector.ts index 326b1bbddb..453608eafb 100644 --- a/packages/core/src/session/projector.ts +++ b/packages/core/src/session/projector.ts @@ -15,7 +15,6 @@ import { WorkspaceV2 } from "../workspace" import { SessionContextEpoch } from "./context-epoch" import { MessageTable, PartTable, SessionInputTable, SessionMessageTable, SessionTable } from "./sql" import type { DeepMutable } from "../schema" -import { SessionMessageID } from "./message-id" type DatabaseService = Database.Interface["db"] @@ -67,7 +66,7 @@ function sessionRow(info: SessionV1.SessionInfo): typeof SessionTable.$inferInse tokens_reasoning: (info.tokens ?? { reasoning: 0 }).reasoning, tokens_cache_read: (info.tokens ?? { cache: { read: 0 } }).cache.read, tokens_cache_write: (info.tokens ?? { cache: { write: 0 } }).cache.write, - revert: info.revert ? { ...info.revert, messageID: SessionMessageID.ID.make(info.revert.messageID) } : null, + revert: info.revert ? { ...info.revert, messageID: SessionMessage.ID.make(info.revert.messageID) } : null, permission: info.permission ? [...info.permission] : undefined, time_created: info.time.created, time_updated: info.time.updated, diff --git a/packages/core/src/session/todo.ts b/packages/core/src/session/todo.ts index 95420f78f7..c5ad70afad 100644 --- a/packages/core/src/session/todo.ts +++ b/packages/core/src/session/todo.ts @@ -2,15 +2,14 @@ export * as SessionTodo from "./todo" import { asc, eq } from "drizzle-orm" import { Context, Effect, Layer } from "effect" -import { SessionTodo, SessionTodoInfo } from "@opencode-ai/schema/session-todo" +import { SessionTodo } from "@opencode-ai/schema/session-todo" import { Database } from "../database/database" import { EventV2 } from "../event" import { SessionSchema } from "./schema" import { TodoTable } from "./sql" -export const Info = SessionTodoInfo +export const Info = SessionTodo.Info export type Info = typeof Info.Type - export const Event = SessionTodo.Event export interface Interface { diff --git a/packages/core/test/shared-schema.test.ts b/packages/core/test/shared-schema.test.ts index 81b813a878..959024cd4a 100644 --- a/packages/core/test/shared-schema.test.ts +++ b/packages/core/test/shared-schema.test.ts @@ -9,6 +9,8 @@ import { Model } from "@opencode-ai/schema/model" import { AgentAttachment, FileAttachment, Prompt, Source } from "@opencode-ai/schema/prompt" import { Provider } from "@opencode-ai/schema/provider" import { Project } from "@opencode-ai/schema/project" +import { ProjectDirectories } from "@opencode-ai/schema/project-directories" +import { PermissionV1 } from "@opencode-ai/schema/permission-v1" import { Session } from "@opencode-ai/schema/session" import { SessionInput } from "@opencode-ai/schema/session-input" import { SessionMessage } from "@opencode-ai/schema/session-message" @@ -20,10 +22,14 @@ import { FileSystem } from "@opencode-ai/schema/filesystem" import { Integration } from "@opencode-ai/schema/integration" import { LLM } from "@opencode-ai/schema/llm" import { Permission } from "@opencode-ai/schema/permission" +import { Plugin } from "@opencode-ai/schema/plugin" +import { Pty } from "@opencode-ai/schema/pty" import { Reference } from "@opencode-ai/schema/reference" +import { SessionTodo } from "@opencode-ai/schema/session-todo" import { Skill } from "@opencode-ai/schema/skill" -import { AbsolutePath, DateTimeUtcFromMillis } from "@opencode-ai/schema/schema" +import { AbsolutePath, DateTimeUtcFromMillis, optional, statics } from "@opencode-ai/schema/schema" import { ProviderV2 } from "@opencode-ai/core/provider" +import { PluginV2 } from "@opencode-ai/core/plugin" test("Core reuses the canonical shared schemas", async () => { const [ @@ -35,13 +41,18 @@ test("Core reuses the canonical shared schemas", async () => { coreLocation, coreLLM, corePermission, + corePermissionV1, + coreProjectCopy, + corePty, coreProject, coreReference, coreSessionInput, coreSessionMessage, + coreSessionTodo, corePrompt, coreSkill, coreV2Schema, + coreSchema, coreWorkspace, ] = await Promise.all([ import("@opencode-ai/core/command"), @@ -52,13 +63,18 @@ test("Core reuses the canonical shared schemas", async () => { import("@opencode-ai/core/location"), import("@opencode-ai/llm"), import("@opencode-ai/core/permission"), + import("@opencode-ai/core/v1/permission"), + import("@opencode-ai/core/project/copy"), + import("@opencode-ai/core/pty"), import("@opencode-ai/core/project/schema"), import("@opencode-ai/core/reference"), import("@opencode-ai/core/session/input"), import("@opencode-ai/core/session/message"), + import("@opencode-ai/core/session/todo"), import("@opencode-ai/core/session/prompt"), import("@opencode-ai/core/skill"), import("@opencode-ai/core/v2-schema"), + import("@opencode-ai/core/schema"), import("@opencode-ai/core/workspace"), ]) @@ -111,6 +127,12 @@ test("Core reuses the canonical shared schemas", async () => { [corePermission.Effect, Permission.Effect], [corePermission.Rule, Permission.Rule], [corePermission.Ruleset, Permission.Ruleset], + [corePermissionV1.Event, PermissionV1.Event], + [coreProjectCopy.Event, ProjectDirectories.Event], + [PluginV2.ID, Plugin.ID], + [PluginV2.Event, Plugin.Event], + [corePty.Info, Pty.Info], + [corePty.Event, Pty.Event], [coreProject.ID, Project.ID], [coreReference.LocalSource, Reference.LocalSource], [coreReference.GitSource, Reference.GitSource], @@ -140,6 +162,8 @@ test("Core reuses the canonical shared schemas", async () => { [coreSessionMessage.Assistant, SessionMessage.Assistant], [coreSessionMessage.Compaction, SessionMessage.Compaction], [coreSessionMessage.Message, SessionMessage.Message], + [coreSessionTodo.Info, SessionTodo.Info], + [coreSessionTodo.Event, SessionTodo.Event], [corePrompt.Source, Source], [corePrompt.FileAttachment, FileAttachment], [corePrompt.AgentAttachment, AgentAttachment], @@ -150,6 +174,8 @@ test("Core reuses the canonical shared schemas", async () => { [coreSkill.Source, Skill.Source], [coreSkill.Info, Skill.Info], [coreV2Schema.DateTimeUtcFromMillis, DateTimeUtcFromMillis], + [coreSchema.optional, optional], + [coreSchema.statics, statics], [coreWorkspace.ID, Workspace.ID], ] for (const [core, shared] of schemas) expect(core).toBe(shared) diff --git a/packages/opencode/src/permission/index.ts b/packages/opencode/src/permission/index.ts index 92f236594c..d8e92b2a34 100644 --- a/packages/opencode/src/permission/index.ts +++ b/packages/opencode/src/permission/index.ts @@ -6,9 +6,8 @@ import { Deferred, Effect, Layer, Context } from "effect" import os from "os" import { PermissionV1 } from "@opencode-ai/core/v1/permission" import { EventV2Bridge } from "@/event-v2-bridge" -import { PermissionV1Event } from "@opencode-ai/schema/permission-v1" -export const Event = PermissionV1Event +export const Event = PermissionV1.Event export interface Interface { readonly ask: (input: PermissionV1.AskInput) => Effect.Effect diff --git a/packages/opencode/src/provider/auth.ts b/packages/opencode/src/provider/auth.ts index c429c8fcfb..e7e7495804 100644 --- a/packages/opencode/src/provider/auth.ts +++ b/packages/opencode/src/provider/auth.ts @@ -3,7 +3,7 @@ import type { AuthOAuthResult, Hooks } from "@opencode-ai/plugin" import { serviceUse } from "@opencode-ai/core/effect/service-use" import { Auth } from "@/auth" import { InstanceState } from "@/effect/instance-state" -import { optionalOmitUndefined } from "@opencode-ai/core/schema" +import { optional } from "@opencode-ai/core/schema" import { Plugin } from "../plugin" import { ProviderV2 } from "@opencode-ai/core/provider" import { Array as Arr, Effect, Layer, Record, Result, Context, Schema } from "effect" @@ -18,14 +18,14 @@ const TextPrompt = Schema.Struct({ type: Schema.Literal("text"), key: Schema.String, message: Schema.String, - placeholder: optionalOmitUndefined(Schema.String), - when: optionalOmitUndefined(When), + placeholder: optional(Schema.String), + when: optional(When), }) const SelectOption = Schema.Struct({ label: Schema.String, value: Schema.String, - hint: optionalOmitUndefined(Schema.String), + hint: optional(Schema.String), }) const SelectPrompt = Schema.Struct({ @@ -33,7 +33,7 @@ const SelectPrompt = Schema.Struct({ key: Schema.String, message: Schema.String, options: Schema.Array(SelectOption), - when: optionalOmitUndefined(When), + when: optional(When), }) const Prompt = Schema.Union([TextPrompt, SelectPrompt]) @@ -41,7 +41,7 @@ const Prompt = Schema.Union([TextPrompt, SelectPrompt]) export class Method extends Schema.Class("ProviderAuthMethod")({ type: Schema.Literals(["oauth", "api"]), label: Schema.String, - prompts: optionalOmitUndefined(Schema.Array(Prompt)), + prompts: optional(Schema.Array(Prompt)), }) {} export const Methods = Schema.Record(Schema.String, Schema.Array(Method)) diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index 088aa2fd76..0b68cd4318 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -24,7 +24,7 @@ import { InstanceState } from "@/effect/instance-state" import { EffectPromise } from "@/effect/promise" import { FSUtil } from "@opencode-ai/core/fs-util" import { isRecord } from "@/util/record" -import { optionalOmitUndefined } from "@opencode-ai/core/schema" +import { optional } from "@opencode-ai/core/schema" import { ProviderTransform } from "./transform" import { ProviderV2 } from "@opencode-ai/core/provider" import { ModelV2 } from "@opencode-ai/core/model" @@ -999,8 +999,8 @@ const ProviderCost = Schema.Struct({ input: Schema.Finite, output: Schema.Finite, cache: ProviderCacheCost, - tiers: optionalOmitUndefined(Schema.Array(ProviderCostTier)), - experimentalOver200K: optionalOmitUndefined( + tiers: optional(Schema.Array(ProviderCostTier)), + experimentalOver200K: optional( Schema.Struct({ input: Schema.Finite, output: Schema.Finite, @@ -1011,7 +1011,7 @@ const ProviderCost = Schema.Struct({ const ProviderLimit = Schema.Struct({ context: Schema.Finite, - input: optionalOmitUndefined(Schema.Finite), + input: optional(Schema.Finite), output: Schema.Finite, }) @@ -1020,7 +1020,7 @@ export const Model = Schema.Struct({ providerID: ProviderV2.ID, api: ProviderApiInfo, name: Schema.String, - family: optionalOmitUndefined(Schema.String), + family: optional(Schema.String), capabilities: ProviderCapabilities, cost: ProviderCost, limit: ProviderLimit, @@ -1028,7 +1028,7 @@ export const Model = Schema.Struct({ options: Schema.Record(Schema.String, Schema.Any), headers: Schema.Record(Schema.String, Schema.String), release_date: Schema.String, - variants: optionalOmitUndefined(Schema.Record(Schema.String, Schema.Record(Schema.String, Schema.Any))), + variants: optional(Schema.Record(Schema.String, Schema.Record(Schema.String, Schema.Any))), }).annotate({ identifier: "Model" }) export type Model = Types.DeepMutable> @@ -1037,7 +1037,7 @@ export const Info = Schema.Struct({ name: Schema.String, source: Schema.Literals(["env", "config", "custom", "api"]), env: Schema.Array(Schema.String), - key: optionalOmitUndefined(Schema.String), + key: optional(Schema.String), options: Schema.Record(Schema.String, Schema.Any), models: Schema.Record(Schema.String, Model), }).annotate({ identifier: "Provider" }) diff --git a/packages/opencode/src/session/schema.ts b/packages/opencode/src/session/schema.ts index 4a49d110c8..162c2a4f45 100644 --- a/packages/opencode/src/session/schema.ts +++ b/packages/opencode/src/session/schema.ts @@ -2,14 +2,14 @@ import { Schema } from "effect" import { Identifier } from "@/id/id" import { SessionV2 } from "@opencode-ai/core/session" -import { withStatics } from "@opencode-ai/core/schema" +import { statics } from "@opencode-ai/core/schema" export const SessionID = SessionV2.ID export type SessionID = Schema.Schema.Type export const MessageID = Schema.String.check(Schema.isStartsWith("msg")).pipe( Schema.brand("MessageID"), - withStatics((s) => ({ + statics((s) => ({ ascending: (id?: string) => s.make(Identifier.ascending("message", id)), })), ) @@ -18,7 +18,7 @@ export type MessageID = Schema.Schema.Type export const PartID = Schema.String.check(Schema.isStartsWith("prt")).pipe( Schema.brand("PartID"), - withStatics((s) => ({ + statics((s) => ({ ascending: (id?: string) => s.make(Identifier.ascending("part", id)), })), ) diff --git a/packages/opencode/src/session/session.ts b/packages/opencode/src/session/session.ts index 2d13c2e2f3..4f36a8ea0a 100644 --- a/packages/opencode/src/session/session.ts +++ b/packages/opencode/src/session/session.ts @@ -39,11 +39,11 @@ import { SessionID, MessageID, PartID } from "./schema" import type { Provider } from "@/provider/provider" import { Global } from "@opencode-ai/core/global" import { Effect, Layer, Option, Context, Schema, Types } from "effect" -import { NonNegativeInt, optionalOmitUndefined } from "@opencode-ai/core/schema" +import { NonNegativeInt, optional } from "@opencode-ai/core/schema" import { RuntimeFlags } from "@/effect/runtime-flags" import { ProviderV2 } from "@opencode-ai/core/provider" import { ModelV2 } from "@opencode-ai/core/model" -import { SessionMessageID } from "@opencode-ai/schema/session-message-id" +import { SessionMessage } from "@opencode-ai/schema/session-message" const runtime = makeRuntime(Database.Service, Database.defaultLayer) @@ -146,7 +146,7 @@ export function toRow(info: Info) { tokens_cache_write: (info.tokens ?? EmptyTokens).cache.write, revert: info.revert ? { - messageID: SessionMessageID.ID.make(info.revert.messageID), + messageID: SessionMessage.ID.make(info.revert.messageID), partID: info.revert.partID, snapshot: info.revert.snapshot, diff: info.revert.diff, @@ -178,7 +178,7 @@ const Summary = Schema.Struct({ additions: Schema.Finite, deletions: Schema.Finite, files: Schema.Finite, - diffs: optionalOmitUndefined(Schema.Array(Snapshot.FileDiff)), + diffs: optional(Schema.Array(Snapshot.FileDiff)), }) const Tokens = Schema.Struct({ @@ -204,21 +204,21 @@ export const ArchivedTimestamp = Schema.Finite const Time = Schema.Struct({ created: NonNegativeInt, updated: NonNegativeInt, - compacting: optionalOmitUndefined(NonNegativeInt), - archived: optionalOmitUndefined(ArchivedTimestamp), + compacting: optional(NonNegativeInt), + archived: optional(ArchivedTimestamp), }) const Revert = Schema.Struct({ messageID: MessageID, - partID: optionalOmitUndefined(PartID), - snapshot: optionalOmitUndefined(Schema.String), - diff: optionalOmitUndefined(Schema.String), + partID: optional(PartID), + snapshot: optional(Schema.String), + diff: optional(Schema.String), }) const Model = Schema.Struct({ id: ModelV2.ID, providerID: ProviderV2.ID, - variant: optionalOmitUndefined(Schema.String), + variant: optional(Schema.String), }) export const Metadata = Schema.Record(Schema.String, Schema.Any) @@ -227,28 +227,28 @@ export const Info = Schema.Struct({ id: SessionID, slug: Schema.String, projectID: ProjectV2.ID, - workspaceID: optionalOmitUndefined(WorkspaceV2.ID), + workspaceID: optional(WorkspaceV2.ID), directory: Schema.String, - path: optionalOmitUndefined(Schema.String), - parentID: optionalOmitUndefined(SessionID), - summary: optionalOmitUndefined(Summary), - cost: optionalOmitUndefined(Schema.Finite), - tokens: optionalOmitUndefined(Tokens), - share: optionalOmitUndefined(Share), + path: optional(Schema.String), + parentID: optional(SessionID), + summary: optional(Summary), + cost: optional(Schema.Finite), + tokens: optional(Tokens), + share: optional(Share), title: Schema.String, - agent: optionalOmitUndefined(Schema.String), - model: optionalOmitUndefined(Model), + agent: optional(Schema.String), + model: optional(Model), version: Schema.String, - metadata: optionalOmitUndefined(Metadata), + metadata: optional(Metadata), time: Time, - permission: optionalOmitUndefined(PermissionV1.Ruleset), - revert: optionalOmitUndefined(Revert), + permission: optional(PermissionV1.Ruleset), + revert: optional(Revert), }).annotate({ identifier: "Session" }) export type Info = Types.DeepMutable> export const ProjectInfo = Schema.Struct({ id: ProjectV2.ID, - name: optionalOmitUndefined(Schema.String), + name: optional(Schema.String), worktree: Schema.String, }).annotate({ identifier: "ProjectSummary" }) export type ProjectInfo = Types.DeepMutable> diff --git a/packages/opencode/src/sync/schema.ts b/packages/opencode/src/sync/schema.ts index 4ff9d2fc33..39b9b92b45 100644 --- a/packages/opencode/src/sync/schema.ts +++ b/packages/opencode/src/sync/schema.ts @@ -1,11 +1,11 @@ import { Schema } from "effect" import { Identifier } from "@/id/id" -import { withStatics } from "@opencode-ai/core/schema" +import { statics } from "@opencode-ai/core/schema" export const EventID = Schema.String.check(Schema.isStartsWith("evt")).pipe( Schema.brand("EventID"), - withStatics((s) => ({ + statics((s) => ({ ascending: (id?: string) => s.make(Identifier.ascending("event", id)), })), ) diff --git a/packages/opencode/src/tool/schema.ts b/packages/opencode/src/tool/schema.ts index cdeadb74d6..c83444866e 100644 --- a/packages/opencode/src/tool/schema.ts +++ b/packages/opencode/src/tool/schema.ts @@ -1,14 +1,14 @@ import { Schema } from "effect" import { Identifier } from "@/id/id" -import { withStatics } from "@opencode-ai/core/schema" +import { statics } from "@opencode-ai/core/schema" const toolIdSchema = Schema.String.check(Schema.isStartsWith("tool")).pipe(Schema.brand("ToolID")) export type ToolID = typeof toolIdSchema.Type export const ToolID = toolIdSchema.pipe( - withStatics((schema: typeof toolIdSchema) => ({ + statics((schema: typeof toolIdSchema) => ({ ascending: (id?: string) => schema.make(Identifier.ascending("tool", id)), })), ) diff --git a/packages/protocol/src/groups/session.ts b/packages/protocol/src/groups/session.ts index dba39e765d..431deb860e 100644 --- a/packages/protocol/src/groups/session.ts +++ b/packages/protocol/src/groups/session.ts @@ -3,7 +3,7 @@ import { SessionInput } from "@opencode-ai/schema/session-input" import { Prompt } from "@opencode-ai/schema/prompt" import { Session } from "@opencode-ai/schema/session" import { Project } from "@opencode-ai/schema/project" -import { AbsolutePath, PositiveInt, RelativePath, withStatics } from "@opencode-ai/schema/schema" +import { AbsolutePath, PositiveInt, RelativePath, statics } from "@opencode-ai/schema/schema" import { Workspace } from "@opencode-ai/schema/workspace" import { Context, Encoding, Result, Schema, Struct } from "effect" import { HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware, HttpApiSchema, OpenApi } from "effect/unstable/httpapi" @@ -62,7 +62,7 @@ const decodeSessionsCursor = Schema.decodeUnknownEffect(SessionsCursorJson) export const SessionsCursor = Schema.String.pipe( Schema.brand("SessionsCursor"), - withStatics((schema) => { + statics((schema) => { const make = schema.make.bind(schema) return { make: (input: typeof SessionsCursorInput.Type) => make(Encoding.encodeBase64Url(encodeSessionsCursor(input))), diff --git a/packages/schema/src/agent.ts b/packages/schema/src/agent.ts index b2e0102efe..65dbb04377 100644 --- a/packages/schema/src/agent.ts +++ b/packages/schema/src/agent.ts @@ -4,7 +4,7 @@ import { Schema } from "effect" import { Model } from "./model" import { Permission } from "./permission" import { Provider } from "./provider" -import { PositiveInt, withStatics } from "./schema" +import { PositiveInt, statics } from "./schema" export const ID = Schema.String.pipe(Schema.brand("AgentV2.ID")) export type ID = typeof ID.Type @@ -30,7 +30,7 @@ export const Info = Schema.Struct({ }) .annotate({ identifier: "AgentV2.Info" }) .pipe( - withStatics((schema) => ({ + statics((schema) => ({ empty: (id: ID) => schema.make({ id, request: { headers: {}, body: {} }, mode: "all", hidden: false, permissions: [] }), })), diff --git a/packages/schema/src/credential.ts b/packages/schema/src/credential.ts index f94046885b..6bfa6276d8 100644 --- a/packages/schema/src/credential.ts +++ b/packages/schema/src/credential.ts @@ -3,11 +3,11 @@ export * as Credential from "./credential" import { Schema } from "effect" import { IntegrationMethodID } from "./integration-id" import { ascending } from "./identifier" -import { NonNegativeInt, withStatics } from "./schema" +import { NonNegativeInt, statics } from "./schema" export const ID = Schema.String.pipe( Schema.brand("Credential.ID"), - withStatics((schema) => ({ create: () => schema.make("cred_" + ascending()) })), + statics((schema) => ({ create: () => schema.make("cred_" + ascending()) })), ) export type ID = typeof ID.Type diff --git a/packages/schema/src/event.ts b/packages/schema/src/event.ts index 58bbd690e6..849ffb8902 100644 --- a/packages/schema/src/event.ts +++ b/packages/schema/src/event.ts @@ -3,11 +3,11 @@ export * as Event from "./event" import { Schema } from "effect" import { ascending } from "./identifier" import { Location } from "./location" -import { withStatics } from "./schema" +import { statics } from "./schema" export const ID = Schema.String.check(Schema.isStartsWith("evt_")).pipe( Schema.brand("Event.ID"), - withStatics((schema) => ({ create: () => schema.make("evt_" + ascending()) })), + statics((schema) => ({ create: () => schema.make("evt_" + ascending()) })), ) export type ID = typeof ID.Type diff --git a/packages/schema/src/integration.ts b/packages/schema/src/integration.ts index 81abfd0ae7..a948422ac0 100644 --- a/packages/schema/src/integration.ts +++ b/packages/schema/src/integration.ts @@ -4,7 +4,7 @@ import { Schema } from "effect" import { define, inventory } from "./event" import { Connection } from "./connection" import { ascending } from "./identifier" -import { withStatics } from "./schema" +import { statics } from "./schema" import { IntegrationID, IntegrationMethodID } from "./integration-id" export const ID = IntegrationID @@ -102,7 +102,7 @@ export class Info extends Schema.Class("Integration.Info")({ export const AttemptID = Schema.String.pipe( Schema.brand("Integration.AttemptID"), - withStatics((schema) => ({ create: () => schema.make("con_" + ascending()) })), + statics((schema) => ({ create: () => schema.make("con_" + ascending()) })), ) export type AttemptID = typeof AttemptID.Type diff --git a/packages/schema/src/location.ts b/packages/schema/src/location.ts index d6832758b0..b9421bfd55 100644 --- a/packages/schema/src/location.ts +++ b/packages/schema/src/location.ts @@ -1,7 +1,7 @@ export * as Location from "./location" import { Effect, Schema } from "effect" -import { AbsolutePath, optionalOmitUndefined } from "./schema" +import { AbsolutePath, optional } from "./schema" import { ProjectID } from "./project-id" import { WorkspaceID } from "./workspace-id" @@ -16,7 +16,7 @@ export const Ref = Schema.Struct({ export class Info extends Schema.Class("Location.Info")({ directory: AbsolutePath, - workspaceID: optionalOmitUndefined(WorkspaceID), + workspaceID: optional(WorkspaceID), project: Schema.Struct({ id: ProjectID, directory: AbsolutePath, diff --git a/packages/schema/src/model.ts b/packages/schema/src/model.ts index a41b540b4d..e6b5823cbc 100644 --- a/packages/schema/src/model.ts +++ b/packages/schema/src/model.ts @@ -2,7 +2,7 @@ export * as Model from "./model" import { Schema } from "effect" import { Provider } from "./provider" -import { withStatics } from "./schema" +import { statics } from "./schema" export const ID = Schema.String.pipe(Schema.brand("ModelV2.ID")) export type ID = typeof ID.Type @@ -83,7 +83,7 @@ export const Info = Schema.Struct({ }) .annotate({ identifier: "ModelV2.Info" }) .pipe( - withStatics((schema) => ({ + statics((schema) => ({ empty: (providerID: Provider.ID, modelID: ID) => schema.make({ id: modelID, diff --git a/packages/schema/src/permission-saved.ts b/packages/schema/src/permission-saved.ts index 927a493069..2815d51f95 100644 --- a/packages/schema/src/permission-saved.ts +++ b/packages/schema/src/permission-saved.ts @@ -3,11 +3,11 @@ export * as PermissionSaved from "./permission-saved" import { Schema } from "effect" import { ascending } from "./identifier" import { ProjectID } from "./project-id" -import { withStatics } from "./schema" +import { statics } from "./schema" export const ID = Schema.String.pipe( Schema.brand("PermissionSaved.ID"), - withStatics((schema) => ({ create: () => schema.make("psv_" + ascending()) })), + statics((schema) => ({ create: () => schema.make("psv_" + ascending()) })), ) export type ID = typeof ID.Type diff --git a/packages/schema/src/permission-v1.ts b/packages/schema/src/permission-v1.ts index d0db4fa940..26cac5950c 100644 --- a/packages/schema/src/permission-v1.ts +++ b/packages/schema/src/permission-v1.ts @@ -4,12 +4,12 @@ import { Schema } from "effect" import { define, inventory } from "./event" import { ascending } from "./identifier" import { Project } from "./project" -import { withStatics } from "./schema" +import { statics } from "./schema" import { SessionID } from "./session-id" export const ID = Schema.String.check(Schema.isStartsWith("per")).pipe( Schema.brand("PermissionID"), - withStatics((schema) => ({ ascending: (id?: string) => schema.make(id ?? "per_" + ascending()) })), + statics((schema) => ({ ascending: (id?: string) => schema.make(id ?? "per_" + ascending()) })), ) export type ID = typeof ID.Type @@ -64,4 +64,3 @@ const Replied = define({ schema: { sessionID: SessionID, requestID: ID, reply: Reply }, }) export const Event = { Asked, Replied, Definitions: inventory(Asked, Replied) } -export const PermissionV1Event = Event diff --git a/packages/schema/src/permission.ts b/packages/schema/src/permission.ts index fc4235a530..733c1e0b9b 100644 --- a/packages/schema/src/permission.ts +++ b/packages/schema/src/permission.ts @@ -4,11 +4,11 @@ import { Schema } from "effect" import { define, inventory } from "./event" import { ascending } from "./identifier" import { SessionID } from "./session-id" -import { withStatics } from "./schema" +import { statics } from "./schema" export const ID = Schema.String.check(Schema.isStartsWith("per")).pipe( Schema.brand("PermissionV2.ID"), - withStatics((schema) => ({ create: (id?: string) => schema.make(id ?? "per_" + ascending()) })), + statics((schema) => ({ create: (id?: string) => schema.make(id ?? "per_" + ascending()) })), ) export type ID = typeof ID.Type diff --git a/packages/schema/src/plugin.ts b/packages/schema/src/plugin.ts index 6202bcd64e..c23f79582e 100644 --- a/packages/schema/src/plugin.ts +++ b/packages/schema/src/plugin.ts @@ -5,11 +5,9 @@ import { define, inventory } from "./event" export const ID = Schema.String.pipe(Schema.brand("Plugin.ID")) export type ID = typeof ID.Type -export const PluginID = ID const Added = define({ type: "plugin.added", schema: { id: ID }, }) export const Event = { Added, Definitions: inventory(Added) } -export const PluginEvent = Event diff --git a/packages/schema/src/project-directories.ts b/packages/schema/src/project-directories.ts index a589a6bd3c..e6cbde8649 100644 --- a/packages/schema/src/project-directories.ts +++ b/packages/schema/src/project-directories.ts @@ -8,4 +8,3 @@ const Updated = define({ schema: { projectID: Project.ID }, }) export const Event = { Updated, Definitions: inventory(Updated) } -export const ProjectDirectoriesEvent = Event diff --git a/packages/schema/src/project-id.ts b/packages/schema/src/project-id.ts index c2590983a0..8d2f061517 100644 --- a/packages/schema/src/project-id.ts +++ b/packages/schema/src/project-id.ts @@ -1,8 +1,8 @@ import { Schema } from "effect" -import { withStatics } from "./schema" +import { statics } from "./schema" export const ProjectID = Schema.String.pipe( Schema.brand("Project.ID"), - withStatics((schema) => ({ global: schema.make("global") })), + statics((schema) => ({ global: schema.make("global") })), ) export type ProjectID = typeof ProjectID.Type diff --git a/packages/schema/src/project.ts b/packages/schema/src/project.ts index bab52f1b9e..6cee635c60 100644 --- a/packages/schema/src/project.ts +++ b/packages/schema/src/project.ts @@ -2,7 +2,7 @@ export * as Project from "./project" import { Schema } from "effect" import { define, inventory } from "./event" -import { NonNegativeInt, optionalOmitUndefined } from "./schema" +import { NonNegativeInt, optional } from "./schema" import { ProjectID } from "./project-id" export const ID = ProjectID @@ -10,28 +10,28 @@ export type ID = typeof ID.Type export const Vcs = Schema.Literal("git") export const Icon = Schema.Struct({ - url: optionalOmitUndefined(Schema.String), - override: optionalOmitUndefined(Schema.String), - color: optionalOmitUndefined(Schema.String), + url: optional(Schema.String), + override: optional(Schema.String), + color: optional(Schema.String), }) export const Commands = Schema.Struct({ - start: optionalOmitUndefined( + start: optional( Schema.String.annotate({ description: "Startup script to run when creating a new workspace (worktree)" }), ), }) export const Time = Schema.Struct({ created: NonNegativeInt, updated: NonNegativeInt, - initialized: optionalOmitUndefined(NonNegativeInt), + initialized: optional(NonNegativeInt), }) export const Info = Schema.Struct({ id: ID, worktree: Schema.String, - vcs: optionalOmitUndefined(Vcs), - name: optionalOmitUndefined(Schema.String), - icon: optionalOmitUndefined(Icon), - commands: optionalOmitUndefined(Commands), + vcs: optional(Vcs), + name: optional(Schema.String), + icon: optional(Icon), + commands: optional(Commands), time: Time, sandboxes: Schema.Array(Schema.String), }).annotate({ identifier: "Project" }) diff --git a/packages/schema/src/prompt.ts b/packages/schema/src/prompt.ts index ac7f4275ff..87441bc01e 100644 --- a/packages/schema/src/prompt.ts +++ b/packages/schema/src/prompt.ts @@ -1,5 +1,5 @@ import { Schema } from "effect" -import { withStatics } from "./schema" +import { statics } from "./schema" export interface Source extends Schema.Schema.Type {} export const Source = Schema.Struct({ @@ -18,7 +18,7 @@ export const FileAttachment = Schema.Struct({ }) .annotate({ identifier: "Prompt.FileAttachment" }) .pipe( - withStatics((schema) => ({ + statics((schema) => ({ create: (input: FileAttachment) => schema.make({ uri: input.uri, @@ -44,7 +44,7 @@ export const Prompt = Schema.Struct({ }) .annotate({ identifier: "Prompt" }) .pipe( - withStatics((schema) => ({ + statics((schema) => ({ equivalence: Schema.toEquivalence(schema), fromUserMessage: (input: Pick) => schema.make({ diff --git a/packages/schema/src/provider.ts b/packages/schema/src/provider.ts index d3d5109608..a18800a4b1 100644 --- a/packages/schema/src/provider.ts +++ b/packages/schema/src/provider.ts @@ -2,11 +2,11 @@ export * as Provider from "./provider" import { Schema } from "effect" import { Integration } from "./integration" -import { withStatics } from "./schema" +import { statics } from "./schema" export const ID = Schema.String.pipe( Schema.brand("ProviderV2.ID"), - withStatics((schema) => ({ + statics((schema) => ({ opencode: schema.make("opencode"), anthropic: schema.make("anthropic"), openai: schema.make("openai"), @@ -57,7 +57,7 @@ export const Info = Schema.Struct({ }) .annotate({ identifier: "ProviderV2.Info" }) .pipe( - withStatics((schema) => ({ + statics((schema) => ({ empty: (id: ID) => schema.make({ id, diff --git a/packages/schema/src/pty.ts b/packages/schema/src/pty.ts index 026f49bd36..9d6120ccde 100644 --- a/packages/schema/src/pty.ts +++ b/packages/schema/src/pty.ts @@ -3,13 +3,12 @@ export * as Pty from "./pty" import { Schema } from "effect" import { define, inventory } from "./event" import { ascending } from "./identifier" -import { NonNegativeInt, PositiveInt } from "./schema" -import { withStatics } from "./schema" +import { NonNegativeInt, PositiveInt, statics } from "./schema" const IDSchema = Schema.String.check(Schema.isStartsWith("pty")).pipe(Schema.brand("PtyID")) export const ID = IDSchema.pipe( - withStatics((schema: typeof IDSchema) => ({ + statics((schema: typeof IDSchema) => ({ ascending: (id?: string) => schema.make(id ?? "pty_" + ascending()), })), ) @@ -25,14 +24,12 @@ export const Info = Schema.Struct({ pid: NonNegativeInt, exitCode: Schema.optional(NonNegativeInt), }).annotate({ identifier: "Pty" }) -export const PtyInfo = Info const Created = define({ type: "pty.created", schema: { info: Info } }) const Updated = define({ type: "pty.updated", schema: { info: Info } }) const Exited = define({ type: "pty.exited", schema: { id: ID, exitCode: NonNegativeInt } }) const Deleted = define({ type: "pty.deleted", schema: { id: ID } }) export const Event = { Created, Updated, Exited, Deleted, Definitions: inventory(Created, Updated, Exited, Deleted) } -export const PtyEvent = Event export const CreateInput = Schema.Struct({ command: Schema.optional(Schema.String), diff --git a/packages/schema/src/question-v1.ts b/packages/schema/src/question-v1.ts index cea377917e..837a51a469 100644 --- a/packages/schema/src/question-v1.ts +++ b/packages/schema/src/question-v1.ts @@ -3,13 +3,13 @@ export * as QuestionV1 from "./question-v1" import { Schema } from "effect" import { define, inventory } from "./event" import { ascending } from "./identifier" -import { withStatics } from "./schema" +import { statics } from "./schema" import { SessionID } from "./session-id" import { SessionV1 } from "./session-v1" export const ID = Schema.String.check(Schema.isStartsWith("que")).pipe( Schema.brand("QuestionID"), - withStatics((schema) => ({ ascending: (id?: string) => schema.make(id ?? "que_" + ascending()) })), + statics((schema) => ({ ascending: (id?: string) => schema.make(id ?? "que_" + ascending()) })), ) export const Option = Schema.Struct({ diff --git a/packages/schema/src/question.ts b/packages/schema/src/question.ts index 3794e811ef..0933c11ec1 100644 --- a/packages/schema/src/question.ts +++ b/packages/schema/src/question.ts @@ -4,11 +4,11 @@ import { Schema } from "effect" import { define, inventory } from "./event" import { ascending } from "./identifier" import { SessionID } from "./session-id" -import { withStatics } from "./schema" +import { statics } from "./schema" export const ID = Schema.String.check(Schema.isStartsWith("que")).pipe( Schema.brand("QuestionV2.ID"), - withStatics((schema) => ({ ascending: (id?: string) => schema.make(id ?? "que_" + ascending()) })), + statics((schema) => ({ ascending: (id?: string) => schema.make(id ?? "que_" + ascending()) })), ) export type ID = typeof ID.Type diff --git a/packages/schema/src/revert.ts b/packages/schema/src/revert.ts index 16e36e1f40..4ac0977420 100644 --- a/packages/schema/src/revert.ts +++ b/packages/schema/src/revert.ts @@ -2,7 +2,7 @@ export * as Revert from "./revert" import { Schema } from "effect" import { NonNegativeInt, RelativePath } from "./schema" -import { SessionMessageID } from "./session-message-id" +import { SessionMessage } from "./session-message" export const FileDiff = Schema.Struct({ path: RelativePath, @@ -14,7 +14,7 @@ export const FileDiff = Schema.Struct({ export type FileDiff = typeof FileDiff.Type export const State = Schema.Struct({ - messageID: SessionMessageID.ID, + messageID: SessionMessage.ID, partID: Schema.String.pipe(Schema.optional), snapshot: Schema.String.pipe(Schema.optional), diff: Schema.String.pipe(Schema.optional), diff --git a/packages/schema/src/schema.ts b/packages/schema/src/schema.ts index 405fd9b606..1cadffdf60 100644 --- a/packages/schema/src/schema.ts +++ b/packages/schema/src/schema.ts @@ -9,7 +9,7 @@ export type RelativePath = typeof RelativePath.Type export const AbsolutePath = Schema.String.pipe(Schema.brand("AbsolutePath")) export type AbsolutePath = typeof AbsolutePath.Type -export const optionalOmitUndefined = (schema: S) => +export const optional = (schema: S) => Schema.optionalKey(schema).pipe( Schema.decodeTo(Schema.optional(schema), { decode: SchemaGetter.passthrough({ strict: false }), @@ -17,7 +17,7 @@ export const optionalOmitUndefined = (schema: S) => }), ) -export const withStatics = +export const statics = >(methods: (schema: S) => M) => (schema: S): S & M => Object.assign(schema, methods(schema)) diff --git a/packages/schema/src/session-event.ts b/packages/schema/src/session-event.ts index 2e71667e37..e94cf94c5b 100644 --- a/packages/schema/src/session-event.ts +++ b/packages/schema/src/session-event.ts @@ -9,7 +9,6 @@ import { DateTimeUtcFromMillis, NonNegativeInt, RelativePath } from "./schema" import { FileAttachment, Prompt } from "./prompt" import { SessionID } from "./session-id" import { Location } from "./location" -import { SessionMessageID } from "./session-message-id" import { SessionMessage } from "./session-message" import { Revert } from "./revert" @@ -30,7 +29,7 @@ const Base = { } const PromptFields = { ...Base, - messageID: SessionMessageID.ID, + messageID: SessionMessage.ID, prompt: Prompt, delivery: Delivery, } @@ -56,7 +55,7 @@ export const AgentSwitched = Event.define({ ...options, schema: { ...Base, - messageID: SessionMessageID.ID, + messageID: SessionMessage.ID, agent: Schema.String, }, }) @@ -67,7 +66,7 @@ export const ModelSwitched = Event.define({ ...options, schema: { ...Base, - messageID: SessionMessageID.ID, + messageID: SessionMessage.ID, model: Model.Ref, }, }) @@ -103,7 +102,7 @@ export const ContextUpdated = Event.define({ ...options, schema: { ...Base, - messageID: SessionMessageID.ID, + messageID: SessionMessage.ID, text: Schema.String, }, }) @@ -114,7 +113,7 @@ export const Synthetic = Event.define({ ...options, schema: { ...Base, - messageID: SessionMessageID.ID, + messageID: SessionMessage.ID, text: Schema.String, }, }) @@ -126,7 +125,7 @@ export namespace Shell { ...options, schema: { ...Base, - messageID: SessionMessageID.ID, + messageID: SessionMessage.ID, callID: Schema.String, command: Schema.String, }, @@ -151,7 +150,7 @@ export namespace Step { ...options, schema: { ...Base, - assistantMessageID: SessionMessageID.ID, + assistantMessageID: SessionMessage.ID, agent: Schema.String, model: Model.Ref, snapshot: Schema.String.pipe(Schema.optional), @@ -164,7 +163,7 @@ export namespace Step { ...stepSettlementOptions, schema: { ...Base, - assistantMessageID: SessionMessageID.ID, + assistantMessageID: SessionMessage.ID, finish: Schema.String, cost: Schema.Finite, tokens: Schema.Struct({ @@ -187,7 +186,7 @@ export namespace Step { ...stepSettlementOptions, schema: { ...Base, - assistantMessageID: SessionMessageID.ID, + assistantMessageID: SessionMessage.ID, error: UnknownError, }, }) @@ -200,7 +199,7 @@ export namespace Text { ...options, schema: { ...Base, - assistantMessageID: SessionMessageID.ID, + assistantMessageID: SessionMessage.ID, textID: Schema.String, }, }) @@ -211,7 +210,7 @@ export namespace Text { type: "session.next.text.delta", schema: { ...Base, - assistantMessageID: SessionMessageID.ID, + assistantMessageID: SessionMessage.ID, textID: Schema.String, delta: Schema.String, }, @@ -223,7 +222,7 @@ export namespace Text { ...options, schema: { ...Base, - assistantMessageID: SessionMessageID.ID, + assistantMessageID: SessionMessage.ID, textID: Schema.String, text: Schema.String, }, @@ -237,7 +236,7 @@ export namespace Reasoning { ...options, schema: { ...Base, - assistantMessageID: SessionMessageID.ID, + assistantMessageID: SessionMessage.ID, reasoningID: Schema.String, providerMetadata: ProviderMetadata.pipe(Schema.optional), }, @@ -249,7 +248,7 @@ export namespace Reasoning { type: "session.next.reasoning.delta", schema: { ...Base, - assistantMessageID: SessionMessageID.ID, + assistantMessageID: SessionMessage.ID, reasoningID: Schema.String, delta: Schema.String, }, @@ -261,7 +260,7 @@ export namespace Reasoning { ...options, schema: { ...Base, - assistantMessageID: SessionMessageID.ID, + assistantMessageID: SessionMessage.ID, reasoningID: Schema.String, text: Schema.String, providerMetadata: ProviderMetadata.pipe(Schema.optional), @@ -273,7 +272,7 @@ export namespace Reasoning { export namespace Tool { const ToolBase = { ...Base, - assistantMessageID: SessionMessageID.ID, + assistantMessageID: SessionMessage.ID, callID: Schema.String, } @@ -401,7 +400,7 @@ export namespace Compaction { ...options, schema: { ...Base, - messageID: SessionMessageID.ID, + messageID: SessionMessage.ID, reason: Schema.Union([Schema.Literal("auto"), Schema.Literal("manual")]), }, }) @@ -411,7 +410,7 @@ export namespace Compaction { type: "session.next.compaction.delta", schema: { ...Base, - messageID: SessionMessageID.ID, + messageID: SessionMessage.ID, text: Schema.String, }, }) @@ -422,7 +421,7 @@ export namespace Compaction { ...options, schema: { ...Base, - messageID: SessionMessageID.ID, + messageID: SessionMessage.ID, reason: Started.data.fields.reason, text: Schema.String, recent: Schema.String, @@ -441,7 +440,7 @@ export namespace RevertEvent { export const Committed = Event.define({ type: "session.next.revert.committed", ...options, - schema: { ...Base, messageID: SessionMessageID.ID }, + schema: { ...Base, messageID: SessionMessage.ID }, }) } diff --git a/packages/schema/src/session-id.ts b/packages/schema/src/session-id.ts index 747413e030..3603ebe703 100644 --- a/packages/schema/src/session-id.ts +++ b/packages/schema/src/session-id.ts @@ -1,10 +1,10 @@ import { Schema } from "effect" import { descending } from "./identifier" -import { withStatics } from "./schema" +import { statics } from "./schema" export const SessionID = Schema.String.check(Schema.isStartsWith("ses")).pipe( Schema.brand("SessionID"), - withStatics((schema) => { + statics((schema) => { const create = () => schema.make("ses_" + descending()) return { create, diff --git a/packages/schema/src/session-input.ts b/packages/schema/src/session-input.ts index 55010c1916..219dfa10ec 100644 --- a/packages/schema/src/session-input.ts +++ b/packages/schema/src/session-input.ts @@ -5,7 +5,7 @@ import { Prompt } from "./prompt" import { DateTimeUtcFromMillis, NonNegativeInt } from "./schema" import { SessionDelivery } from "./session-delivery" import { SessionID } from "./session-id" -import { SessionMessageID } from "./session-message-id" +import { SessionMessage } from "./session-message" export const Delivery = SessionDelivery.Delivery export type Delivery = SessionDelivery.Delivery @@ -13,7 +13,7 @@ export type Delivery = SessionDelivery.Delivery export interface Admitted extends Schema.Schema.Type {} export const Admitted = Schema.Struct({ admittedSeq: NonNegativeInt, - id: SessionMessageID.ID, + id: SessionMessage.ID, sessionID: SessionID, prompt: Prompt, delivery: Delivery, diff --git a/packages/schema/src/session-message-id.ts b/packages/schema/src/session-message-id.ts deleted file mode 100644 index ea0d808b76..0000000000 --- a/packages/schema/src/session-message-id.ts +++ /dev/null @@ -1,11 +0,0 @@ -export * as SessionMessageID from "./session-message-id" - -import { Schema } from "effect" -import { ascending } from "./identifier" -import { withStatics } from "./schema" - -export const ID = Schema.String.check(Schema.isStartsWith("msg_")).pipe( - Schema.brand("Session.Message.ID"), - withStatics((schema) => ({ create: () => schema.make("msg_" + ascending()) })), -) -export type ID = typeof ID.Type diff --git a/packages/schema/src/session-message.ts b/packages/schema/src/session-message.ts index 63cc25b43d..c365e08ba6 100644 --- a/packages/schema/src/session-message.ts +++ b/packages/schema/src/session-message.ts @@ -4,12 +4,15 @@ import { Schema } from "effect" import { ProviderMetadata, ToolContent } from "./llm" import { Model } from "./model" import { FileAttachment, Prompt } from "./prompt" -import { DateTimeUtcFromMillis, RelativePath } from "./schema" +import { DateTimeUtcFromMillis, RelativePath, statics } from "./schema" import { SessionID } from "./session-id" -import { SessionMessageID } from "./session-message-id" +import { ascending } from "./identifier" -export const ID = SessionMessageID.ID -export type ID = SessionMessageID.ID +export const ID = Schema.String.check(Schema.isStartsWith("msg_")).pipe( + Schema.brand("Session.Message.ID"), + statics((schema) => ({ create: () => schema.make("msg_" + ascending()) })), +) +export type ID = typeof ID.Type export interface UnknownError extends Schema.Schema.Type {} export const UnknownError = Schema.Struct({ diff --git a/packages/schema/src/session-todo.ts b/packages/schema/src/session-todo.ts index cf62c5186c..5a05d51096 100644 --- a/packages/schema/src/session-todo.ts +++ b/packages/schema/src/session-todo.ts @@ -12,7 +12,6 @@ export const Info = Schema.Struct({ priority: Schema.String.annotate({ description: "Priority level of the task: high, medium, low" }), }).annotate({ identifier: "Todo" }) export type Info = typeof Info.Type -export const SessionTodoInfo = Info const Updated = define({ type: "todo.updated", diff --git a/packages/schema/src/session-v1.ts b/packages/schema/src/session-v1.ts index 6892041fc5..6766e9296b 100644 --- a/packages/schema/src/session-v1.ts +++ b/packages/schema/src/session-v1.ts @@ -7,7 +7,7 @@ import { PermissionV1 } from "./permission-v1" import { Project } from "./project" import { Provider } from "./provider" import { Model } from "./model" -import { NonNegativeInt, optionalOmitUndefined, withStatics } from "./schema" +import { NonNegativeInt, optional, statics } from "./schema" import { ascending } from "./identifier" import { SessionID } from "./session-id" import { WorkspaceID } from "./workspace-id" @@ -16,13 +16,13 @@ const Timestamp = Schema.Finite.check(Schema.isGreaterThanOrEqualTo(0)) export const MessageID = Schema.String.check(Schema.isStartsWith("msg")).pipe( Schema.brand("MessageID"), - withStatics((schema) => ({ ascending: (id?: string) => schema.make(id ?? "msg_" + ascending()) })), + statics((schema) => ({ ascending: (id?: string) => schema.make(id ?? "msg_" + ascending()) })), ) export type MessageID = typeof MessageID.Type export const PartID = Schema.String.check(Schema.isStartsWith("prt")).pipe( Schema.brand("PartID"), - withStatics((schema) => ({ ascending: (id?: string) => schema.make(id ?? "prt_" + ascending()) })), + statics((schema) => ({ ascending: (id?: string) => schema.make(id ?? "prt_" + ascending()) })), ) export type PartID = typeof PartID.Type @@ -510,7 +510,7 @@ const SessionSummary = Schema.Struct({ additions: Schema.Finite, deletions: Schema.Finite, files: Schema.Finite, - diffs: optionalOmitUndefined(Schema.Array(FileDiff.Info)), + diffs: optional(Schema.Array(FileDiff.Info)), }) const SessionTokens = Schema.Struct({ @@ -529,42 +529,42 @@ const SessionShare = Schema.Struct({ const SessionRevert = Schema.Struct({ messageID: MessageID, - partID: optionalOmitUndefined(PartID), - snapshot: optionalOmitUndefined(Schema.String), - diff: optionalOmitUndefined(Schema.String), + partID: optional(PartID), + snapshot: optional(Schema.String), + diff: optional(Schema.String), }) const SessionModel = Schema.Struct({ id: Model.ID, providerID: Provider.ID, - variant: optionalOmitUndefined(Schema.String), + variant: optional(Schema.String), }) export const SessionInfo = Schema.Struct({ id: SessionID, slug: Schema.String, projectID: Project.ID, - workspaceID: optionalOmitUndefined(WorkspaceID), + workspaceID: optional(WorkspaceID), directory: Schema.String, - path: optionalOmitUndefined(Schema.String), - parentID: optionalOmitUndefined(SessionID), - summary: optionalOmitUndefined(SessionSummary), - cost: optionalOmitUndefined(Schema.Finite), - tokens: optionalOmitUndefined(SessionTokens), - share: optionalOmitUndefined(SessionShare), + path: optional(Schema.String), + parentID: optional(SessionID), + summary: optional(SessionSummary), + cost: optional(Schema.Finite), + tokens: optional(SessionTokens), + share: optional(SessionShare), title: Schema.String, - agent: optionalOmitUndefined(Schema.String), - model: optionalOmitUndefined(SessionModel), + agent: optional(Schema.String), + model: optional(SessionModel), version: Schema.String, - metadata: optionalOmitUndefined(Schema.Record(Schema.String, Schema.Any)), + metadata: optional(Schema.Record(Schema.String, Schema.Any)), time: Schema.Struct({ created: NonNegativeInt, updated: NonNegativeInt, - compacting: optionalOmitUndefined(NonNegativeInt), - archived: optionalOmitUndefined(Schema.Finite), + compacting: optional(NonNegativeInt), + archived: optional(Schema.Finite), }), - permission: optionalOmitUndefined(PermissionV1.Ruleset), - revert: optionalOmitUndefined(SessionRevert), + permission: optional(PermissionV1.Ruleset), + revert: optional(SessionRevert), }).annotate({ identifier: "Session" }) export type SessionInfo = typeof SessionInfo.Type diff --git a/packages/schema/src/session.ts b/packages/schema/src/session.ts index 952730b5ca..1db7dd7f7c 100644 --- a/packages/schema/src/session.ts +++ b/packages/schema/src/session.ts @@ -5,7 +5,7 @@ import { Agent } from "./agent" import { Location } from "./location" import { Model } from "./model" import { Project } from "./project" -import { DateTimeUtcFromMillis, optionalOmitUndefined, RelativePath } from "./schema" +import { DateTimeUtcFromMillis, optional, RelativePath } from "./schema" import { SessionEvent } from "./session-event" import { SessionID } from "./session-id" import { Revert } from "./revert" @@ -18,7 +18,7 @@ export const Event = SessionEvent export interface Info extends Schema.Schema.Type {} export const Info = Schema.Struct({ id: ID, - parentID: ID.pipe(optionalOmitUndefined), + parentID: ID.pipe(optional), projectID: Project.ID, agent: Agent.ID.pipe(Schema.optional), model: Model.Ref.pipe(Schema.optional), diff --git a/packages/schema/src/workspace-id.ts b/packages/schema/src/workspace-id.ts index e69a562ffc..e43e9673f6 100644 --- a/packages/schema/src/workspace-id.ts +++ b/packages/schema/src/workspace-id.ts @@ -1,10 +1,10 @@ import { Schema } from "effect" import { ascending } from "./identifier" -import { withStatics } from "./schema" +import { statics } from "./schema" export const WorkspaceID = Schema.String.check(Schema.isStartsWith("wrk")).pipe( Schema.brand("WorkspaceV2.ID"), - withStatics((schema) => { + statics((schema) => { const create = () => schema.make("wrk_" + ascending()) return { ascending: (id?: string) => { diff --git a/specs/v2/instructions.md b/specs/v2/instructions.md index e780e9821b..f3cdcdf5b3 100644 --- a/specs/v2/instructions.md +++ b/specs/v2/instructions.md @@ -92,7 +92,7 @@ Use Effect schemas as the public contract: - branded schemas for ids - `Schema.Class` or `Schema.Struct` for domain data - `Schema.TaggedErrorClass` for expected errors -- existing core helpers like `DeepMutable`, `withStatics`, and integer schemas where appropriate +- existing core helpers like `DeepMutable`, `statics`, and integer schemas where appropriate Prefer `Info` objects as the stored domain records. Add static `empty(...)` constructors when update APIs need to create records on first mutation. diff --git a/specs/v2/provider-model.md b/specs/v2/provider-model.md index c63a9a8d49..775ef2c30d 100644 --- a/specs/v2/provider-model.md +++ b/specs/v2/provider-model.md @@ -5,7 +5,7 @@ ```ts export const ID = Schema.String.pipe( Schema.brand("ProviderV2.ID"), - withStatics((schema) => ({ + statics((schema) => ({ opencode: schema.make("opencode"), anthropic: schema.make("anthropic"), openai: schema.make("openai"),