@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.
- package/CHANGELOG.md +46 -0
- package/dist/api-contracts.d.mts +665 -715
- package/dist/api-contracts.mjs +91 -4
- package/dist/api-contracts.mjs.map +1 -1
- package/dist/api-task-graph.mjs +14 -5
- package/dist/api-task-graph.mjs.map +1 -1
- package/dist/api.d.mts +58 -11
- package/dist/api.mjs +715 -399
- package/dist/api.mjs.map +1 -1
- package/dist/approval-access.d.mts +1 -1
- package/dist/approval-contracts.d.mts +3 -4
- package/dist/approval-contracts.mjs +1 -2
- package/dist/approval-contracts.mjs.map +1 -1
- package/dist/blob/index.d.mts +1 -1
- package/dist/budget.mjs +20 -3
- package/dist/budget.mjs.map +1 -1
- package/dist/change-verification/brief.d.mts +1 -1
- package/dist/change-verification/dispatch.mjs +8 -1
- package/dist/change-verification/dispatch.mjs.map +1 -1
- package/dist/changes/eve-record-change.mjs +4 -1
- package/dist/changes/eve-record-change.mjs.map +1 -1
- package/dist/client-stream.d.mts +19 -2
- package/dist/client-stream.mjs +115 -53
- package/dist/client-stream.mjs.map +1 -1
- package/dist/client-transcript.d.mts +25 -2
- package/dist/client-transcript.mjs +95 -13
- package/dist/client-transcript.mjs.map +1 -1
- package/dist/client.d.mts +145 -19
- package/dist/client.mjs +89 -16
- package/dist/client.mjs.map +1 -1
- package/dist/code-review/contracts.d.mts +1 -0
- package/dist/code-review/eve-post-review.d.mts +4 -2
- package/dist/code-review/eve-post-review.mjs +8 -0
- package/dist/code-review/eve-post-review.mjs.map +1 -1
- package/dist/code-review/github-reporter.d.mts +6 -2
- package/dist/code-review/github-reporter.mjs +86 -35
- package/dist/code-review/github-reporter.mjs.map +1 -1
- package/dist/code-review/preparation.d.mts +2 -1
- package/dist/code-review/preparation.mjs +2 -1
- package/dist/code-review/preparation.mjs.map +1 -1
- package/dist/code-review/stall.mjs +11 -2
- package/dist/code-review/stall.mjs.map +1 -1
- package/dist/connectors/github.d.mts +1 -1
- package/dist/connectors/index.d.mts +1 -1
- package/dist/connectors/slack.d.mts +1 -1
- package/dist/delivery-metrics/metrics.d.mts +1 -1
- package/dist/dispatch.mjs +3 -3
- package/dist/dispatch.mjs.map +1 -1
- package/dist/eve/index.d.mts +1 -1
- package/dist/eve/index.mjs +8 -1
- package/dist/eve/index.mjs.map +1 -1
- package/dist/eve/task-execution.d.mts +4 -4
- package/dist/eve/transcript.d.mts +3 -1
- package/dist/eve/transcript.mjs.map +1 -1
- package/dist/finding-remediation/admission.d.mts +1 -1
- package/dist/finding-remediation/brief.d.mts +1 -1
- package/dist/github-app.d.mts +1 -1
- package/dist/github-publication.d.mts +1 -1
- package/dist/github.d.mts +9 -1
- package/dist/github.mjs +29 -11
- package/dist/github.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/intake-contracts.d.mts +1 -0
- package/dist/intake-contracts.mjs +2 -1
- package/dist/intake-contracts.mjs.map +1 -1
- package/dist/integrations/github-issues.d.mts +53 -0
- package/dist/integrations/github-issues.mjs +170 -0
- package/dist/integrations/github-issues.mjs.map +1 -0
- package/dist/integrations/github.d.mts +2 -1
- package/dist/integrations/github.mjs +2 -1
- package/dist/multi-repository-changes/coordination.mjs +1 -1
- package/dist/planning/reconcile.mjs +15 -2
- package/dist/planning/reconcile.mjs.map +1 -1
- package/dist/postgres/index.d.mts +2 -1
- package/dist/postgres/index.mjs +11 -5
- package/dist/postgres/index.mjs.map +1 -1
- package/dist/postgres/indexed-codec.mjs +137 -0
- package/dist/postgres/indexed-codec.mjs.map +1 -0
- package/dist/postgres/indexed-schema.mjs +99 -0
- package/dist/postgres/indexed-schema.mjs.map +1 -0
- package/dist/postgres/indexed.d.mts +28 -0
- package/dist/postgres/indexed.mjs +277 -0
- package/dist/postgres/indexed.mjs.map +1 -0
- package/dist/postgres/record-predicates.mjs +23 -0
- package/dist/postgres/record-predicates.mjs.map +1 -0
- package/dist/presets/software-development/deepsec-brief.d.mts +1 -1
- package/dist/presets/software-development/dispatch.mjs +1 -1
- package/dist/presets/software-development/dispatch.mjs.map +1 -1
- package/dist/presets/software-development/recovery.mjs +9 -2
- package/dist/presets/software-development/recovery.mjs.map +1 -1
- package/dist/pull-requests/eve-fetch.d.mts +4 -1
- package/dist/pull-requests/eve-fetch.mjs +9 -0
- package/dist/pull-requests/eve-fetch.mjs.map +1 -1
- package/dist/pull-requests/github-publisher.d.mts +1 -1
- package/dist/pull-requests/github-publisher.mjs +19 -7
- package/dist/pull-requests/github-publisher.mjs.map +1 -1
- package/dist/repositories.mjs +20 -13
- package/dist/repositories.mjs.map +1 -1
- package/dist/sandbox/execution-run-ledger.d.mts +2 -2
- package/dist/sandbox/execution-run-ledger.mjs.map +1 -1
- package/dist/sandbox/execution.d.mts +2 -2
- package/dist/sandbox/execution.mjs.map +1 -1
- package/dist/schema/catalog.mjs +1 -1
- package/dist/schema/change.d.mts +1 -1
- package/dist/schema/communication.d.mts +2 -2
- package/dist/schema/factory-config.d.mts +1 -1
- package/dist/schema/outbox.d.mts +6 -6
- package/dist/schema/session-summary.d.mts +218 -0
- package/dist/schema/session-summary.mjs +68 -0
- package/dist/schema/session-summary.mjs.map +1 -0
- package/dist/schema/session.d.mts +39 -59
- package/dist/schema/session.mjs +6 -6
- package/dist/schema/session.mjs.map +1 -1
- package/dist/schema/task-graph.d.mts +24 -24
- package/dist/schema/transcript.d.mts +141 -3
- package/dist/schema/transcript.mjs +19 -3
- package/dist/schema/transcript.mjs.map +1 -1
- package/dist/schema/transitions.d.mts +1 -1
- package/dist/schema/transitions.mjs +1 -1
- package/dist/schema/transitions.mjs.map +1 -1
- package/dist/signals.d.mts +1 -1
- package/dist/stall.mjs +10 -2
- package/dist/stall.mjs.map +1 -1
- package/dist/storage.d.mts +10 -1
- package/dist/storage.mjs +7 -1
- package/dist/store/approvals.d.mts +14 -0
- package/dist/store/approvals.mjs +78 -0
- package/dist/store/approvals.mjs.map +1 -0
- package/dist/store/conversations.d.mts +59 -0
- package/dist/store/conversations.mjs +549 -0
- package/dist/store/conversations.mjs.map +1 -0
- package/dist/store/driver.d.mts +1 -1
- package/dist/store/driver.mjs.map +1 -1
- package/dist/store/engine.d.mts +38 -16
- package/dist/store/engine.mjs +229 -106
- package/dist/store/engine.mjs.map +1 -1
- package/dist/store/indexed-engine.d.mts +57 -0
- package/dist/store/indexed-engine.mjs +155 -0
- package/dist/store/indexed-engine.mjs.map +1 -0
- package/dist/store/indexed-memory.d.mts +7 -0
- package/dist/store/indexed-memory.mjs +200 -0
- package/dist/store/indexed-memory.mjs.map +1 -0
- package/dist/store/indexed-projections.d.mts +280 -0
- package/dist/store/indexed-projections.mjs +481 -0
- package/dist/store/indexed-projections.mjs.map +1 -0
- package/dist/store/indexed.d.mts +101 -0
- package/dist/store/indexed.mjs +19 -0
- package/dist/store/indexed.mjs.map +1 -0
- package/dist/store/iterate.d.mts +9 -0
- package/dist/store/iterate.mjs +23 -0
- package/dist/store/iterate.mjs.map +1 -0
- package/dist/store/query-scope.mjs +62 -0
- package/dist/store/query-scope.mjs.map +1 -0
- package/dist/store/query.d.mts +32 -0
- package/dist/store/query.mjs +103 -0
- package/dist/store/query.mjs.map +1 -0
- package/dist/store/session-history.mjs +24 -0
- package/dist/store/session-history.mjs.map +1 -0
- package/dist/store/slack-pr-notifications.d.mts +2 -2
- package/dist/store/slack-pr-notifications.mjs.map +1 -1
- package/dist/store/state.d.mts +26 -0
- package/dist/store/state.mjs +95 -0
- package/dist/store/state.mjs.map +1 -0
- package/dist/store/task-effects.d.mts +1 -1
- package/dist/store/task-graphs.d.mts +1 -1
- package/dist/store/task-messages.d.mts +1 -1
- package/dist/store/task-work.d.mts +1 -1
- package/dist/store/task-work.mjs +1 -1
- package/dist/store/transcripts.mjs +308 -0
- package/dist/store/transcripts.mjs.map +1 -0
- package/dist/sweep.d.mts +1 -1
- package/dist/sweep.mjs +12 -7
- package/dist/sweep.mjs.map +1 -1
- package/dist/task-communication.mjs +15 -1
- package/dist/task-communication.mjs.map +1 -1
- package/dist/task-protocols.d.mts +3 -3
- package/dist/tasks.d.mts +1 -1
- package/dist/vercel.d.mts +1 -1
- package/dist/work-triage/find-existing-work.d.mts +1 -1
- package/dist/work-triage/find-existing-work.mjs +12 -2
- package/dist/work-triage/find-existing-work.mjs.map +1 -1
- package/docs/index.md +4 -0
- package/docs/recipes/persistence-recovery.md +15 -9
- package/docs/recipes/postgres-indexed-engine.md +108 -0
- package/docs/recipes/postgres-indexed-storage.md +145 -0
- 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":";;;;;AA8BA,SAAS,MAAM,IAAY,QAAoC;CAC7D,OAAO,IAAI,SAAS,YAAY;EAC9B,MAAM,eAAe;GACnB,aAAa,KAAK;GAClB,OAAO,oBAAoB,SAAS,MAAM;GAC1C,QAAQ;EACV;EACA,MAAM,QAAQ,WAAW,QAAQ,EAAE;EACnC,OAAO,iBAAiB,SAAS,QAAQ,EAAE,MAAM,KAAK,CAAC;EACvD,IAAI,OAAO,SAAS,OAAO;CAC7B,CAAC;AACH;AAEA,eAAe,aACb,QACA,OAUA;CACA,IAAI,WAAW;CACf,OAAO,CAAC,MAAM,OAAO,SACnB,IAAI;EACF,MAAM,gBAAgB,YAAY,IAAI,CAAC,MAAM,QAAQ,YAAY,QAAQ,IAAM,CAAC,CAAC;EACjF,MAAM,WAAW,MAAM,OAAO,6BAA6B;GACzD,WAAW,MAAM;GACjB,aAAa,MAAM;GACnB,GAAI,MAAM,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,MAAM,OAAO;GAC7D,GAAI,MAAM,UAAU,EAAE,SAAS,KAAK,IAAI,CAAC;GACzC,QAAQ;EACV,CAAC;EACD,MAAM,WAAW,QAAQ,yBAAyB,MAAM,MAAM,SAAS,KAAK,CAAC,CAAC;EAC9E;CACF,SAAS,OAAO;EACd,IAAI,MAAM,OAAO,SAAS;EAC1B,IAAI,iBAAiB,UAAU,MAAM;EACrC,MAAM,UAAU,KAAK;EACrB;EACA,MAAM,MACJ,KAAK,IAAI,MAAQ,MAAM,iBAAiB,KAAK,KAAK,IAAI,UAAU,CAAC,CAAC,GAClE,MAAM,MACR;CACF;AAEJ;AAEA,eAAe,YACb,QACA,SACmD;CACnD,MAAM,UAAU,QAAQ,WAAW,CAAC;CACpC,MAAM,0BAAU,IAAI,IAAoD;CACxE,IAAI,OAAO;CACX,MAAM,QAAQ,IACZ,MAAM,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,QAAQ,MAAM,EAAE,GAAG,YAAY;EAC9D,OAAO,OAAO,QAAQ,QAAQ;GAC5B,MAAM,QAAQ;GACd,MAAM,QAAQ,QAAQ;GACtB,IAAI,CAAC,OAAO,MAAM,IAAI,MAAM,4CAA4C;GACxE,MAAM,KAAK,MAAM,UAAU;GAC3B,MAAM,WAAW,IAAI,WAAW,MAAM,SAAS,MAAM,WAAW;GAChE,MAAM,SAAS;IACb,IAAI;IACJ,MAAM;IACN,OAAO,MAAM;IACb,MAAM,MAAM,SAAS,kBAAkB,MAAM,WAAW;GAC1D;GACA,IAAI;IACF,MAAM,gBAAgB,YAAY,IAAI,CAAC,QAAQ,QAAQ,YAAY,QAAQ,IAAM,CAAC,CAAC;IACnF,MAAM,aAAa,QAAQ;KACzB,WAAW,QAAQ;KACnB,aAAa;KACb,SAAS;KACT,YAAY;KACZ,QAAQ;KACR,gBAAgB,QAAQ,kBAAkB;IAC5C,CAAC;IACD,IAAI,cAAc,WAAW,CAAC,QAAQ,OAAO,SAC3C,MAAM,IAAI,MAAM,yCAAyC;GAC7D,SAAS,OAAO;IACd,IAAI,QAAQ,OAAO,SAAS;IAC5B,IAAI,iBAAiB,YAAY,CAAC,KAAK,GAAG,CAAC,CAAC,SAAS,MAAM,MAAM,GAAG,MAAM;IAC1E,SAAS,IAAI;KACX,IAAI;KACJ,MAAM;KACN,OAAO;KACP,MAAM;IACR,CAAC;GACH;GACA,SAAS,OAAO,QAAQ,MAAM;GAC9B,QAAQ,IAAI,OAAO;IAAE;IAAI,YAAY;GAAS,CAAC;EACjD;CACF,CAAC,CACH;CACA,OAAO,QAAQ,KAAK,GAAG,UAAU;EAC/B,MAAM,SAAS,QAAQ,IAAI,KAAK;EAChC,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,gDAAgD;EAC7E,OAAO;CACT,CAAC;AACH;AAEA,eAAe,eACb,QACA,SACkB;CAClB,MAAM,cAAc,QAAQ;CAC5B,IAAI,gBAAgB,MAAM,OAAO;CACjC,IAAI,WAAW;CACf,OAAO,CAAC,QAAQ,OAAO,SACrB,IAAI;EACF,MAAM,aAAa,QAAQ;GACzB,WAAW,QAAQ;GACnB;GACA,QAAQ,QAAQ;GAChB,SAAS;GACT,YAAY,QAAQ;GACpB,QAAQ,QAAQ;GAChB,gBAAgB,QAAQ,kBAAkB;GAC1C,UAAU,UAAU;IAClB,QAAQ,aAAa,cAAc;IACnC,QAAQ,QAAQ,KAAK;GACvB;EACF,CAAC;EACD,IAAI,QAAQ,OAAO,SAAS,OAAO;EACnC,QAAQ,aAAa,WAAW;EAChC,OAAO;CACT,SAAS,OAAO;EACd,IAAI,QAAQ,OAAO,SAAS,OAAO;EACnC,QAAQ,aAAa,cAAc;EACnC;EACA,QAAQ,QAAQ,KAAK;EACrB,IACE,iBAAiB,YACjB;GAAC;GAAG;GAAK;GAAK;GAAK;GAAK;GAAK;GAAK;EAAG,CAAC,CAAC,SAAS,MAAM,MAAM,GAE5D,OAAO;EACT,IAAI,iBAAiB,YAAY,MAAM,WAAW,KAAK,OAAO;EAC9D,IAAI,iBAAiB,YAAY,MAAM,WAAW,KAAK;GACrD,MAAM,QAAQ,WAAW;GACzB,OAAO;EACT;EACA,MAAM,MACJ,KAAK,IAAI,OAAS,QAAQ,kBAAkB,OAAQ,KAAK,KAAK,IAAI,UAAU,CAAC,CAAC,GAC9E,QAAQ,MACV;CACF;CAEF,OAAO;AACT;;AAGA,eAAsB,oBACpB,QACA,SACe;CACf,MAAM,EAAE,WAAW,aAAa,YAAY,WAAW;CACvD,IAAI;CACJ,IAAI;CACJ,IAAI;EACF,CAAC,SAAS,YAAY,MAAM,QAAQ,IAAI,CACtC,YAAY,QAAQ,OAAO,GAC3B,eAAe,QAAQ,OAAO,CAChC,CAAC;CACH,SAAS,OAAO;EACd,IAAI,CAAC,OAAO,SAAS,QAAQ,QAAQ,KAAK;EAC1C;CACF;CACA,IAAI,OAAO,WAAW,CAAC,UAAU;CACjC,WAAW,eAAe,OAAO;CACjC,IAAI,gBAAgB,MAAM,WAAW,QAAQ;CAC7C,QAAQ,WAAW;CACnB,IAAI,gBAAgB,QAAQ,CAAC,aAAa,QAAQ,CAAC,CAAC,SAAS,WAAW,KAAK,GAAG;CAChF,IAAI,WAAW;CACf,OAAO,CAAC,OAAO,SAAS;EACtB,MAAM,UAAU,YAAY,QAAQ,GAAM;EAC1C,IAAI,cAAc;EAClB,IAAI;GACF,MAAM,WAAW,MAAM,OAAO,8BAA8B;IAC1D;IACA;IACA,QAAQ,WAAW;IACnB,GAAI,QAAQ,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,QAAQ,OAAO;IACjE,QAAQ,YAAY,IAAI,CAAC,QAAQ,OAAO,CAAC;GAC3C,CAAC;GACD,IAAI,CAAC,SAAS,MAAM,MAAM,IAAI,MAAM,sCAAsC;GAC1E,cAAc;GACd,QAAQ,aAAa,WAAW;GAChC,WAAW,MAAM,SAAS,WAAW,SAAS,IAAI,GAAG;IACnD,IAAI,OAAO,SAAS;IACpB,WAAW,OAAO,KAAK;IACvB,WAAW;IACX,QAAQ,SAAS;GACnB;GACA,IAAI,CAAC,aAAa,QAAQ,CAAC,CAAC,SAAS,WAAW,KAAK,GAAG;EAC1D,SAAS,OAAO;GACd,IAAI,OAAO,SAAS;GACpB,QAAQ,aAAa,cAAc;GACnC,IAAI,QAAQ,WAAW,aAAa;IAClC,WAAW;IACX;GACF;GACA;GACA,QAAQ,QAAQ,KAAK;GACrB,IACE,iBAAiB,YACjB;IAAC;IAAG;IAAK;IAAK;IAAK;IAAK;IAAK;IAAK;GAAG,CAAC,CAAC,SAAS,MAAM,MAAM,GAE5D;GACF,IAAI,iBAAiB,YAAY,MAAM,WAAW,KAAK;IACrD,IAAI,WAAW,UAAU,WAAW;KAClC,WAAW,QAAQ;KACnB,QAAQ,SAAS;IACnB;IACA;GACF;GACA,IAAI,iBAAiB,YAAY,MAAM,WAAW,KAAK;IACrD,MAAM,QAAQ,WAAW;IACzB;GACF;EACF;EACA,MAAM,MACJ,KAAK,IAAI,OAAS,QAAQ,kBAAkB,OAAQ,KAAK,KAAK,IAAI,UAAU,CAAC,CAAC,GAC9E,MACF;CACF;AACF"}
|
|
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
|
-
|
|
80
|
-
|
|
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
|
-
|
|
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) =>
|
|
203
|
-
|
|
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":";;;AAkBA,SAAS,OAAO,OAAyC;CACvD,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK,IACrE,QACD,CAAC;AACP;AACA,SAAS,OAAO,OAAwB;CACtC,OAAO,OAAO,UAAU,WAAW,QAAS,KAAK,UAAU,OAAO,MAAM,CAAC,KAAK;AAChF;AACA,SAAS,WAAW,MAAuB;CACzC,IAAI;EACF,OAAO,KAAK,MAAM,IAAI;CACxB,QAAQ;EACN;CACF;AACF;AACA,SAAS,QAAQ,MAAgB;CAC/B,OAAO;EAAC;EAAa;EAAU;EAAa;CAAU,CAAC,CAAC,SAAS,KAAK,KAAK;AAC7E;;AAGA,IAAa,aAAb,MAAwB;CAUZ;CACA;CAVV,SAA4B,CAAC;CAC7B,yBAAS,IAAI,IAA0B;CACvC,SAAS;CACT,QAAQ;CACR;CACA,SAAS;CACT,uBAAe,IAAI,IAAY;CAC/B,wBAAgB,IAAI,IAAsB;CAC1C,YACE,gBACA,oBACA;EAFQ,KAAA,iBAAA;EACA,KAAA,qBAAA;CACP;CAEH,WAA+B;EAC7B,OAAO,yBAAyB,MAAM;GACpC,QAAQ,KAAK;GACb,QAAQ,CAAC,GAAG,KAAK,OAAO,OAAO,CAAC;GAChC,QAAQ,KAAK;GACb,OAAO,KAAK;GACZ,QAAQ,KAAK;GACb,QAAQ,KAAK;EACf,CAAC;CACH;CAEA,QAAQ,OAAiC;EACvC,MAAM,WAAW,yBAAyB,MAAM,KAAK;EACrD,KAAK,SAAS,SAAS,OAAO,KAAK,WAAW,EAAE,GAAG,MAAM,EAAE;EAC3D,MAAM,YAAY,KAAK,OAAO,MAC3B,UAA+D,MAAM,SAAS,MACjF;EACA,IACE,cAAc,KAAA,MACb,KAAK,mBAAmB,KAAA,KAAa,KAAK,uBAAuB,KAAA,IAClE;GACA,MAAM,OAAO,KAAK,kBAAkB,UAAU;GAC9C,MAAM,cAAc,KAAK,sBAAsB,UAAU;GACzD,MAAM,iBAAiB,KAAK,OAAO,QAAQ,SAAS;GACpD,IAAI,aAAa,QACf,KAAK,OAAO,kBAAkB;IAAE,GAAG;IAAW;IAAM,aAAa,CAAC,GAAG,WAAW;GAAE;QAC7E;IACL,MAAM,EAAE,aAAa,cAAc,GAAG,uBAAuB;IAC7D,KAAK,OAAO,kBAAkB;KAAE,GAAG;KAAoB;IAAK;GAC9D;EACF;EACA,KAAK,SAAS,IAAI,IAAI,SAAS,OAAO,KAAK,YAAY,CAAC,QAAQ,WAAW,OAAO,CAAC,CAAC;EACpF,KAAK,SAAS,SAAS;EACvB,KAAK,QAAQ,SAAS;EACtB,KAAK,SAAS,SAAS;EACvB,KAAK,SAAS,SAAS;EACvB,KAAK,KAAK,MAAM;EAChB,KAAK,QAAQ,IAAI,IACf,KAAK,OAAO,SAAS,UACnB,MAAM,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,MAAM,IAAI,CAAU,IAAI,CAAC,CAC7D,CACF;EACA,KAAK,iBAAiB,KAAA;EACtB,KAAK,qBAAqB,KAAA;CAC5B;CAEA,IAAI,OAAwB;EAC1B,MAAM,QAAQ,KAAK,OAAO,WAAW,SAAS,KAAK,OAAO,MAAM,EAAE;EAClE,IAAI,QAAQ,GAAG,KAAK,OAAO,KAAK,KAAK;OAChC,KAAK,OAAO,SAAS;CAC5B;CAEA,cAAc,IAAY,YAAwB;EAChD,KAAK,MAAM,SAAS,WAAW,QAAQ,KAAK,IAAI;GAAE,GAAG;GAAO,IAAI,WAAW,GAAG,GAAG,MAAM;EAAK,CAAC;CAC/F;CAEA,eAAe,SAA4D;EACzE,MAAM,UAAU,QAAQ,SAAS,EAAE,IAAI,iBACrC,WAAW,OAAO,KAAK,WAAW;GAAE,GAAG;GAAO,IAAI,WAAW,GAAG,GAAG,MAAM;EAAK,EAAE,CAClF;EACA,MAAM,MAAM,IAAI,IAAI,QAAQ,KAAK,UAAU,MAAM,EAAE,CAAC;EACpD,KAAK,SAAS,CAAC,GAAG,SAAS,GAAG,KAAK,OAAO,QAAQ,UAAU,CAAC,IAAI,IAAI,MAAM,EAAE,CAAC,CAAC;CACjF;CAEA,OAAO,OAAoB;EACzB,KAAK;EACL,IAAI,MAAM,MAAM,OAAO,KAAA,GAAW;GAChC,IAAI,KAAK,KAAK,IAAI,MAAM,KAAK,EAAE,GAAG;GAClC,KAAK,KAAK,IAAI,MAAM,KAAK,EAAE;EAC7B;EACA,MAAM,EAAE,MAAM,SAAS;EACvB,MAAM,aAAa,GAAG,KAAK,OAAO,GAAG,KAAK,UAAU,GAAG,KAAK;EAC5D,IAAI,SAAS,gBAAgB;GAC3B,KAAK,SAAS,OAAO,KAAK,MAAM;GAChC,KAAK,QAAQ;EACf;EACA,IAAI,SAAS,oBAAoB;GAC/B,MAAM,cAAc,KAAK,sBAAsB,eAAe,KAAK,KAAK;GACxE,MAAM,YAAY,MAAM,QAAQ,KAAK,KAAK,IACtC,KAAK,MACF,QAAQ,SAAS,OAAO,IAAI,CAAC,CAAC,SAAS,MAAM,CAAC,CAC9C,KAAK,SAAS,OAAO,OAAO,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CACxC,KAAK,IAAI,IACZ,KAAA;GACJ,KAAK,IAAI;IACP,IAAI,QAAQ,MAAM,MAAM,MAAM,KAAK;IACnC,MAAM;IACN,OAAO;IACP,MACE,KAAK,mBAAmB,YAAY,SAAU,aAAa,KAAM,OAAO,KAAK,OAAO;IACtF,GAAI,YAAY,SAAS,EAAE,aAAa,CAAC,GAAG,WAAW,EAAE,IAAI,CAAC;GAChE,CAAC;GACD,KAAK,iBAAiB,KAAA;GACtB,KAAK,qBAAqB,KAAA;EAC5B;EACA,IAAI,SAAS,sBAAsB,SAAS,qBAC1C,KAAK,IAAI;GACP,IAAI,WAAW;GACf,MAAM;GACN,OAAO;GACP,MAAM,OAAO,KAAK,OAAO;EAC3B,CAAC;EACH,IAAI,SAAS,oBACX,KAAK,IAAI;GACP,IAAI,UAAU;GACd,MAAM;GACN,OAAO;GACP,MAAM,eAAe,OAAO,KAAK,MAAM,EAAE;EAC3C,CAAC;EACH,IAAI,SAAS,wBAAwB,SAAS,uBAC5C,KAAK,IAAI;GACP,IAAI,aAAa;GACjB,MAAM;GACN,OAAO;GACP,MAAM,OAAO,KAAK,SAAS;EAC7B,CAAC;EACH,IAAI,SAAS,uBAAuB,MAAM,QAAQ,KAAK,OAAO,GAC5D,KAAK,MAAM,QAAQ,KAAK,SAAS;GAC/B,MAAM,SAAS,OAAO,IAAI;GAC1B,MAAM,SAAS,OAAO,OAAO,MAAM;GACnC,MAAM,WAAW,KAAK,MAAM,IAAI,MAAM;GACtC,KAAK,KAAK;IACR,GAAG;IACH;IACA,OAAO,OAAO;IACd,WAAW,OAAO,OAAO,KAAK;IAC9B,MAAM,OAAO,OAAO,YAAY,OAAO,QAAQ,OAAO,IAAI;IAC1D,OAAO,UAAU,UAAU,oBAAoB,YAAa,UAAU,SAAS;GACjF,CAAC;EACH;EACF,IAAI,SAAS,yBAAyB;GACpC,MAAM,KAAK,OAAO,KAAK,MAAM;GAC7B,MAAM,WAAW,KAAK,MAAM,IAAI,EAAE;GAClC,MAAM,SAAS,KAAK;GACpB,MAAM,QAAQ,OAAO,KAAK,cAAc;GACxC,KACG,CAAC,YAAY,SAAS,UAAU,uBAChC,WAAW,KAAK,WAAW,UAAU,UAAU,SAChD;IACA,MAAM,aAAa,WAAW,IAAI,KAAM,UAAU,aAAa,MAAO;IACtE,KAAK,KAAK;KACR,QAAQ;KACR,OAAO,WAAW,SAAS;KAC3B;KACA,MAAM,OAAO,KAAK,QAAQ;KAC1B,OAAO;IACT,CAAC;GACH;EACF;EACA,IAAI,SAAS,mBAAmB,SAAS,kBAAkB;GACzD,MAAM,SAAS,OAAO,KAAK,MAAM;GACjC,MAAM,KAAK,OAAO,OAAO,MAAM;GAC/B,MAAM,WAAW,KAAK,MAAM,IAAI,EAAE;GAClC,IAAI,SAAS,oBAAoB,CAAC,YAAY,CAAC,QAAQ,QAAQ,GAC7D,KAAK,KAAK;IACR,GAAG;IACH,QAAQ;IACR,OAAO,UAAU;IACjB,WAAW,UAAU,aAAa;IAClC,MAAM,UAAU,QAAQ,OAAO,OAAO,YAAY,OAAO,IAAI;IAC7D,QAAQ,YAAY,SAAS,OAAO,SAAS;IAC7C,OAAO,KAAK;IACZ,OACE,SAAS,mBACL,YACA,KAAK,WAAW,aACd,aACA,KAAK,WAAW,YAAY,KAAK,SAAS,OACxC,WACA;GACZ,CAAC;EACL;EACA,IAAI,SAAS,oBAAoB,SAAS,iBAAiB,SAAS,kBAC7D;QAAA,MAAM,QAAQ,KAAK,MAAM,OAAO,GACnC,IAAI,CAAC,QAAQ,IAAI,GACf,KAAK,KAAK;IACR,GAAG;IACH,OAAO,SAAS,mBAAmB,cAAc;IACjD,OAAO,KAAK;GACd,CAAC;EAAA;EAEP,IAAI,SAAS,mBAAmB;GAC9B,KAAK,MAAM,WAAW,mBAAmB,MAAM,CAAC,CAAC,MAAM,KAAK,QAAQ,GAClE,KAAK,OAAO,IAAI,QAAQ,WAAW,OAAO;GAC5C,KAAK,QAAQ;EACf;EACA,IAAI,SAAS,oBAAoB,MAAM,QAAQ,KAAK,WAAW,GAC7D,KAAK,MAAM,cAAc,KAAK,aAC5B,KAAK,OAAO,OAAO,OAAO,OAAO,UAAU,CAAC,CAAC,SAAS,CAAC;EAC3D,IAAI,SAAS,kBAAkB;GAC7B,MAAM,QAAQ,OAAO,KAAK,KAAK;GAC/B,MAAM,SAAS,UACb,OAAO,UAAU,WAAW,QAAQ,OAAO,OAAO,KAAK,CAAC,CAAC,SAAS,CAAC;GACrE,KAAK,UAAU,MAAM,MAAM,WAAW,IAAI,MAAM,MAAM,YAAY;EACpE;EACA,IACE,SAAS,qBACR;GAAC;GAAkB;GAAe;EAAgB,CAAC,CAAC,SAAS,IAAI,MAC/D,KAAK,WAAW,KAAA,KAAa,KAAK,WAAW,KAAK,SAErD,KAAK,QAAQ,KAAK,OAAO,OAAO,IAAI,gBAAgB;EACtD,IAAI,CAAC,qBAAqB,gBAAgB,CAAC,CAAC,SAAS,IAAI,GAAG,KAAK,QAAQ,KAAK,MAAM,CAAC;EACrF,IACE,KAAK,SAAS,SAAS,KACvB,SAAS,oBACT,KAAK,WAAW,aAAa,KAC7B,KAAK,WAAW,gBAAgB,KAChC,KAAK,WAAW,WAAW,GAE3B,KAAK,IAAI;GACP,IAAI,SAAS,MAAM,MAAM,MAAM,KAAK;GACpC,MAAM,KAAK,SAAS,SAAS,IAAI,UAAU;GAC3C,OAAO;GACP,MAAM,OACJ,KAAK,WAAW,KAAK,UAAU,KAAK,iBAAiB,KAAK,gBAAgB,KAAK,QAAQ,EACzF;EACF,CAAC;CAEL;CAEA,KAAa,MAAgB;EAC3B,KAAK,MAAM,IAAI,KAAK,QAAQ,IAAI;EAChC,MAAM,SAAS,KAAK,SAAS,KAAK;EAClC,KAAK,IAAI;GACP,IAAI,QAAQ,KAAK;GACjB,MAAM;GACN,OAAO,KAAK;GACZ;GACA,MAAM,sBAAsB,KAAK,UAAU,UAAU,WAAW,KAAA,IAAY,KAAK,uBAAuB,OAAO,MAAM,EAAE;EACzH,CAAC;CACH;AACF"}
|
|
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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"}
|