import { Identifier } from "@/id/id" import { withStatics } from "@/util/schema" import * as DateTime from "effect/DateTime" import { Schema } from "effect" export namespace SessionEvent { export const ID = Schema.String.pipe( Schema.brand("Session.Event.ID"), withStatics((s) => ({ create: () => s.make(Identifier.create("evt", "ascending")), })), ) export type ID = Schema.Schema.Type type Stamp = Schema.Schema.Type type BaseInput = { id?: ID metadata?: Record timestamp?: Stamp } const Base = { id: ID, metadata: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional), timestamp: Schema.DateTimeUtc, } export class Source extends Schema.Class("Session.Event.Source")({ start: Schema.Number, end: Schema.Number, text: Schema.String, }) {} export class FileAttachment extends Schema.Class("Session.Event.FileAttachment")({ uri: Schema.String, mime: Schema.String, name: Schema.String.pipe(Schema.optional), description: Schema.String.pipe(Schema.optional), source: Source.pipe(Schema.optional), }) { static create(input: FileAttachment) { return new FileAttachment({ uri: input.uri, mime: input.mime, name: input.name, description: input.description, source: input.source, }) } } export class AgentAttachment extends Schema.Class("Session.Event.AgentAttachment")({ name: Schema.String, source: Source.pipe(Schema.optional), }) {} export class Prompt extends Schema.Class("Session.Event.Prompt")({ ...Base, type: Schema.Literal("prompt"), text: Schema.String, files: Schema.Array(FileAttachment).pipe(Schema.optional), agents: Schema.Array(AgentAttachment).pipe(Schema.optional), }) { static create(input: BaseInput & { text: string; files?: FileAttachment[]; agents?: AgentAttachment[] }) { return new Prompt({ id: input.id ?? ID.create(), type: "prompt", timestamp: input.timestamp ?? DateTime.makeUnsafe(Date.now()), metadata: input.metadata, text: input.text, files: input.files, agents: input.agents, }) } } export class Synthetic extends Schema.Class("Session.Event.Synthetic")({ ...Base, type: Schema.Literal("synthetic"), text: Schema.String, }) { static create(input: BaseInput & { text: string }) { return new Synthetic({ id: input.id ?? ID.create(), type: "synthetic", timestamp: input.timestamp ?? DateTime.makeUnsafe(Date.now()), metadata: input.metadata, text: input.text, }) } } export namespace Step { export class Started extends Schema.Class("Session.Event.Step.Started")({ ...Base, type: Schema.Literal("step.started"), model: Schema.Struct({ id: Schema.String, providerID: Schema.String, variant: Schema.String.pipe(Schema.optional), }), }) { static create(input: BaseInput & { model: { id: string; providerID: string; variant?: string } }) { return new Started({ id: input.id ?? ID.create(), type: "step.started", timestamp: input.timestamp ?? DateTime.makeUnsafe(Date.now()), metadata: input.metadata, model: input.model, }) } } export class Ended extends Schema.Class("Session.Event.Step.Ended")({ ...Base, type: Schema.Literal("step.ended"), reason: Schema.String, cost: Schema.Number, tokens: Schema.Struct({ input: Schema.Number, output: Schema.Number, reasoning: Schema.Number, cache: Schema.Struct({ read: Schema.Number, write: Schema.Number, }), }), }) { static create(input: BaseInput & { reason: string; cost: number; tokens: Ended["tokens"] }) { return new Ended({ id: input.id ?? ID.create(), type: "step.ended", timestamp: input.timestamp ?? DateTime.makeUnsafe(Date.now()), metadata: input.metadata, reason: input.reason, cost: input.cost, tokens: input.tokens, }) } } } export namespace Text { export class Started extends Schema.Class("Session.Event.Text.Started")({ ...Base, type: Schema.Literal("text.started"), }) { static create(input: BaseInput = {}) { return new Started({ id: input.id ?? ID.create(), type: "text.started", timestamp: input.timestamp ?? DateTime.makeUnsafe(Date.now()), metadata: input.metadata, }) } } export class Delta extends Schema.Class("Session.Event.Text.Delta")({ ...Base, type: Schema.Literal("text.delta"), delta: Schema.String, }) { static create(input: BaseInput & { delta: string }) { return new Delta({ id: input.id ?? ID.create(), type: "text.delta", timestamp: input.timestamp ?? DateTime.makeUnsafe(Date.now()), metadata: input.metadata, delta: input.delta, }) } } export class Ended extends Schema.Class("Session.Event.Text.Ended")({ ...Base, type: Schema.Literal("text.ended"), text: Schema.String, }) { static create(input: BaseInput & { text: string }) { return new Ended({ id: input.id ?? ID.create(), type: "text.ended", timestamp: input.timestamp ?? DateTime.makeUnsafe(Date.now()), metadata: input.metadata, text: input.text, }) } } } export namespace Reasoning { export class Started extends Schema.Class("Session.Event.Reasoning.Started")({ ...Base, type: Schema.Literal("reasoning.started"), }) { static create(input: BaseInput = {}) { return new Started({ id: input.id ?? ID.create(), type: "reasoning.started", timestamp: input.timestamp ?? DateTime.makeUnsafe(Date.now()), metadata: input.metadata, }) } } export class Delta extends Schema.Class("Session.Event.Reasoning.Delta")({ ...Base, type: Schema.Literal("reasoning.delta"), delta: Schema.String, }) { static create(input: BaseInput & { delta: string }) { return new Delta({ id: input.id ?? ID.create(), type: "reasoning.delta", timestamp: input.timestamp ?? DateTime.makeUnsafe(Date.now()), metadata: input.metadata, delta: input.delta, }) } } export class Ended extends Schema.Class("Session.Event.Reasoning.Ended")({ ...Base, type: Schema.Literal("reasoning.ended"), text: Schema.String, }) { static create(input: BaseInput & { text: string }) { return new Ended({ id: input.id ?? ID.create(), type: "reasoning.ended", timestamp: input.timestamp ?? DateTime.makeUnsafe(Date.now()), metadata: input.metadata, text: input.text, }) } } } export namespace Tool { export namespace Input { export class Started extends Schema.Class("Session.Event.Tool.Input.Started")({ ...Base, callID: Schema.String, name: Schema.String, type: Schema.Literal("tool.input.started"), }) { static create(input: BaseInput & { callID: string; name: string }) { return new Started({ id: input.id ?? ID.create(), type: "tool.input.started", timestamp: input.timestamp ?? DateTime.makeUnsafe(Date.now()), metadata: input.metadata, callID: input.callID, name: input.name, }) } } export class Delta extends Schema.Class("Session.Event.Tool.Input.Delta")({ ...Base, callID: Schema.String, type: Schema.Literal("tool.input.delta"), delta: Schema.String, }) { static create(input: BaseInput & { callID: string; delta: string }) { return new Delta({ id: input.id ?? ID.create(), type: "tool.input.delta", timestamp: input.timestamp ?? DateTime.makeUnsafe(Date.now()), metadata: input.metadata, callID: input.callID, delta: input.delta, }) } } export class Ended extends Schema.Class("Session.Event.Tool.Input.Ended")({ ...Base, callID: Schema.String, type: Schema.Literal("tool.input.ended"), text: Schema.String, }) { static create(input: BaseInput & { callID: string; text: string }) { return new Ended({ id: input.id ?? ID.create(), type: "tool.input.ended", timestamp: input.timestamp ?? DateTime.makeUnsafe(Date.now()), metadata: input.metadata, callID: input.callID, text: input.text, }) } } } export class Called extends Schema.Class("Session.Event.Tool.Called")({ ...Base, type: Schema.Literal("tool.called"), callID: Schema.String, tool: Schema.String, input: Schema.Record(Schema.String, Schema.Unknown), provider: Schema.Struct({ executed: Schema.Boolean, metadata: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional), }), }) { static create( input: BaseInput & { callID: string tool: string input: Record provider: Called["provider"] }, ) { return new Called({ id: input.id ?? ID.create(), type: "tool.called", timestamp: input.timestamp ?? DateTime.makeUnsafe(Date.now()), metadata: input.metadata, callID: input.callID, tool: input.tool, input: input.input, provider: input.provider, }) } } export class Success extends Schema.Class("Session.Event.Tool.Success")({ ...Base, type: Schema.Literal("tool.success"), callID: Schema.String, title: Schema.String, output: Schema.String.pipe(Schema.optional), attachments: Schema.Array(FileAttachment).pipe(Schema.optional), provider: Schema.Struct({ executed: Schema.Boolean, metadata: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional), }), }) { static create( input: BaseInput & { callID: string title: string output?: string attachments?: FileAttachment[] provider: Success["provider"] }, ) { return new Success({ id: input.id ?? ID.create(), type: "tool.success", timestamp: input.timestamp ?? DateTime.makeUnsafe(Date.now()), metadata: input.metadata, callID: input.callID, title: input.title, output: input.output, attachments: input.attachments, provider: input.provider, }) } } export class Error extends Schema.Class("Session.Event.Tool.Error")({ ...Base, type: Schema.Literal("tool.error"), callID: Schema.String, error: Schema.String, provider: Schema.Struct({ executed: Schema.Boolean, metadata: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional), }), }) { static create(input: BaseInput & { callID: string; error: string; provider: Error["provider"] }) { return new Error({ id: input.id ?? ID.create(), type: "tool.error", timestamp: input.timestamp ?? DateTime.makeUnsafe(Date.now()), metadata: input.metadata, callID: input.callID, error: input.error, provider: input.provider, }) } } } export class Retried extends Schema.Class("Session.Event.Retried")({ ...Base, type: Schema.Literal("retried"), error: Schema.String, }) { static create(input: BaseInput & { error: string }) { return new Retried({ id: input.id ?? ID.create(), type: "retried", timestamp: input.timestamp ?? DateTime.makeUnsafe(Date.now()), metadata: input.metadata, error: input.error, }) } } export class Compacted extends Schema.Class("Session.Event.Compated")({ ...Base, type: Schema.Literal("compacted"), auto: Schema.Boolean, overflow: Schema.Boolean.pipe(Schema.optional), }) { static create(input: BaseInput & { auto: boolean; overflow?: boolean }) { return new Compacted({ id: input.id ?? ID.create(), type: "compacted", timestamp: input.timestamp ?? DateTime.makeUnsafe(Date.now()), metadata: input.metadata, auto: input.auto, overflow: input.overflow, }) } } export const Event = Schema.Union( [ Prompt, Synthetic, Step.Started, Step.Ended, Text.Started, Text.Delta, Text.Ended, Tool.Input.Started, Tool.Input.Delta, Tool.Input.Ended, Tool.Called, Tool.Success, Tool.Error, Reasoning.Started, Reasoning.Delta, Reasoning.Ended, Retried, Compacted, ], { mode: "oneOf", }, ) export type Event = Schema.Schema.Type export type Type = Event["type"] }