summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDax Raad <[email protected]>2026-04-12 13:14:33 -0400
committerDax Raad <[email protected]>2026-04-12 13:14:46 -0400
commit2aa6110c6e72a77e0b8c017091ff26487f69fc67 (patch)
treea397561e119a582ea4b632380d2aa62769fba257
parent8b9b9ad31ee715301613f7254424590f0cc8805b (diff)
downloadopencode-2aa6110c6e72a77e0b8c017091ff26487f69fc67.tar.gz
opencode-2aa6110c6e72a77e0b8c017091ff26487f69fc67.zip
ignore: exploration
-rw-r--r--packages/opencode/src/v2/message.ts99
-rw-r--r--packages/opencode/src/v2/session.ts71
2 files changed, 144 insertions, 26 deletions
diff --git a/packages/opencode/src/v2/message.ts b/packages/opencode/src/v2/message.ts
index 008a45a36..868ab8280 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<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>
+}
diff --git a/packages/opencode/src/v2/session.ts b/packages/opencode/src/v2/session.ts
new file mode 100644
index 000000000..4b4fa1978
--- /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<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),
+ })
+ }
+}