Kaynağa Gözat

ignore: exploration

Dax Raad 6 gün önce
ebeveyn
işleme
2aa6110c6e

+ 73 - 26
packages/opencode/src/v2/message.ts

@@ -10,59 +10,106 @@ export namespace Message {
     })),
   )
 
-  export class File extends Schema.Class<File>("Message.File")({
-    url: Schema.String,
+  export class Source extends Schema.Class<Source>("Message.Source")({
+    start: Schema.Number,
+    end: Schema.Number,
+    text: Schema.String,
+  }) {}
+
+  export class FileAttachment extends Schema.Class<FileAttachment>("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<UserContent>("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<AgentAttachment>("Message.Agent.Attachment")({
+    name: Schema.String,
+    source: Source.pipe(Schema.optional),
   }) {}
 
   export class User extends Schema.Class<User>("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<typeof UserContent>) {
+    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<Synthetic>("Message.Synthetic")({
+    id: ID,
+    type: Schema.Literal("synthetic"),
+    text: Schema.String,
+    time: Schema.Struct({
+      created: Schema.DateTimeUtc,
+    }),
+  }) {}
 
-const msg = Message.User.create({
-  text: "Hello world",
-  files: [Message.File.create("file://example.com/file.txt")],
-})
+  export class Request extends Schema.Class<Request>("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<Text>("Message.Text")({
+    id: ID,
+    type: Schema.Literal("text"),
+    text: Schema.String,
+    time: Schema.Struct({
+      created: Schema.DateTimeUtc,
+      completed: Schema.DateTimeUtc.pipe(Schema.optional),
+    }),
+  }) {}
 
-console.log(JSON.stringify(msg, null, 2))
+  export class Complete extends Schema.Class<Complete>("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<typeof Info>
+}

+ 71 - 0
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<typeof ID>
+
+  export class PromptInput extends Schema.Class<PromptInput>("Session.PromptInput")({
+    ...Struct.omit(Message.User.fields, ["time", "type"]),
+    id: Schema.optionalKey(Message.ID),
+    sessionID: SessionV2.ID,
+  }) {}
+
+  export class CreateInput extends Schema.Class<CreateInput>("Session.CreateInput")({
+    id: Schema.optionalKey(SessionV2.ID),
+  }) {}
+
+  export class Info extends Schema.Class<Info>("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<Info>
+    create: (input: CreateInput) => Effect.Effect<Info>
+    prompt: (input: PromptInput) => Effect.Effect<Message.User>
+  }
+
+  export class Service extends Context.Service<Service, Interface>()("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),
+    })
+  }
+}