|
|
@@ -2,317 +2,317 @@ import { Schema } from "effect"
|
|
|
import { SessionEvent } from "./session-event"
|
|
|
import { produce } from "immer"
|
|
|
|
|
|
-export namespace SessionEntry {
|
|
|
- export const ID = SessionEvent.ID
|
|
|
- export type ID = Schema.Schema.Type<typeof ID>
|
|
|
+export const ID = SessionEvent.ID
|
|
|
+export type ID = Schema.Schema.Type<typeof ID>
|
|
|
|
|
|
- const Base = {
|
|
|
- id: SessionEvent.ID,
|
|
|
- metadata: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional),
|
|
|
- time: Schema.Struct({
|
|
|
- created: Schema.DateTimeUtc,
|
|
|
- }),
|
|
|
- }
|
|
|
+const Base = {
|
|
|
+ id: SessionEvent.ID,
|
|
|
+ metadata: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional),
|
|
|
+ time: Schema.Struct({
|
|
|
+ created: Schema.DateTimeUtc,
|
|
|
+ }),
|
|
|
+}
|
|
|
|
|
|
- export class User extends Schema.Class<User>("Session.Entry.User")({
|
|
|
- ...Base,
|
|
|
- text: SessionEvent.Prompt.fields.text,
|
|
|
- files: SessionEvent.Prompt.fields.files,
|
|
|
- agents: SessionEvent.Prompt.fields.agents,
|
|
|
- type: Schema.Literal("user"),
|
|
|
- time: Schema.Struct({
|
|
|
- created: Schema.DateTimeUtc,
|
|
|
- }),
|
|
|
- }) {
|
|
|
- static fromEvent(event: SessionEvent.Prompt) {
|
|
|
- return new User({
|
|
|
- id: event.id,
|
|
|
- type: "user",
|
|
|
- metadata: event.metadata,
|
|
|
- text: event.text,
|
|
|
- files: event.files,
|
|
|
- agents: event.agents,
|
|
|
- time: { created: event.timestamp },
|
|
|
- })
|
|
|
- }
|
|
|
+export class User extends Schema.Class<User>("Session.Entry.User")({
|
|
|
+ ...Base,
|
|
|
+ text: SessionEvent.Prompt.fields.text,
|
|
|
+ files: SessionEvent.Prompt.fields.files,
|
|
|
+ agents: SessionEvent.Prompt.fields.agents,
|
|
|
+ type: Schema.Literal("user"),
|
|
|
+ time: Schema.Struct({
|
|
|
+ created: Schema.DateTimeUtc,
|
|
|
+ }),
|
|
|
+}) {
|
|
|
+ static fromEvent(event: SessionEvent.Prompt) {
|
|
|
+ return new User({
|
|
|
+ id: event.id,
|
|
|
+ type: "user",
|
|
|
+ metadata: event.metadata,
|
|
|
+ text: event.text,
|
|
|
+ files: event.files,
|
|
|
+ agents: event.agents,
|
|
|
+ time: { created: event.timestamp },
|
|
|
+ })
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- export class Synthetic extends Schema.Class<Synthetic>("Session.Entry.Synthetic")({
|
|
|
- ...SessionEvent.Synthetic.fields,
|
|
|
- ...Base,
|
|
|
- type: Schema.Literal("synthetic"),
|
|
|
- }) {}
|
|
|
+export class Synthetic extends Schema.Class<Synthetic>("Session.Entry.Synthetic")({
|
|
|
+ ...SessionEvent.Synthetic.fields,
|
|
|
+ ...Base,
|
|
|
+ type: Schema.Literal("synthetic"),
|
|
|
+}) {}
|
|
|
|
|
|
- export class ToolStatePending extends Schema.Class<ToolStatePending>("Session.Entry.ToolState.Pending")({
|
|
|
- status: Schema.Literal("pending"),
|
|
|
- input: Schema.String,
|
|
|
- }) {}
|
|
|
+export class ToolStatePending extends Schema.Class<ToolStatePending>("Session.Entry.ToolState.Pending")({
|
|
|
+ status: Schema.Literal("pending"),
|
|
|
+ input: Schema.String,
|
|
|
+}) {}
|
|
|
|
|
|
- export class ToolStateRunning extends Schema.Class<ToolStateRunning>("Session.Entry.ToolState.Running")({
|
|
|
- status: Schema.Literal("running"),
|
|
|
- input: Schema.Record(Schema.String, Schema.Unknown),
|
|
|
- title: Schema.String.pipe(Schema.optional),
|
|
|
- metadata: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional),
|
|
|
- }) {}
|
|
|
+export class ToolStateRunning extends Schema.Class<ToolStateRunning>("Session.Entry.ToolState.Running")({
|
|
|
+ status: Schema.Literal("running"),
|
|
|
+ input: Schema.Record(Schema.String, Schema.Unknown),
|
|
|
+ title: Schema.String.pipe(Schema.optional),
|
|
|
+ metadata: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional),
|
|
|
+}) {}
|
|
|
|
|
|
- export class ToolStateCompleted extends Schema.Class<ToolStateCompleted>("Session.Entry.ToolState.Completed")({
|
|
|
- status: Schema.Literal("completed"),
|
|
|
- input: Schema.Record(Schema.String, Schema.Unknown),
|
|
|
- output: Schema.String,
|
|
|
- title: Schema.String,
|
|
|
- metadata: Schema.Record(Schema.String, Schema.Unknown),
|
|
|
- attachments: SessionEvent.FileAttachment.pipe(Schema.Array, Schema.optional),
|
|
|
- }) {}
|
|
|
+export class ToolStateCompleted extends Schema.Class<ToolStateCompleted>("Session.Entry.ToolState.Completed")({
|
|
|
+ status: Schema.Literal("completed"),
|
|
|
+ input: Schema.Record(Schema.String, Schema.Unknown),
|
|
|
+ output: Schema.String,
|
|
|
+ title: Schema.String,
|
|
|
+ metadata: Schema.Record(Schema.String, Schema.Unknown),
|
|
|
+ attachments: SessionEvent.FileAttachment.pipe(Schema.Array, Schema.optional),
|
|
|
+}) {}
|
|
|
|
|
|
- export class ToolStateError extends Schema.Class<ToolStateError>("Session.Entry.ToolState.Error")({
|
|
|
- status: Schema.Literal("error"),
|
|
|
- input: Schema.Record(Schema.String, Schema.Unknown),
|
|
|
- error: Schema.String,
|
|
|
- metadata: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional),
|
|
|
- }) {}
|
|
|
+export class ToolStateError extends Schema.Class<ToolStateError>("Session.Entry.ToolState.Error")({
|
|
|
+ status: Schema.Literal("error"),
|
|
|
+ input: Schema.Record(Schema.String, Schema.Unknown),
|
|
|
+ error: Schema.String,
|
|
|
+ metadata: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional),
|
|
|
+}) {}
|
|
|
|
|
|
- export const ToolState = Schema.Union([ToolStatePending, ToolStateRunning, ToolStateCompleted, ToolStateError])
|
|
|
- export type ToolState = Schema.Schema.Type<typeof ToolState>
|
|
|
+export const ToolState = Schema.Union([ToolStatePending, ToolStateRunning, ToolStateCompleted, ToolStateError])
|
|
|
+export type ToolState = Schema.Schema.Type<typeof ToolState>
|
|
|
|
|
|
- export class AssistantTool extends Schema.Class<AssistantTool>("Session.Entry.Assistant.Tool")({
|
|
|
- type: Schema.Literal("tool"),
|
|
|
- callID: Schema.String,
|
|
|
- name: Schema.String,
|
|
|
- state: ToolState,
|
|
|
- time: Schema.Struct({
|
|
|
- created: Schema.DateTimeUtc,
|
|
|
- ran: Schema.DateTimeUtc.pipe(Schema.optional),
|
|
|
- completed: Schema.DateTimeUtc.pipe(Schema.optional),
|
|
|
- pruned: Schema.DateTimeUtc.pipe(Schema.optional),
|
|
|
- }),
|
|
|
- }) {}
|
|
|
+export class AssistantTool extends Schema.Class<AssistantTool>("Session.Entry.Assistant.Tool")({
|
|
|
+ type: Schema.Literal("tool"),
|
|
|
+ callID: Schema.String,
|
|
|
+ name: Schema.String,
|
|
|
+ state: ToolState,
|
|
|
+ time: Schema.Struct({
|
|
|
+ created: Schema.DateTimeUtc,
|
|
|
+ ran: Schema.DateTimeUtc.pipe(Schema.optional),
|
|
|
+ completed: Schema.DateTimeUtc.pipe(Schema.optional),
|
|
|
+ pruned: Schema.DateTimeUtc.pipe(Schema.optional),
|
|
|
+ }),
|
|
|
+}) {}
|
|
|
|
|
|
- export class AssistantText extends Schema.Class<AssistantText>("Session.Entry.Assistant.Text")({
|
|
|
- type: Schema.Literal("text"),
|
|
|
- text: Schema.String,
|
|
|
- }) {}
|
|
|
+export class AssistantText extends Schema.Class<AssistantText>("Session.Entry.Assistant.Text")({
|
|
|
+ type: Schema.Literal("text"),
|
|
|
+ text: Schema.String,
|
|
|
+}) {}
|
|
|
|
|
|
- export class AssistantReasoning extends Schema.Class<AssistantReasoning>("Session.Entry.Assistant.Reasoning")({
|
|
|
- type: Schema.Literal("reasoning"),
|
|
|
- text: Schema.String,
|
|
|
- }) {}
|
|
|
+export class AssistantReasoning extends Schema.Class<AssistantReasoning>("Session.Entry.Assistant.Reasoning")({
|
|
|
+ type: Schema.Literal("reasoning"),
|
|
|
+ text: Schema.String,
|
|
|
+}) {}
|
|
|
|
|
|
- export const AssistantContent = Schema.Union([AssistantText, AssistantReasoning, AssistantTool])
|
|
|
- export type AssistantContent = Schema.Schema.Type<typeof AssistantContent>
|
|
|
+export const AssistantContent = Schema.Union([AssistantText, AssistantReasoning, AssistantTool])
|
|
|
+export type AssistantContent = Schema.Schema.Type<typeof AssistantContent>
|
|
|
|
|
|
- export class Assistant extends Schema.Class<Assistant>("Session.Entry.Assistant")({
|
|
|
- ...Base,
|
|
|
- type: Schema.Literal("assistant"),
|
|
|
- content: AssistantContent.pipe(Schema.Array),
|
|
|
- cost: Schema.Number.pipe(Schema.optional),
|
|
|
- tokens: Schema.Struct({
|
|
|
- input: Schema.Number,
|
|
|
- output: Schema.Number,
|
|
|
- reasoning: Schema.Number,
|
|
|
- cache: Schema.Struct({
|
|
|
- read: Schema.Number,
|
|
|
- write: Schema.Number,
|
|
|
- }),
|
|
|
- }).pipe(Schema.optional),
|
|
|
- error: Schema.String.pipe(Schema.optional),
|
|
|
- time: Schema.Struct({
|
|
|
- created: Schema.DateTimeUtc,
|
|
|
- completed: Schema.DateTimeUtc.pipe(Schema.optional),
|
|
|
+export class Assistant extends Schema.Class<Assistant>("Session.Entry.Assistant")({
|
|
|
+ ...Base,
|
|
|
+ type: Schema.Literal("assistant"),
|
|
|
+ content: AssistantContent.pipe(Schema.Array),
|
|
|
+ cost: Schema.Number.pipe(Schema.optional),
|
|
|
+ tokens: Schema.Struct({
|
|
|
+ input: Schema.Number,
|
|
|
+ output: Schema.Number,
|
|
|
+ reasoning: Schema.Number,
|
|
|
+ cache: Schema.Struct({
|
|
|
+ read: Schema.Number,
|
|
|
+ write: Schema.Number,
|
|
|
}),
|
|
|
- }) {}
|
|
|
+ }).pipe(Schema.optional),
|
|
|
+ error: Schema.String.pipe(Schema.optional),
|
|
|
+ time: Schema.Struct({
|
|
|
+ created: Schema.DateTimeUtc,
|
|
|
+ completed: Schema.DateTimeUtc.pipe(Schema.optional),
|
|
|
+ }),
|
|
|
+}) {}
|
|
|
|
|
|
- export class Compaction extends Schema.Class<Compaction>("Session.Entry.Compaction")({
|
|
|
- ...SessionEvent.Compacted.fields,
|
|
|
- type: Schema.Literal("compaction"),
|
|
|
- ...Base,
|
|
|
- }) {}
|
|
|
+export class Compaction extends Schema.Class<Compaction>("Session.Entry.Compaction")({
|
|
|
+ ...SessionEvent.Compacted.fields,
|
|
|
+ type: Schema.Literal("compaction"),
|
|
|
+ ...Base,
|
|
|
+}) {}
|
|
|
|
|
|
- export const Entry = Schema.Union([User, Synthetic, Assistant, Compaction])
|
|
|
+export const Entry = Schema.Union([User, Synthetic, Assistant, Compaction])
|
|
|
|
|
|
- export type Entry = Schema.Schema.Type<typeof Entry>
|
|
|
+export type Entry = Schema.Schema.Type<typeof Entry>
|
|
|
|
|
|
- export type Type = Entry["type"]
|
|
|
+export type Type = Entry["type"]
|
|
|
|
|
|
- export type History = {
|
|
|
- entries: Entry[]
|
|
|
- pending: Entry[]
|
|
|
- }
|
|
|
+export type History = {
|
|
|
+ entries: Entry[]
|
|
|
+ pending: Entry[]
|
|
|
+}
|
|
|
|
|
|
- export function step(old: History, event: SessionEvent.Event): History {
|
|
|
- return produce(old, (draft) => {
|
|
|
- const lastAssistant = draft.entries.findLast((x) => x.type === "assistant")
|
|
|
- const pendingAssistant = lastAssistant && !lastAssistant.time.completed ? lastAssistant : undefined
|
|
|
+export function step(old: History, event: SessionEvent.Event): History {
|
|
|
+ return produce(old, (draft) => {
|
|
|
+ const lastAssistant = draft.entries.findLast((x) => x.type === "assistant")
|
|
|
+ const pendingAssistant = lastAssistant && !lastAssistant.time.completed ? lastAssistant : undefined
|
|
|
|
|
|
- switch (event.type) {
|
|
|
- case "prompt": {
|
|
|
- if (pendingAssistant) {
|
|
|
- // @ts-expect-error
|
|
|
- draft.pending.push(User.fromEvent(event))
|
|
|
- break
|
|
|
- }
|
|
|
+ switch (event.type) {
|
|
|
+ case "prompt": {
|
|
|
+ if (pendingAssistant) {
|
|
|
// @ts-expect-error
|
|
|
- draft.entries.push(User.fromEvent(event))
|
|
|
- break
|
|
|
- }
|
|
|
- case "step.started": {
|
|
|
- if (pendingAssistant) pendingAssistant.time.completed = event.timestamp
|
|
|
- draft.entries.push({
|
|
|
- id: event.id,
|
|
|
- type: "assistant",
|
|
|
- time: {
|
|
|
- created: event.timestamp,
|
|
|
- },
|
|
|
- content: [],
|
|
|
- })
|
|
|
- break
|
|
|
- }
|
|
|
- case "text.started": {
|
|
|
- if (!pendingAssistant) break
|
|
|
- pendingAssistant.content.push({
|
|
|
- type: "text",
|
|
|
- text: "",
|
|
|
- })
|
|
|
+ draft.pending.push(User.fromEvent(event))
|
|
|
break
|
|
|
}
|
|
|
- case "text.delta": {
|
|
|
- if (!pendingAssistant) break
|
|
|
- const match = pendingAssistant.content.findLast((x) => x.type === "text")
|
|
|
- if (match) match.text += event.delta
|
|
|
- break
|
|
|
- }
|
|
|
- case "text.ended": {
|
|
|
- break
|
|
|
- }
|
|
|
- case "tool.input.started": {
|
|
|
- if (!pendingAssistant) break
|
|
|
- pendingAssistant.content.push({
|
|
|
- type: "tool",
|
|
|
- callID: event.callID,
|
|
|
- name: event.name,
|
|
|
- time: {
|
|
|
- created: event.timestamp,
|
|
|
- },
|
|
|
- state: {
|
|
|
- status: "pending",
|
|
|
- input: "",
|
|
|
- },
|
|
|
- })
|
|
|
- break
|
|
|
- }
|
|
|
- case "tool.input.delta": {
|
|
|
- if (!pendingAssistant) break
|
|
|
- const match = pendingAssistant.content.findLast((x) => x.type === "tool")
|
|
|
- // oxlint-disable-next-line no-base-to-string -- event.delta is a Schema.String (runtime string)
|
|
|
- if (match) match.state.input += event.delta
|
|
|
- break
|
|
|
- }
|
|
|
- case "tool.input.ended": {
|
|
|
- break
|
|
|
- }
|
|
|
- case "tool.called": {
|
|
|
- if (!pendingAssistant) break
|
|
|
- const match = pendingAssistant.content.findLast((x) => x.type === "tool")
|
|
|
- if (match) {
|
|
|
- match.time.ran = event.timestamp
|
|
|
- match.state = {
|
|
|
- status: "running",
|
|
|
- input: event.input,
|
|
|
- }
|
|
|
+ // @ts-expect-error
|
|
|
+ draft.entries.push(User.fromEvent(event))
|
|
|
+ break
|
|
|
+ }
|
|
|
+ case "step.started": {
|
|
|
+ if (pendingAssistant) pendingAssistant.time.completed = event.timestamp
|
|
|
+ draft.entries.push({
|
|
|
+ id: event.id,
|
|
|
+ type: "assistant",
|
|
|
+ time: {
|
|
|
+ created: event.timestamp,
|
|
|
+ },
|
|
|
+ content: [],
|
|
|
+ })
|
|
|
+ break
|
|
|
+ }
|
|
|
+ case "text.started": {
|
|
|
+ if (!pendingAssistant) break
|
|
|
+ pendingAssistant.content.push({
|
|
|
+ type: "text",
|
|
|
+ text: "",
|
|
|
+ })
|
|
|
+ break
|
|
|
+ }
|
|
|
+ case "text.delta": {
|
|
|
+ if (!pendingAssistant) break
|
|
|
+ const match = pendingAssistant.content.findLast((x) => x.type === "text")
|
|
|
+ if (match) match.text += event.delta
|
|
|
+ break
|
|
|
+ }
|
|
|
+ case "text.ended": {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ case "tool.input.started": {
|
|
|
+ if (!pendingAssistant) break
|
|
|
+ pendingAssistant.content.push({
|
|
|
+ type: "tool",
|
|
|
+ callID: event.callID,
|
|
|
+ name: event.name,
|
|
|
+ time: {
|
|
|
+ created: event.timestamp,
|
|
|
+ },
|
|
|
+ state: {
|
|
|
+ status: "pending",
|
|
|
+ input: "",
|
|
|
+ },
|
|
|
+ })
|
|
|
+ break
|
|
|
+ }
|
|
|
+ case "tool.input.delta": {
|
|
|
+ if (!pendingAssistant) break
|
|
|
+ const match = pendingAssistant.content.findLast((x) => x.type === "tool")
|
|
|
+ // oxlint-disable-next-line no-base-to-string -- event.delta is a Schema.String (runtime string)
|
|
|
+ if (match) match.state.input += event.delta
|
|
|
+ break
|
|
|
+ }
|
|
|
+ case "tool.input.ended": {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ case "tool.called": {
|
|
|
+ if (!pendingAssistant) break
|
|
|
+ const match = pendingAssistant.content.findLast((x) => x.type === "tool")
|
|
|
+ if (match) {
|
|
|
+ match.time.ran = event.timestamp
|
|
|
+ match.state = {
|
|
|
+ status: "running",
|
|
|
+ input: event.input,
|
|
|
}
|
|
|
- break
|
|
|
}
|
|
|
- case "tool.success": {
|
|
|
- if (!pendingAssistant) break
|
|
|
- const match = pendingAssistant.content.findLast((x) => x.type === "tool")
|
|
|
- if (match && match.state.status === "running") {
|
|
|
- match.state = {
|
|
|
- status: "completed",
|
|
|
- input: match.state.input,
|
|
|
- output: event.output ?? "",
|
|
|
- title: event.title,
|
|
|
- metadata: event.metadata ?? {},
|
|
|
- // @ts-expect-error
|
|
|
- attachments: event.attachments ?? [],
|
|
|
- }
|
|
|
+ break
|
|
|
+ }
|
|
|
+ case "tool.success": {
|
|
|
+ if (!pendingAssistant) break
|
|
|
+ const match = pendingAssistant.content.findLast((x) => x.type === "tool")
|
|
|
+ if (match && match.state.status === "running") {
|
|
|
+ match.state = {
|
|
|
+ status: "completed",
|
|
|
+ input: match.state.input,
|
|
|
+ output: event.output ?? "",
|
|
|
+ title: event.title,
|
|
|
+ metadata: event.metadata ?? {},
|
|
|
+ // @ts-expect-error
|
|
|
+ attachments: event.attachments ?? [],
|
|
|
}
|
|
|
- break
|
|
|
}
|
|
|
- case "tool.error": {
|
|
|
- if (!pendingAssistant) break
|
|
|
- const match = pendingAssistant.content.findLast((x) => x.type === "tool")
|
|
|
- if (match && match.state.status === "running") {
|
|
|
- match.state = {
|
|
|
- status: "error",
|
|
|
- error: event.error,
|
|
|
- input: match.state.input,
|
|
|
- metadata: event.metadata ?? {},
|
|
|
- }
|
|
|
+ break
|
|
|
+ }
|
|
|
+ case "tool.error": {
|
|
|
+ if (!pendingAssistant) break
|
|
|
+ const match = pendingAssistant.content.findLast((x) => x.type === "tool")
|
|
|
+ if (match && match.state.status === "running") {
|
|
|
+ match.state = {
|
|
|
+ status: "error",
|
|
|
+ error: event.error,
|
|
|
+ input: match.state.input,
|
|
|
+ metadata: event.metadata ?? {},
|
|
|
}
|
|
|
- break
|
|
|
- }
|
|
|
- case "reasoning.started": {
|
|
|
- if (!pendingAssistant) break
|
|
|
- pendingAssistant.content.push({
|
|
|
- type: "reasoning",
|
|
|
- text: "",
|
|
|
- })
|
|
|
- break
|
|
|
- }
|
|
|
- case "reasoning.delta": {
|
|
|
- if (!pendingAssistant) break
|
|
|
- const match = pendingAssistant.content.findLast((x) => x.type === "reasoning")
|
|
|
- if (match) match.text += event.delta
|
|
|
- break
|
|
|
- }
|
|
|
- case "reasoning.ended": {
|
|
|
- if (!pendingAssistant) break
|
|
|
- const match = pendingAssistant.content.findLast((x) => x.type === "reasoning")
|
|
|
- if (match) match.text = event.text
|
|
|
- break
|
|
|
- }
|
|
|
- case "step.ended": {
|
|
|
- if (!pendingAssistant) break
|
|
|
- pendingAssistant.time.completed = event.timestamp
|
|
|
- pendingAssistant.cost = event.cost
|
|
|
- pendingAssistant.tokens = event.tokens
|
|
|
- break
|
|
|
}
|
|
|
+ break
|
|
|
}
|
|
|
- })
|
|
|
- }
|
|
|
+ case "reasoning.started": {
|
|
|
+ if (!pendingAssistant) break
|
|
|
+ pendingAssistant.content.push({
|
|
|
+ type: "reasoning",
|
|
|
+ text: "",
|
|
|
+ })
|
|
|
+ break
|
|
|
+ }
|
|
|
+ case "reasoning.delta": {
|
|
|
+ if (!pendingAssistant) break
|
|
|
+ const match = pendingAssistant.content.findLast((x) => x.type === "reasoning")
|
|
|
+ if (match) match.text += event.delta
|
|
|
+ break
|
|
|
+ }
|
|
|
+ case "reasoning.ended": {
|
|
|
+ if (!pendingAssistant) break
|
|
|
+ const match = pendingAssistant.content.findLast((x) => x.type === "reasoning")
|
|
|
+ if (match) match.text = event.text
|
|
|
+ break
|
|
|
+ }
|
|
|
+ case "step.ended": {
|
|
|
+ if (!pendingAssistant) break
|
|
|
+ pendingAssistant.time.completed = event.timestamp
|
|
|
+ pendingAssistant.cost = event.cost
|
|
|
+ pendingAssistant.tokens = event.tokens
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
|
|
|
- /*
|
|
|
- export interface Interface {
|
|
|
- readonly decode: (row: typeof SessionEntryTable.$inferSelect) => Entry
|
|
|
- readonly fromSession: (sessionID: SessionID) => Effect.Effect<Entry[], never>
|
|
|
- }
|
|
|
+/*
|
|
|
+export interface Interface {
|
|
|
+ readonly decode: (row: typeof SessionEntryTable.$inferSelect) => Entry
|
|
|
+ readonly fromSession: (sessionID: SessionID) => Effect.Effect<Entry[], never>
|
|
|
+}
|
|
|
|
|
|
- export class Service extends Context.Service<Service, Interface>()("@opencode/SessionEntry") {}
|
|
|
+export class Service extends Context.Service<Service, Interface>()("@opencode/SessionEntry") {}
|
|
|
|
|
|
- export const layer: Layer.Layer<Service, never, never> = Layer.effect(
|
|
|
- Service,
|
|
|
- Effect.gen(function* () {
|
|
|
- const decodeEntry = Schema.decodeUnknownSync(Entry)
|
|
|
+export const layer: Layer.Layer<Service, never, never> = Layer.effect(
|
|
|
+ Service,
|
|
|
+ Effect.gen(function* () {
|
|
|
+ const decodeEntry = Schema.decodeUnknownSync(Entry)
|
|
|
|
|
|
- const decode: (typeof Service.Service)["decode"] = (row) => decodeEntry({ ...row, id: row.id, type: row.type })
|
|
|
+ const decode: (typeof Service.Service)["decode"] = (row) => decodeEntry({ ...row, id: row.id, type: row.type })
|
|
|
|
|
|
- const fromSession = Effect.fn("SessionEntry.fromSession")(function* (sessionID: SessionID) {
|
|
|
- return Database.use((db) =>
|
|
|
- db
|
|
|
- .select()
|
|
|
- .from(SessionEntryTable)
|
|
|
- .where(eq(SessionEntryTable.session_id, sessionID))
|
|
|
- .orderBy(SessionEntryTable.id)
|
|
|
- .all()
|
|
|
- .map((row) => decode(row)),
|
|
|
- )
|
|
|
- })
|
|
|
+ const fromSession = Effect.fn("SessionEntry.fromSession")(function* (sessionID: SessionID) {
|
|
|
+ return Database.use((db) =>
|
|
|
+ db
|
|
|
+ .select()
|
|
|
+ .from(SessionEntryTable)
|
|
|
+ .where(eq(SessionEntryTable.session_id, sessionID))
|
|
|
+ .orderBy(SessionEntryTable.id)
|
|
|
+ .all()
|
|
|
+ .map((row) => decode(row)),
|
|
|
+ )
|
|
|
+ })
|
|
|
|
|
|
- return Service.of({
|
|
|
- decode,
|
|
|
- fromSession,
|
|
|
- })
|
|
|
- }),
|
|
|
- )
|
|
|
- */
|
|
|
-}
|
|
|
+ return Service.of({
|
|
|
+ decode,
|
|
|
+ fromSession,
|
|
|
+ })
|
|
|
+ }),
|
|
|
+)
|
|
|
+*/
|
|
|
+
|
|
|
+export * as SessionEntry from "./session-entry"
|