session.test.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import { describe, expect, test } from "bun:test"
  2. import path from "path"
  3. import { Session } from "../../src/session"
  4. import { Bus } from "../../src/bus"
  5. import { Log } from "../../src/util/log"
  6. import { Instance } from "../../src/project/instance"
  7. import { MessageV2 } from "../../src/session/message-v2"
  8. import { MessageID, PartID } from "../../src/session/schema"
  9. const projectRoot = path.join(__dirname, "../..")
  10. Log.init({ print: false })
  11. describe("session.created event", () => {
  12. test("should emit session.created event when session is created", async () => {
  13. await Instance.provide({
  14. directory: projectRoot,
  15. fn: async () => {
  16. let eventReceived = false
  17. let receivedInfo: Session.Info | undefined
  18. const unsub = Bus.subscribe(Session.Event.Created, (event) => {
  19. eventReceived = true
  20. receivedInfo = event.properties.info as Session.Info
  21. })
  22. const session = await Session.create({})
  23. await new Promise((resolve) => setTimeout(resolve, 100))
  24. unsub()
  25. expect(eventReceived).toBe(true)
  26. expect(receivedInfo).toBeDefined()
  27. expect(receivedInfo?.id).toBe(session.id)
  28. expect(receivedInfo?.projectID).toBe(session.projectID)
  29. expect(receivedInfo?.directory).toBe(session.directory)
  30. expect(receivedInfo?.title).toBe(session.title)
  31. await Session.remove(session.id)
  32. },
  33. })
  34. })
  35. test("session.created event should be emitted before session.updated", async () => {
  36. await Instance.provide({
  37. directory: projectRoot,
  38. fn: async () => {
  39. const events: string[] = []
  40. const unsubCreated = Bus.subscribe(Session.Event.Created, () => {
  41. events.push("created")
  42. })
  43. const unsubUpdated = Bus.subscribe(Session.Event.Updated, () => {
  44. events.push("updated")
  45. })
  46. const session = await Session.create({})
  47. await new Promise((resolve) => setTimeout(resolve, 100))
  48. unsubCreated()
  49. unsubUpdated()
  50. expect(events).toContain("created")
  51. expect(events).toContain("updated")
  52. expect(events.indexOf("created")).toBeLessThan(events.indexOf("updated"))
  53. await Session.remove(session.id)
  54. },
  55. })
  56. })
  57. })
  58. describe("step-finish token propagation via Bus event", () => {
  59. test(
  60. "non-zero tokens propagate through PartUpdated event",
  61. async () => {
  62. await Instance.provide({
  63. directory: projectRoot,
  64. fn: async () => {
  65. const session = await Session.create({})
  66. const messageID = MessageID.ascending()
  67. await Session.updateMessage({
  68. id: messageID,
  69. sessionID: session.id,
  70. role: "user",
  71. time: { created: Date.now() },
  72. agent: "user",
  73. model: { providerID: "test", modelID: "test" },
  74. tools: {},
  75. mode: "",
  76. } as unknown as MessageV2.Info)
  77. let received: MessageV2.Part | undefined
  78. const unsub = Bus.subscribe(MessageV2.Event.PartUpdated, (event) => {
  79. received = event.properties.part
  80. })
  81. const tokens = {
  82. total: 1500,
  83. input: 500,
  84. output: 800,
  85. reasoning: 200,
  86. cache: { read: 100, write: 50 },
  87. }
  88. const partInput = {
  89. id: PartID.ascending(),
  90. messageID,
  91. sessionID: session.id,
  92. type: "step-finish" as const,
  93. reason: "stop",
  94. cost: 0.005,
  95. tokens,
  96. }
  97. await Session.updatePart(partInput)
  98. await new Promise((resolve) => setTimeout(resolve, 100))
  99. expect(received).toBeDefined()
  100. expect(received!.type).toBe("step-finish")
  101. const finish = received as MessageV2.StepFinishPart
  102. expect(finish.tokens.input).toBe(500)
  103. expect(finish.tokens.output).toBe(800)
  104. expect(finish.tokens.reasoning).toBe(200)
  105. expect(finish.tokens.total).toBe(1500)
  106. expect(finish.tokens.cache.read).toBe(100)
  107. expect(finish.tokens.cache.write).toBe(50)
  108. expect(finish.cost).toBe(0.005)
  109. expect(received).not.toBe(partInput)
  110. unsub()
  111. await Session.remove(session.id)
  112. },
  113. })
  114. },
  115. { timeout: 30000 },
  116. )
  117. })