From 2aa6110c6e72a77e0b8c017091ff26487f69fc67 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Sun, 12 Apr 2026 13:14:33 -0400 Subject: [PATCH] ignore: exploration --- packages/opencode/src/v2/message.ts | 101 ++++++++++++++++++++-------- packages/opencode/src/v2/session.ts | 71 +++++++++++++++++++ 2 files changed, 145 insertions(+), 27 deletions(-) create mode 100644 packages/opencode/src/v2/session.ts diff --git a/packages/opencode/src/v2/message.ts b/packages/opencode/src/v2/message.ts index 008a45a369..868ab82802 100644 --- a/packages/opencode/src/v2/message.ts +++ b/packages/opencode/src/v2/message.ts @@ -10,59 +10,106 @@ export namespace Message { })), ) - export class File extends Schema.Class("Message.File")({ - url: Schema.String, + export class Source extends Schema.Class("Message.Source")({ + start: Schema.Number, + end: Schema.Number, + text: Schema.String, + }) {} + + export class FileAttachment extends Schema.Class("Message.File.Attachment")({ + 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(url: string) { - return new File({ - url, + return new FileAttachment({ + uri: url, mime: "text/plain", }) } } - export class UserContent extends Schema.Class("Message.User.Content")({ - text: Schema.String, - synthetic: Schema.Boolean.pipe(Schema.optional), - agent: Schema.String.pipe(Schema.optional), - files: Schema.Array(File).pipe(Schema.optional), + export class AgentAttachment extends Schema.Class("Message.Agent.Attachment")({ + name: Schema.String, + source: Source.pipe(Schema.optional), }) {} export class User extends Schema.Class("Message.User")({ id: ID, type: Schema.Literal("user"), + text: Schema.String, + files: Schema.Array(FileAttachment).pipe(Schema.optional), + agents: Schema.Array(AgentAttachment).pipe(Schema.optional), time: Schema.Struct({ created: Schema.DateTimeUtc, }), - content: UserContent, }) { - static create(content: Schema.Schema.Type) { + static create(input: { text: User["text"]; files?: User["files"]; agents?: User["agents"] }) { const msg = new User({ id: ID.create(), type: "user", + ...input, time: { created: Effect.runSync(DateTime.now), }, - content, }) return msg } - - static file(url: string) { - return new File({ - url, - mime: "text/plain", - }) - } } - export namespace User {} + export class Synthetic extends Schema.Class("Message.Synthetic")({ + id: ID, + type: Schema.Literal("synthetic"), + text: Schema.String, + time: Schema.Struct({ + created: Schema.DateTimeUtc, + }), + }) {} + + export class Request extends Schema.Class("Message.Request")({ + id: ID, + type: Schema.Literal("start"), + model: Schema.Struct({ + id: Schema.String, + providerID: Schema.String, + variant: Schema.String.pipe(Schema.optional), + }), + time: Schema.Struct({ + created: Schema.DateTimeUtc, + }), + }) {} + + export class Text extends Schema.Class("Message.Text")({ + id: ID, + type: Schema.Literal("text"), + text: Schema.String, + time: Schema.Struct({ + created: Schema.DateTimeUtc, + completed: Schema.DateTimeUtc.pipe(Schema.optional), + }), + }) {} + + export class Complete extends Schema.Class("Message.Complete")({ + id: ID, + type: Schema.Literal("complete"), + time: Schema.Struct({ + created: Schema.DateTimeUtc, + }), + cost: Schema.Number, + tokens: Schema.Struct({ + total: Schema.Number, + input: Schema.Number, + output: Schema.Number, + reasoning: Schema.Number, + cache: Schema.Struct({ + read: Schema.Number, + write: Schema.Number, + }), + }), + }) {} + + export const Info = Schema.Union([User, Text]) + export type Info = Schema.Schema.Type } - -const msg = Message.User.create({ - text: "Hello world", - files: [Message.File.create("file://example.com/file.txt")], -}) - -console.log(JSON.stringify(msg, null, 2)) diff --git a/packages/opencode/src/v2/session.ts b/packages/opencode/src/v2/session.ts new file mode 100644 index 0000000000..4b4fa1978a --- /dev/null +++ b/packages/opencode/src/v2/session.ts @@ -0,0 +1,71 @@ +import { Context, Layer, Schema, Effect } from "effect" +import { Message } from "./message" +import { Struct } from "effect" +import { Identifier } from "@/id/id" +import { withStatics } from "@/util/schema" +import { Session } from "@/session" +import { SessionID } from "@/session/schema" + +export namespace SessionV2 { + export const ID = SessionID + + export type ID = Schema.Schema.Type + + export class PromptInput extends Schema.Class("Session.PromptInput")({ + ...Struct.omit(Message.User.fields, ["time", "type"]), + id: Schema.optionalKey(Message.ID), + sessionID: SessionV2.ID, + }) {} + + export class CreateInput extends Schema.Class("Session.CreateInput")({ + id: Schema.optionalKey(SessionV2.ID), + }) {} + + export class Info extends Schema.Class("Session.Info")({ + id: SessionV2.ID, + model: Schema.Struct({ + id: Schema.String, + providerID: Schema.String, + modelID: Schema.String, + }).pipe(Schema.optional), + }) {} + + export interface Interface { + fromID: (id: SessionV2.ID) => Effect.Effect + create: (input: CreateInput) => Effect.Effect + prompt: (input: PromptInput) => Effect.Effect + } + + export class Service extends Context.Service()("Session.Service") {} + + export const layer = Layer.effect(Service)( + Effect.gen(function* () { + const session = yield* Session.Service + + const create: Interface["create"] = Effect.fn("Session.create")(function* (input) { + throw new Error("Not implemented") + }) + + const prompt: Interface["prompt"] = Effect.fn("Session.prompt")(function* (input) { + throw new Error("Not implemented") + }) + + const fromID: Interface["fromID"] = Effect.fn("Session.fromID")(function* (id) { + const match = yield* session.get(id) + return fromV1(match) + }) + + return Service.of({ + create, + prompt, + fromID, + }) + }), + ) + + function fromV1(input: Session.Info): Info { + return new Info({ + id: SessionV2.ID.make(input.id), + }) + } +}