| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- import { expect, test } from "bun:test"
- import { Effect } from "effect"
- import * as DateTime from "effect/DateTime"
- import { SessionID } from "../../src/session/schema"
- import { EventV2 } from "@kirincode-ai/core/event"
- import { ModelV2 } from "@kirincode-ai/core/model"
- import { ProviderV2 } from "@kirincode-ai/core/provider"
- import { SessionEvent } from "@kirincode-ai/core/session/event"
- import { SessionMessageUpdater } from "@kirincode-ai/core/session/message-updater"
- import { SessionMessage } from "@kirincode-ai/core/session/message"
- test.skip("step snapshots carry over to assistant messages", () => {
- const state: SessionMessageUpdater.MemoryState = { messages: [] }
- const sessionID = SessionID.make("session")
- const assistantMessageID = SessionMessage.ID.create()
- Effect.runSync(
- SessionMessageUpdater.update(SessionMessageUpdater.memory(state), {
- id: EventV2.ID.create(),
- type: "session.next.step.started",
- data: {
- sessionID,
- assistantMessageID,
- timestamp: DateTime.makeUnsafe(1),
- agent: "build",
- model: {
- id: ModelV2.ID.make("model"),
- providerID: ProviderV2.ID.make("provider"),
- variant: ModelV2.VariantID.make("default"),
- },
- snapshot: "before",
- },
- } satisfies SessionEvent.Event),
- )
- expect(state.messages).toEqual([])
- Effect.runSync(
- SessionMessageUpdater.update(SessionMessageUpdater.memory(state), {
- id: EventV2.ID.create(),
- type: "session.next.step.ended",
- data: {
- sessionID,
- assistantMessageID,
- timestamp: DateTime.makeUnsafe(2),
- finish: "stop",
- cost: 0,
- tokens: {
- input: 1,
- output: 2,
- reasoning: 0,
- cache: { read: 0, write: 0 },
- },
- snapshot: "after",
- },
- } satisfies SessionEvent.Event),
- )
- expect(state.messages[0]?.type).toBe("assistant")
- if (state.messages[0]?.type !== "assistant") return
- expect(state.messages[0].snapshot).toEqual({ start: "before", end: "after" })
- expect(state.messages[0].finish).toBe("stop")
- })
- test.skip("text ended populates assistant text content", () => {
- const state: SessionMessageUpdater.MemoryState = { messages: [] }
- const sessionID = SessionID.make("session")
- const assistantMessageID = SessionMessage.ID.create()
- Effect.runSync(
- SessionMessageUpdater.update(SessionMessageUpdater.memory(state), {
- id: EventV2.ID.create(),
- type: "session.next.step.started",
- data: {
- sessionID,
- assistantMessageID,
- timestamp: DateTime.makeUnsafe(1),
- agent: "build",
- model: {
- id: ModelV2.ID.make("model"),
- providerID: ProviderV2.ID.make("provider"),
- variant: ModelV2.VariantID.make("default"),
- },
- },
- } satisfies SessionEvent.Event),
- )
- Effect.runSync(
- SessionMessageUpdater.update(SessionMessageUpdater.memory(state), {
- id: EventV2.ID.create(),
- type: "session.next.text.started",
- data: {
- sessionID,
- assistantMessageID,
- timestamp: DateTime.makeUnsafe(2),
- textID: "text-1",
- },
- } satisfies SessionEvent.Event),
- )
- Effect.runSync(
- SessionMessageUpdater.update(SessionMessageUpdater.memory(state), {
- id: EventV2.ID.create(),
- type: "session.next.text.ended",
- data: {
- sessionID,
- assistantMessageID,
- timestamp: DateTime.makeUnsafe(3),
- textID: "text-1",
- text: "hello assistant",
- },
- } satisfies SessionEvent.Event),
- )
- expect(state.messages[0]?.type).toBe("assistant")
- if (state.messages[0]?.type !== "assistant") return
- expect(state.messages[0].content).toEqual([{ type: "text", id: "text-1", text: "hello assistant" }])
- })
- test.skip("tool completion stores completed timestamp", () => {
- const state: SessionMessageUpdater.MemoryState = { messages: [] }
- const sessionID = SessionID.make("session")
- const callID = "call"
- const assistantMessageID = SessionMessage.ID.create()
- Effect.runSync(
- SessionMessageUpdater.update(SessionMessageUpdater.memory(state), {
- id: EventV2.ID.create(),
- type: "session.next.step.started",
- data: {
- sessionID,
- assistantMessageID,
- timestamp: DateTime.makeUnsafe(1),
- agent: "build",
- model: {
- id: ModelV2.ID.make("model"),
- providerID: ProviderV2.ID.make("provider"),
- variant: ModelV2.VariantID.make("default"),
- },
- },
- } satisfies SessionEvent.Event),
- )
- Effect.runSync(
- SessionMessageUpdater.update(SessionMessageUpdater.memory(state), {
- id: EventV2.ID.create(),
- type: "session.next.tool.input.started",
- data: {
- sessionID,
- assistantMessageID,
- timestamp: DateTime.makeUnsafe(2),
- callID,
- name: "bash",
- },
- } satisfies SessionEvent.Event),
- )
- Effect.runSync(
- SessionMessageUpdater.update(SessionMessageUpdater.memory(state), {
- id: EventV2.ID.create(),
- type: "session.next.tool.called",
- data: {
- sessionID,
- assistantMessageID,
- timestamp: DateTime.makeUnsafe(3),
- callID,
- tool: "bash",
- input: { command: "pwd" },
- provider: { executed: true, metadata: { fake: { source: "provider" } } },
- },
- } satisfies SessionEvent.Event),
- )
- Effect.runSync(
- SessionMessageUpdater.update(SessionMessageUpdater.memory(state), {
- id: EventV2.ID.create(),
- type: "session.next.tool.success",
- data: {
- sessionID,
- assistantMessageID,
- timestamp: DateTime.makeUnsafe(4),
- callID,
- structured: {},
- content: [{ type: "text", text: "/tmp" }],
- provider: { executed: true, metadata: { fake: { status: "done" } } },
- },
- } satisfies SessionEvent.Event),
- )
- expect(state.messages[0]?.type).toBe("assistant")
- if (state.messages[0]?.type !== "assistant") return
- expect(state.messages[0].content[0]?.type).toBe("tool")
- if (state.messages[0].content[0]?.type !== "tool") return
- expect(state.messages[0].content[0].time.completed).toEqual(DateTime.makeUnsafe(4))
- expect(state.messages[0].content[0].provider).toEqual({ executed: true, metadata: { fake: { status: "done" } } })
- })
- test("compaction events reduce to compaction message only when completed", () => {
- const state: SessionMessageUpdater.MemoryState = { messages: [] }
- const sessionID = SessionID.make("session")
- const id = EventV2.ID.create()
- const compactionID = SessionMessage.ID.create()
- Effect.runSync(
- SessionMessageUpdater.update(SessionMessageUpdater.memory(state), {
- id,
- type: "session.next.compaction.started",
- data: {
- sessionID,
- messageID: compactionID,
- timestamp: DateTime.makeUnsafe(1),
- reason: "auto",
- },
- } satisfies SessionEvent.Event),
- )
- expect(state.messages).toEqual([])
- Effect.runSync(
- SessionMessageUpdater.update(SessionMessageUpdater.memory(state), {
- id: EventV2.ID.create(),
- type: "session.next.compaction.delta",
- data: {
- sessionID,
- messageID: compactionID,
- timestamp: DateTime.makeUnsafe(2),
- text: "hello ",
- },
- } satisfies SessionEvent.Event),
- )
- Effect.runSync(
- SessionMessageUpdater.update(SessionMessageUpdater.memory(state), {
- id: EventV2.ID.create(),
- type: "session.next.compaction.delta",
- data: {
- sessionID,
- messageID: compactionID,
- timestamp: DateTime.makeUnsafe(3),
- text: "summary",
- },
- } satisfies SessionEvent.Event),
- )
- Effect.runSync(
- SessionMessageUpdater.update(SessionMessageUpdater.memory(state), {
- id: EventV2.ID.create(),
- type: "session.next.compaction.ended",
- data: {
- sessionID,
- messageID: compactionID,
- timestamp: DateTime.makeUnsafe(4),
- reason: "auto",
- text: "final summary",
- recent: "recent context",
- },
- } satisfies SessionEvent.Event),
- )
- expect(state.messages).toHaveLength(1)
- expect(state.messages[0]).toMatchObject({
- id: compactionID,
- type: "compaction",
- reason: "auto",
- summary: "final summary",
- recent: "recent context",
- time: { created: DateTime.makeUnsafe(4) },
- })
- })
|