@vercel/factory 0.0.17 → 0.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/dist/api-contracts.d.mts +665 -715
  3. package/dist/api-contracts.mjs +91 -4
  4. package/dist/api-contracts.mjs.map +1 -1
  5. package/dist/api-task-graph.mjs +14 -5
  6. package/dist/api-task-graph.mjs.map +1 -1
  7. package/dist/api.d.mts +58 -11
  8. package/dist/api.mjs +715 -399
  9. package/dist/api.mjs.map +1 -1
  10. package/dist/approval-access.d.mts +1 -1
  11. package/dist/approval-contracts.d.mts +3 -4
  12. package/dist/approval-contracts.mjs +1 -2
  13. package/dist/approval-contracts.mjs.map +1 -1
  14. package/dist/blob/index.d.mts +1 -1
  15. package/dist/budget.mjs +20 -3
  16. package/dist/budget.mjs.map +1 -1
  17. package/dist/change-verification/brief.d.mts +1 -1
  18. package/dist/change-verification/dispatch.mjs +8 -1
  19. package/dist/change-verification/dispatch.mjs.map +1 -1
  20. package/dist/changes/eve-record-change.mjs +4 -1
  21. package/dist/changes/eve-record-change.mjs.map +1 -1
  22. package/dist/client-stream.d.mts +19 -2
  23. package/dist/client-stream.mjs +115 -53
  24. package/dist/client-stream.mjs.map +1 -1
  25. package/dist/client-transcript.d.mts +25 -2
  26. package/dist/client-transcript.mjs +95 -13
  27. package/dist/client-transcript.mjs.map +1 -1
  28. package/dist/client.d.mts +145 -19
  29. package/dist/client.mjs +89 -16
  30. package/dist/client.mjs.map +1 -1
  31. package/dist/code-review/contracts.d.mts +1 -0
  32. package/dist/code-review/eve-post-review.d.mts +4 -2
  33. package/dist/code-review/eve-post-review.mjs +8 -0
  34. package/dist/code-review/eve-post-review.mjs.map +1 -1
  35. package/dist/code-review/github-reporter.d.mts +6 -2
  36. package/dist/code-review/github-reporter.mjs +86 -35
  37. package/dist/code-review/github-reporter.mjs.map +1 -1
  38. package/dist/code-review/preparation.d.mts +2 -1
  39. package/dist/code-review/preparation.mjs +2 -1
  40. package/dist/code-review/preparation.mjs.map +1 -1
  41. package/dist/code-review/stall.mjs +11 -2
  42. package/dist/code-review/stall.mjs.map +1 -1
  43. package/dist/connectors/github.d.mts +1 -1
  44. package/dist/connectors/index.d.mts +1 -1
  45. package/dist/connectors/slack.d.mts +1 -1
  46. package/dist/delivery-metrics/metrics.d.mts +1 -1
  47. package/dist/dispatch.mjs +3 -3
  48. package/dist/dispatch.mjs.map +1 -1
  49. package/dist/eve/index.d.mts +1 -1
  50. package/dist/eve/index.mjs +8 -1
  51. package/dist/eve/index.mjs.map +1 -1
  52. package/dist/eve/task-execution.d.mts +4 -4
  53. package/dist/eve/transcript.d.mts +3 -1
  54. package/dist/eve/transcript.mjs.map +1 -1
  55. package/dist/finding-remediation/admission.d.mts +1 -1
  56. package/dist/finding-remediation/brief.d.mts +1 -1
  57. package/dist/github-app.d.mts +1 -1
  58. package/dist/github-publication.d.mts +1 -1
  59. package/dist/github.d.mts +9 -1
  60. package/dist/github.mjs +29 -11
  61. package/dist/github.mjs.map +1 -1
  62. package/dist/index.d.mts +1 -1
  63. package/dist/intake-contracts.d.mts +1 -0
  64. package/dist/intake-contracts.mjs +2 -1
  65. package/dist/intake-contracts.mjs.map +1 -1
  66. package/dist/integrations/github-issues.d.mts +53 -0
  67. package/dist/integrations/github-issues.mjs +170 -0
  68. package/dist/integrations/github-issues.mjs.map +1 -0
  69. package/dist/integrations/github.d.mts +2 -1
  70. package/dist/integrations/github.mjs +2 -1
  71. package/dist/multi-repository-changes/coordination.mjs +1 -1
  72. package/dist/planning/reconcile.mjs +15 -2
  73. package/dist/planning/reconcile.mjs.map +1 -1
  74. package/dist/postgres/index.d.mts +2 -1
  75. package/dist/postgres/index.mjs +11 -5
  76. package/dist/postgres/index.mjs.map +1 -1
  77. package/dist/postgres/indexed-codec.mjs +137 -0
  78. package/dist/postgres/indexed-codec.mjs.map +1 -0
  79. package/dist/postgres/indexed-schema.mjs +99 -0
  80. package/dist/postgres/indexed-schema.mjs.map +1 -0
  81. package/dist/postgres/indexed.d.mts +28 -0
  82. package/dist/postgres/indexed.mjs +277 -0
  83. package/dist/postgres/indexed.mjs.map +1 -0
  84. package/dist/postgres/record-predicates.mjs +23 -0
  85. package/dist/postgres/record-predicates.mjs.map +1 -0
  86. package/dist/presets/software-development/deepsec-brief.d.mts +1 -1
  87. package/dist/presets/software-development/dispatch.mjs +1 -1
  88. package/dist/presets/software-development/dispatch.mjs.map +1 -1
  89. package/dist/presets/software-development/recovery.mjs +9 -2
  90. package/dist/presets/software-development/recovery.mjs.map +1 -1
  91. package/dist/pull-requests/eve-fetch.d.mts +4 -1
  92. package/dist/pull-requests/eve-fetch.mjs +9 -0
  93. package/dist/pull-requests/eve-fetch.mjs.map +1 -1
  94. package/dist/pull-requests/github-publisher.d.mts +1 -1
  95. package/dist/pull-requests/github-publisher.mjs +19 -7
  96. package/dist/pull-requests/github-publisher.mjs.map +1 -1
  97. package/dist/repositories.mjs +20 -13
  98. package/dist/repositories.mjs.map +1 -1
  99. package/dist/sandbox/execution-run-ledger.d.mts +2 -2
  100. package/dist/sandbox/execution-run-ledger.mjs.map +1 -1
  101. package/dist/sandbox/execution.d.mts +2 -2
  102. package/dist/sandbox/execution.mjs.map +1 -1
  103. package/dist/schema/catalog.mjs +1 -1
  104. package/dist/schema/change.d.mts +1 -1
  105. package/dist/schema/communication.d.mts +2 -2
  106. package/dist/schema/factory-config.d.mts +1 -1
  107. package/dist/schema/outbox.d.mts +6 -6
  108. package/dist/schema/session-summary.d.mts +218 -0
  109. package/dist/schema/session-summary.mjs +68 -0
  110. package/dist/schema/session-summary.mjs.map +1 -0
  111. package/dist/schema/session.d.mts +39 -59
  112. package/dist/schema/session.mjs +6 -6
  113. package/dist/schema/session.mjs.map +1 -1
  114. package/dist/schema/task-graph.d.mts +24 -24
  115. package/dist/schema/transcript.d.mts +141 -3
  116. package/dist/schema/transcript.mjs +19 -3
  117. package/dist/schema/transcript.mjs.map +1 -1
  118. package/dist/schema/transitions.d.mts +1 -1
  119. package/dist/schema/transitions.mjs +1 -1
  120. package/dist/schema/transitions.mjs.map +1 -1
  121. package/dist/signals.d.mts +1 -1
  122. package/dist/stall.mjs +10 -2
  123. package/dist/stall.mjs.map +1 -1
  124. package/dist/storage.d.mts +10 -1
  125. package/dist/storage.mjs +7 -1
  126. package/dist/store/approvals.d.mts +14 -0
  127. package/dist/store/approvals.mjs +78 -0
  128. package/dist/store/approvals.mjs.map +1 -0
  129. package/dist/store/conversations.d.mts +59 -0
  130. package/dist/store/conversations.mjs +549 -0
  131. package/dist/store/conversations.mjs.map +1 -0
  132. package/dist/store/driver.d.mts +1 -1
  133. package/dist/store/driver.mjs.map +1 -1
  134. package/dist/store/engine.d.mts +38 -16
  135. package/dist/store/engine.mjs +229 -106
  136. package/dist/store/engine.mjs.map +1 -1
  137. package/dist/store/indexed-engine.d.mts +57 -0
  138. package/dist/store/indexed-engine.mjs +155 -0
  139. package/dist/store/indexed-engine.mjs.map +1 -0
  140. package/dist/store/indexed-memory.d.mts +7 -0
  141. package/dist/store/indexed-memory.mjs +200 -0
  142. package/dist/store/indexed-memory.mjs.map +1 -0
  143. package/dist/store/indexed-projections.d.mts +280 -0
  144. package/dist/store/indexed-projections.mjs +481 -0
  145. package/dist/store/indexed-projections.mjs.map +1 -0
  146. package/dist/store/indexed.d.mts +101 -0
  147. package/dist/store/indexed.mjs +19 -0
  148. package/dist/store/indexed.mjs.map +1 -0
  149. package/dist/store/iterate.d.mts +9 -0
  150. package/dist/store/iterate.mjs +23 -0
  151. package/dist/store/iterate.mjs.map +1 -0
  152. package/dist/store/query-scope.mjs +62 -0
  153. package/dist/store/query-scope.mjs.map +1 -0
  154. package/dist/store/query.d.mts +32 -0
  155. package/dist/store/query.mjs +103 -0
  156. package/dist/store/query.mjs.map +1 -0
  157. package/dist/store/session-history.mjs +24 -0
  158. package/dist/store/session-history.mjs.map +1 -0
  159. package/dist/store/slack-pr-notifications.d.mts +2 -2
  160. package/dist/store/slack-pr-notifications.mjs.map +1 -1
  161. package/dist/store/state.d.mts +26 -0
  162. package/dist/store/state.mjs +95 -0
  163. package/dist/store/state.mjs.map +1 -0
  164. package/dist/store/task-effects.d.mts +1 -1
  165. package/dist/store/task-graphs.d.mts +1 -1
  166. package/dist/store/task-messages.d.mts +1 -1
  167. package/dist/store/task-work.d.mts +1 -1
  168. package/dist/store/task-work.mjs +1 -1
  169. package/dist/store/transcripts.mjs +308 -0
  170. package/dist/store/transcripts.mjs.map +1 -0
  171. package/dist/sweep.d.mts +1 -1
  172. package/dist/sweep.mjs +12 -7
  173. package/dist/sweep.mjs.map +1 -1
  174. package/dist/task-communication.mjs +15 -1
  175. package/dist/task-communication.mjs.map +1 -1
  176. package/dist/task-protocols.d.mts +3 -3
  177. package/dist/tasks.d.mts +1 -1
  178. package/dist/vercel.d.mts +1 -1
  179. package/dist/work-triage/find-existing-work.d.mts +1 -1
  180. package/dist/work-triage/find-existing-work.mjs +12 -2
  181. package/dist/work-triage/find-existing-work.mjs.map +1 -1
  182. package/docs/index.md +4 -0
  183. package/docs/recipes/persistence-recovery.md +15 -9
  184. package/docs/recipes/postgres-indexed-engine.md +108 -0
  185. package/docs/recipes/postgres-indexed-storage.md +145 -0
  186. package/package.json +3 -1
@@ -1 +1 @@
1
- {"version":3,"file":"client-stream.mjs","names":[],"sources":["../src/client-stream.ts"],"sourcesContent":["import { ApiError, type FactoryClient } from \"./client\";\nimport { readEvents } from \"./client-events\";\nimport { Transcript } from \"./client-transcript\";\nimport type { SessionView } from \"./api-contracts\";\nimport type { TaskId } from \"./schema/id\";\nimport type { AgentSessionId } from \"./schema/session\";\nimport { transcriptSnapshotSchema } from \"./schema/transcript\";\n\n/** Client operations required to hydrate and follow a Factory session stream. */\nexport type SessionStreamClient = Pick<\n FactoryClient,\n \"getSessionTranscriptResponse\" | \"getSessionEventStreamResponse\"\n>;\n\n/** Callbacks and exact execution identity used while following a session stream. */\nexport interface FollowSessionStreamOptions {\n readonly sessionId: AgentSessionId;\n readonly executionId: string | null;\n readonly taskId?: TaskId;\n readonly history?: readonly NonNullable<SessionView[\"history\"]>[number][];\n readonly transcript: Transcript;\n readonly signal: AbortSignal;\n readonly pollIntervalMs?: number;\n readonly onHydrated: () => void;\n readonly onChange: () => void;\n readonly onConnection: (state: \"connected\" | \"reconnecting\") => void;\n readonly onError: (error: unknown) => void;\n readonly onConflict: () => Promise<void>;\n}\n\nfunction pause(ms: number, signal: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n const finish = () => {\n clearTimeout(timer);\n signal.removeEventListener(\"abort\", finish);\n resolve();\n };\n const timer = setTimeout(finish, ms);\n signal.addEventListener(\"abort\", finish, { once: true });\n if (signal.aborted) finish();\n });\n}\n\nasync function readSnapshot(\n client: SessionStreamClient,\n input: {\n sessionId: AgentSessionId;\n executionId: string;\n taskId?: TaskId;\n history: boolean;\n transcript: Transcript;\n signal: AbortSignal;\n pollIntervalMs: number;\n onRetry?(error: unknown): void;\n },\n) {\n let failures = 0;\n while (!input.signal.aborted) {\n try {\n const requestSignal = AbortSignal.any([input.signal, AbortSignal.timeout(15_000)]);\n const response = await client.getSessionTranscriptResponse({\n sessionId: input.sessionId,\n executionId: input.executionId,\n ...(input.taskId === undefined ? {} : { taskId: input.taskId }),\n ...(input.history ? { history: true } : {}),\n signal: requestSignal,\n });\n input.transcript.hydrate(transcriptSnapshotSchema.parse(await response.json()));\n return;\n } catch (error) {\n if (input.signal.aborted) return;\n if (error instanceof ApiError) throw error;\n input.onRetry?.(error);\n failures++;\n await pause(\n Math.min(15_000, input.pollIntervalMs * 2 ** Math.min(failures, 3)),\n input.signal,\n );\n }\n }\n}\n\nasync function loadHistory(\n client: SessionStreamClient,\n options: FollowSessionStreamOptions,\n): Promise<{ id: string; transcript: Transcript }[]> {\n const entries = options.history ?? [];\n const results = new Map<number, { id: string; transcript: Transcript }>();\n let next = 0;\n await Promise.all(\n Array.from({ length: Math.min(4, entries.length) }, async () => {\n while (next < entries.length) {\n const index = next++;\n const entry = entries[index];\n if (!entry) throw new Error(\"Historical transcript index is unavailable\");\n const id = entry.execution.sessionId;\n const previous = new Transcript(entry.message, entry.attachments);\n const header = {\n id: \"run\",\n kind: \"status\",\n title: entry.agent,\n text: entry.taskId ? `Earlier work · ${entry.taskId}` : \"Earlier execution\",\n } as const;\n try {\n const historySignal = AbortSignal.any([options.signal, AbortSignal.timeout(15_000)]);\n await readSnapshot(client, {\n sessionId: options.sessionId,\n executionId: id,\n history: true,\n transcript: previous,\n signal: historySignal,\n pollIntervalMs: options.pollIntervalMs ?? 2000,\n });\n if (historySignal.aborted && !options.signal.aborted)\n throw new Error(\"Historical transcript loading timed out\");\n } catch (error) {\n if (options.signal.aborted) return;\n if (error instanceof ApiError && [401, 403].includes(error.status)) throw error;\n previous.put({\n id: \"unavailable\",\n kind: \"status\",\n title: \"History unavailable\",\n text: \"This execution's transcript could not be loaded.\",\n });\n }\n previous.blocks.unshift(header);\n results.set(index, { id, transcript: previous });\n }\n }),\n );\n return entries.map((_, index) => {\n const result = results.get(index);\n if (!result) throw new Error(\"Historical transcript loading did not complete\");\n return result;\n });\n}\n\nasync function hydrateCurrent(\n client: SessionStreamClient,\n options: FollowSessionStreamOptions,\n): Promise<boolean> {\n const executionId = options.executionId;\n if (executionId === null) return true;\n let failures = 0;\n while (!options.signal.aborted) {\n try {\n await readSnapshot(client, {\n sessionId: options.sessionId,\n executionId,\n taskId: options.taskId,\n history: false,\n transcript: options.transcript,\n signal: options.signal,\n pollIntervalMs: options.pollIntervalMs ?? 2000,\n onRetry: (error) => {\n options.onConnection(\"reconnecting\");\n options.onError(error);\n },\n });\n if (options.signal.aborted) return false;\n options.onConnection(\"connected\");\n return true;\n } catch (error) {\n if (options.signal.aborted) return false;\n options.onConnection(\"reconnecting\");\n failures++;\n options.onError(error);\n if (\n error instanceof ApiError &&\n [0, 301, 302, 303, 307, 308, 401, 403].includes(error.status)\n )\n return false;\n if (error instanceof ApiError && error.status === 404) return false;\n if (error instanceof ApiError && error.status === 409) {\n await options.onConflict();\n return false;\n }\n await pause(\n Math.min(15_000, (options.pollIntervalMs ?? 2000) * 2 ** Math.min(failures, 3)),\n options.signal,\n );\n }\n }\n return false;\n}\n\n/** Hydrates a transcript and follows its current execution until completion or disconnection. */\nexport async function followSessionStream(\n client: SessionStreamClient,\n options: FollowSessionStreamOptions,\n): Promise<void> {\n const { sessionId, executionId, transcript, signal } = options;\n let history: { id: string; transcript: Transcript }[];\n let hydrated: boolean;\n try {\n [history, hydrated] = await Promise.all([\n loadHistory(client, options),\n hydrateCurrent(client, options),\n ]);\n } catch (error) {\n if (!signal.aborted) options.onError(error);\n return;\n }\n if (signal.aborted || !hydrated) return;\n transcript.prependHistory(history);\n if (executionId === null) transcript.state = \"waiting\";\n options.onHydrated();\n if (executionId === null || [\"completed\", \"failed\"].includes(transcript.state)) return;\n let failures = 0;\n while (!signal.aborted) {\n const recycle = AbortSignal.timeout(60_000);\n let established = false;\n try {\n const response = await client.getSessionEventStreamResponse({\n sessionId,\n executionId,\n cursor: transcript.cursor,\n ...(options.taskId === undefined ? {} : { taskId: options.taskId }),\n signal: AbortSignal.any([signal, recycle]),\n });\n if (!response.body) throw new Error(\"The factory returned an empty stream\");\n established = true;\n options.onConnection(\"connected\");\n for await (const event of readEvents(response.body)) {\n if (signal.aborted) return;\n transcript.accept(event);\n failures = 0;\n options.onChange();\n }\n if ([\"completed\", \"failed\"].includes(transcript.state)) return;\n } catch (error) {\n if (signal.aborted) return;\n options.onConnection(\"reconnecting\");\n if (recycle.aborted && established) {\n failures = 0;\n continue;\n }\n failures++;\n options.onError(error);\n if (\n error instanceof ApiError &&\n [0, 301, 302, 303, 307, 308, 401, 403].includes(error.status)\n )\n return;\n if (error instanceof ApiError && error.status === 404) {\n if (transcript.state === \"running\") {\n transcript.state = \"connecting\";\n options.onChange();\n }\n return;\n }\n if (error instanceof ApiError && error.status === 409) {\n await options.onConflict();\n return;\n }\n }\n await pause(\n Math.min(15_000, (options.pollIntervalMs ?? 2000) * 2 ** Math.min(failures, 3)),\n signal,\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client-stream.mjs","names":[],"sources":["../src/client-stream.ts"],"sourcesContent":["import { ApiError, type FactoryClient } from \"./client\";\nimport { readEvents } from \"./client-events\";\nimport { Transcript } from \"./client-transcript\";\nimport type { SessionView } from \"./api-contracts\";\nimport type { TaskId } from \"./schema/id\";\nimport type { AgentSessionId } from \"./schema/session\";\nimport {\n transcriptBlockSchema,\n transcriptPageSchema,\n type TranscriptBlock,\n} from \"./schema/transcript\";\n\n/** Client operations required to hydrate and follow a Factory session stream. */\nexport type SessionStreamClient = Pick<\n FactoryClient,\n \"getSessionTranscriptResponse\" | \"getSessionEventStreamResponse\" | \"getSessionHistory\"\n>;\n\n/** Callbacks and exact execution identity used while following a session stream. */\nexport interface FollowSessionStreamOptions {\n readonly sessionId: AgentSessionId;\n readonly executionId: string | null;\n readonly taskId?: TaskId;\n /** Task bound to the conversation; absent for direct Foreman conversations. */\n readonly sessionTaskId?: TaskId;\n readonly historyNextCursor?: string | null;\n readonly history?: readonly NonNullable<SessionView[\"history\"]>[number][];\n readonly transcript: Transcript;\n readonly signal: AbortSignal;\n readonly pollIntervalMs?: number;\n readonly onHydrated: () => void;\n readonly onChange: () => void;\n readonly onConnection: (state: \"connected\" | \"reconnecting\") => void;\n readonly onError: (error: unknown) => void;\n readonly onConflict: () => Promise<void>;\n}\n\nfunction pause(ms: number, signal: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n const finish = () => {\n clearTimeout(timer);\n signal.removeEventListener(\"abort\", finish);\n resolve();\n };\n const timer = setTimeout(finish, ms);\n signal.addEventListener(\"abort\", finish, { once: true });\n if (signal.aborted) finish();\n });\n}\n\nasync function readSnapshot(\n client: SessionStreamClient,\n input: {\n sessionId: AgentSessionId;\n executionId: string;\n taskId?: TaskId;\n history: boolean;\n transcript: Transcript;\n signal: AbortSignal;\n pollIntervalMs: number;\n onRetry?(error: unknown): void;\n },\n) {\n let failures = 0;\n while (!input.signal.aborted) {\n try {\n const requestSignal = AbortSignal.any([input.signal, AbortSignal.timeout(15_000)]);\n const response = await client.getSessionTranscriptResponse({\n sessionId: input.sessionId,\n executionId: input.executionId,\n ...(input.taskId === undefined ? {} : { taskId: input.taskId }),\n ...(input.history ? { history: true } : {}),\n signal: requestSignal,\n });\n if (response.status === 202) {\n await response.body?.cancel();\n await pause(input.pollIntervalMs, input.signal);\n continue;\n }\n const page = transcriptPageSchema.parse(await response.json());\n input.transcript.hydrate(page.snapshot, page.nextCursor === null);\n input.transcript.historyPages.set(input.executionId, {\n executionId: input.executionId,\n taskId: input.taskId,\n history: input.history,\n nextCursor: page.nextCursor,\n loaded: true,\n });\n return;\n } catch (error) {\n if (input.signal.aborted) return;\n if (error instanceof ApiError) throw error;\n input.onRetry?.(error);\n failures++;\n await pause(\n Math.min(15_000, input.pollIntervalMs * 2 ** Math.min(failures, 3)),\n input.signal,\n );\n }\n }\n}\n\n/** Loads one older page, preserving live cursor/state and execution ordering. */\nexport async function loadPreviousTranscriptPage(\n client: SessionStreamClient,\n input: { sessionId: AgentSessionId; transcript: Transcript; signal: AbortSignal },\n): Promise<boolean> {\n let reference = [...input.transcript.historyPages.values()]\n .reverse()\n .find((page) => !page.loaded || page.nextCursor !== null);\n while (!reference && input.transcript.historyNextCursor && !input.signal.aborted) {\n const page = await client.getSessionHistory(input.sessionId, {\n cursor: input.transcript.historyNextCursor,\n signal: input.signal,\n });\n if (input.signal.aborted) return false;\n const previous = new Map(input.transcript.historyPages);\n input.transcript.historyPages.clear();\n for (const entry of [...page.items].reverse()) {\n if (entry.taskId && !input.transcript.sessionTaskId) continue;\n input.transcript.historyPages.set(entry.execution.sessionId, {\n executionId: entry.execution.sessionId,\n history: true,\n loaded: false,\n nextCursor: null,\n message: entry.message,\n attachments: entry.attachments,\n agent: entry.agent,\n });\n }\n for (const [key, value] of previous) input.transcript.historyPages.set(key, value);\n input.transcript.historyNextCursor = page.nextCursor;\n reference = [...input.transcript.historyPages.values()]\n .reverse()\n .find((entry) => !entry.loaded || entry.nextCursor !== null);\n }\n if (!reference) return false;\n const response = await client.getSessionTranscriptResponse({\n sessionId: input.sessionId,\n executionId: reference.executionId,\n taskId: reference.taskId,\n history: reference.history,\n cursor: reference.nextCursor ?? undefined,\n limit: 30,\n signal: input.signal,\n });\n if (response.status === 202) {\n await response.body?.cancel();\n throw new Error(\"Earlier messages are still being saved. Try loading them again shortly.\");\n }\n const page = transcriptPageSchema.parse(await response.json());\n if (input.signal.aborted) return false;\n const previous = new Transcript(reference.message, reference.attachments);\n previous.hydrate(page.snapshot, page.nextCursor === null);\n if (reference.history && !reference.loaded)\n previous.blocks.unshift({\n id: \"run\",\n kind: \"status\",\n title: reference.agent ?? \"Earlier execution\",\n text: reference.label ?? \"Earlier execution\",\n });\n input.transcript.prependPage(\n previous.blocks,\n reference.history ? reference.executionId : undefined,\n page.nextCursor === null,\n );\n input.transcript.historyPages.set(reference.executionId, {\n ...reference,\n loaded: true,\n nextCursor: page.nextCursor,\n });\n return true;\n}\n\n/** Expands one saved block without replacing newer live content. */\nexport async function expandTranscriptBlock(\n client: SessionStreamClient,\n input: {\n sessionId: AgentSessionId;\n transcript: Transcript;\n block: TranscriptBlock;\n signal: AbortSignal;\n },\n): Promise<void> {\n if (!input.block.contentRef) return;\n const references = [...input.transcript.historyPages.values()];\n const reference =\n references.find(\n (page) => page.history && input.block.id.startsWith(`history:${page.executionId}:`),\n ) ?? references.find((page) => !page.history);\n if (!reference) throw new Error(\"Transcript execution is unavailable\");\n const cursor = input.transcript.cursor;\n const response = await client.getSessionTranscriptResponse({\n sessionId: input.sessionId,\n executionId: reference.executionId,\n taskId: reference.taskId,\n history: reference.history,\n blockId: input.block.contentRef.blockId,\n signal: input.signal,\n });\n const block = transcriptBlockSchema.parse(await response.json());\n if (input.signal.aborted) return;\n if (!reference.history && input.transcript.cursor !== cursor)\n throw new Error(\"Transcript changed while loading content; try again\");\n input.transcript.put({ ...block, id: input.block.id });\n}\n\nasync function hydrateCurrent(\n client: SessionStreamClient,\n options: FollowSessionStreamOptions,\n): Promise<boolean> {\n const executionId = options.executionId;\n if (executionId === null) return true;\n let failures = 0;\n while (!options.signal.aborted) {\n try {\n await readSnapshot(client, {\n sessionId: options.sessionId,\n executionId,\n taskId: options.taskId,\n history: false,\n transcript: options.transcript,\n signal: options.signal,\n pollIntervalMs: options.pollIntervalMs ?? 2000,\n onRetry: (error) => {\n options.onConnection(\"reconnecting\");\n options.onError(error);\n },\n });\n if (options.signal.aborted) return false;\n options.onConnection(\"connected\");\n return true;\n } catch (error) {\n if (options.signal.aborted) return false;\n options.onConnection(\"reconnecting\");\n failures++;\n options.onError(error);\n if (\n error instanceof ApiError &&\n [0, 301, 302, 303, 307, 308, 401, 403].includes(error.status)\n )\n return false;\n if (error instanceof ApiError && error.status === 404) return false;\n if (error instanceof ApiError && error.status === 409) {\n await options.onConflict();\n return false;\n }\n await pause(\n Math.min(15_000, (options.pollIntervalMs ?? 2000) * 2 ** Math.min(failures, 3)),\n options.signal,\n );\n }\n }\n return false;\n}\n\n/** Hydrates a transcript and follows its current execution until completion or disconnection. */\nexport async function followSessionStream(\n client: SessionStreamClient,\n options: FollowSessionStreamOptions,\n): Promise<void> {\n const { sessionId, executionId, transcript, signal } = options;\n transcript.sessionTaskId = options.sessionTaskId;\n transcript.historyNextCursor = options.historyNextCursor ?? null;\n for (const entry of options.history ?? []) {\n if (entry.taskId && !options.sessionTaskId) continue;\n transcript.historyPages.set(entry.execution.sessionId, {\n executionId: entry.execution.sessionId,\n history: true,\n nextCursor: null,\n loaded: false,\n message: entry.message,\n attachments: entry.attachments,\n agent: entry.agent,\n label: entry.taskId ? `Earlier work · ${entry.taskId}` : \"Earlier execution\",\n });\n }\n let hydrated: boolean;\n try {\n hydrated = await hydrateCurrent(client, options);\n if (executionId === null && !signal.aborted)\n await loadPreviousTranscriptPage(client, { sessionId, transcript, signal });\n } catch (error) {\n if (!signal.aborted) options.onError(error);\n return;\n }\n if (signal.aborted || !hydrated) return;\n if (executionId === null) transcript.state = \"waiting\";\n options.onHydrated();\n if (executionId === null || [\"completed\", \"failed\"].includes(transcript.state)) return;\n let failures = 0;\n while (!signal.aborted) {\n const recycle = AbortSignal.timeout(60_000);\n let established = false;\n try {\n const response = await client.getSessionEventStreamResponse({\n sessionId,\n executionId,\n cursor: transcript.cursor,\n ...(options.taskId === undefined ? {} : { taskId: options.taskId }),\n signal: AbortSignal.any([signal, recycle]),\n });\n if (!response.body) throw new Error(\"The factory returned an empty stream\");\n established = true;\n options.onConnection(\"connected\");\n for await (const event of readEvents(response.body)) {\n if (signal.aborted) return;\n transcript.accept(event);\n failures = 0;\n options.onChange();\n }\n if ([\"completed\", \"failed\"].includes(transcript.state)) return;\n } catch (error) {\n if (signal.aborted) return;\n options.onConnection(\"reconnecting\");\n if (recycle.aborted && established) {\n failures = 0;\n continue;\n }\n failures++;\n options.onError(error);\n if (\n error instanceof ApiError &&\n [0, 301, 302, 303, 307, 308, 401, 403].includes(error.status)\n )\n return;\n if (error instanceof ApiError && error.status === 404) {\n if (transcript.state === \"running\") {\n transcript.state = \"connecting\";\n options.onChange();\n }\n return;\n }\n if (error instanceof ApiError && error.status === 409) {\n await options.onConflict();\n return;\n }\n }\n await pause(\n Math.min(15_000, (options.pollIntervalMs ?? 2000) * 2 ** Math.min(failures, 3)),\n signal,\n );\n }\n}\n"],"mappings":"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"}
@@ -1,12 +1,30 @@
1
+ import { TaskId } from "./schema/id.mjs";
1
2
  import { ImageAttachment } from "./image-input.mjs";
2
3
  import { InputRequest, ToolCall, TranscriptBlock, TranscriptSnapshot } from "./schema/transcript.mjs";
3
4
  import { StreamEvent } from "./client-events.mjs";
4
5
  //#region src/client-transcript.d.ts
6
+ /** Client-local position for loading older blocks from one authorized execution. */
7
+ interface TranscriptHistoryPage {
8
+ readonly executionId: string;
9
+ readonly taskId?: TaskId;
10
+ readonly history: boolean;
11
+ readonly nextCursor: string | null;
12
+ readonly loaded: boolean;
13
+ readonly message?: string;
14
+ readonly attachments?: readonly ImageAttachment[];
15
+ readonly agent?: string;
16
+ readonly label?: string;
17
+ }
5
18
  /** Mutable client-side projection of snapshot and live Factory transcript events. */
6
19
  declare class Transcript {
7
20
  private initialMessage?;
8
21
  private initialAttachments?;
9
22
  blocks: TranscriptBlock[];
23
+ /** Continuation for provider executions older than the loaded history. */
24
+ historyNextCursor: string | null;
25
+ /** Conversation binding used to exclude delegated history from direct chats. */
26
+ sessionTaskId?: TaskId;
27
+ historyPages: Map<string, TranscriptHistoryPage>;
10
28
  inputs: Map<string, Readonly<{
11
29
  requestId: string;
12
30
  prompt: string;
@@ -22,11 +40,16 @@ declare class Transcript {
22
40
  state: string;
23
41
  turnId?: string;
24
42
  tokens: number;
43
+ /** Execution-local measured usage; missing fields represent unreported totals. */
44
+ usage: TranscriptSnapshot["usage"];
25
45
  private seen;
26
46
  private tools;
47
+ private deferredInitialMessage?;
48
+ private deferredInitialAttachments?;
27
49
  constructor(initialMessage?: string | undefined, initialAttachments?: readonly ImageAttachment[] | undefined);
28
50
  snapshot(): TranscriptSnapshot;
29
- hydrate(value: TranscriptSnapshot): void;
51
+ hydrate(value: TranscriptSnapshot, containsBeginning?: boolean): void;
52
+ prependPage(blocks: readonly TranscriptBlock[], executionId?: string, containsBeginning?: boolean): void;
30
53
  put(block: TranscriptBlock): void;
31
54
  appendHistory(id: string, transcript: Transcript): void;
32
55
  prependHistory(entries: readonly {
@@ -37,5 +60,5 @@ declare class Transcript {
37
60
  private tool;
38
61
  }
39
62
  //#endregion
40
- export { type InputRequest, type ToolCall, Transcript, type TranscriptBlock, type TranscriptSnapshot };
63
+ export { type InputRequest, type ToolCall, Transcript, type TranscriptBlock, TranscriptHistoryPage, type TranscriptSnapshot };
41
64
  //# sourceMappingURL=client-transcript.d.mts.map
@@ -1,5 +1,6 @@
1
1
  import { receivedImages } from "./image-input.mjs";
2
2
  import { inputRequestSchema, transcriptSnapshotSchema } from "./schema/transcript.mjs";
3
+ import { z } from "zod";
3
4
  //#region src/client-transcript.ts
4
5
  function record(value) {
5
6
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
@@ -27,13 +28,27 @@ var Transcript = class {
27
28
  initialMessage;
28
29
  initialAttachments;
29
30
  blocks = [];
31
+ /** Continuation for provider executions older than the loaded history. */
32
+ historyNextCursor = null;
33
+ /** Conversation binding used to exclude delegated history from direct chats. */
34
+ sessionTaskId;
35
+ historyPages = /* @__PURE__ */ new Map();
30
36
  inputs = /* @__PURE__ */ new Map();
31
37
  cursor = 0;
32
38
  state = "connecting";
33
39
  turnId;
34
40
  tokens = 0;
41
+ /** Execution-local measured usage; missing fields represent unreported totals. */
42
+ usage = {
43
+ steps: 0,
44
+ costUsd: 0,
45
+ inputTokens: 0,
46
+ outputTokens: 0
47
+ };
35
48
  seen = /* @__PURE__ */ new Set();
36
49
  tools = /* @__PURE__ */ new Map();
50
+ deferredInitialMessage;
51
+ deferredInitialAttachments;
37
52
  constructor(initialMessage, initialAttachments) {
38
53
  this.initialMessage = initialMessage;
39
54
  this.initialAttachments = initialAttachments;
@@ -45,14 +60,15 @@ var Transcript = class {
45
60
  cursor: this.cursor,
46
61
  state: this.state,
47
62
  turnId: this.turnId,
48
- tokens: this.tokens
63
+ tokens: this.tokens,
64
+ usage: this.usage
49
65
  });
50
66
  }
51
- hydrate(value) {
67
+ hydrate(value, containsBeginning = true) {
52
68
  const snapshot = transcriptSnapshotSchema.parse(value);
53
69
  this.blocks = snapshot.blocks.map((block) => ({ ...block }));
54
70
  const firstUser = this.blocks.find((block) => block.kind === "user");
55
- if (firstUser !== void 0 && (this.initialMessage !== void 0 || this.initialAttachments !== void 0)) {
71
+ if (containsBeginning && firstUser !== void 0 && (this.initialMessage !== void 0 || this.initialAttachments !== void 0)) {
56
72
  const text = this.initialMessage ?? firstUser.text;
57
73
  const attachments = this.initialAttachments ?? firstUser.attachments;
58
74
  const firstUserIndex = this.blocks.indexOf(firstUser);
@@ -74,12 +90,52 @@ var Transcript = class {
74
90
  this.state = snapshot.state;
75
91
  this.turnId = snapshot.turnId;
76
92
  this.tokens = snapshot.tokens;
93
+ this.usage = snapshot.usage ?? (snapshot.cursor === 0 ? {
94
+ steps: 0,
95
+ costUsd: 0,
96
+ inputTokens: 0,
97
+ outputTokens: 0
98
+ } : void 0);
77
99
  this.seen.clear();
78
100
  this.tools = new Map(this.blocks.flatMap((block) => block.tool ? [[block.tool.callId, block.tool]] : []));
79
- this.initialMessage = void 0;
80
- this.initialAttachments = void 0;
101
+ if (!containsBeginning) {
102
+ this.deferredInitialMessage = this.initialMessage;
103
+ this.deferredInitialAttachments = this.initialAttachments;
104
+ }
105
+ if (!containsBeginning || firstUser !== void 0) {
106
+ this.initialMessage = void 0;
107
+ this.initialAttachments = void 0;
108
+ }
109
+ }
110
+ prependPage(blocks, executionId, containsBeginning = false) {
111
+ const prefix = executionId === void 0 ? void 0 : `history:${executionId}:`;
112
+ const existing = new Set(this.blocks.map((block) => block.id));
113
+ const earlier = blocks.map((block) => ({
114
+ ...block,
115
+ id: prefix ? `${prefix}${block.id}` : block.id
116
+ })).filter((block) => !existing.has(block.id));
117
+ if (prefix === void 0 && containsBeginning) {
118
+ const index = earlier.findIndex((block) => block.kind === "user");
119
+ const first = earlier[index];
120
+ if (first?.kind === "user") {
121
+ const attachments = this.deferredInitialAttachments ?? first.attachments;
122
+ earlier[index] = {
123
+ ...first,
124
+ text: this.deferredInitialMessage ?? first.text,
125
+ attachments
126
+ };
127
+ }
128
+ this.deferredInitialMessage = void 0;
129
+ this.deferredInitialAttachments = void 0;
130
+ }
131
+ const start = this.blocks.findIndex((block) => prefix ? block.id.startsWith(prefix) && block.id !== `${prefix}run` : !block.id.startsWith("history:"));
132
+ this.blocks.splice(start < 0 ? 0 : start, 0, ...earlier);
133
+ if (prefix === void 0) {
134
+ for (const block of earlier) if (block.tool && !this.tools.has(block.tool.callId)) this.tools.set(block.tool.callId, block.tool);
135
+ }
81
136
  }
82
137
  put(block) {
138
+ if (block.tool && !block.id.startsWith("history:")) this.tools.set(block.tool.callId, block.tool);
83
139
  const index = this.blocks.findIndex((item) => item.id === block.id);
84
140
  if (index < 0) this.blocks.push(block);
85
141
  else this.blocks[index] = block;
@@ -105,6 +161,8 @@ var Transcript = class {
105
161
  this.seen.add(event.meta.id);
106
162
  }
107
163
  const { type, data } = event;
164
+ const timestamp = z.iso.datetime().safeParse(event.meta?.at);
165
+ const createdAt = timestamp.success ? timestamp.data : void 0;
108
166
  const coordinate = `${data.turnId}:${data.stepIndex}:${data.sequence}`;
109
167
  if (type === "turn.started") {
110
168
  this.turnId = string(data.turnId);
@@ -117,6 +175,7 @@ var Transcript = class {
117
175
  id: `user:${event.meta?.id ?? this.cursor}`,
118
176
  kind: "user",
119
177
  title: "You",
178
+ createdAt,
120
179
  text: this.initialMessage ?? (attachments.length ? partsText ?? "" : string(data.message)),
121
180
  ...attachments.length ? { attachments: [...attachments] } : {}
122
181
  });
@@ -127,19 +186,22 @@ var Transcript = class {
127
186
  id: `message:${coordinate}`,
128
187
  kind: "assistant",
129
188
  title: "Assistant",
189
+ createdAt: this.blocks.find((block) => block.id === `message:${coordinate}`)?.createdAt ?? createdAt,
130
190
  text: string(data.message)
131
191
  });
132
192
  if (type === "result.completed") this.put({
133
193
  id: `result:${coordinate}`,
134
194
  kind: "assistant",
135
195
  title: "Result",
196
+ createdAt,
136
197
  text: `\`\`\`json\n${string(data.result)}\n\`\`\``
137
198
  });
138
199
  if (type === "reasoning.appended" || type === "reasoning.completed") this.put({
139
200
  id: `reasoning:${coordinate}`,
140
201
  kind: "reasoning",
141
202
  title: "Reasoning",
142
- text: string(data.reasoning)
203
+ createdAt: this.blocks.find((block) => block.id === `reasoning:${coordinate}`)?.createdAt ?? createdAt,
204
+ text: type === "reasoning.appended" ? typeof data.reasoning === "string" ? data.reasoning : (this.blocks.find((block) => block.id === `reasoning:${coordinate}`)?.text ?? "") + string(data.reasoningDelta) : string(data.reasoning)
143
205
  });
144
206
  if (type === "actions.requested" && Array.isArray(data.actions)) for (const item of data.actions) {
145
207
  const action = record(item);
@@ -152,7 +214,7 @@ var Transcript = class {
152
214
  inputText: string(action.input),
153
215
  name: string(action.toolName ?? action.name ?? action.kind),
154
216
  state: previous?.state === "input-streaming" ? "running" : previous?.state ?? "running"
155
- });
217
+ }, createdAt);
156
218
  }
157
219
  if (type === "action.input.appended") {
158
220
  const id = string(data.callId);
@@ -167,7 +229,7 @@ var Transcript = class {
167
229
  inputText,
168
230
  name: string(data.toolName),
169
231
  state: "input-streaming"
170
- });
232
+ }, createdAt);
171
233
  }
172
234
  }
173
235
  if (type === "action.result" || type === "action.partial") {
@@ -183,14 +245,14 @@ var Transcript = class {
183
245
  output: "output" in result ? result.output : result,
184
246
  error: data.error,
185
247
  state: type === "action.partial" ? "running" : data.status === "rejected" ? "rejected" : data.status === "failed" || data.error != null ? "failed" : "completed"
186
- });
248
+ }, createdAt);
187
249
  }
188
250
  if (type === "turn.cancelled" || type === "turn.failed" || type === "session.failed") {
189
251
  for (const tool of this.tools.values()) if (!settled(tool)) this.tool({
190
252
  ...tool,
191
253
  state: type === "turn.cancelled" ? "cancelled" : "failed",
192
254
  error: data.message
193
- });
255
+ }, createdAt);
194
256
  }
195
257
  if (type === "input.requested") {
196
258
  for (const request of inputRequestSchema.array().parse(data.requests)) this.inputs.set(request.requestId, request);
@@ -199,8 +261,23 @@ var Transcript = class {
199
261
  if (type === "input.resolved" && Array.isArray(data.resolutions)) for (const resolution of data.resolutions) this.inputs.delete(string(record(resolution).requestId));
200
262
  if (type === "step.completed") {
201
263
  const usage = record(data.usage);
202
- const total = (value) => typeof value === "number" ? value : Number(record(value).total ?? 0);
203
- this.tokens += total(usage.inputTokens) + total(usage.outputTokens);
264
+ const total = (value) => {
265
+ const count = typeof value === "number" ? value : record(value).total;
266
+ return typeof count === "number" && Number.isSafeInteger(count) && count >= 0 ? count : void 0;
267
+ };
268
+ const inputTokens = total(usage.inputTokens);
269
+ const outputTokens = total(usage.outputTokens);
270
+ const costUsd = typeof usage.costUsd === "number" && Number.isFinite(usage.costUsd) && usage.costUsd >= 0 ? usage.costUsd : void 0;
271
+ this.tokens += (inputTokens ?? 0) + (outputTokens ?? 0);
272
+ if (this.usage) {
273
+ const add = (previous, current) => previous === void 0 || current === void 0 ? void 0 : previous + current;
274
+ this.usage = {
275
+ steps: this.usage.steps + 1,
276
+ costUsd: add(this.usage.costUsd, costUsd),
277
+ inputTokens: add(this.usage.inputTokens, inputTokens),
278
+ outputTokens: add(this.usage.outputTokens, outputTokens)
279
+ };
280
+ }
204
281
  }
205
282
  if (type === "session.waiting" || [
206
283
  "turn.completed",
@@ -212,17 +289,22 @@ var Transcript = class {
212
289
  id: `event:${event.meta?.id ?? this.cursor}`,
213
290
  kind: type.endsWith(".failed") ? "error" : "status",
214
291
  title: type,
292
+ createdAt,
215
293
  text: string(data.message ?? data.output ?? data.authorization ?? data.subagentName ?? data.name ?? "")
216
294
  });
217
295
  }
218
- tool(tool) {
296
+ tool(tool, createdAt) {
219
297
  this.tools.set(tool.callId, tool);
220
298
  const output = tool.error ?? tool.output;
299
+ const previous = this.blocks.find((block) => block.id === `tool:${tool.callId}`);
300
+ const contentRef = previous?.contentRef;
221
301
  this.put({
222
302
  id: `tool:${tool.callId}`,
223
303
  kind: "tool",
224
304
  title: tool.name,
305
+ createdAt: previous?.createdAt ?? createdAt,
225
306
  tool,
307
+ ...contentRef ? { contentRef } : {},
226
308
  text: `Input\n\`\`\`json\n${tool.inputText}\n\`\`\`${output === void 0 ? "" : `\n\nOutput\n\`\`\`\n${string(output)}\n\`\`\``}`
227
309
  });
228
310
  }
@@ -1 +1 @@
1
- {"version":3,"file":"client-transcript.mjs","names":[],"sources":["../src/client-transcript.ts"],"sourcesContent":["import { receivedImages, type ImageAttachment } from \"./image-input\";\nimport type { StreamEvent } from \"./client-events\";\nimport {\n inputRequestSchema,\n transcriptSnapshotSchema,\n type InputRequest,\n type ToolCall,\n type TranscriptBlock,\n type TranscriptSnapshot,\n} from \"./schema/transcript\";\n\nexport type {\n InputRequest,\n ToolCall,\n TranscriptBlock,\n TranscriptSnapshot,\n} from \"./schema/transcript\";\n\nfunction record(value: unknown): Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {};\n}\nfunction string(value: unknown): string {\n return typeof value === \"string\" ? value : (JSON.stringify(value, null, 2) ?? \"\");\n}\nfunction parseInput(text: string): unknown {\n try {\n return JSON.parse(text);\n } catch {\n return undefined;\n }\n}\nfunction settled(tool: ToolCall) {\n return [\"completed\", \"failed\", \"cancelled\", \"rejected\"].includes(tool.state);\n}\n\n/** Mutable client-side projection of snapshot and live Factory transcript events. */\nexport class Transcript {\n blocks: TranscriptBlock[] = [];\n inputs = new Map<string, InputRequest>();\n cursor = 0;\n state = \"connecting\";\n turnId?: string;\n tokens = 0;\n private seen = new Set<string>();\n private tools = new Map<string, ToolCall>();\n constructor(\n private initialMessage?: string,\n private initialAttachments?: readonly ImageAttachment[],\n ) {}\n\n snapshot(): TranscriptSnapshot {\n return transcriptSnapshotSchema.parse({\n blocks: this.blocks,\n inputs: [...this.inputs.values()],\n cursor: this.cursor,\n state: this.state,\n turnId: this.turnId,\n tokens: this.tokens,\n });\n }\n\n hydrate(value: TranscriptSnapshot): void {\n const snapshot = transcriptSnapshotSchema.parse(value);\n this.blocks = snapshot.blocks.map((block) => ({ ...block }));\n const firstUser = this.blocks.find(\n (block): block is Extract<TranscriptBlock, { kind: \"user\" }> => block.kind === \"user\",\n );\n if (\n firstUser !== undefined &&\n (this.initialMessage !== undefined || this.initialAttachments !== undefined)\n ) {\n const text = this.initialMessage ?? firstUser.text;\n const attachments = this.initialAttachments ?? firstUser.attachments;\n const firstUserIndex = this.blocks.indexOf(firstUser);\n if (attachments?.length) {\n this.blocks[firstUserIndex] = { ...firstUser, text, attachments: [...attachments] };\n } else {\n const { attachments: _attachments, ...withoutAttachments } = firstUser;\n this.blocks[firstUserIndex] = { ...withoutAttachments, text };\n }\n }\n this.inputs = new Map(snapshot.inputs.map((request) => [request.requestId, request]));\n this.cursor = snapshot.cursor;\n this.state = snapshot.state;\n this.turnId = snapshot.turnId;\n this.tokens = snapshot.tokens;\n this.seen.clear();\n this.tools = new Map(\n this.blocks.flatMap((block) =>\n block.tool ? [[block.tool.callId, block.tool] as const] : [],\n ),\n );\n this.initialMessage = undefined;\n this.initialAttachments = undefined;\n }\n\n put(block: TranscriptBlock) {\n const index = this.blocks.findIndex((item) => item.id === block.id);\n if (index < 0) this.blocks.push(block);\n else this.blocks[index] = block;\n }\n\n appendHistory(id: string, transcript: Transcript) {\n for (const block of transcript.blocks) this.put({ ...block, id: `history:${id}:${block.id}` });\n }\n\n prependHistory(entries: readonly { id: string; transcript: Transcript }[]) {\n const history = entries.flatMap(({ id, transcript }) =>\n transcript.blocks.map((block) => ({ ...block, id: `history:${id}:${block.id}` })),\n );\n const ids = new Set(history.map((block) => block.id));\n this.blocks = [...history, ...this.blocks.filter((block) => !ids.has(block.id))];\n }\n\n accept(event: StreamEvent) {\n this.cursor++;\n if (event.meta?.id !== undefined) {\n if (this.seen.has(event.meta.id)) return;\n this.seen.add(event.meta.id);\n }\n const { type, data } = event;\n const coordinate = `${data.turnId}:${data.stepIndex}:${data.sequence}`;\n if (type === \"turn.started\") {\n this.turnId = string(data.turnId);\n this.state = \"running\";\n }\n if (type === \"message.received\") {\n const attachments = this.initialAttachments ?? receivedImages(data.parts);\n const partsText = Array.isArray(data.parts)\n ? data.parts\n .filter((part) => record(part).type === \"text\")\n .map((part) => string(record(part).text))\n .join(\"\\n\")\n : undefined;\n this.put({\n id: `user:${event.meta?.id ?? this.cursor}`,\n kind: \"user\",\n title: \"You\",\n text:\n this.initialMessage ?? (attachments.length ? (partsText ?? \"\") : string(data.message)),\n ...(attachments.length ? { attachments: [...attachments] } : {}),\n });\n this.initialMessage = undefined;\n this.initialAttachments = undefined;\n }\n if (type === \"message.appended\" || type === \"message.completed\")\n this.put({\n id: `message:${coordinate}`,\n kind: \"assistant\",\n title: \"Assistant\",\n text: string(data.message),\n });\n if (type === \"result.completed\")\n this.put({\n id: `result:${coordinate}`,\n kind: \"assistant\",\n title: \"Result\",\n text: `\\`\\`\\`json\\n${string(data.result)}\\n\\`\\`\\``,\n });\n if (type === \"reasoning.appended\" || type === \"reasoning.completed\")\n this.put({\n id: `reasoning:${coordinate}`,\n kind: \"reasoning\",\n title: \"Reasoning\",\n text: string(data.reasoning),\n });\n if (type === \"actions.requested\" && Array.isArray(data.actions))\n for (const item of data.actions) {\n const action = record(item);\n const callId = string(action.callId);\n const previous = this.tools.get(callId);\n this.tool({\n ...previous,\n callId,\n input: action.input,\n inputText: string(action.input),\n name: string(action.toolName ?? action.name ?? action.kind),\n state: previous?.state === \"input-streaming\" ? \"running\" : (previous?.state ?? \"running\"),\n });\n }\n if (type === \"action.input.appended\") {\n const id = string(data.callId);\n const previous = this.tools.get(id);\n const offset = data.inputTextOffset;\n const delta = string(data.inputTextDelta);\n if (\n (!previous || previous.state === \"input-streaming\") &&\n (offset === 0 || offset === previous?.inputText.length)\n ) {\n const inputText = (offset === 0 ? \"\" : (previous?.inputText ?? \"\")) + delta;\n this.tool({\n callId: id,\n input: parseInput(inputText),\n inputText,\n name: string(data.toolName),\n state: \"input-streaming\",\n });\n }\n }\n if (type === \"action.result\" || type === \"action.partial\") {\n const result = record(data.result);\n const id = string(result.callId);\n const previous = this.tools.get(id);\n if (type !== \"action.partial\" || !previous || !settled(previous))\n this.tool({\n ...previous,\n callId: id,\n input: previous?.input,\n inputText: previous?.inputText ?? \"\",\n name: previous?.name ?? string(result.toolName ?? result.kind),\n output: \"output\" in result ? result.output : result,\n error: data.error,\n state:\n type === \"action.partial\"\n ? \"running\"\n : data.status === \"rejected\"\n ? \"rejected\"\n : data.status === \"failed\" || data.error != null\n ? \"failed\"\n : \"completed\",\n });\n }\n if (type === \"turn.cancelled\" || type === \"turn.failed\" || type === \"session.failed\")\n for (const tool of this.tools.values()) {\n if (!settled(tool))\n this.tool({\n ...tool,\n state: type === \"turn.cancelled\" ? \"cancelled\" : \"failed\",\n error: data.message,\n });\n }\n if (type === \"input.requested\") {\n for (const request of inputRequestSchema.array().parse(data.requests))\n this.inputs.set(request.requestId, request);\n this.state = \"needs input\";\n }\n if (type === \"input.resolved\" && Array.isArray(data.resolutions))\n for (const resolution of data.resolutions)\n this.inputs.delete(string(record(resolution).requestId));\n if (type === \"step.completed\") {\n const usage = record(data.usage);\n const total = (value: unknown) =>\n typeof value === \"number\" ? value : Number(record(value).total ?? 0);\n this.tokens += total(usage.inputTokens) + total(usage.outputTokens);\n }\n if (\n type === \"session.waiting\" ||\n ([\"turn.completed\", \"turn.failed\", \"turn.cancelled\"].includes(type) &&\n (this.turnId === undefined || data.turnId === this.turnId))\n )\n this.state = this.inputs.size > 0 ? \"needs input\" : \"waiting\";\n if ([\"session.completed\", \"session.failed\"].includes(type)) this.state = type.slice(8);\n if (\n type.endsWith(\".failed\") ||\n type === \"turn.cancelled\" ||\n type.startsWith(\"compaction.\") ||\n type.startsWith(\"authorization.\") ||\n type.startsWith(\"subagent.\")\n ) {\n this.put({\n id: `event:${event.meta?.id ?? this.cursor}`,\n kind: type.endsWith(\".failed\") ? \"error\" : \"status\",\n title: type,\n text: string(\n data.message ?? data.output ?? data.authorization ?? data.subagentName ?? data.name ?? \"\",\n ),\n });\n }\n }\n\n private tool(tool: ToolCall) {\n this.tools.set(tool.callId, tool);\n const output = tool.error ?? tool.output;\n this.put({\n id: `tool:${tool.callId}`,\n kind: \"tool\",\n title: tool.name,\n tool,\n text: `Input\\n\\`\\`\\`json\\n${tool.inputText}\\n\\`\\`\\`${output === undefined ? \"\" : `\\n\\nOutput\\n\\`\\`\\`\\n${string(output)}\\n\\`\\`\\``}`,\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client-transcript.mjs","names":[],"sources":["../src/client-transcript.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { receivedImages, type ImageAttachment } from \"./image-input\";\nimport type { StreamEvent } from \"./client-events\";\nimport type { TaskId } from \"./schema/id\";\nimport {\n inputRequestSchema,\n transcriptSnapshotSchema,\n type InputRequest,\n type ToolCall,\n type TranscriptBlock,\n type TranscriptSnapshot,\n} from \"./schema/transcript\";\n\nexport type {\n InputRequest,\n ToolCall,\n TranscriptBlock,\n TranscriptSnapshot,\n} from \"./schema/transcript\";\n\nfunction record(value: unknown): Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {};\n}\nfunction string(value: unknown): string {\n return typeof value === \"string\" ? value : (JSON.stringify(value, null, 2) ?? \"\");\n}\nfunction parseInput(text: string): unknown {\n try {\n return JSON.parse(text);\n } catch {\n return undefined;\n }\n}\nfunction settled(tool: ToolCall) {\n return [\"completed\", \"failed\", \"cancelled\", \"rejected\"].includes(tool.state);\n}\n\n/** Client-local position for loading older blocks from one authorized execution. */\nexport interface TranscriptHistoryPage {\n readonly executionId: string;\n readonly taskId?: TaskId;\n readonly history: boolean;\n readonly nextCursor: string | null;\n readonly loaded: boolean;\n readonly message?: string;\n readonly attachments?: readonly ImageAttachment[];\n readonly agent?: string;\n readonly label?: string;\n}\n\n/** Mutable client-side projection of snapshot and live Factory transcript events. */\nexport class Transcript {\n blocks: TranscriptBlock[] = [];\n /** Continuation for provider executions older than the loaded history. */\n historyNextCursor: string | null = null;\n /** Conversation binding used to exclude delegated history from direct chats. */\n sessionTaskId?: TaskId;\n historyPages = new Map<string, TranscriptHistoryPage>();\n inputs = new Map<string, InputRequest>();\n cursor = 0;\n state = \"connecting\";\n turnId?: string;\n tokens = 0;\n /** Execution-local measured usage; missing fields represent unreported totals. */\n usage: TranscriptSnapshot[\"usage\"] = { steps: 0, costUsd: 0, inputTokens: 0, outputTokens: 0 };\n private seen = new Set<string>();\n private tools = new Map<string, ToolCall>();\n private deferredInitialMessage?: string;\n private deferredInitialAttachments?: readonly ImageAttachment[];\n constructor(\n private initialMessage?: string,\n private initialAttachments?: readonly ImageAttachment[],\n ) {}\n\n snapshot(): TranscriptSnapshot {\n return transcriptSnapshotSchema.parse({\n blocks: this.blocks,\n inputs: [...this.inputs.values()],\n cursor: this.cursor,\n state: this.state,\n turnId: this.turnId,\n tokens: this.tokens,\n usage: this.usage,\n });\n }\n\n hydrate(value: TranscriptSnapshot, containsBeginning = true): void {\n const snapshot = transcriptSnapshotSchema.parse(value);\n this.blocks = snapshot.blocks.map((block) => ({ ...block }));\n const firstUser = this.blocks.find(\n (block): block is Extract<TranscriptBlock, { kind: \"user\" }> => block.kind === \"user\",\n );\n if (\n containsBeginning &&\n firstUser !== undefined &&\n (this.initialMessage !== undefined || this.initialAttachments !== undefined)\n ) {\n const text = this.initialMessage ?? firstUser.text;\n const attachments = this.initialAttachments ?? firstUser.attachments;\n const firstUserIndex = this.blocks.indexOf(firstUser);\n if (attachments?.length) {\n this.blocks[firstUserIndex] = { ...firstUser, text, attachments: [...attachments] };\n } else {\n const { attachments: _attachments, ...withoutAttachments } = firstUser;\n this.blocks[firstUserIndex] = { ...withoutAttachments, text };\n }\n }\n this.inputs = new Map(snapshot.inputs.map((request) => [request.requestId, request]));\n this.cursor = snapshot.cursor;\n this.state = snapshot.state;\n this.turnId = snapshot.turnId;\n this.tokens = snapshot.tokens;\n this.usage =\n snapshot.usage ??\n (snapshot.cursor === 0\n ? { steps: 0, costUsd: 0, inputTokens: 0, outputTokens: 0 }\n : undefined);\n this.seen.clear();\n this.tools = new Map(\n this.blocks.flatMap((block) =>\n block.tool ? [[block.tool.callId, block.tool] as const] : [],\n ),\n );\n if (!containsBeginning) {\n this.deferredInitialMessage = this.initialMessage;\n this.deferredInitialAttachments = this.initialAttachments;\n }\n if (!containsBeginning || firstUser !== undefined) {\n this.initialMessage = undefined;\n this.initialAttachments = undefined;\n }\n }\n\n prependPage(blocks: readonly TranscriptBlock[], executionId?: string, containsBeginning = false) {\n const prefix = executionId === undefined ? undefined : `history:${executionId}:`;\n const existing = new Set(this.blocks.map((block) => block.id));\n const earlier = blocks\n .map((block) => ({ ...block, id: prefix ? `${prefix}${block.id}` : block.id }))\n .filter((block) => !existing.has(block.id));\n if (prefix === undefined && containsBeginning) {\n const index = earlier.findIndex((block) => block.kind === \"user\");\n const first = earlier[index];\n if (first?.kind === \"user\") {\n const attachments = this.deferredInitialAttachments ?? first.attachments;\n earlier[index] = { ...first, text: this.deferredInitialMessage ?? first.text, attachments };\n }\n this.deferredInitialMessage = undefined;\n this.deferredInitialAttachments = undefined;\n }\n const start = this.blocks.findIndex((block) =>\n prefix\n ? block.id.startsWith(prefix) && block.id !== `${prefix}run`\n : !block.id.startsWith(\"history:\"),\n );\n this.blocks.splice(start < 0 ? 0 : start, 0, ...earlier);\n if (prefix === undefined)\n for (const block of earlier)\n if (block.tool && !this.tools.has(block.tool.callId))\n this.tools.set(block.tool.callId, block.tool);\n }\n\n put(block: TranscriptBlock) {\n if (block.tool && !block.id.startsWith(\"history:\"))\n this.tools.set(block.tool.callId, block.tool);\n const index = this.blocks.findIndex((item) => item.id === block.id);\n if (index < 0) this.blocks.push(block);\n else this.blocks[index] = block;\n }\n\n appendHistory(id: string, transcript: Transcript) {\n for (const block of transcript.blocks) this.put({ ...block, id: `history:${id}:${block.id}` });\n }\n\n prependHistory(entries: readonly { id: string; transcript: Transcript }[]) {\n const history = entries.flatMap(({ id, transcript }) =>\n transcript.blocks.map((block) => ({ ...block, id: `history:${id}:${block.id}` })),\n );\n const ids = new Set(history.map((block) => block.id));\n this.blocks = [...history, ...this.blocks.filter((block) => !ids.has(block.id))];\n }\n\n accept(event: StreamEvent) {\n this.cursor++;\n if (event.meta?.id !== undefined) {\n if (this.seen.has(event.meta.id)) return;\n this.seen.add(event.meta.id);\n }\n const { type, data } = event;\n const timestamp = z.iso.datetime().safeParse(event.meta?.at);\n const createdAt = timestamp.success ? timestamp.data : undefined;\n const coordinate = `${data.turnId}:${data.stepIndex}:${data.sequence}`;\n if (type === \"turn.started\") {\n this.turnId = string(data.turnId);\n this.state = \"running\";\n }\n if (type === \"message.received\") {\n const attachments = this.initialAttachments ?? receivedImages(data.parts);\n const partsText = Array.isArray(data.parts)\n ? data.parts\n .filter((part) => record(part).type === \"text\")\n .map((part) => string(record(part).text))\n .join(\"\\n\")\n : undefined;\n this.put({\n id: `user:${event.meta?.id ?? this.cursor}`,\n kind: \"user\",\n title: \"You\",\n createdAt,\n text:\n this.initialMessage ?? (attachments.length ? (partsText ?? \"\") : string(data.message)),\n ...(attachments.length ? { attachments: [...attachments] } : {}),\n });\n this.initialMessage = undefined;\n this.initialAttachments = undefined;\n }\n if (type === \"message.appended\" || type === \"message.completed\")\n this.put({\n id: `message:${coordinate}`,\n kind: \"assistant\",\n title: \"Assistant\",\n createdAt:\n this.blocks.find((block) => block.id === `message:${coordinate}`)?.createdAt ?? createdAt,\n text: string(data.message),\n });\n if (type === \"result.completed\")\n this.put({\n id: `result:${coordinate}`,\n kind: \"assistant\",\n title: \"Result\",\n createdAt,\n text: `\\`\\`\\`json\\n${string(data.result)}\\n\\`\\`\\``,\n });\n if (type === \"reasoning.appended\" || type === \"reasoning.completed\")\n this.put({\n id: `reasoning:${coordinate}`,\n kind: \"reasoning\",\n title: \"Reasoning\",\n createdAt:\n this.blocks.find((block) => block.id === `reasoning:${coordinate}`)?.createdAt ??\n createdAt,\n text:\n type === \"reasoning.appended\"\n ? typeof data.reasoning === \"string\"\n ? data.reasoning\n : (this.blocks.find((block) => block.id === `reasoning:${coordinate}`)?.text ?? \"\") +\n string(data.reasoningDelta)\n : string(data.reasoning),\n });\n if (type === \"actions.requested\" && Array.isArray(data.actions))\n for (const item of data.actions) {\n const action = record(item);\n const callId = string(action.callId);\n const previous = this.tools.get(callId);\n this.tool(\n {\n ...previous,\n callId,\n input: action.input,\n inputText: string(action.input),\n name: string(action.toolName ?? action.name ?? action.kind),\n state:\n previous?.state === \"input-streaming\" ? \"running\" : (previous?.state ?? \"running\"),\n },\n createdAt,\n );\n }\n if (type === \"action.input.appended\") {\n const id = string(data.callId);\n const previous = this.tools.get(id);\n const offset = data.inputTextOffset;\n const delta = string(data.inputTextDelta);\n if (\n (!previous || previous.state === \"input-streaming\") &&\n (offset === 0 || offset === previous?.inputText.length)\n ) {\n const inputText = (offset === 0 ? \"\" : (previous?.inputText ?? \"\")) + delta;\n this.tool(\n {\n callId: id,\n input: parseInput(inputText),\n inputText,\n name: string(data.toolName),\n state: \"input-streaming\",\n },\n createdAt,\n );\n }\n }\n if (type === \"action.result\" || type === \"action.partial\") {\n const result = record(data.result);\n const id = string(result.callId);\n const previous = this.tools.get(id);\n if (type !== \"action.partial\" || !previous || !settled(previous))\n this.tool(\n {\n ...previous,\n callId: id,\n input: previous?.input,\n inputText: previous?.inputText ?? \"\",\n name: previous?.name ?? string(result.toolName ?? result.kind),\n output: \"output\" in result ? result.output : result,\n error: data.error,\n state:\n type === \"action.partial\"\n ? \"running\"\n : data.status === \"rejected\"\n ? \"rejected\"\n : data.status === \"failed\" || data.error != null\n ? \"failed\"\n : \"completed\",\n },\n createdAt,\n );\n }\n if (type === \"turn.cancelled\" || type === \"turn.failed\" || type === \"session.failed\")\n for (const tool of this.tools.values()) {\n if (!settled(tool))\n this.tool(\n {\n ...tool,\n state: type === \"turn.cancelled\" ? \"cancelled\" : \"failed\",\n error: data.message,\n },\n createdAt,\n );\n }\n if (type === \"input.requested\") {\n for (const request of inputRequestSchema.array().parse(data.requests))\n this.inputs.set(request.requestId, request);\n this.state = \"needs input\";\n }\n if (type === \"input.resolved\" && Array.isArray(data.resolutions))\n for (const resolution of data.resolutions)\n this.inputs.delete(string(record(resolution).requestId));\n if (type === \"step.completed\") {\n const usage = record(data.usage);\n const total = (value: unknown): number | undefined => {\n const count = typeof value === \"number\" ? value : record(value).total;\n return typeof count === \"number\" && Number.isSafeInteger(count) && count >= 0\n ? count\n : undefined;\n };\n const inputTokens = total(usage.inputTokens);\n const outputTokens = total(usage.outputTokens);\n const costUsd =\n typeof usage.costUsd === \"number\" && Number.isFinite(usage.costUsd) && usage.costUsd >= 0\n ? usage.costUsd\n : undefined;\n this.tokens += (inputTokens ?? 0) + (outputTokens ?? 0);\n if (this.usage) {\n const add = (previous: number | undefined, current: number | undefined) =>\n previous === undefined || current === undefined ? undefined : previous + current;\n this.usage = {\n steps: this.usage.steps + 1,\n costUsd: add(this.usage.costUsd, costUsd),\n inputTokens: add(this.usage.inputTokens, inputTokens),\n outputTokens: add(this.usage.outputTokens, outputTokens),\n };\n }\n }\n if (\n type === \"session.waiting\" ||\n ([\"turn.completed\", \"turn.failed\", \"turn.cancelled\"].includes(type) &&\n (this.turnId === undefined || data.turnId === this.turnId))\n )\n this.state = this.inputs.size > 0 ? \"needs input\" : \"waiting\";\n if ([\"session.completed\", \"session.failed\"].includes(type)) this.state = type.slice(8);\n if (\n type.endsWith(\".failed\") ||\n type === \"turn.cancelled\" ||\n type.startsWith(\"compaction.\") ||\n type.startsWith(\"authorization.\") ||\n type.startsWith(\"subagent.\")\n ) {\n this.put({\n id: `event:${event.meta?.id ?? this.cursor}`,\n kind: type.endsWith(\".failed\") ? \"error\" : \"status\",\n title: type,\n createdAt,\n text: string(\n data.message ?? data.output ?? data.authorization ?? data.subagentName ?? data.name ?? \"\",\n ),\n });\n }\n }\n\n private tool(tool: ToolCall, createdAt?: string) {\n this.tools.set(tool.callId, tool);\n const output = tool.error ?? tool.output;\n const previous = this.blocks.find((block) => block.id === `tool:${tool.callId}`);\n const contentRef = previous?.contentRef;\n this.put({\n id: `tool:${tool.callId}`,\n kind: \"tool\",\n title: tool.name,\n createdAt: previous?.createdAt ?? createdAt,\n tool,\n ...(contentRef ? { contentRef } : {}),\n text: `Input\\n\\`\\`\\`json\\n${tool.inputText}\\n\\`\\`\\`${output === undefined ? \"\" : `\\n\\nOutput\\n\\`\\`\\`\\n${string(output)}\\n\\`\\`\\``}`,\n });\n }\n}\n"],"mappings":"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"}