@yaklabs-ai/plugin-sdk 0.15.1 → 0.15.3

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.
@@ -0,0 +1,3842 @@
1
+ // packages/herd-transcript/dist/context-messages.js
2
+ var UI_ACTION_CUSTOM_TYPE = "ui_action";
3
+ var USER_PASTED_CONTENT_CUSTOM_TYPE = "user_pasted_content";
4
+ var ATTACHMENTS_CUSTOM_TYPE = "attachments";
5
+ var DAEMON_SERVICE_TURN_CUSTOM_TYPE = "daemon_service_turn";
6
+ var MID_TURN_COMPACTION_OUTCOME_CUSTOM_TYPE = "mid_turn_compaction_outcome";
7
+ var RUN_CONTINUATION_CARRIER_CUSTOM_TYPE = "herd_run_continuation";
8
+ var DYNAMIC_CONTEXT_CUSTOM_TYPE = "dynamic_context";
9
+ var USER_INVOKED_CUSTOM_TYPE = "user_invoked";
10
+
11
+ // packages/herd-transcript/dist/turn-messages.js
12
+ var SUBAGENT_RESULT_CUSTOM_TYPE = "subagent_result";
13
+ var BACKGROUND_TASK_RESULT_CUSTOM_TYPE = "background_task_result";
14
+
15
+ // packages/herd-transcript/dist/run-failure-reason.js
16
+ var RUN_FAILURE_REASONS = [
17
+ "auth",
18
+ "cancelled",
19
+ "content_blocked",
20
+ "context_overflow",
21
+ "invalid_request",
22
+ "model_disabled",
23
+ "model_unavailable",
24
+ "network",
25
+ "organization_unavailable",
26
+ "overloaded",
27
+ "quota_exhausted",
28
+ "rate_limit",
29
+ "runtime_interrupted",
30
+ "safeguard_block",
31
+ "seat_unpaid",
32
+ "server_error",
33
+ "sign_in_required",
34
+ "stream_interrupted",
35
+ "timeout",
36
+ "unknown"
37
+ ];
38
+
39
+ // packages/herd-transcript/dist/run-failure.js
40
+ import { z as z3 } from "zod";
41
+
42
+ // packages/failures/dist/failure.js
43
+ import { z } from "zod";
44
+
45
+ // packages/failures/dist/json-snapshot.js
46
+ var FAILURE_MAX_BYTES = 16 * 1024;
47
+ var FAILURE_MAX_DEPTH = 16;
48
+ function utf8Bytes(value) {
49
+ let bytes = 0;
50
+ for (const character of value) {
51
+ const point = character.codePointAt(0) ?? 0;
52
+ bytes += point <= 127 ? 1 : point <= 2047 ? 2 : point <= 65535 ? 3 : 4;
53
+ }
54
+ return bytes;
55
+ }
56
+ function snapshotJson(input) {
57
+ let bytes = 0;
58
+ const ancestors = /* @__PURE__ */ new Set();
59
+ function charge(text) {
60
+ bytes += utf8Bytes(text);
61
+ if (bytes > FAILURE_MAX_BYTES)
62
+ throw "too-large";
63
+ }
64
+ function visit2(value, depth) {
65
+ if (depth > FAILURE_MAX_DEPTH)
66
+ throw "too-deep";
67
+ if (value === null || typeof value === "boolean" || typeof value === "number") {
68
+ if (typeof value === "number" && !Number.isFinite(value))
69
+ throw "invalid-json";
70
+ charge(JSON.stringify(value));
71
+ return Object.is(value, -0) ? 0 : value;
72
+ }
73
+ if (typeof value === "string") {
74
+ if (value.length > FAILURE_MAX_BYTES)
75
+ throw "too-large";
76
+ charge(JSON.stringify(value));
77
+ return value;
78
+ }
79
+ if (typeof value !== "object")
80
+ throw "invalid-json";
81
+ if (ancestors.has(value))
82
+ throw "invalid-json";
83
+ const array = Array.isArray(value);
84
+ if (!array && ![Object.prototype, null].includes(Object.getPrototypeOf(value))) {
85
+ throw "invalid-json";
86
+ }
87
+ ancestors.add(value);
88
+ charge(array ? "[]" : "{}");
89
+ const keys = Reflect.ownKeys(value);
90
+ if (keys.length > FAILURE_MAX_BYTES)
91
+ throw "too-large";
92
+ let result;
93
+ if (array) {
94
+ const length = Object.getOwnPropertyDescriptor(value, "length")?.value;
95
+ if (typeof length !== "number" || !Number.isSafeInteger(length) || length < 0)
96
+ throw "invalid-json";
97
+ if (length > FAILURE_MAX_BYTES)
98
+ throw "too-large";
99
+ if (keys.some((key) => key !== "length" && (typeof key !== "string" || !/^(0|[1-9]\d*)$/.test(key) || Number(key) >= length))) {
100
+ throw "invalid-json";
101
+ }
102
+ const items = [];
103
+ for (let index = 0; index < length; index++) {
104
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
105
+ if (!descriptor || !("value" in descriptor))
106
+ throw "invalid-json";
107
+ if (index > 0)
108
+ charge(",");
109
+ items.push(visit2(descriptor.value, depth + 1));
110
+ }
111
+ result = Object.freeze(items);
112
+ } else {
113
+ const members = /* @__PURE__ */ Object.create(null);
114
+ let count2 = 0;
115
+ if (keys.some((key) => typeof key !== "string"))
116
+ throw "invalid-json";
117
+ for (const key of keys.sort()) {
118
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
119
+ if (!descriptor)
120
+ throw "unreadable";
121
+ if (!descriptor.enumerable)
122
+ continue;
123
+ if (typeof key !== "string" || !("value" in descriptor))
124
+ throw "invalid-json";
125
+ if (key.length > FAILURE_MAX_BYTES)
126
+ throw "too-large";
127
+ charge((count2++ > 0 ? "," : "") + JSON.stringify(key) + ":");
128
+ members[key] = visit2(descriptor.value, depth + 1);
129
+ }
130
+ result = Object.freeze(members);
131
+ }
132
+ ancestors.delete(value);
133
+ return result;
134
+ }
135
+ try {
136
+ const value = visit2(input, 0);
137
+ return { status: "valid", value, canonical: JSON.stringify(value) };
138
+ } catch (error) {
139
+ return {
140
+ status: "invalid",
141
+ reason: error === "invalid-json" || error === "too-large" || error === "too-deep" ? error : "unreadable"
142
+ };
143
+ }
144
+ }
145
+
146
+ // packages/failures/dist/failure.js
147
+ var failureRefSchema = z.strictObject({
148
+ authority: z.string().min(1).max(512),
149
+ id: z.string().min(1).max(512)
150
+ });
151
+ var FAILURE_RELATIONS = [
152
+ "caused-by",
153
+ "retry-of",
154
+ "recovery-of",
155
+ "cleanup-of"
156
+ ];
157
+ function failureSchema(cause) {
158
+ const name = z.string().min(1).max(512);
159
+ return z.strictObject({
160
+ ref: failureRefSchema,
161
+ sourceRef: failureRefSchema,
162
+ domain: name,
163
+ code: name,
164
+ context: z.strictObject({
165
+ component: name,
166
+ operation: name,
167
+ operationRef: failureRefSchema.optional(),
168
+ attemptRef: failureRefSchema.optional(),
169
+ phase: name.optional(),
170
+ requestRef: failureRefSchema.optional(),
171
+ traceId: name.optional(),
172
+ spanId: name.optional()
173
+ }),
174
+ cause,
175
+ relations: z.array(z.strictObject({
176
+ kind: z.enum(FAILURE_RELATIONS),
177
+ failureRef: failureRefSchema
178
+ })).optional(),
179
+ diagnosticRef: failureRefSchema.optional()
180
+ });
181
+ }
182
+ function readFailure(schema, input) {
183
+ const before = snapshotJson(input);
184
+ if (before.status === "invalid")
185
+ return before;
186
+ try {
187
+ const parsed = schema.safeParse(before.value);
188
+ if (!parsed.success)
189
+ return { status: "invalid", reason: "schema-rejected" };
190
+ const after = snapshotJson(parsed.data);
191
+ if (after.status === "invalid")
192
+ return after;
193
+ if (before.canonical !== after.canonical)
194
+ return { status: "invalid", reason: "schema-changed" };
195
+ return {
196
+ status: "valid",
197
+ failure: after.value
198
+ };
199
+ } catch (error) {
200
+ void error;
201
+ return { status: "invalid", reason: "schema-threw" };
202
+ }
203
+ }
204
+ var jsonFailureSchema = failureSchema(z.custom());
205
+
206
+ // packages/failures/dist/sequence.js
207
+ import { z as z2 } from "zod";
208
+ var coverageSchema = z2.strictObject({
209
+ scope: failureRefSchema,
210
+ status: z2.enum(["complete", "partial", "unknown"]),
211
+ knownOmittedCount: z2.number().int().nonnegative().optional()
212
+ }).refine((value) => value.status !== "complete" || !value.knownOmittedCount);
213
+
214
+ // packages/herd-transcript/dist/run-failure.js
215
+ var RUN_FAILURE_DIAGNOSTIC_TYPE = "herd.run.failure";
216
+ var runFailureCauseSchema = z3.strictObject({
217
+ reason: z3.enum(RUN_FAILURE_REASONS),
218
+ source: z3.enum(["assistant_message", "exception", "runtime"]),
219
+ authDisposition: z3.enum(["unauthorized", "forbidden"]).optional(),
220
+ provider: z3.string().optional(),
221
+ api: z3.string().optional(),
222
+ model: z3.string().optional(),
223
+ httpStatus: z3.number().int().optional(),
224
+ providerCode: z3.string().optional(),
225
+ exitCode: z3.number().int().nullable().optional(),
226
+ signal: z3.string().nullable().optional(),
227
+ observation: z3.enum(["process_exit", "next_launch"]).optional(),
228
+ retryAfterMs: z3.number().finite().nonnegative().optional(),
229
+ retryable: z3.boolean().optional(),
230
+ accountId: z3.string().optional(),
231
+ authSource: z3.enum(["oauth", "api-key"]).optional(),
232
+ credentialRef: z3.string().optional()
233
+ });
234
+ var runFailureSchema = failureSchema(runFailureCauseSchema).extend({
235
+ domain: z3.enum(["model", "runtime"])
236
+ });
237
+ var runFailureRecordSchema = z3.strictObject({
238
+ failure: runFailureSchema.refine((failure) => readFailure(runFailureSchema, failure).status === "valid", "invalid or oversized model failure occurrence"),
239
+ errorText: z3.string()
240
+ });
241
+ function readRunFailureOccurrence(message) {
242
+ const diagnostics = message.diagnostics ?? [];
243
+ for (let i = diagnostics.length - 1; i >= 0; i--) {
244
+ const diagnostic = diagnostics[i];
245
+ if (diagnostic?.type !== RUN_FAILURE_DIAGNOSTIC_TYPE)
246
+ continue;
247
+ const details = diagnostic.details;
248
+ if (typeof details !== "object" || details === null)
249
+ return void 0;
250
+ const read = readFailure(runFailureSchema, details.failure);
251
+ return read.status === "valid" ? read.failure : void 0;
252
+ }
253
+ return void 0;
254
+ }
255
+ var runRecoveryOutcomeSchema = z3.strictObject({
256
+ failureRef: failureRefSchema,
257
+ action: z3.enum(["compact", "retry", "switch_model", "switch_account"]),
258
+ outcome: z3.enum(["succeeded", "failed", "aborted"]),
259
+ resultFailureRef: failureRefSchema.optional()
260
+ });
261
+
262
+ // packages/herd-transcript/dist/events/projections.js
263
+ import { z as z4 } from "zod";
264
+ var ManagedQueuePresentationAnchor = z4.strictObject({
265
+ sentAt: z4.number().finite(),
266
+ turnId: z4.string().min(1).optional(),
267
+ itemId: z4.string().min(1),
268
+ contentOffset: z4.number().int().nonnegative().optional()
269
+ });
270
+ var ManagedQueueAttachmentRef = z4.strictObject({
271
+ uri: z4.string().min(1),
272
+ name: z4.string().min(1),
273
+ mimeType: z4.string().min(1)
274
+ });
275
+ var ManagedQueueContextPart = z4.discriminatedUnion("kind", [
276
+ z4.strictObject({
277
+ kind: z4.literal("tab_context"),
278
+ body: z4.string(),
279
+ surface: z4.string()
280
+ }),
281
+ z4.strictObject({
282
+ kind: z4.literal("ui_action"),
283
+ action: z4.string(),
284
+ toolCallId: z4.string(),
285
+ payload: z4.string()
286
+ }),
287
+ z4.strictObject({
288
+ kind: z4.literal("composer_references"),
289
+ mentions: z4.array(z4.strictObject({
290
+ ref: z4.string(),
291
+ serviceId: z4.string(),
292
+ entityType: z4.string()
293
+ })),
294
+ invocations: z4.array(z4.strictObject({ id: z4.string(), serviceId: z4.string() }))
295
+ }),
296
+ z4.strictObject({
297
+ kind: z4.literal("user_pasted_content"),
298
+ items: z4.array(z4.union([
299
+ z4.strictObject({
300
+ id: z4.string(),
301
+ lineCount: z4.number().int().positive(),
302
+ text: z4.string(),
303
+ /** These exact bytes also appear in the message text, verbatim. */
304
+ inline: z4.literal(true).optional(),
305
+ attachment: z4.never().optional()
306
+ }),
307
+ z4.strictObject({
308
+ id: z4.string(),
309
+ lineCount: z4.number().int().positive(),
310
+ text: z4.never().optional(),
311
+ inline: z4.never().optional(),
312
+ attachment: z4.strictObject({
313
+ name: z4.string(),
314
+ uri: z4.string().optional()
315
+ })
316
+ })
317
+ ]))
318
+ })
319
+ ]);
320
+ var ContextAttribution = z4.object({
321
+ source: z4.string().min(1),
322
+ path: z4.string().optional(),
323
+ scope: z4.string().optional(),
324
+ origin: z4.string().optional(),
325
+ baseDir: z4.string().optional(),
326
+ id: z4.string().optional(),
327
+ sourceId: z4.string().optional(),
328
+ label: z4.string().optional()
329
+ }).strict();
330
+ var ContextWindowBucketCategory = z4.enum([
331
+ "system_prompt:base",
332
+ "system_prompt:append",
333
+ "system_prompt:tool_section",
334
+ "system_prompt:connectable_tools",
335
+ "system_prompt:guidelines",
336
+ "system_prompt:addressable_resources",
337
+ "system_prompt:plugins",
338
+ "system_prompt:documentation",
339
+ "system_prompt:context_file",
340
+ "system_prompt:skills",
341
+ "system_prompt:connected_accounts",
342
+ "system_prompt:metadata",
343
+ "system_prompt:layout",
344
+ "system_prompt:headless_operation",
345
+ "system_prompt:agent_configuration",
346
+ "tool_definitions",
347
+ "user_message",
348
+ "assistant_message",
349
+ "tool_result",
350
+ "context_message",
351
+ "context_message:dynamic_context",
352
+ "context_message:subagent_result",
353
+ "compaction_summary"
354
+ ]);
355
+ var HerdContextWindowSnapshot = z4.strictObject({
356
+ revision: z4.number().int().positive(),
357
+ /**
358
+ * The ACTUAL context usage (provider-anchored; see `ContextUsage` in ../context-window.ts).
359
+ * The buckets/estimatedTotalTokens below are estimated-composition metadata
360
+ * and must never drive a headline percentage or system decision.
361
+ */
362
+ usage: z4.strictObject({
363
+ tokens: z4.number().int().nonnegative(),
364
+ basis: z4.enum(["provider", "estimate"]),
365
+ anchorTokens: z4.number().int().nonnegative(),
366
+ tailTokens: z4.number().int().nonnegative()
367
+ }),
368
+ buckets: z4.array(z4.strictObject({
369
+ label: z4.string(),
370
+ category: ContextWindowBucketCategory,
371
+ estimatedTokens: z4.number().int().nonnegative(),
372
+ attributions: z4.array(ContextAttribution),
373
+ resourceIdentity: z4.strictObject({
374
+ id: z4.string().min(1),
375
+ version: z4.string().min(1),
376
+ variantId: z4.string().min(1).optional()
377
+ }).optional()
378
+ })),
379
+ estimatedTotalTokens: z4.number().int().nonnegative(),
380
+ model: z4.strictObject({
381
+ provider: z4.string().min(1),
382
+ id: z4.string().min(1),
383
+ contextWindow: z4.number().int().positive().optional()
384
+ })
385
+ });
386
+ var HERD_MESSAGE_DELTA_CONTENT_INDEX_MAX = 1024;
387
+ var boundedDeltaPlacement = z4.json().refine((delta) => {
388
+ if (typeof delta !== "object" || delta === null || Array.isArray(delta)) {
389
+ return true;
390
+ }
391
+ const contentIndex = delta["contentIndex"];
392
+ return contentIndex === void 0 || typeof contentIndex === "number" && Number.isInteger(contentIndex) && contentIndex >= 0 && contentIndex <= HERD_MESSAGE_DELTA_CONTENT_INDEX_MAX;
393
+ }, { message: "delta contentIndex out of bounds" });
394
+ var HerdSessionProjection = z4.discriminatedUnion("type", [
395
+ z4.strictObject({
396
+ type: z4.literal("herd.message.delta"),
397
+ runId: z4.string().min(1).optional(),
398
+ messageId: z4.string().min(1).optional(),
399
+ timestamp: z4.iso.datetime(),
400
+ delta: boundedDeltaPlacement
401
+ }),
402
+ z4.strictObject({
403
+ type: z4.literal("herd.custom.entry.appended"),
404
+ customType: z4.string().min(1),
405
+ data: z4.json()
406
+ }),
407
+ z4.strictObject({
408
+ type: z4.literal("herd.context.window.updated"),
409
+ snapshot: HerdContextWindowSnapshot,
410
+ /**
411
+ * Why this snapshot was taken. `provider_request` — emitted synchronously
412
+ * from the model-boundary context hook (every LLM request boundary);
413
+ * `refresh` — emitted on all other paths (post-compaction rebuild, model
414
+ * change, post-run settlement). Absent on legacy stored projections.
415
+ */
416
+ cause: z4.enum(["provider_request", "refresh"]).optional(),
417
+ /**
418
+ * Counters from the model-boundary supersede pass, present only on a `provider_request`
419
+ * projection whose pass actually elided something. Absent means the pass was a no-op for
420
+ * that request, never "unknown". `reclaimedTokens` is CARRIED (re-counted on every later
421
+ * request the elision keeps content off the wire), and `firstRequestAfterBoundary` is the cold/warm
422
+ * discriminator any pricing MUST split on — see `ContextElisionStats` in herd's
423
+ * context-projection module for the full read rules.
424
+ */
425
+ elision: z4.strictObject({
426
+ supersededResults: z4.number().int().positive(),
427
+ reclaimedTokens: z4.number().int().nonnegative(),
428
+ firstRequestAfterBoundary: z4.boolean(),
429
+ coldBoundaryMs: z4.number().int().nonnegative()
430
+ }).optional(),
431
+ /** Identified subagent task ids included in this request; `[]` means none, absent means legacy. */
432
+ requestIncludedSubagentTaskIds: z4.array(z4.string().min(1).max(1024)).max(4096).optional()
433
+ }),
434
+ z4.strictObject({
435
+ type: z4.literal("herd.managed.human.queue.updated"),
436
+ snapshot: z4.strictObject({
437
+ revision: z4.number().int().nonnegative(),
438
+ items: z4.array(z4.strictObject({
439
+ id: z4.string().min(1),
440
+ clientIntentId: z4.string().min(1).optional(),
441
+ presentationAnchor: ManagedQueuePresentationAnchor.optional(),
442
+ attachments: z4.array(ManagedQueueAttachmentRef).optional(),
443
+ context: z4.array(ManagedQueueContextPart).optional(),
444
+ resendError: z4.string().optional(),
445
+ text: z4.string(),
446
+ channel: z4.enum(["follow_up", "steer"]),
447
+ status: z4.enum(["queued", "editing"])
448
+ }))
449
+ })
450
+ })
451
+ ]);
452
+ var HerdSessionDiagnostic = z4.strictObject({
453
+ type: z4.literal("herd.kernel.event.redacted"),
454
+ originalType: z4.string().min(1)
455
+ });
456
+
457
+ // packages/herd-transcript/dist/final-output.js
458
+ var RESERVED_FINAL_OUTPUT_TOOL_NAME = "submit_final";
459
+ function finalOutputCaptureFromDetails(toolCallId, details) {
460
+ if (details === null || typeof details !== "object")
461
+ return void 0;
462
+ const value = details;
463
+ return value.kind === "final_output" && "result" in value ? {
464
+ toolCallId,
465
+ ...typeof value.terminatesRun === "boolean" ? { terminatesRun: value.terminatesRun } : {},
466
+ // Legacy transcripts carry the duplicated reply prose; new entries do
467
+ // not. Read it only when it is actually a string — durable data.
468
+ ...typeof value.message === "string" ? { message: value.message } : {},
469
+ result: value.result,
470
+ // Re-checked on the way out of durable storage, not trusted from it: a
471
+ // replayed log entry is data, and a non-string here would otherwise
472
+ // reach the rename path untyped.
473
+ ...typeof value.sessionTitle === "string" ? { sessionTitle: value.sessionTitle } : {}
474
+ } : void 0;
475
+ }
476
+ var FINAL_OUTPUT_REPAIR_CUSTOM_TYPE = "herd.final_output_repair";
477
+
478
+ // packages/herd-transcript/dist/interactive/embedded-agent-continuation.js
479
+ var DETACHED_WORK_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
480
+ function isSettledDetachedWork(details) {
481
+ const status = details["status"];
482
+ return typeof status === "string" && DETACHED_WORK_STATUSES.has(status);
483
+ }
484
+ function isSubagentResultDetails(details) {
485
+ const record = asRecord(details);
486
+ if (record === void 0 || !isSettledDetachedWork(record))
487
+ return false;
488
+ const provenance = asRecord(record["provenance"]);
489
+ const attribution = asRecord(record["attribution"]);
490
+ return provenance?.["source"] === "subagent" && isNonEmptyString(provenance["sourceId"]) || attribution?.["kind"] === "subagent" && isNonEmptyString(attribution["childSessionId"]);
491
+ }
492
+ function isBackgroundTaskResultDetails(details) {
493
+ const record = asRecord(details);
494
+ if (record === void 0 || !isSettledDetachedWork(record))
495
+ return false;
496
+ const provenance = asRecord(record["provenance"]);
497
+ return provenance?.["source"] === "background_task" && isNonEmptyString(provenance["sourceId"]) && (record["taskKind"] === "bash" || record["taskKind"] === "agent") && typeof record["truncated"] === "boolean";
498
+ }
499
+ function isDaemonWakeDetails(details) {
500
+ const record = asRecord(details);
501
+ const provenance = asRecord(record?.["provenance"]);
502
+ if (provenance?.["source"] !== "daemon")
503
+ return false;
504
+ const service = record?.["service"];
505
+ return service === "wake" && provenance["sourceId"] === "wake" || service === "subagent_wake" && provenance["sourceId"] === "subagent_wake";
506
+ }
507
+ function isEmbeddedAgentResultMessage(item) {
508
+ if (item.role !== "custom" || item.status !== "complete")
509
+ return false;
510
+ if (item.customType === SUBAGENT_RESULT_CUSTOM_TYPE)
511
+ return isSubagentResultDetails(item.details);
512
+ if (item.customType === BACKGROUND_TASK_RESULT_CUSTOM_TYPE)
513
+ return isBackgroundTaskResultDetails(item.details);
514
+ return false;
515
+ }
516
+ function isRequiredFinalOutputRepairMessage(item) {
517
+ return item.role === "custom" && item.status === "complete" && item.customType === FINAL_OUTPUT_REPAIR_CUSTOM_TYPE;
518
+ }
519
+ function isDaemonWakeMessage(item) {
520
+ return item.role === "custom" && item.status === "complete" && item.customType === DAEMON_SERVICE_TURN_CUSTOM_TYPE && isDaemonWakeDetails(item.details);
521
+ }
522
+ function asRecord(value) {
523
+ return value !== null && typeof value === "object" ? value : void 0;
524
+ }
525
+ function isNonEmptyString(value) {
526
+ return typeof value === "string" && value.length > 0;
527
+ }
528
+
529
+ // packages/herd-transcript/dist/message-roles.js
530
+ var TOOL_RESULT_ROLE = "toolResult";
531
+ var KERNEL_MESSAGE_ROLES = {
532
+ user: true,
533
+ assistant: true,
534
+ toolResult: true,
535
+ // pi-ai 0.86+: the system prompt travels as a transcript `system` message
536
+ // (TranscriptContext). It is a model-boundary carrier, not chat content.
537
+ system: true
538
+ };
539
+ function isKernelMessageRole(role) {
540
+ return Object.hasOwn(KERNEL_MESSAGE_ROLES, role);
541
+ }
542
+
543
+ // packages/herd-transcript/dist/run-failure-classifier.js
544
+ var MAX_FAILURE_TEXT_CHARS = 2e3;
545
+ function boundedFailureText(text) {
546
+ const normalized = text?.trim() || "Run failed.";
547
+ return normalized.length > MAX_FAILURE_TEXT_CHARS ? `${normalized.slice(0, MAX_FAILURE_TEXT_CHARS)}\u2026` : normalized;
548
+ }
549
+ var HTML_DOCUMENT_PREFIX = /^(?:<!doctype\s+html|<html[\s>]|<head[\s>]|<body[\s>])/;
550
+ var MAX_HTML_EXTRACT_CHARS = 16e3;
551
+ var OPAQUE_HTML_FAILURE_TEXT = "The model provider returned an HTML error page with no readable message.";
552
+ function looksLikeHtml(text) {
553
+ return HTML_DOCUMENT_PREFIX.test(text.trimStart().slice(0, 128).toLowerCase());
554
+ }
555
+ function readableFailureText(text) {
556
+ const normalized = text?.trim() || "Run failed.";
557
+ if (!looksLikeHtml(normalized))
558
+ return boundedFailureText(normalized);
559
+ const extracted = htmlToReadableText(normalized);
560
+ return boundedFailureText(extracted === "" ? OPAQUE_HTML_FAILURE_TEXT : extracted);
561
+ }
562
+ function htmlToReadableText(html) {
563
+ const capped = html.slice(0, MAX_HTML_EXTRACT_CHARS);
564
+ const title = plainText(/<title\b[^>]*>([\s\S]*?)<\/title>/i.exec(capped)?.[1] ?? "");
565
+ const body = plainText(capped);
566
+ if (title === "" || body.includes(title))
567
+ return body === "" ? title : body;
568
+ return body === "" ? title : `${title} ${body}`;
569
+ }
570
+ function plainText(html) {
571
+ const withoutComments = html.includes("-->") ? html.replace(/<!--[\s\S]*?-->/g, " ") : html;
572
+ const text = withoutComments.replace(/<(script|style|template|svg|head)\b[^>]*>[\s\S]*?<\/\1>/gi, " ").replace(/<[^>]+>/g, " ").replace(/<[^>]*$/, " ");
573
+ return collapseWhitespace(decodeCommonHtmlEntities(text));
574
+ }
575
+ function decodeCommonHtmlEntities(text) {
576
+ return text.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#0?39;/g, "'").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&");
577
+ }
578
+ function collapseWhitespace(text) {
579
+ return text.replace(/\s+/g, " ").trim();
580
+ }
581
+
582
+ // packages/herd-transcript/dist/interactive/presentation-anchor.js
583
+ var PRESENTATION_ANCHOR_KEYS = /* @__PURE__ */ new Set([
584
+ "sentAt",
585
+ "turnId",
586
+ "itemId",
587
+ "contentOffset"
588
+ ]);
589
+ function parsePresentationAnchor(value) {
590
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
591
+ return void 0;
592
+ }
593
+ const record = value;
594
+ if (Object.keys(record).some((key) => !PRESENTATION_ANCHOR_KEYS.has(key))) {
595
+ return void 0;
596
+ }
597
+ const { sentAt, turnId, itemId, contentOffset } = record;
598
+ if (typeof sentAt !== "number" || !Number.isFinite(sentAt)) {
599
+ return void 0;
600
+ }
601
+ if (typeof itemId !== "string" || itemId.length === 0) {
602
+ return void 0;
603
+ }
604
+ if (turnId !== void 0 && (typeof turnId !== "string" || turnId.length === 0)) {
605
+ return void 0;
606
+ }
607
+ if (contentOffset !== void 0 && (typeof contentOffset !== "number" || !Number.isInteger(contentOffset) || contentOffset < 0)) {
608
+ return void 0;
609
+ }
610
+ return {
611
+ sentAt,
612
+ itemId,
613
+ ...Object.hasOwn(record, "turnId") ? { turnId } : {},
614
+ ...Object.hasOwn(record, "contentOffset") ? { contentOffset } : {}
615
+ };
616
+ }
617
+
618
+ // packages/herd-transcript/dist/tool-call-failure.js
619
+ import { z as z5 } from "zod";
620
+
621
+ // packages/herd-transcript/dist/is-object.js
622
+ function isObject(value) {
623
+ return typeof value === "object" && value !== null && !Array.isArray(value);
624
+ }
625
+
626
+ // packages/herd-transcript/dist/tool-call-failure.js
627
+ var TOOL_CALL_FAILURE_DETAILS_KEY = "toolCallFailure";
628
+ var TOOL_CALL_FAILURE_DOMAIN = "tool-call";
629
+ var TOOL_CALL_FAILURE_CATEGORIES = [
630
+ "invalid-input",
631
+ "not-connected",
632
+ "unsupported-operation",
633
+ "not-found",
634
+ "provider",
635
+ "permission",
636
+ "timeout",
637
+ "unavailable",
638
+ "cancelled",
639
+ "unknown"
640
+ ];
641
+ var TOOL_CALL_FAILURE_ACTIONS = [
642
+ "correct-input",
643
+ "connect",
644
+ "retry",
645
+ "none",
646
+ "unknown"
647
+ ];
648
+ var TOOL_CALL_FAILURE_CODES = [
649
+ "tool.invalid_input",
650
+ "tool.blocked",
651
+ "tool.cancelled",
652
+ "tool.timeout",
653
+ "tool.not_found",
654
+ "tool.unavailable",
655
+ "tool.execution_failed",
656
+ "provider.http",
657
+ "provider.api",
658
+ "provider.transport",
659
+ "uri.not_found",
660
+ "uri.unsupported_operation",
661
+ "uri.not_connected",
662
+ "uri.auth_unavailable",
663
+ "permission.denied",
664
+ "edit.empty_edits",
665
+ "edit.text_not_found",
666
+ "edit.text_not_unique",
667
+ "edit.empty_old_text",
668
+ "edit.overlapping_edits",
669
+ "edit.no_change"
670
+ ];
671
+ var count = z5.number().int().nonnegative();
672
+ var toolCallFailureDetailsSchema = z5.strictObject({
673
+ moduleId: z5.string().optional(),
674
+ /**
675
+ * [#5042] The registration that owns the FAILING TOOL, host-stamped from the
676
+ * session's own tool source index — `herd.core` for a kernel tool,
677
+ * `kay.task-introspection` for a daemon app-extension's, a plugin's id for a
678
+ * plugin's, and the bare layer sentinel (`builtin`, `host`, `extension`) when
679
+ * a registration named no owner.
680
+ *
681
+ * Distinct from {@link moduleId}, which names a URI MODULE and is stamped
682
+ * only by a URI verb dispatch (#4954). Every failure has an owning tool; only
683
+ * a URI dispatch has a module. Read together they answer "who failed" for
684
+ * every tool call rather than only the URI ones — the fall-through #4954 left
685
+ * open, where a `task`-kind tool throwing a plain `Error` reached the
686
+ * classifier's terminal branch with nothing to attribute it to.
687
+ *
688
+ * Never self-reported: like the dispatch identity, this comes from the host's
689
+ * registry, not from the error, so a plugin cannot claim one of ours.
690
+ */
691
+ toolOwnerId: z5.string().optional(),
692
+ operation: z5.string().optional(),
693
+ uri: z5.string().optional(),
694
+ path: z5.string().optional(),
695
+ validationField: z5.string().optional(),
696
+ errorName: z5.string().optional(),
697
+ errorCode: z5.string().optional(),
698
+ providerCode: z5.string().optional(),
699
+ status: z5.number().int().min(100).max(599).optional(),
700
+ editIndex: count.optional(),
701
+ occurrences: count.optional(),
702
+ /** Provider-directed delay before retrying, in milliseconds. */
703
+ retryAfterMs: count.optional()
704
+ });
705
+ var toolCallFailureCauseSchema = z5.strictObject({
706
+ category: z5.enum(TOOL_CALL_FAILURE_CATEGORIES),
707
+ retryable: z5.boolean(),
708
+ action: z5.enum(TOOL_CALL_FAILURE_ACTIONS),
709
+ details: toolCallFailureDetailsSchema.optional()
710
+ });
711
+ var toolCallFailureOccurrenceSchema = failureSchema(toolCallFailureCauseSchema).extend({
712
+ domain: z5.literal(TOOL_CALL_FAILURE_DOMAIN),
713
+ code: z5.enum(TOOL_CALL_FAILURE_CODES)
714
+ });
715
+ var toolCallFailureSchema = toolCallFailureCauseSchema.extend({
716
+ code: toolCallFailureOccurrenceSchema.shape.code
717
+ });
718
+ function readToolCallFailure(details) {
719
+ if (!isObject(details))
720
+ return void 0;
721
+ const read = readFailure(toolCallFailureOccurrenceSchema, details[TOOL_CALL_FAILURE_DETAILS_KEY]);
722
+ return read.status === "valid" ? read.failure : void 0;
723
+ }
724
+
725
+ // packages/herd-transcript/dist/interactive/reducer.js
726
+ var UNKNOWN_ACTIVITY_CUSTOM_TYPE = "herd.unknown_activity";
727
+ var TOOL_ACTIVITY_KINDS = /* @__PURE__ */ new Set([
728
+ "inspect-workspace",
729
+ "run-command",
730
+ "edit-files",
731
+ "view-image",
732
+ "wait"
733
+ ]);
734
+ function createInteractiveModeState(options = {}) {
735
+ return {
736
+ items: normalizeToolIdentities(options.items ?? []),
737
+ ...stringField("sessionName", options.sessionName),
738
+ ...stringField("streamingAssistantId", options.streamingAssistantId),
739
+ pendingToolsByCallId: options.pendingToolsByCallId ?? {},
740
+ queue: options.queue ?? [],
741
+ ...options.queueRevision !== void 0 ? { queueRevision: options.queueRevision } : {},
742
+ run: options.run ?? { status: "idle" },
743
+ ...options.terminalFailure === void 0 ? {} : { terminalFailure: options.terminalFailure },
744
+ ...options.completedRunBoundaryAnchors === void 0 ? {} : { completedRunBoundaryAnchors: options.completedRunBoundaryAnchors },
745
+ backgroundTasksById: options.backgroundTasksById ?? {},
746
+ nextItemIndex: options.nextItemIndex ?? 1,
747
+ customEntries: options.customEntries ?? {},
748
+ ...options.activity !== void 0 ? { activity: options.activity } : {}
749
+ };
750
+ }
751
+ function withActivity(state, activity) {
752
+ return { ...state, activity };
753
+ }
754
+ function clearActivity(state) {
755
+ if (state.activity === void 0)
756
+ return state;
757
+ const { activity: _omitted, ...rest } = state;
758
+ void _omitted;
759
+ return rest;
760
+ }
761
+ function recordCompletedRunBoundary(state) {
762
+ const item = state.items.at(-1);
763
+ if (item === void 0)
764
+ return state;
765
+ const anchor = { type: item.type, id: item.id };
766
+ const prior = state.completedRunBoundaryAnchors ?? [];
767
+ const previous = prior.at(-1);
768
+ if (previous?.type === anchor.type && previous.id === anchor.id)
769
+ return state;
770
+ return {
771
+ ...state,
772
+ completedRunBoundaryAnchors: [...prior, anchor]
773
+ };
774
+ }
775
+ var COMPACTION_MARKER_CUSTOM_TYPE = "compaction";
776
+ function reduceSessionCompact(state, event, replay) {
777
+ const cleared = state.activity?.kind === "compaction" ? clearActivity(state) : state;
778
+ const entry = asRecord2(asRecord2(event)?.["compactionEntry"]);
779
+ const at = getString(entry, "timestamp") ?? getTimestamp(event);
780
+ const id = getString(entry, "id") ?? allocateItemId(cleared, "compaction-marker");
781
+ const summary = getString(entry, "summary");
782
+ const details = {
783
+ ...at === void 0 ? {} : { at },
784
+ ...summary === void 0 || summary.length === 0 ? {} : { summary }
785
+ };
786
+ const item = {
787
+ id,
788
+ type: "message",
789
+ role: "custom",
790
+ customType: COMPACTION_MARKER_CUSTOM_TYPE,
791
+ status: "complete",
792
+ text: "",
793
+ parts: [],
794
+ details,
795
+ ...at !== void 0 ? { startedAt: at, completedAt: at } : {}
796
+ };
797
+ return upsertMessageItem(cleared, item, replay);
798
+ }
799
+ function normalizeToolIdentities(items) {
800
+ let changed = false;
801
+ let activeWaveId;
802
+ const generationsByCorrelationId = /* @__PURE__ */ new Map();
803
+ const normalized = items.map((item) => {
804
+ if (item.type !== "tool") {
805
+ activeWaveId = void 0;
806
+ return item;
807
+ }
808
+ const recordedGeneration = Number.isInteger(item.attemptGeneration) && item.attemptGeneration > 0 ? item.attemptGeneration : void 0;
809
+ const generation = recordedGeneration ?? (generationsByCorrelationId.get(item.toolCallId) ?? 0) + 1;
810
+ generationsByCorrelationId.set(item.toolCallId, Math.max(generationsByCorrelationId.get(item.toolCallId) ?? 0, generation));
811
+ const attemptId = item.attemptId ?? `tool-attempt:${encodeURIComponent(item.id)}`;
812
+ const waveId = item.waveId ?? activeWaveId ?? canonicalWaveId(item.responseId ?? item.sourceMessageId ?? `legacy:${item.id}`);
813
+ activeWaveId = waveId;
814
+ if (item.attemptId === attemptId && item.waveId === waveId && item.attemptGeneration === generation) {
815
+ return item;
816
+ }
817
+ changed = true;
818
+ return { ...item, attemptId, waveId, attemptGeneration: generation };
819
+ });
820
+ return changed ? normalized : items;
821
+ }
822
+ function reduceInteractiveModeEventsForReplay(events) {
823
+ let state = createInteractiveModeState();
824
+ const replay = createReplayIndex(state);
825
+ for (const event of events) {
826
+ state = event.type === "host_run_status" ? reduceHostRun(state, event.run, replay) : reduceInteractiveModeEventInternal(state, event, replay);
827
+ }
828
+ return state;
829
+ }
830
+ function reduceHostRun(state, next, replay) {
831
+ switch (next.status) {
832
+ case "idle":
833
+ return clearTransientState(state, { status: "idle" }, { status: "interrupted" }, replay);
834
+ case "running": {
835
+ const previous = state.run;
836
+ if (previous.status === "running" && previous.resuming !== true && previous.runId === next.runId) {
837
+ if (previous.retry === void 0)
838
+ return state;
839
+ const { retry: _retry, ...run } = previous;
840
+ void _retry;
841
+ return { ...state, run };
842
+ }
843
+ return withoutTerminalFailure({
844
+ ...state,
845
+ run: { status: "running", ...stringField("runId", next.runId) }
846
+ });
847
+ }
848
+ case "retry_waiting":
849
+ return {
850
+ ...state,
851
+ run: {
852
+ ...state.run,
853
+ status: "running",
854
+ ...stringField("runId", next.runId),
855
+ retry: {
856
+ ...stringField("waitId", next.retry.waitId),
857
+ attempt: next.retry.attempt,
858
+ maxAttempts: next.retry.maxAttempts,
859
+ ...next.retry.reason === void 0 ? {} : { reason: next.retry.reason }
860
+ }
861
+ }
862
+ };
863
+ case "resuming":
864
+ return clearTransientState(state, {
865
+ status: "running",
866
+ ...stringField("runId", next.runId),
867
+ resuming: true
868
+ }, { status: "interrupted" }, replay);
869
+ case "settled":
870
+ return reduceSettledRun(state, next, replay);
871
+ }
872
+ }
873
+ function reduceSettledRun(state, next, replay) {
874
+ switch (next.outcome) {
875
+ case "completed":
876
+ return withoutTerminalFailure(recordCompletedRunBoundary(clearTransientState(state, { status: "settled" }, { status: "interrupted" }, replay)));
877
+ case "interrupted":
878
+ case "cancelled":
879
+ return withoutTerminalFailure(clearTransientState(markAbortedAssistant(state, replay), { status: "aborted" }, { status: "interrupted" }, replay));
880
+ case "failed": {
881
+ const errorText = next.failure?.errorText;
882
+ const selected = runFailureRecordSchema.safeParse({
883
+ failure: next.failure?.failure,
884
+ errorText
885
+ });
886
+ const rest = withoutTerminalFailure(state);
887
+ return clearTransientState(selected.success ? { ...rest, terminalFailure: selected.data } : rest, { status: "error", ...stringField("errorText", errorText) }, { status: "error", ...stringField("errorText", errorText) }, replay);
888
+ }
889
+ }
890
+ }
891
+ function withoutTerminalFailure(state) {
892
+ if (state.terminalFailure === void 0)
893
+ return state;
894
+ const { terminalFailure: _terminalFailure, ...rest } = state;
895
+ void _terminalFailure;
896
+ return rest;
897
+ }
898
+ function reduceInteractiveModeEventInternal(state, event, replay) {
899
+ switch (event.type) {
900
+ case "session_info_updated":
901
+ return withSessionName(state, getString(event, "name"));
902
+ case "agent_start": {
903
+ const { terminalFailure: _terminalFailure, ...active } = state;
904
+ const base = resetReplayIndex(replay, {
905
+ ...withoutStreamingAssistant(terminalizeOpenItems(active, { status: "interrupted" }, replay)),
906
+ pendingToolsByCallId: {},
907
+ run: { status: "running" }
908
+ });
909
+ return base.activity?.phase === "failed" ? clearActivity(base) : base;
910
+ }
911
+ case "turn_start":
912
+ return {
913
+ ...state,
914
+ run: { status: "running" }
915
+ };
916
+ case "queue_update":
917
+ return state.queueRevision === void 0 ? { ...state, queue: extractQueuedMessages(event) } : state;
918
+ case "managed_human_queue_update":
919
+ return reduceManagedHumanQueueUpdate(state, event);
920
+ case "message_start":
921
+ case "message_update":
922
+ case "message_end": {
923
+ switch (messageRoleDisposition(getRawMessageRole(event))) {
924
+ case "fold_tool_result":
925
+ return reduceToolResultMessage(state, event, replay);
926
+ case "drop":
927
+ return state;
928
+ case "project_unknown": {
929
+ const normalized = normalizeUnknownMessageEvent(event);
930
+ return event.type === "message_start" ? reduceMessageStart(state, normalized, replay) : event.type === "message_update" ? reduceMessageUpdate(state, normalized, replay) : reduceMessageEnd(state, normalized, replay);
931
+ }
932
+ case "project":
933
+ return event.type === "message_start" ? reduceMessageStart(state, event, replay) : event.type === "message_update" ? reduceMessageUpdate(state, event, replay) : reduceMessageEnd(state, event, replay);
934
+ }
935
+ }
936
+ case "tool_execution_start":
937
+ return reduceToolExecution(state, event, "running", replay);
938
+ case "tool_execution_update":
939
+ return reduceToolExecution(state, event, "running", replay);
940
+ case "tool_execution_end":
941
+ return reduceToolCompletion(state, normalizeToolExecutionCompletion(event), replay);
942
+ case "background_task_started":
943
+ return reduceBackgroundTask(state, event, "running", replay);
944
+ case "background_task_progress":
945
+ return reduceBackgroundTask(state, event, "running", replay);
946
+ case "background_task_completed":
947
+ return reduceBackgroundTask(state, event, "complete", replay);
948
+ case "background_task_failed":
949
+ return reduceBackgroundTask(state, event, "failed", replay);
950
+ case "background_task_cancelled":
951
+ return reduceBackgroundTask(state, event, "cancelled", replay);
952
+ case "abort":
953
+ return clearTransientState(markAbortedAssistant(state, replay), { status: "aborted" }, { status: "interrupted" }, replay);
954
+ case "settled":
955
+ return recordCompletedRunBoundary(clearTransientState(state, { status: "settled" }, { status: "interrupted" }, replay));
956
+ case "turn_end":
957
+ return clearTransientState(state, state.run, { status: "interrupted" }, replay);
958
+ case "agent_end":
959
+ return clearTransientState(state, { status: "idle" }, { status: "interrupted" }, replay);
960
+ case "compaction_triggered":
961
+ return withActivity(state, { kind: "compaction", phase: "running" });
962
+ case "session_compact":
963
+ return reduceSessionCompact(state, event, replay);
964
+ case "compaction_failed":
965
+ return withActivity(state, { kind: "compaction", phase: "failed" });
966
+ case "custom_entry":
967
+ return reduceCustomEntry(state, event);
968
+ case "run_failed": {
969
+ if (!drivesTheReducedRun(event))
970
+ return state;
971
+ const selected = runFailureRecordSchema.safeParse({
972
+ failure: asRecord2(event)?.["failure"],
973
+ errorText: getString(event, "errorText")
974
+ });
975
+ const { terminalFailure: _oldFailure, ...rest } = state;
976
+ return clearTransientState({
977
+ ...rest,
978
+ ...selected.success ? { terminalFailure: selected.data } : {}
979
+ }, {
980
+ status: "error",
981
+ ...stringField("errorText", getString(event, "errorText"))
982
+ }, {
983
+ status: "error",
984
+ ...stringField("errorText", getString(event, "errorText"))
985
+ }, replay);
986
+ }
987
+ case "run_retrying": {
988
+ if (!drivesTheReducedRun(event))
989
+ return state;
990
+ const retryReason = getString(event, "reason");
991
+ return clearTransientState(state, {
992
+ status: "running",
993
+ retry: {
994
+ attempt: getNumber(event, "attempt") ?? 0,
995
+ maxAttempts: getNumber(event, "maxAttempts") ?? 0,
996
+ ...retryReason !== void 0 ? { reason: retryReason } : {}
997
+ }
998
+ }, {
999
+ status: "error",
1000
+ ...stringField("errorText", getString(event, "errorText"))
1001
+ }, replay);
1002
+ }
1003
+ case "run_recovered": {
1004
+ if (!drivesTheReducedRun(event))
1005
+ return state;
1006
+ const { retry: _retry, ...run } = state.run;
1007
+ void _retry;
1008
+ return { ...state, run };
1009
+ }
1010
+ default:
1011
+ return state;
1012
+ }
1013
+ }
1014
+ function reduceMessageStart(state, event, replay) {
1015
+ const role = getMessageRole(event);
1016
+ const itemId = getMessageId(event) ?? allocateItemId(state, "message");
1017
+ const extractedParts = extractContentParts(event);
1018
+ const parts = role === "assistant" ? sanitizeAssistantContentParts(extractedParts) : extractedParts;
1019
+ const text = parts.length > 0 ? textFromContentParts(parts) : role === "assistant" ? sanitizeAssistantText(extractText(event)) : extractText(event);
1020
+ const display = role === "custom" ? getMessageDisplay(event) : void 0;
1021
+ const item = {
1022
+ id: itemId,
1023
+ ...stringField("entryId", getEntryId(event)),
1024
+ type: "message",
1025
+ role,
1026
+ ...role === "custom" ? stringField("customType", getCustomType(event)) : {},
1027
+ ...role === "custom" && getMessageDetails(event) !== void 0 ? { details: getMessageDetails(event) } : {},
1028
+ ...display === void 0 ? {} : { display },
1029
+ ...role === "user" ? stringField("deliveredVia", getDeliveredVia(event)) : {},
1030
+ ...role === "user" ? presentationAnchorField(getPresentationAnchor(event)) : {},
1031
+ status: role === "assistant" ? "streaming" : "complete",
1032
+ text,
1033
+ parts,
1034
+ ...stringField("startedAt", getTimestamp(event)),
1035
+ ...role === "assistant" && text.trim().length > 0 ? stringField("firstTextAt", getTimestamp(event)) : {},
1036
+ // A message that starts already-terminal (user/custom, or a replayed
1037
+ // entry) has no later end event to stamp its completion.
1038
+ ...role === "assistant" ? {} : stringField("completedAt", getTimestamp(event)),
1039
+ ...messageMetadata(event, role === "assistant" ? "provisional" : void 0)
1040
+ };
1041
+ const nextState = upsertMessageItem(state, item, replay);
1042
+ const withTools = upsertToolCalls(nextState, extractToolCalls(event), "declared", messageAttemptContext(item), replay);
1043
+ return {
1044
+ ...withTools,
1045
+ ...role === "assistant" ? { streamingAssistantId: itemId } : {}
1046
+ };
1047
+ }
1048
+ function reduceMessageUpdate(state, event, replay) {
1049
+ const messageId = getMessageId(event) ?? state.streamingAssistantId;
1050
+ const current = messageId !== void 0 ? findMessageItem(state, messageId, replay) : void 0;
1051
+ const updated = current === void 0 ? void 0 : mergeMessageUpdate(current, event);
1052
+ const baseState = updated !== void 0 ? replaceMessageItem(state, updated, replay) : reduceMessageStart(state, {
1053
+ ...event,
1054
+ role: "assistant"
1055
+ }, replay);
1056
+ const message = updated ?? (messageId !== void 0 ? findMessageItem(baseState, messageId, replay) : void 0);
1057
+ return upsertToolCalls(baseState, message === void 0 ? extractToolCalls(event) : extractToolCalls({ content: message.parts }), "declared", message === void 0 ? void 0 : messageAttemptContext(message), replay);
1058
+ }
1059
+ function mergeMessageUpdate(item, event) {
1060
+ const record = asRecord2(event);
1061
+ if (record?.["delta"] === void 0 || record["message"] !== void 0 || record["entry"] !== void 0 || record["text"] !== void 0 || record["content"] !== void 0 || record["partial"] !== void 0 || record["assistantMessageEvent"] !== void 0) {
1062
+ return mergeMessageContent(item, event, "streaming");
1063
+ }
1064
+ return mergeMessageDelta(item, event);
1065
+ }
1066
+ function reduceMessageEnd(state, event, replay) {
1067
+ const messageId = getMessageId(event) ?? state.streamingAssistantId;
1068
+ const current = messageId !== void 0 ? findMessageItem(state, messageId, replay) : void 0;
1069
+ const withMessage = current !== void 0 ? upsertMessageItem(state, mergeMessageContent(current, event, hasMessageError(event) ? "error" : "complete"), replay) : state;
1070
+ const withTools = upsertToolCalls(withMessage, extractToolCalls(event), "arguments_complete", current === void 0 ? void 0 : messageAttemptContext(current), replay);
1071
+ const finalized = messageId === void 0 || withTools.streamingAssistantId !== messageId ? withTools : withoutStreamingAssistant(withTools);
1072
+ const finishReason = finishReasonFor(event, extractContentParts(event));
1073
+ if (finishReason !== "interrupted" && finishReason !== "cancelled" && finishReason !== "error") {
1074
+ return finalized;
1075
+ }
1076
+ const errorText = finishReason === "error" ? getErrorText(asRecord2(event)) : void 0;
1077
+ if (messageId === void 0)
1078
+ return finalized;
1079
+ return terminalizeMessageItems(finalized, messageId, {
1080
+ status: finishReason === "error" ? "error" : "interrupted",
1081
+ ...errorText === void 0 ? {} : { errorText }
1082
+ }, replay);
1083
+ }
1084
+ function mergeMessageContent(item, event, status) {
1085
+ const extractedParts = extractContentParts(event);
1086
+ const parts = item.role === "assistant" ? sanitizeAssistantContentParts(extractedParts) : extractedParts;
1087
+ const text = parts.length > 0 ? textFromContentParts(parts) : item.role === "assistant" ? sanitizeAssistantText(extractText(event)) : extractText(event);
1088
+ const effectiveParts = parts.length > 0 ? parts : item.parts;
1089
+ const mergedText = text !== "" ? text : item.text;
1090
+ return {
1091
+ ...item,
1092
+ ...stringField("entryId", getEntryId(event)),
1093
+ ...item.role === "assistant" ? stringField("forkEntryId", getEntryId(event)) : {},
1094
+ status,
1095
+ text: mergedText,
1096
+ parts: effectiveParts,
1097
+ ...item.firstTextAt === void 0 && mergedText.trim().length > 0 ? stringField("firstTextAt", getTimestamp(event)) : {},
1098
+ // The terminal merge (message_end) stamps completion; `startedAt` was
1099
+ // stamped at message_start and is never overwritten by later events.
1100
+ ...status === "streaming" || item.completedAt !== void 0 ? {} : stringField("completedAt", getTimestamp(event)),
1101
+ ...messageMetadata(event, textPhaseFor(event, effectiveParts), effectiveParts)
1102
+ };
1103
+ }
1104
+ function mergeMessageDelta(item, event) {
1105
+ const delta = asRecord2(getPath(event, ["delta"]));
1106
+ const deltaType = getString(delta, "type");
1107
+ if (delta === void 0 || deltaType === void 0) {
1108
+ return { ...item, status: "streaming" };
1109
+ }
1110
+ const declared = getNumber(delta, "contentIndex");
1111
+ if (declared !== void 0 && (!Number.isInteger(declared) || declared < 0 || declared > HERD_MESSAGE_DELTA_CONTENT_INDEX_MAX)) {
1112
+ return item;
1113
+ }
1114
+ const parts = [...item.parts];
1115
+ const contentIndex = resolveDeltaContentIndex(parts, delta, deltaType);
1116
+ const updatedPart = applyMessageDeltaPart(parts[contentIndex], delta, deltaType, contentIndex);
1117
+ if (updatedPart !== void 0)
1118
+ parts[contentIndex] = updatedPart;
1119
+ const text = textFromContentParts(parts);
1120
+ return {
1121
+ ...item,
1122
+ status: "streaming",
1123
+ text,
1124
+ parts,
1125
+ ...item.firstTextAt === void 0 && text.trim().length > 0 ? stringField("firstTextAt", getTimestamp(event)) : {},
1126
+ ...messageMetadata(event, textPhaseFor(event, parts), parts)
1127
+ };
1128
+ }
1129
+ function resolveDeltaContentIndex(parts, delta, deltaType) {
1130
+ const declared = getNumber(delta, "contentIndex");
1131
+ if (declared !== void 0 && Number.isInteger(declared) && declared >= 0) {
1132
+ return Math.min(declared, parts.length);
1133
+ }
1134
+ const expectedType = deltaType.startsWith("text_") ? "text" : deltaType.startsWith("thinking_") ? "thinking" : deltaType.startsWith("toolcall_") ? "tool_call" : void 0;
1135
+ if (expectedType !== void 0) {
1136
+ for (let index = parts.length - 1; index >= 0; index--) {
1137
+ if (parts[index]?.type === expectedType)
1138
+ return index;
1139
+ }
1140
+ }
1141
+ return parts.length;
1142
+ }
1143
+ function applyMessageDeltaPart(current, delta, deltaType, contentIndex) {
1144
+ switch (deltaType) {
1145
+ case "text_start": {
1146
+ const declared = parseContentPart(delta["block"]).find((part) => part.type === "text");
1147
+ return declared ?? { type: "text", text: "" };
1148
+ }
1149
+ case "text_delta": {
1150
+ const chunk = getString(delta, "delta");
1151
+ if (chunk === void 0)
1152
+ return current;
1153
+ const previous = current?.type === "text" ? current.text : "";
1154
+ return {
1155
+ ...current?.type === "text" ? current : { type: "text" },
1156
+ text: sanitizeAssistantText(previous + chunk)
1157
+ };
1158
+ }
1159
+ case "text_end": {
1160
+ const content = getString(delta, "content");
1161
+ return content === void 0 ? current : parseContentPart({
1162
+ type: "text",
1163
+ text: content,
1164
+ textSignature: getString(delta, "contentSignature")
1165
+ }).find((part) => part.type === "text") ?? current;
1166
+ }
1167
+ case "thinking_start":
1168
+ return { type: "thinking", text: "" };
1169
+ case "thinking_delta": {
1170
+ const chunk = getString(delta, "delta");
1171
+ if (chunk === void 0)
1172
+ return current;
1173
+ const previous = current?.type === "thinking" ? current.text : "";
1174
+ return { type: "thinking", text: previous + chunk };
1175
+ }
1176
+ case "thinking_end": {
1177
+ const content = getString(delta, "content");
1178
+ return content === void 0 ? current : { type: "thinking", text: content };
1179
+ }
1180
+ case "toolcall_start": {
1181
+ const toolCallId = getToolCallId(delta);
1182
+ if (toolCallId === void 0)
1183
+ return current;
1184
+ return {
1185
+ type: "tool_call",
1186
+ toolCallId,
1187
+ ...stringField("name", getToolName(delta)),
1188
+ argumentsText: ""
1189
+ };
1190
+ }
1191
+ case "toolcall_delta": {
1192
+ const chunk = getString(delta, "delta");
1193
+ if (chunk === void 0 || current?.type !== "tool_call")
1194
+ return current;
1195
+ return {
1196
+ ...current,
1197
+ argumentsText: (current.argumentsText ?? "") + chunk
1198
+ };
1199
+ }
1200
+ case "toolcall_end": {
1201
+ const completed = parseContentPart(delta["toolCall"]).find((part) => part.type === "tool_call");
1202
+ return completed ?? current;
1203
+ }
1204
+ default:
1205
+ return current ?? {
1206
+ type: "unknown",
1207
+ providerType: deltaType,
1208
+ value: { ...delta, contentIndex }
1209
+ };
1210
+ }
1211
+ }
1212
+ function messageAttemptContext(item) {
1213
+ return {
1214
+ sourceMessageId: item.id,
1215
+ responseId: item.responseId ?? item.id
1216
+ };
1217
+ }
1218
+ function hasMessageError(event) {
1219
+ const record = asRecord2(event);
1220
+ if (record === void 0)
1221
+ return false;
1222
+ const stopReason = getStringPath(record, ["message", "stopReason"]) ?? getStringPath(record, ["entry", "stopReason"]) ?? getString(record, "stopReason");
1223
+ return stopReason === "error" || getErrorText(record) !== void 0;
1224
+ }
1225
+ function messageMetadata(event, textPhase, parts = extractContentParts(event)) {
1226
+ const finishReason = finishReasonFor(event, parts);
1227
+ return {
1228
+ ...stringField("responseId", getResponseId(event)),
1229
+ ...finishReason === void 0 ? {} : { finishReason },
1230
+ ...textPhase === void 0 ? {} : { textPhase },
1231
+ ...stringField("provider", getProvider(event)),
1232
+ ...stringField("adapter", getAdapter(event)),
1233
+ ...stringField("model", getModel(event)),
1234
+ ...finishReason === "error" ? messageFailureReason(event) : {}
1235
+ };
1236
+ }
1237
+ function messageFailureReason(event) {
1238
+ const record = asRecord2(event);
1239
+ if (record === void 0)
1240
+ return {};
1241
+ const message = asRecord2(record["message"]) ?? asRecord2(record["entry"]) ?? record;
1242
+ const diagnostics = message["diagnostics"];
1243
+ const failure = readRunFailureOccurrence(Array.isArray(diagnostics) ? { diagnostics } : {});
1244
+ const errorText = getErrorText(record);
1245
+ return {
1246
+ ...failure === void 0 ? {} : { failure },
1247
+ failureReason: failure?.cause.reason ?? "unknown",
1248
+ ...errorText === void 0 ? {} : { failureText: readableFailureText(errorText) }
1249
+ };
1250
+ }
1251
+ function textPhaseFor(event, parts) {
1252
+ if (event.type !== "message_end")
1253
+ return "provisional";
1254
+ switch (finishReasonFor(event, parts)) {
1255
+ case "tool_use":
1256
+ return "narration";
1257
+ case "complete":
1258
+ return "final";
1259
+ case "interrupted":
1260
+ case "cancelled":
1261
+ return "interrupted";
1262
+ case "error":
1263
+ return "error";
1264
+ case "unknown":
1265
+ return parts.some((part) => part.type === "tool_call") ? "narration" : "final";
1266
+ case void 0:
1267
+ return "final";
1268
+ }
1269
+ }
1270
+ function finishReasonFor(event, parts) {
1271
+ const raw = getStringPath(event, ["message", "stopReason"]) ?? getStringPath(event, ["entry", "stopReason"]) ?? getString(event, "stopReason");
1272
+ if (raw !== void 0)
1273
+ return normalizeFinishReason(raw);
1274
+ if (event.type !== "message_end")
1275
+ return void 0;
1276
+ if (hasMessageError(event))
1277
+ return "error";
1278
+ return parts.some((part) => part.type === "tool_call") ? "tool_use" : "complete";
1279
+ }
1280
+ function normalizeFinishReason(value) {
1281
+ switch (value) {
1282
+ case "toolUse":
1283
+ case "tool_use":
1284
+ case "tool-use":
1285
+ return "tool_use";
1286
+ case "stop":
1287
+ case "complete":
1288
+ case "completed":
1289
+ case "end_turn":
1290
+ return "complete";
1291
+ case "abort":
1292
+ case "aborted":
1293
+ case "interrupted":
1294
+ return "interrupted";
1295
+ case "cancel":
1296
+ case "cancelled":
1297
+ case "canceled":
1298
+ return "cancelled";
1299
+ case "error":
1300
+ case "failed":
1301
+ return "error";
1302
+ default:
1303
+ return "unknown";
1304
+ }
1305
+ }
1306
+ function reduceToolExecution(state, event, status, replay) {
1307
+ const toolCallId = getToolCallId(event);
1308
+ if (toolCallId === void 0)
1309
+ return state;
1310
+ return upsertToolCall(state, {
1311
+ toolCallId,
1312
+ status,
1313
+ ...stringField("name", getToolName(event)),
1314
+ ...activityKindsField(event),
1315
+ ...stringField("argumentsText", getArgumentsText(event)),
1316
+ ...stringField("resultText", getResultText(event)),
1317
+ ...stringField("errorText", getErrorText(event)),
1318
+ ...toolCallFailureField(event),
1319
+ ...unknownField("resultDetails", getPath(asRecord2(event) ?? {}, ["details"])),
1320
+ ...stringField("startedAt", status === "running" ? getTimestamp(event) : void 0),
1321
+ ...stringField("completedAt", status === "complete" || status === "error" ? getTimestamp(event) : void 0)
1322
+ }, {
1323
+ forceNewAttempt: event.type === "tool_execution_start" && state.pendingToolsByCallId[toolCallId] === void 0
1324
+ }, replay);
1325
+ }
1326
+ function normalizeToolExecutionCompletion(event) {
1327
+ const record = asRecord2(event);
1328
+ const result = asRecord2(record?.["result"]);
1329
+ const toolCallId = getToolCallId(event);
1330
+ if (toolCallId === void 0)
1331
+ return void 0;
1332
+ const isError = record?.["isError"] === true || getErrorText(event) !== void 0;
1333
+ const resultText = getResultText(result) ?? getResultText(event);
1334
+ const errorText = isError ? getErrorText(event) ?? resultText : void 0;
1335
+ const resultDetails = result !== void 0 && Object.hasOwn(result, "details") ? result["details"] : record?.["details"];
1336
+ return {
1337
+ toolCallId,
1338
+ ...stringField("entryId", getEntryId(event)),
1339
+ ...stringField("name", getToolName(event)),
1340
+ ...stringField("resultText", resultText),
1341
+ ...unknownField("resultDetails", resultDetails),
1342
+ isError,
1343
+ ...stringField("errorText", errorText),
1344
+ ...toolCallFailureField(event),
1345
+ ...stringField("completedAt", getTimestamp(event))
1346
+ };
1347
+ }
1348
+ function reduceToolCompletion(state, completion, replay) {
1349
+ if (completion === void 0)
1350
+ return state;
1351
+ const status = completion.isError ? completion.failure?.cause.category === "cancelled" || state.run.status === "aborted" ? "interrupted" : "error" : "complete";
1352
+ const withTool = upsertToolCall(state, {
1353
+ toolCallId: completion.toolCallId,
1354
+ status,
1355
+ ...stringField("name", completion.name),
1356
+ ...stringField("resultText", completion.resultText),
1357
+ ...unknownField("resultDetails", completion.resultDetails),
1358
+ ...stringField("resultEntryId", completion.entryId),
1359
+ ...stringField("errorText", completion.errorText),
1360
+ ...completion.failure === void 0 ? {} : { failure: completion.failure },
1361
+ ...stringField("completedAt", status === "complete" || status === "error" ? completion.completedAt : void 0)
1362
+ }, {}, replay);
1363
+ if (completion.entryId === void 0)
1364
+ return withTool;
1365
+ const tool = findToolItemByCallId(withTool, completion.toolCallId, replay);
1366
+ if (tool?.sourceMessageId === void 0)
1367
+ return withTool;
1368
+ const source = findMessageItem(withTool, tool.sourceMessageId, replay);
1369
+ if (source?.role !== "assistant")
1370
+ return withTool;
1371
+ return upsertMessageItem(withTool, { ...source, forkEntryId: completion.entryId }, replay);
1372
+ }
1373
+ function reduceToolResultMessage(state, event, replay) {
1374
+ const body = getPath(asRecord2(event) ?? {}, ["message"]) ?? getPath(asRecord2(event) ?? {}, ["entry"]) ?? event;
1375
+ return reduceToolCompletion(state, normalizeToolResultMessageCompletion(body, getTimestamp(event), getEntryId(event)), replay);
1376
+ }
1377
+ function normalizeToolResultMessageCompletion(body, completedAt, entryId) {
1378
+ const record = asRecord2(body);
1379
+ const toolCallId = getToolCallId(body);
1380
+ if (record === void 0 || toolCallId === void 0)
1381
+ return void 0;
1382
+ const isError = record["isError"] === true || getErrorText(record) !== void 0;
1383
+ const resultText = getResultText(record);
1384
+ return {
1385
+ toolCallId,
1386
+ ...stringField("entryId", entryId),
1387
+ ...stringField("name", getToolName(record)),
1388
+ ...stringField("resultText", resultText),
1389
+ ...unknownField("resultDetails", record["details"]),
1390
+ isError,
1391
+ ...stringField("errorText", isError ? getErrorText(record) ?? resultText : void 0),
1392
+ ...toolCallFailureField(record),
1393
+ ...stringField("completedAt", completedAt)
1394
+ };
1395
+ }
1396
+ function reduceBackgroundTask(state, event, status, replay) {
1397
+ const taskId = getString(event, "taskId");
1398
+ const toolCallId = getString(event, "toolCallId");
1399
+ const taskKind = getString(event, "taskKind");
1400
+ if (taskId === void 0 || toolCallId === void 0 || taskKind === void 0) {
1401
+ return state;
1402
+ }
1403
+ const previous = state.backgroundTasksById[taskId];
1404
+ const ownerId = getString(event, "ownerId") ?? previous?.ownerId;
1405
+ const text = getString(event, "text") ?? previous?.text;
1406
+ const output = getString(event, "output") ?? previous?.output;
1407
+ const errorText = getErrorText(event) ?? previous?.errorText;
1408
+ const snapshot = asRecord2(event)?.["snapshot"] ?? previous?.snapshot;
1409
+ const nextTask = {
1410
+ taskId,
1411
+ taskKind,
1412
+ toolCallId,
1413
+ status,
1414
+ ...stringField("ownerId", ownerId),
1415
+ ...stringField("text", text),
1416
+ ...stringField("output", output),
1417
+ ...stringField("errorText", errorText),
1418
+ ...snapshot !== void 0 ? { snapshot } : {}
1419
+ };
1420
+ const withTask = {
1421
+ ...state,
1422
+ backgroundTasksById: {
1423
+ ...state.backgroundTasksById,
1424
+ [taskId]: nextTask
1425
+ }
1426
+ };
1427
+ return upsertToolCall(withTask, {
1428
+ toolCallId,
1429
+ status: toToolStatus(status),
1430
+ backgroundTaskId: taskId,
1431
+ ...stringField("resultText", getString(event, "output")),
1432
+ ...stringField("errorText", getErrorText(event))
1433
+ }, {}, replay);
1434
+ }
1435
+ function reduceCustomEntry(state, event) {
1436
+ const customType = getString(event, "customType");
1437
+ if (customType === void 0)
1438
+ return state;
1439
+ const data = asRecord2(event)?.data;
1440
+ if (data === void 0)
1441
+ return state;
1442
+ const previous = state.customEntries[customType] ?? [];
1443
+ return {
1444
+ ...state,
1445
+ customEntries: {
1446
+ ...state.customEntries,
1447
+ [customType]: [...previous, data]
1448
+ }
1449
+ };
1450
+ }
1451
+ function toToolStatus(status) {
1452
+ switch (status) {
1453
+ case "running":
1454
+ return "running";
1455
+ case "complete":
1456
+ return "complete";
1457
+ case "cancelled":
1458
+ return "cancelled";
1459
+ case "failed":
1460
+ return "error";
1461
+ }
1462
+ }
1463
+ function stringField(key, value) {
1464
+ return value === void 0 ? {} : { [key]: value };
1465
+ }
1466
+ function unknownField(key, value) {
1467
+ return value === void 0 ? {} : { [key]: value };
1468
+ }
1469
+ function activityKindsField(value) {
1470
+ const raw = asRecord2(value)?.["activityKinds"];
1471
+ if (!Array.isArray(raw))
1472
+ return {};
1473
+ const activityKinds = raw.filter((kind) => typeof kind === "string" && TOOL_ACTIVITY_KINDS.has(kind));
1474
+ return activityKinds.length === 0 ? {} : { activityKinds };
1475
+ }
1476
+ function withSessionName(state, sessionName) {
1477
+ const { sessionName: _previousSessionName, ...rest } = state;
1478
+ void _previousSessionName;
1479
+ return {
1480
+ ...rest,
1481
+ ...stringField("sessionName", sessionName)
1482
+ };
1483
+ }
1484
+ function markAbortedAssistant(state, replay) {
1485
+ for (let index = state.items.length - 1; index >= 0; index -= 1) {
1486
+ const item = state.items[index];
1487
+ if (item?.type !== "message")
1488
+ continue;
1489
+ if (item.role === "user" && item.deliveredVia !== "steer")
1490
+ return state;
1491
+ if (item.role !== "assistant")
1492
+ continue;
1493
+ if (item.finishReason !== "tool_use" || item.runAborted)
1494
+ return state;
1495
+ return upsertMessageItem(state, { ...item, runAborted: true }, replay);
1496
+ }
1497
+ return state;
1498
+ }
1499
+ function clearTransientState(state, run, terminal, replay) {
1500
+ const terminalized = terminalizeOpenItems(state, terminal, replay);
1501
+ if (terminalized === state && replay !== void 0) {
1502
+ for (const key of Object.keys(replay.pendingToolsByCallId)) {
1503
+ delete replay.pendingToolsByCallId[key];
1504
+ }
1505
+ return {
1506
+ ...withoutStreamingAssistant(state),
1507
+ pendingToolsByCallId: replay.pendingToolsByCallId,
1508
+ run
1509
+ };
1510
+ }
1511
+ return resetReplayIndex(replay, {
1512
+ ...withoutStreamingAssistant(terminalized),
1513
+ pendingToolsByCallId: {},
1514
+ run
1515
+ });
1516
+ }
1517
+ function terminalizeMessageItems(state, sourceMessageId, terminal, replay) {
1518
+ const terminalizedCallIds = /* @__PURE__ */ new Set();
1519
+ const closes = (item) => item.type === "tool" && item.sourceMessageId === sourceMessageId && isClosable(state, item);
1520
+ let items;
1521
+ if (replay === void 0) {
1522
+ items = state.items.map((item) => {
1523
+ if (!closes(item))
1524
+ return item;
1525
+ terminalizedCallIds.add(item.toolCallId);
1526
+ return closedTool(item, terminal);
1527
+ });
1528
+ } else {
1529
+ for (const index of Array.from(replay.openItemIndexes)) {
1530
+ const item = replay.items[index];
1531
+ if (item === void 0 || !closes(item))
1532
+ continue;
1533
+ terminalizedCallIds.add(item.toolCallId);
1534
+ writeClosedReplayItem(replay, index, closedTool(item, terminal));
1535
+ }
1536
+ items = replay.items;
1537
+ }
1538
+ const pendingToolsByCallId = Object.fromEntries(Object.entries(state.pendingToolsByCallId).filter(([toolCallId]) => !terminalizedCallIds.has(toolCallId)));
1539
+ return resetReplayIndex(replay, {
1540
+ ...withoutStreamingAssistant(state),
1541
+ items,
1542
+ pendingToolsByCallId
1543
+ });
1544
+ }
1545
+ function terminalizeOpenItems(state, terminal, replay) {
1546
+ let changed = false;
1547
+ if (replay !== void 0) {
1548
+ for (const index of Array.from(replay.openItemIndexes)) {
1549
+ const item = replay.items[index];
1550
+ if (item === void 0 || !isClosable(state, item))
1551
+ continue;
1552
+ changed = true;
1553
+ writeClosedReplayItem(replay, index, closedItem(item, terminal));
1554
+ }
1555
+ return changed ? { ...state, items: replay.items } : state;
1556
+ }
1557
+ const items = state.items.map((item) => {
1558
+ if (!isClosable(state, item))
1559
+ return item;
1560
+ changed = true;
1561
+ return closedItem(item, terminal);
1562
+ });
1563
+ return changed ? { ...state, items } : state;
1564
+ }
1565
+ function isOpenItem(item) {
1566
+ return item.type === "message" ? item.status === "streaming" : !isTerminalToolStatus(item.status);
1567
+ }
1568
+ function isClosable(state, item) {
1569
+ return isOpenItem(item) && (item.type === "message" || !isRunningBackgroundTool(state, item));
1570
+ }
1571
+ function closedItem(item, terminal) {
1572
+ if (item.type === "tool")
1573
+ return closedTool(item, terminal);
1574
+ return {
1575
+ ...item,
1576
+ status: terminal.status,
1577
+ finishReason: terminal.status,
1578
+ textPhase: terminal.status
1579
+ };
1580
+ }
1581
+ function closedTool(item, terminal) {
1582
+ return {
1583
+ ...item,
1584
+ status: terminal.status,
1585
+ ...terminal.errorText === void 0 ? {} : { errorText: terminal.errorText }
1586
+ };
1587
+ }
1588
+ function isRunningBackgroundTool(state, item) {
1589
+ if (item.backgroundTaskId === void 0)
1590
+ return false;
1591
+ return state.backgroundTasksById[item.backgroundTaskId]?.status === "running";
1592
+ }
1593
+ function isTerminalToolStatus(status) {
1594
+ return status === "complete" || status === "interrupted" || status === "cancelled" || status === "error";
1595
+ }
1596
+ function withoutStreamingAssistant(state) {
1597
+ const { streamingAssistantId: _streamingAssistantId, ...rest } = state;
1598
+ void _streamingAssistantId;
1599
+ return rest;
1600
+ }
1601
+ function createReplayIndex(state) {
1602
+ const replay = {
1603
+ items: [...state.items],
1604
+ messageIndexById: /* @__PURE__ */ new Map(),
1605
+ toolIndexById: /* @__PURE__ */ new Map(),
1606
+ toolIndexByAttemptId: /* @__PURE__ */ new Map(),
1607
+ latestToolIndexByCallId: /* @__PURE__ */ new Map(),
1608
+ maxToolGenerationByCallId: /* @__PURE__ */ new Map(),
1609
+ pendingToolsByCallId: { ...state.pendingToolsByCallId },
1610
+ openItemIndexes: /* @__PURE__ */ new Set(),
1611
+ latestToolIndexBehind: false
1612
+ };
1613
+ indexReplayItems(replay);
1614
+ return replay;
1615
+ }
1616
+ function resetReplayIndex(replay, state) {
1617
+ if (replay === void 0)
1618
+ return state;
1619
+ const copied = state.items !== replay.items;
1620
+ if (copied) {
1621
+ replay.items.length = 0;
1622
+ for (const item of state.items)
1623
+ replay.items.push(item);
1624
+ }
1625
+ for (const key of Object.keys(replay.pendingToolsByCallId)) {
1626
+ delete replay.pendingToolsByCallId[key];
1627
+ }
1628
+ Object.assign(replay.pendingToolsByCallId, state.pendingToolsByCallId);
1629
+ if (copied || replay.latestToolIndexBehind)
1630
+ indexReplayItems(replay);
1631
+ return {
1632
+ ...state,
1633
+ items: replay.items,
1634
+ pendingToolsByCallId: replay.pendingToolsByCallId
1635
+ };
1636
+ }
1637
+ function indexReplayItems(replay) {
1638
+ replay.messageIndexById.clear();
1639
+ replay.toolIndexById.clear();
1640
+ replay.toolIndexByAttemptId.clear();
1641
+ replay.latestToolIndexByCallId.clear();
1642
+ replay.maxToolGenerationByCallId.clear();
1643
+ replay.openItemIndexes.clear();
1644
+ replay.latestToolIndexBehind = false;
1645
+ replay.items.forEach((item, index) => indexReplayItem(replay, item, index));
1646
+ }
1647
+ function indexReplayItem(replay, item, index) {
1648
+ if (isOpenItem(item))
1649
+ replay.openItemIndexes.add(index);
1650
+ else
1651
+ replay.openItemIndexes.delete(index);
1652
+ if (item.type === "message") {
1653
+ replay.messageIndexById.set(item.id, index);
1654
+ return;
1655
+ }
1656
+ replay.toolIndexById.set(item.id, index);
1657
+ if (item.attemptId !== void 0) {
1658
+ replay.toolIndexByAttemptId.set(item.attemptId, index);
1659
+ }
1660
+ const latest = replay.latestToolIndexByCallId.get(item.toolCallId);
1661
+ if (latest !== void 0 && latest > index) {
1662
+ replay.latestToolIndexBehind = true;
1663
+ }
1664
+ replay.latestToolIndexByCallId.set(item.toolCallId, index);
1665
+ replay.maxToolGenerationByCallId.set(item.toolCallId, Math.max(replay.maxToolGenerationByCallId.get(item.toolCallId) ?? 0, item.attemptGeneration ?? 0));
1666
+ }
1667
+ function writeClosedReplayItem(replay, index, item) {
1668
+ replay.items[index] = item;
1669
+ replay.openItemIndexes.delete(index);
1670
+ }
1671
+ function replaceReplayItem(replay, index, item) {
1672
+ const previous = replay.items[index];
1673
+ replay.items[index] = item;
1674
+ if (previous?.type === "tool" && item.type === "tool" && (previous.toolCallId !== item.toolCallId || previous.attemptId !== item.attemptId || previous.attemptGeneration !== item.attemptGeneration)) {
1675
+ indexReplayItems(replay);
1676
+ return;
1677
+ }
1678
+ indexReplayItem(replay, item, index);
1679
+ }
1680
+ function upsertMessageItem(state, item, replay) {
1681
+ const itemIndex = replay === void 0 ? state.items.findIndex((candidate) => candidate.type === "message" && candidate.id === item.id) : replay.messageIndexById.get(item.id) ?? -1;
1682
+ if (itemIndex === -1) {
1683
+ if (replay !== void 0) {
1684
+ const index = replay.items.length;
1685
+ replay.items.push(item);
1686
+ indexReplayItem(replay, item, index);
1687
+ }
1688
+ return {
1689
+ ...state,
1690
+ items: replay?.items ?? [...state.items, item],
1691
+ nextItemIndex: nextItemIndexAfter(state, item.id)
1692
+ };
1693
+ }
1694
+ return replaceMessageItem(state, item, replay);
1695
+ }
1696
+ function replaceMessageItem(state, item, replay) {
1697
+ if (replay !== void 0) {
1698
+ const itemIndex = replay.messageIndexById.get(item.id);
1699
+ if (itemIndex !== void 0)
1700
+ replaceReplayItem(replay, itemIndex, item);
1701
+ }
1702
+ return {
1703
+ ...state,
1704
+ items: replay?.items ?? state.items.map((candidate) => candidate.type === "message" && candidate.id === item.id ? item : candidate)
1705
+ };
1706
+ }
1707
+ function upsertToolCalls(state, toolCalls, status = "declared", context, replay) {
1708
+ return toolCalls.reduce((nextState, toolCall) => upsertToolCall(nextState, {
1709
+ ...toolCall,
1710
+ status,
1711
+ ...context
1712
+ }, {}, replay), state);
1713
+ }
1714
+ function upsertToolCall(state, update, options = {}, replay) {
1715
+ const declaredAttemptId = update.sourceMessageId === void 0 ? void 0 : canonicalAttemptId(update.responseId ?? update.sourceMessageId, update.ordinal ?? 0);
1716
+ const declaredCandidate = declaredAttemptId === void 0 ? void 0 : findToolItemByAttemptId(state, declaredAttemptId, replay);
1717
+ const declaredConflict = declaredCandidate !== void 0 && declaredCandidate.toolCallId !== void 0 && declaredCandidate.toolCallId !== update.toolCallId;
1718
+ const declaredMatch = declaredConflict ? void 0 : declaredCandidate;
1719
+ const usableDeclaredAttemptId = declaredConflict ? void 0 : declaredAttemptId;
1720
+ const pendingItemId = declaredMatch?.id ?? state.pendingToolsByCallId[update.toolCallId];
1721
+ const settledMatch = pendingItemId === void 0 && options.forceNewAttempt !== true ? findToolItemByCallId(state, update.toolCallId, replay) : void 0;
1722
+ const foldableMatch = settledMatch !== void 0 && (update.sourceMessageId === void 0 || settledMatch.sourceMessageId === update.sourceMessageId) && settledMatch.status === "error" === (update.status === "error") ? settledMatch : void 0;
1723
+ const matched = declaredMatch ?? (pendingItemId === void 0 ? void 0 : findToolItem(state, pendingItemId, replay)) ?? foldableMatch;
1724
+ const attemptGeneration = matched?.attemptGeneration ?? nextAttemptGeneration(state, update.toolCallId, replay);
1725
+ const responseId = update.responseId ?? matched?.responseId;
1726
+ const sourceMessageId = update.sourceMessageId ?? matched?.sourceMessageId;
1727
+ const waveId = matched?.waveId ?? canonicalWaveId(responseId ?? sourceMessageId ?? "unscoped");
1728
+ const attemptId = usableDeclaredAttemptId ?? matched?.attemptId ?? canonicalExecutionAttemptId("unscoped", update.toolCallId, attemptGeneration);
1729
+ const itemId = matched?.id ?? attemptId;
1730
+ const previous = findToolItem(state, itemId, replay);
1731
+ const name = update.name ?? previous?.name;
1732
+ const activityKinds = update.activityKinds ?? previous?.activityKinds;
1733
+ const argumentsText = previous?.argumentsText !== void 0 && isEmptyStructuredArguments(update.argumentsText) ? previous.argumentsText : update.argumentsText ?? previous?.argumentsText;
1734
+ const resultText = update.resultText ?? previous?.resultText;
1735
+ const resultDetails = update.resultDetails !== void 0 ? update.resultDetails : previous?.resultDetails;
1736
+ const errorText = update.errorText ?? previous?.errorText;
1737
+ const failure = update.failure ?? previous?.failure;
1738
+ const backgroundTaskId = update.backgroundTaskId ?? previous?.backgroundTaskId;
1739
+ const startedAt = update.startedAt ?? previous?.startedAt;
1740
+ const completedAt = update.completedAt ?? previous?.completedAt;
1741
+ const nextItem = {
1742
+ id: itemId,
1743
+ type: "tool",
1744
+ toolCallId: update.toolCallId,
1745
+ status: update.status,
1746
+ attemptId,
1747
+ waveId,
1748
+ attemptGeneration,
1749
+ ...stringField("name", name),
1750
+ ...activityKinds === void 0 ? {} : { activityKinds },
1751
+ ...stringField("argumentsText", argumentsText),
1752
+ ...stringField("resultText", resultText),
1753
+ ...unknownField("resultDetails", resultDetails),
1754
+ ...stringField("resultEntryId", update.resultEntryId ?? previous?.resultEntryId),
1755
+ ...stringField("errorText", errorText),
1756
+ ...failure === void 0 ? {} : { failure },
1757
+ ...stringField("backgroundTaskId", backgroundTaskId),
1758
+ ...stringField("responseId", responseId),
1759
+ ...stringField("sourceMessageId", sourceMessageId),
1760
+ ...stringField("startedAt", startedAt),
1761
+ ...stringField("completedAt", completedAt)
1762
+ };
1763
+ let items;
1764
+ if (replay === void 0) {
1765
+ items = previous === void 0 ? [...state.items, nextItem] : state.items.map((candidate) => candidate.type === "tool" && candidate.id === itemId ? nextItem : candidate);
1766
+ } else if (previous === void 0) {
1767
+ const index = replay.items.length;
1768
+ replay.items.push(nextItem);
1769
+ indexReplayItem(replay, nextItem, index);
1770
+ items = replay.items;
1771
+ } else {
1772
+ const index = replay.toolIndexById.get(itemId);
1773
+ if (index !== void 0)
1774
+ replaceReplayItem(replay, index, nextItem);
1775
+ items = replay.items;
1776
+ }
1777
+ let pendingToolsByCallId;
1778
+ if (replay === void 0) {
1779
+ pendingToolsByCallId = isTerminalToolStatus(update.status) ? omitKey(state.pendingToolsByCallId, update.toolCallId) : {
1780
+ ...state.pendingToolsByCallId,
1781
+ [update.toolCallId]: itemId
1782
+ };
1783
+ } else {
1784
+ if (isTerminalToolStatus(update.status)) {
1785
+ delete replay.pendingToolsByCallId[update.toolCallId];
1786
+ } else {
1787
+ replay.pendingToolsByCallId[update.toolCallId] = itemId;
1788
+ }
1789
+ pendingToolsByCallId = replay.pendingToolsByCallId;
1790
+ }
1791
+ return {
1792
+ ...state,
1793
+ items,
1794
+ pendingToolsByCallId,
1795
+ nextItemIndex: previous === void 0 ? nextItemIndexAfter(state, itemId) : state.nextItemIndex
1796
+ };
1797
+ }
1798
+ function isEmptyStructuredArguments(value) {
1799
+ const trimmed = value?.trim();
1800
+ return trimmed === "{}" || trimmed === "[]";
1801
+ }
1802
+ function findToolItemByAttemptId(state, attemptId, replay) {
1803
+ if (replay !== void 0) {
1804
+ const replayIndex = replay.toolIndexByAttemptId.get(attemptId);
1805
+ const item = replayIndex === void 0 ? void 0 : replay.items[replayIndex];
1806
+ return item?.type === "tool" ? item : void 0;
1807
+ }
1808
+ return state.items.find((candidate) => candidate.type === "tool" && candidate.attemptId === attemptId);
1809
+ }
1810
+ function nextAttemptGeneration(state, toolCallId, replay) {
1811
+ if (replay !== void 0) {
1812
+ return (replay.maxToolGenerationByCallId.get(toolCallId) ?? 0) + 1;
1813
+ }
1814
+ return state.items.reduce((highest, item) => item.type === "tool" && item.toolCallId === toolCallId ? Math.max(highest, item.attemptGeneration ?? 0) : highest, 0) + 1;
1815
+ }
1816
+ function canonicalWaveId(responseId) {
1817
+ return `tool-wave:${encodeURIComponent(responseId)}`;
1818
+ }
1819
+ function canonicalAttemptId(sourceMessageId, ordinal) {
1820
+ return `tool-attempt:${encodeURIComponent(sourceMessageId)}:${ordinal}`;
1821
+ }
1822
+ function canonicalExecutionAttemptId(turnId, toolCallId, generation) {
1823
+ return `tool-attempt:${encodeURIComponent(turnId)}:${encodeURIComponent(toolCallId)}:${generation}`;
1824
+ }
1825
+ function findMessageItem(state, itemId, replay) {
1826
+ if (replay !== void 0) {
1827
+ const replayIndex = replay.messageIndexById.get(itemId);
1828
+ const item = replayIndex === void 0 ? void 0 : replay.items[replayIndex];
1829
+ return item?.type === "message" ? item : void 0;
1830
+ }
1831
+ return state.items.find((candidate) => candidate.type === "message" && candidate.id === itemId);
1832
+ }
1833
+ function findToolItem(state, itemId, replay) {
1834
+ if (replay !== void 0) {
1835
+ const replayIndex = replay.toolIndexById.get(itemId);
1836
+ const item = replayIndex === void 0 ? void 0 : replay.items[replayIndex];
1837
+ return item?.type === "tool" ? item : void 0;
1838
+ }
1839
+ return state.items.find((candidate) => candidate.type === "tool" && candidate.id === itemId);
1840
+ }
1841
+ function findToolItemByCallId(state, toolCallId, replay) {
1842
+ if (replay !== void 0) {
1843
+ const replayIndex = replay.latestToolIndexByCallId.get(toolCallId);
1844
+ const item = replayIndex === void 0 ? void 0 : replay.items[replayIndex];
1845
+ return item?.type === "tool" ? item : void 0;
1846
+ }
1847
+ for (let i = state.items.length - 1; i >= 0; i--) {
1848
+ const candidate = state.items[i];
1849
+ if (candidate?.type === "tool" && candidate.toolCallId === toolCallId) {
1850
+ return candidate;
1851
+ }
1852
+ }
1853
+ return void 0;
1854
+ }
1855
+ function allocateItemId(state, prefix) {
1856
+ return `${prefix}-${state.nextItemIndex}`;
1857
+ }
1858
+ function nextItemIndexAfter(state, itemId) {
1859
+ const suffix = Number(itemId.match(/-(\d+)$/)?.[1]);
1860
+ return Number.isFinite(suffix) ? Math.max(state.nextItemIndex, suffix + 1) : state.nextItemIndex + 1;
1861
+ }
1862
+ function extractQueuedMessages(event) {
1863
+ const candidates = [
1864
+ getArray(event, "queue"),
1865
+ getArray(event, "messages"),
1866
+ getArray(event, "pendingMessages")
1867
+ ].find((value) => value !== void 0);
1868
+ if (candidates === void 0)
1869
+ return [];
1870
+ return candidates.map((candidate, index) => {
1871
+ const record = asRecord2(candidate);
1872
+ return {
1873
+ id: getQueuedMessageId(record, index),
1874
+ text: getQueuedMessageText(candidate, record),
1875
+ ...stringField("channel", getQueuedMessageChannel(record))
1876
+ };
1877
+ });
1878
+ }
1879
+ function reduceManagedHumanQueueUpdate(state, event) {
1880
+ const snapshot = asRecord2(getPath(event, ["snapshot"]));
1881
+ const revision = snapshot === void 0 ? void 0 : getNumber(snapshot, "revision");
1882
+ const rawItems = snapshot === void 0 ? void 0 : getArray(snapshot, "items");
1883
+ const queue = (rawItems ?? []).flatMap((candidate, index) => {
1884
+ const record = asRecord2(candidate);
1885
+ if (record === void 0)
1886
+ return [];
1887
+ const id = getString(record, "id") ?? `queue-${index + 1}`;
1888
+ const text = getString(record, "text") ?? "";
1889
+ const channel = getString(record, "channel");
1890
+ const status = getString(record, "status");
1891
+ const clientIntentId = getString(record, "clientIntentId");
1892
+ const presentationAnchor = getPresentationAnchor(record);
1893
+ const attachments = getArray(record, "attachments")?.flatMap((ref) => {
1894
+ const uri = getString(ref, "uri");
1895
+ const name = getString(ref, "name");
1896
+ const mimeType = getString(ref, "mimeType");
1897
+ return uri === void 0 || name === void 0 || mimeType === void 0 ? [] : [{ uri, name, mimeType }];
1898
+ });
1899
+ const context = extractQueuedMessageContext(record);
1900
+ const resendError = getString(record, "resendError");
1901
+ return [
1902
+ {
1903
+ id,
1904
+ text,
1905
+ ...channel !== void 0 ? { channel } : {},
1906
+ ...clientIntentId !== void 0 ? { clientIntentId } : {},
1907
+ ...presentationAnchor === void 0 ? {} : { presentationAnchor },
1908
+ ...attachments === void 0 || attachments.length === 0 ? {} : { attachments },
1909
+ ...context === void 0 ? {} : { context },
1910
+ ...resendError === void 0 ? {} : { resendError },
1911
+ ...status === "queued" || status === "editing" ? { status } : {}
1912
+ }
1913
+ ];
1914
+ });
1915
+ return {
1916
+ ...state,
1917
+ queue,
1918
+ ...revision !== void 0 ? { queueRevision: revision } : {}
1919
+ };
1920
+ }
1921
+ function extractQueuedMessageContext(record) {
1922
+ const raw = getArray(record, "context");
1923
+ if (raw === void 0)
1924
+ return void 0;
1925
+ return raw.flatMap((candidate) => {
1926
+ const part = asRecord2(candidate);
1927
+ if (part === void 0)
1928
+ return [];
1929
+ const kind = getString(part, "kind");
1930
+ if (kind === "tab_context" || kind === "ui_action") {
1931
+ const bodyOrAction = getString(part, kind === "tab_context" ? "body" : "action");
1932
+ const surfaceOrToolCallId = getString(part, kind === "tab_context" ? "surface" : "toolCallId");
1933
+ const payload = kind === "ui_action" ? getString(part, "payload") : void 0;
1934
+ return bodyOrAction === void 0 || surfaceOrToolCallId === void 0 || kind === "ui_action" && payload === void 0 ? [] : [
1935
+ kind === "tab_context" ? { kind, body: bodyOrAction, surface: surfaceOrToolCallId } : {
1936
+ kind,
1937
+ action: bodyOrAction,
1938
+ toolCallId: surfaceOrToolCallId,
1939
+ payload
1940
+ }
1941
+ ];
1942
+ }
1943
+ if (kind === "composer_references") {
1944
+ const mentions = getArray(part, "mentions")?.flatMap((value) => {
1945
+ const mention = asRecord2(value);
1946
+ if (mention === void 0)
1947
+ return [];
1948
+ const ref = getString(mention, "ref");
1949
+ const serviceId = getString(mention, "serviceId");
1950
+ const entityType = getString(mention, "entityType");
1951
+ return ref === void 0 || serviceId === void 0 || entityType === void 0 ? [] : [{ ref, serviceId, entityType }];
1952
+ });
1953
+ const invocations = getArray(part, "invocations")?.flatMap((value) => {
1954
+ const invocation = asRecord2(value);
1955
+ if (invocation === void 0)
1956
+ return [];
1957
+ const id = getString(invocation, "id");
1958
+ const serviceId = getString(invocation, "serviceId");
1959
+ return id === void 0 || serviceId === void 0 ? [] : [{ id, serviceId }];
1960
+ });
1961
+ return mentions === void 0 || invocations === void 0 ? [] : [{ kind, mentions, invocations }];
1962
+ }
1963
+ if (kind === "user_pasted_content") {
1964
+ const items = getArray(part, "items")?.flatMap((value) => {
1965
+ const item = asRecord2(value);
1966
+ if (item === void 0)
1967
+ return [];
1968
+ const id = getString(item, "id");
1969
+ const lineCount = getNumber(item, "lineCount");
1970
+ const text = getString(item, "text");
1971
+ const attachment = asRecord2(item["attachment"]);
1972
+ const name = attachment === void 0 ? void 0 : getString(attachment, "name");
1973
+ const uri = attachment === void 0 ? void 0 : getString(attachment, "uri");
1974
+ if (id === void 0 || lineCount === void 0)
1975
+ return [];
1976
+ if (text !== void 0 && attachment === void 0)
1977
+ return [
1978
+ {
1979
+ id,
1980
+ lineCount,
1981
+ text,
1982
+ // Strict `=== true`, so a malformed rehydrated value drops the
1983
+ // provenance claim rather than fabricating one.
1984
+ ...item["inline"] === true ? { inline: true } : {}
1985
+ }
1986
+ ];
1987
+ if (text === void 0 && name !== void 0) {
1988
+ return [
1989
+ {
1990
+ id,
1991
+ lineCount,
1992
+ attachment: { name, ...uri === void 0 ? {} : { uri } }
1993
+ }
1994
+ ];
1995
+ }
1996
+ return [];
1997
+ });
1998
+ return items === void 0 ? [] : [{ kind, items }];
1999
+ }
2000
+ return [];
2001
+ });
2002
+ }
2003
+ function getQueuedMessageId(record, index) {
2004
+ if (record === void 0)
2005
+ return `queue-${index + 1}`;
2006
+ return getString(record, "id") ?? getString(record, "messageId") ?? `queue-${index + 1}`;
2007
+ }
2008
+ function getQueuedMessageText(candidate, record) {
2009
+ if (record !== void 0)
2010
+ return extractText(record);
2011
+ return typeof candidate === "string" ? candidate : "";
2012
+ }
2013
+ function getQueuedMessageChannel(record) {
2014
+ if (record === void 0)
2015
+ return void 0;
2016
+ return getString(record, "channel") ?? getString(record, "type");
2017
+ }
2018
+ var STREAM_MARKER_PATTERN = /(?:<\|(?:eot_id|end_of_turn|endoftext|im_end|eom|bom|eot|end)\|>)/giu;
2019
+ function sanitizeAssistantText(text) {
2020
+ return text.replace(STREAM_MARKER_PATTERN, "");
2021
+ }
2022
+ function sanitizeAssistantContentParts(parts) {
2023
+ return parts.map((part) => part.type === "text" ? { ...part, text: sanitizeAssistantText(part.text) } : part);
2024
+ }
2025
+ function textFromContentParts(parts) {
2026
+ return parts.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
2027
+ }
2028
+ function extractContentParts(event) {
2029
+ const parts = extractMessageContentParts(event);
2030
+ if (parts.length > 0)
2031
+ return parts;
2032
+ const text = extractText(event);
2033
+ const fallbackParts = text === "" ? [] : [{ type: "text", text }];
2034
+ for (const toolCall of extractToolCalls(event)) {
2035
+ fallbackParts.push({
2036
+ type: "tool_call",
2037
+ toolCallId: toolCall.toolCallId,
2038
+ ...stringField("name", toolCall.name),
2039
+ ...stringField("argumentsText", toolCall.argumentsText)
2040
+ });
2041
+ }
2042
+ return fallbackParts;
2043
+ }
2044
+ function extractMessageContentParts(event) {
2045
+ const content = firstArray([
2046
+ getPath(event, ["message", "content"]),
2047
+ getPath(event, ["entry", "message", "content"]),
2048
+ getPath(event, ["entry", "content"]),
2049
+ getPath(event, ["partial", "content"]),
2050
+ getPath(event, ["assistantMessageEvent", "partial", "content"]),
2051
+ getPath(event, ["assistantMessageEvent", "message", "content"]),
2052
+ getPath(event, ["assistantMessageEvent", "error", "content"]),
2053
+ getPath(event, ["assistantMessageEvent", "content"]),
2054
+ getPath(event, ["content"])
2055
+ ]);
2056
+ if (content === void 0)
2057
+ return [];
2058
+ return content.flatMap(parseContentPart);
2059
+ }
2060
+ function parseContentPart(part) {
2061
+ const record = asRecord2(part);
2062
+ if (record === void 0)
2063
+ return [];
2064
+ switch (getString(record, "type")) {
2065
+ case "text":
2066
+ return textContentPart(getString(record, "text"), decodeDeclaredPhase(getString(record, "textSignature")));
2067
+ case "thinking":
2068
+ return thinkingContentPart(record);
2069
+ case "toolCall":
2070
+ case "tool_call":
2071
+ return toolCallContentPart(record);
2072
+ default:
2073
+ return [
2074
+ {
2075
+ type: "unknown",
2076
+ ...stringField("providerType", getString(record, "type")),
2077
+ value: part
2078
+ }
2079
+ ];
2080
+ }
2081
+ }
2082
+ function textContentPart(text, declaredPhase) {
2083
+ if (text === void 0 || text === "")
2084
+ return [];
2085
+ return [
2086
+ {
2087
+ type: "text",
2088
+ text,
2089
+ ...declaredPhase === void 0 ? {} : { declaredPhase }
2090
+ }
2091
+ ];
2092
+ }
2093
+ function decodeDeclaredPhase(signature) {
2094
+ if (signature === void 0 || !signature.startsWith("{"))
2095
+ return void 0;
2096
+ let parsed;
2097
+ try {
2098
+ parsed = JSON.parse(signature);
2099
+ } catch {
2100
+ return void 0;
2101
+ }
2102
+ const phase = asRecord2(parsed)?.["phase"];
2103
+ if (phase === "commentary")
2104
+ return "narration";
2105
+ if (phase === "final_answer")
2106
+ return "final";
2107
+ return void 0;
2108
+ }
2109
+ function thinkingContentPart(record) {
2110
+ const text = getString(record, "thinking") ?? getString(record, "text") ?? getString(record, "content");
2111
+ return text === void 0 || text === "" ? [] : [{ type: "thinking", text }];
2112
+ }
2113
+ function toolCallContentPart(record) {
2114
+ const toolCallId = getToolCallId(record);
2115
+ if (toolCallId === void 0)
2116
+ return [];
2117
+ return [
2118
+ {
2119
+ type: "tool_call",
2120
+ toolCallId,
2121
+ ...stringField("name", getToolName(record)),
2122
+ ...stringField("argumentsText", getArgumentsText(record))
2123
+ }
2124
+ ];
2125
+ }
2126
+ function extractToolCalls(event) {
2127
+ const seen = /* @__PURE__ */ new Set();
2128
+ const toolCalls = [];
2129
+ visit(event, (value) => {
2130
+ const record = asRecord2(value);
2131
+ if (record === void 0)
2132
+ return;
2133
+ const toolCallId = getToolCallId(record);
2134
+ if (toolCallId === void 0 || seen.has(toolCallId))
2135
+ return;
2136
+ const name = getToolName(record);
2137
+ const argumentsText = getArgumentsText(record);
2138
+ const hasToolDetails = name !== void 0 || argumentsText !== void 0 || looksLikeToolCall(record);
2139
+ if (!hasToolDetails) {
2140
+ return;
2141
+ }
2142
+ seen.add(toolCallId);
2143
+ toolCalls.push({
2144
+ toolCallId,
2145
+ ordinal: toolCalls.length,
2146
+ ...stringField("name", name),
2147
+ ...stringField("argumentsText", argumentsText)
2148
+ });
2149
+ });
2150
+ return toolCalls;
2151
+ }
2152
+ function visit(value, callback) {
2153
+ const stack = [value];
2154
+ const seen = /* @__PURE__ */ new Set();
2155
+ while (stack.length > 0) {
2156
+ const current = stack.pop();
2157
+ callback(current);
2158
+ if (Array.isArray(current)) {
2159
+ for (let i = current.length - 1; i >= 0; i--)
2160
+ stack.push(current[i]);
2161
+ continue;
2162
+ }
2163
+ if (typeof current !== "object" || current === null)
2164
+ continue;
2165
+ if (seen.has(current))
2166
+ continue;
2167
+ seen.add(current);
2168
+ const children = Object.values(current);
2169
+ for (let i = children.length - 1; i >= 0; i--)
2170
+ stack.push(children[i]);
2171
+ }
2172
+ }
2173
+ function looksLikeToolCall(record) {
2174
+ return getString(record, "type") === "tool_call" || getString(record, "type") === "toolCall" || getString(record, "kind") === "tool_call" || getString(record, "toolName") !== void 0 || getString(record, "name") !== void 0;
2175
+ }
2176
+ function messageRoleDisposition(rawRole) {
2177
+ if (rawRole === void 0)
2178
+ return "project";
2179
+ if (isKernelMessageRole(rawRole))
2180
+ return kernelRoleDisposition(rawRole);
2181
+ return isProjectableMessageRole(rawRole) ? "project" : "project_unknown";
2182
+ }
2183
+ function normalizeUnknownMessageEvent(event) {
2184
+ const rawRole = getRawMessageRole(event) ?? "unknown";
2185
+ const unknownPart = {
2186
+ type: "unknown_message_role",
2187
+ rawRole,
2188
+ value: event
2189
+ };
2190
+ const message = asRecord2(asRecord2(event)?.["message"]);
2191
+ return {
2192
+ ...event,
2193
+ role: "custom",
2194
+ customType: UNKNOWN_ACTIVITY_CUSTOM_TYPE,
2195
+ details: { rawRole, value: event },
2196
+ content: [unknownPart],
2197
+ ...message === void 0 ? {} : {
2198
+ message: {
2199
+ ...message,
2200
+ role: "custom",
2201
+ customType: UNKNOWN_ACTIVITY_CUSTOM_TYPE,
2202
+ details: { rawRole, value: event },
2203
+ content: [unknownPart]
2204
+ }
2205
+ }
2206
+ };
2207
+ }
2208
+ function kernelRoleDisposition(role) {
2209
+ switch (role) {
2210
+ case "user":
2211
+ case "assistant":
2212
+ return "project";
2213
+ case "toolResult":
2214
+ return "fold_tool_result";
2215
+ // pi-ai 0.86+ added kernel `system` messages (the composed system prompt
2216
+ // as a transcript message). Bonsai renders the system prompt out-of-band;
2217
+ // projecting it here would duplicate it into the chat surface.
2218
+ case "system":
2219
+ return "drop";
2220
+ default: {
2221
+ const _exhaustive = role;
2222
+ void _exhaustive;
2223
+ return "drop";
2224
+ }
2225
+ }
2226
+ }
2227
+ var PROJECTABLE_MESSAGE_ROLES = /* @__PURE__ */ new Set([
2228
+ "assistant",
2229
+ "user",
2230
+ "system",
2231
+ "custom"
2232
+ ]);
2233
+ function getRawMessageRole(event) {
2234
+ return getString(event, "role") ?? getStringPath(event, ["message", "role"]) ?? getStringPath(event, ["entry", "role"]);
2235
+ }
2236
+ function getMessageRole(event) {
2237
+ const role = getRawMessageRole(event);
2238
+ if (role !== void 0 && isProjectableMessageRole(role)) {
2239
+ return role;
2240
+ }
2241
+ return event.type === "message_update" || event.type === "message_end" ? "assistant" : "custom";
2242
+ }
2243
+ function isProjectableMessageRole(role) {
2244
+ return PROJECTABLE_MESSAGE_ROLES.has(role);
2245
+ }
2246
+ function getCustomType(event) {
2247
+ return getString(event, "customType") ?? getStringPath(event, ["message", "customType"]) ?? getStringPath(event, ["entry", "customType"]);
2248
+ }
2249
+ function getMessageDetails(event) {
2250
+ const record = asRecord2(event);
2251
+ const message = asRecord2(record?.["message"]);
2252
+ const entry = asRecord2(record?.["entry"]);
2253
+ return record?.["details"] ?? message?.["details"] ?? entry?.["details"];
2254
+ }
2255
+ function getMessageDisplay(event) {
2256
+ const record = asRecord2(event);
2257
+ const message = asRecord2(record?.["message"]);
2258
+ const entry = asRecord2(record?.["entry"]);
2259
+ const display = record?.["display"] ?? message?.["display"] ?? entry?.["display"];
2260
+ return typeof display === "boolean" ? display : void 0;
2261
+ }
2262
+ function toolCallFailureField(value) {
2263
+ const record = asRecord2(value);
2264
+ if (record === void 0)
2265
+ return {};
2266
+ const result = asRecord2(record["result"]);
2267
+ const message = asRecord2(record["message"]);
2268
+ const entry = asRecord2(record["entry"]);
2269
+ const failure = readToolCallFailure(record["details"]) ?? readToolCallFailure(result?.["details"]) ?? readToolCallFailure(message?.["details"]) ?? readToolCallFailure(entry?.["details"]);
2270
+ return failure === void 0 ? {} : { failure };
2271
+ }
2272
+ function getDeliveredVia(event) {
2273
+ return getStringPath(event, ["message", "deliveredVia"]) ?? getStringPath(event, ["entry", "deliveredVia"]);
2274
+ }
2275
+ function getPresentationAnchor(event) {
2276
+ const record = asRecord2(event);
2277
+ const message = asRecord2(record?.["message"]);
2278
+ const entry = asRecord2(record?.["entry"]);
2279
+ const candidate = record?.["presentationAnchor"] ?? message?.["presentationAnchor"] ?? entry?.["presentationAnchor"];
2280
+ return parsePresentationAnchor(candidate);
2281
+ }
2282
+ function presentationAnchorField(anchor) {
2283
+ return anchor === void 0 ? {} : { presentationAnchor: anchor };
2284
+ }
2285
+ function getMessageId(event) {
2286
+ return getString(event, "messageId") ?? getString(event, "clientIntentId") ?? getStringPath(event, ["message", "clientIntentId"]) ?? getStringPath(event, ["message", "id"]) ?? getStringPath(event, ["entry", "id"]) ?? getString(event, "id");
2287
+ }
2288
+ function getEntryId(event) {
2289
+ return getString(event, "entryId") ?? getStringPath(event, ["entry", "id"]);
2290
+ }
2291
+ function getResponseId(event) {
2292
+ return getString(event, "responseId") ?? getStringPath(event, ["message", "responseId"]) ?? getStringPath(event, ["entry", "responseId"]);
2293
+ }
2294
+ function getProvider(event) {
2295
+ return getString(event, "provider") ?? getStringPath(event, ["message", "provider"]) ?? getStringPath(event, ["entry", "provider"]);
2296
+ }
2297
+ function getAdapter(event) {
2298
+ return getString(event, "api") ?? getStringPath(event, ["message", "api"]) ?? getStringPath(event, ["entry", "api"]);
2299
+ }
2300
+ function getModel(event) {
2301
+ return getString(event, "model") ?? getStringPath(event, ["message", "model"]) ?? getStringPath(event, ["entry", "model"]);
2302
+ }
2303
+ function getTimestamp(value) {
2304
+ const timestamp = getString(value, "timestamp") ?? getStringPath(value, ["message", "timestamp"]) ?? getStringPath(value, ["entry", "timestamp"]);
2305
+ if (timestamp !== void 0)
2306
+ return timestamp;
2307
+ const numeric = getNumber(value, "timestamp");
2308
+ return numeric === void 0 ? void 0 : String(numeric);
2309
+ }
2310
+ function getToolCallId(value) {
2311
+ const record = asRecord2(value);
2312
+ if (record === void 0)
2313
+ return void 0;
2314
+ return getString(record, "toolCallId") ?? getString(record, "tool_call_id") ?? getStringPath(record, ["toolCall", "id"]) ?? getString(record, "id") ?? getString(record, "toolUseId") ?? getString(record, "tool_use_id") ?? getStringPath(record, ["tool_call", "id"]);
2315
+ }
2316
+ function getToolName(value) {
2317
+ const record = asRecord2(value);
2318
+ if (record === void 0)
2319
+ return void 0;
2320
+ return getString(record, "toolName") ?? getString(record, "name") ?? getStringPath(record, ["toolCall", "name"]) ?? getStringPath(record, ["tool_call", "name"]) ?? getStringPath(record, ["function", "name"]);
2321
+ }
2322
+ function getArgumentsText(value) {
2323
+ const record = asRecord2(value);
2324
+ if (record === void 0)
2325
+ return void 0;
2326
+ const candidates = [
2327
+ record.argumentsText,
2328
+ record.arguments,
2329
+ record.args,
2330
+ record.input,
2331
+ getPath(record, ["toolCall", "arguments"]),
2332
+ getPath(record, ["tool_call", "arguments"]),
2333
+ getPath(record, ["function", "arguments"])
2334
+ ];
2335
+ let emptySerialized;
2336
+ for (const candidate of candidates) {
2337
+ let text;
2338
+ if (candidate !== null && typeof candidate === "object") {
2339
+ try {
2340
+ text = JSON.stringify(candidate);
2341
+ } catch {
2342
+ }
2343
+ } else {
2344
+ text = toDisplayText(candidate);
2345
+ }
2346
+ if (text === void 0 || text === "")
2347
+ continue;
2348
+ if (text === "{}" || text === "[]") {
2349
+ emptySerialized ??= text;
2350
+ continue;
2351
+ }
2352
+ return text;
2353
+ }
2354
+ return emptySerialized;
2355
+ }
2356
+ function getResultText(value) {
2357
+ const record = asRecord2(value);
2358
+ if (record === void 0)
2359
+ return void 0;
2360
+ return firstSerializableText([
2361
+ record.result,
2362
+ record.output,
2363
+ record.content,
2364
+ record.text
2365
+ ]);
2366
+ }
2367
+ function getErrorText(value) {
2368
+ const record = asRecord2(value);
2369
+ if (record === void 0)
2370
+ return void 0;
2371
+ return firstSerializableText([
2372
+ record.error,
2373
+ record.errorText,
2374
+ record.errorMessage,
2375
+ getPath(record, ["message", "error"]),
2376
+ getPath(record, ["message", "errorText"]),
2377
+ getPath(record, ["message", "errorMessage"]),
2378
+ getPath(record, ["entry", "error"]),
2379
+ getPath(record, ["entry", "errorText"]),
2380
+ getPath(record, ["entry", "errorMessage"])
2381
+ ]);
2382
+ }
2383
+ function extractText(value) {
2384
+ const record = asRecord2(value);
2385
+ if (typeof value === "string")
2386
+ return value;
2387
+ if (record === void 0)
2388
+ return "";
2389
+ const direct = firstSerializableText([
2390
+ record.text,
2391
+ record.delta,
2392
+ record.content,
2393
+ getPath(record, ["message", "text"]),
2394
+ getPath(record, ["message", "content"]),
2395
+ getPath(record, ["message", "errorMessage"]),
2396
+ getPath(record, ["entry", "text"]),
2397
+ getPath(record, ["entry", "content"]),
2398
+ getPath(record, ["entry", "errorMessage"]),
2399
+ record.errorMessage
2400
+ ]);
2401
+ return direct ?? "";
2402
+ }
2403
+ function firstSerializableText(values) {
2404
+ for (const value of values) {
2405
+ const text = toDisplayText(value);
2406
+ if (text !== void 0 && text !== "")
2407
+ return text;
2408
+ }
2409
+ return void 0;
2410
+ }
2411
+ function firstArray(values) {
2412
+ return values.find((value) => Array.isArray(value));
2413
+ }
2414
+ function toDisplayText(value) {
2415
+ if (typeof value === "string")
2416
+ return value;
2417
+ if (typeof value === "number" || typeof value === "boolean") {
2418
+ return String(value);
2419
+ }
2420
+ if (Array.isArray(value)) {
2421
+ const text = value.map((item) => {
2422
+ const record2 = asRecord2(item);
2423
+ if (record2 !== void 0) {
2424
+ return toDisplayText(record2.text) ?? toDisplayText(record2.content) ?? void 0;
2425
+ }
2426
+ return toDisplayText(item);
2427
+ }).filter((item) => item !== void 0 && item !== "").join("");
2428
+ return text === "" ? void 0 : text;
2429
+ }
2430
+ const record = asRecord2(value);
2431
+ if (record !== void 0) {
2432
+ return toDisplayText(record.text) ?? toDisplayText(record.content) ?? void 0;
2433
+ }
2434
+ return void 0;
2435
+ }
2436
+ function drivesTheReducedRun(event) {
2437
+ const channel = getString(event, "channel");
2438
+ return channel === void 0 || channel === "prompt";
2439
+ }
2440
+ function getString(value, key) {
2441
+ const record = asRecord2(value);
2442
+ const field = record?.[key];
2443
+ return typeof field === "string" ? field : void 0;
2444
+ }
2445
+ function getNumber(value, key) {
2446
+ const record = asRecord2(value);
2447
+ const field = record?.[key];
2448
+ return typeof field === "number" ? field : void 0;
2449
+ }
2450
+ function getArray(value, key) {
2451
+ const record = asRecord2(value);
2452
+ const field = record?.[key];
2453
+ return Array.isArray(field) ? field : void 0;
2454
+ }
2455
+ function getStringPath(value, path) {
2456
+ const found = getPath(value, path);
2457
+ return typeof found === "string" ? found : void 0;
2458
+ }
2459
+ function getPath(value, path) {
2460
+ let current = value;
2461
+ for (const key of path) {
2462
+ const record = asRecord2(current);
2463
+ if (record === void 0)
2464
+ return void 0;
2465
+ current = record[key];
2466
+ }
2467
+ return current;
2468
+ }
2469
+ function asRecord2(value) {
2470
+ return typeof value === "object" && value !== null ? value : void 0;
2471
+ }
2472
+ function omitKey(record, key) {
2473
+ const { [key]: _omitted, ...rest } = record;
2474
+ void _omitted;
2475
+ return rest;
2476
+ }
2477
+
2478
+ // packages/herd-transcript/dist/interactive/custom-message-placement.js
2479
+ var OTHER_CUSTOM_TYPES = "*";
2480
+ function customMessagePlacement(row, details, display) {
2481
+ if (row === void 0)
2482
+ return display === false ? "outside-transcript" : "standalone";
2483
+ return typeof row.placement === "function" ? row.placement(details, display) : row.placement;
2484
+ }
2485
+ var DEFAULT_ROWS = [
2486
+ // The projection fills a user turn's attachments, dynamic context, invoked command and paste
2487
+ // slots from these.
2488
+ ...[
2489
+ ATTACHMENTS_CUSTOM_TYPE,
2490
+ DYNAMIC_CONTEXT_CUSTOM_TYPE,
2491
+ USER_INVOKED_CUSTOM_TYPE,
2492
+ USER_PASTED_CONTENT_CUSTOM_TYPE
2493
+ ].map((typeKey) => ({ typeKey, placement: "companion-of-send" })),
2494
+ // A card answer: the person's input, sent with no text of its own.
2495
+ { typeKey: UI_ACTION_CUSTOM_TYPE, placement: "opens-turn" },
2496
+ // Maintenance the run already performed, not an input the agent resumes on.
2497
+ { typeKey: COMPACTION_MARKER_CUSTOM_TYPE, placement: "standalone" },
2498
+ {
2499
+ typeKey: FINAL_OUTPUT_REPAIR_CUSTOM_TYPE,
2500
+ placement: "continues-agent-turn"
2501
+ },
2502
+ // A spawn can keep its result out of the person's transcript (`display: false`).
2503
+ {
2504
+ typeKey: SUBAGENT_RESULT_CUSTOM_TYPE,
2505
+ placement: (details, display) => display === false ? "outside-transcript" : isSubagentResultDetails(details) ? "continues-agent-turn" : "standalone"
2506
+ },
2507
+ {
2508
+ typeKey: BACKGROUND_TASK_RESULT_CUSTOM_TYPE,
2509
+ placement: (details) => isBackgroundTaskResultDetails(details) ? "continues-agent-turn" : "standalone"
2510
+ },
2511
+ {
2512
+ typeKey: DAEMON_SERVICE_TURN_CUSTOM_TYPE,
2513
+ placement: (details) => isDaemonWakeDetails(details) ? "continues-agent-turn" : "standalone"
2514
+ },
2515
+ // The kernel's notes to the model about a compaction it ran mid-turn and a run it continued.
2516
+ {
2517
+ typeKey: MID_TURN_COMPACTION_OUTCOME_CUSTOM_TYPE,
2518
+ placement: "outside-transcript"
2519
+ },
2520
+ {
2521
+ typeKey: RUN_CONTINUATION_CARRIER_CUSTOM_TYPE,
2522
+ placement: "outside-transcript"
2523
+ }
2524
+ ];
2525
+ var DEFAULT_CUSTOM_MESSAGE_PLACEMENTS = new Map(DEFAULT_ROWS.map((row) => [row.typeKey, row]));
2526
+ function placementOfCustomMessage(item, placements) {
2527
+ const row = (item.customType === void 0 ? void 0 : placements.get(item.customType) ?? DEFAULT_CUSTOM_MESSAGE_PLACEMENTS.get(item.customType)) ?? placements.get(OTHER_CUSTOM_TYPES);
2528
+ return customMessagePlacement(row, item.details, item.display);
2529
+ }
2530
+ function isEmbeddedAgentContinuationMessage(item, placements) {
2531
+ return item.role === "custom" && item.status === "complete" && item.customType !== void 0 && placementOfCustomMessage(item, placements) === "continues-agent-turn";
2532
+ }
2533
+
2534
+ // packages/herd-transcript/dist/interactive/canonical-run-boundaries.js
2535
+ function boundaryAnchorKey(anchor) {
2536
+ return `${anchor.type}:${anchor.id}`;
2537
+ }
2538
+ function hasTerminalFinalOutputInRange(items, from, to) {
2539
+ for (let scan = from; scan < to; scan += 1) {
2540
+ if (isTerminalFinalOutput(items, scan))
2541
+ return true;
2542
+ }
2543
+ return false;
2544
+ }
2545
+ function isBoundaryCausalItem(item) {
2546
+ return item.type === "tool" || item.role === "assistant" || item.role === "user";
2547
+ }
2548
+ function markAnchor(index, anchor, rank) {
2549
+ index.keys.add(boundaryAnchorKey(anchor));
2550
+ let byId = index.firstRankByTypeAndId.get(anchor.type);
2551
+ if (byId === void 0) {
2552
+ byId = /* @__PURE__ */ new Map();
2553
+ index.firstRankByTypeAndId.set(anchor.type, byId);
2554
+ }
2555
+ const first = byId.get(anchor.id);
2556
+ if (first === void 0 || rank < first)
2557
+ byId.set(anchor.id, rank);
2558
+ }
2559
+ function buildAnchorIndex(anchors) {
2560
+ const index = {
2561
+ keys: /* @__PURE__ */ new Set(),
2562
+ firstRankByTypeAndId: /* @__PURE__ */ new Map()
2563
+ };
2564
+ anchors.forEach((anchor, rank) => markAnchor(index, anchor, rank));
2565
+ return index;
2566
+ }
2567
+ function indexCompletedRunBoundaryAnchorsOverKeptItems(anchors, all, kept) {
2568
+ if (anchors === void 0)
2569
+ return void 0;
2570
+ const index = buildAnchorIndex(anchors);
2571
+ if (kept === all)
2572
+ return index;
2573
+ let next = 0;
2574
+ let previous;
2575
+ for (const item of all) {
2576
+ if (kept[next] === item) {
2577
+ next += 1;
2578
+ previous = item;
2579
+ continue;
2580
+ }
2581
+ if (previous === void 0)
2582
+ continue;
2583
+ const rank = index.firstRankByTypeAndId.get(item.type)?.get(item.id);
2584
+ if (rank !== void 0)
2585
+ markAnchor(index, previous, rank);
2586
+ }
2587
+ return index;
2588
+ }
2589
+ function completedBoundaryIndices(items, anchorIndex) {
2590
+ if (anchorIndex === void 0)
2591
+ return [];
2592
+ const found = [];
2593
+ for (let index = 0; index < items.length; index += 1) {
2594
+ const item = items[index];
2595
+ const rank = anchorIndex.firstRankByTypeAndId.get(item.type)?.get(item.id);
2596
+ if (rank !== void 0)
2597
+ found.push({ rank, index });
2598
+ }
2599
+ if (found.length > 1)
2600
+ found.sort((a, b) => a.rank - b.rank);
2601
+ const indices = [];
2602
+ let previousRank = -1;
2603
+ let previousIndex = -1;
2604
+ for (const { rank, index } of found) {
2605
+ if (rank === previousRank)
2606
+ continue;
2607
+ previousRank = rank;
2608
+ if (index <= previousIndex)
2609
+ continue;
2610
+ indices.push(index);
2611
+ previousIndex = index;
2612
+ }
2613
+ return indices;
2614
+ }
2615
+ function finalProseKeysAtCompletedBoundaries(items, anchorIndex) {
2616
+ const keys = /* @__PURE__ */ new Set();
2617
+ let previousBoundaryIndex = -1;
2618
+ for (const boundaryIndex of completedBoundaryIndices(items, anchorIndex)) {
2619
+ for (let index = boundaryIndex; index > previousBoundaryIndex; index -= 1) {
2620
+ const candidate = items[index];
2621
+ if (candidate?.type !== "tool" || candidate.status !== "complete" || candidate.name !== RESERVED_FINAL_OUTPUT_TOOL_NAME)
2622
+ continue;
2623
+ const capture = finalOutputCaptureFromDetails(candidate.toolCallId, candidate.resultDetails);
2624
+ if (capture === void 0 || capture.terminatesRun !== void 0 || capture.message !== void 0)
2625
+ continue;
2626
+ const waveId = canonicalToolWaveId(candidate);
2627
+ let hasLaterCausalItem = false;
2628
+ for (let scan = index + 1; scan <= boundaryIndex; scan += 1) {
2629
+ const later = items[scan];
2630
+ if (later === void 0 || !isBoundaryCausalItem(later))
2631
+ continue;
2632
+ if (later.type === "tool" && canonicalToolWaveId(later) === waveId)
2633
+ continue;
2634
+ hasLaterCausalItem = true;
2635
+ break;
2636
+ }
2637
+ if (hasLaterCausalItem)
2638
+ continue;
2639
+ if (candidate.sourceMessageId !== void 0)
2640
+ keys.add(candidate.sourceMessageId);
2641
+ if (candidate.responseId !== void 0)
2642
+ keys.add(candidate.responseId);
2643
+ break;
2644
+ }
2645
+ previousBoundaryIndex = boundaryIndex;
2646
+ }
2647
+ return keys;
2648
+ }
2649
+ function canonicalToolWaveId(tool) {
2650
+ return tool.waveId ?? canonicalId("tool-wave", tool.responseId ?? tool.sourceMessageId ?? tool.id);
2651
+ }
2652
+ function finalOutputTerminatesRun(capture) {
2653
+ return capture.terminatesRun === true || capture.terminatesRun === void 0 && capture.message !== void 0;
2654
+ }
2655
+ function isTerminalFinalOutput(items, index) {
2656
+ const item = items[index];
2657
+ if (item?.type !== "tool" || item.status !== "complete" || item.name !== RESERVED_FINAL_OUTPUT_TOOL_NAME) {
2658
+ return false;
2659
+ }
2660
+ const capture = finalOutputCaptureFromDetails(item.toolCallId, item.resultDetails);
2661
+ return capture !== void 0 && finalOutputTerminatesRun(capture);
2662
+ }
2663
+ function hasTerminalFinalOutput(items) {
2664
+ return items.some((_, index) => isTerminalFinalOutput(items, index));
2665
+ }
2666
+ function hasExhaustedRequiredFinalOutputRepair(items) {
2667
+ const repairIndex = items.findIndex((item) => item.type === "message" && isRequiredFinalOutputRepairMessage(item));
2668
+ if (repairIndex === -1)
2669
+ return false;
2670
+ return items.slice(repairIndex + 1).some((item) => item.type === "message" && item.role === "assistant" && item.status === "complete" && item.finishReason === "complete");
2671
+ }
2672
+ function continuationFollowsLastAssistant(items, placements) {
2673
+ const lastAssistantIndex = items.findLastIndex((item) => item.type === "message" && item.role === "assistant");
2674
+ return items.slice(lastAssistantIndex + 1).some((item) => item.type === "message" && isEmbeddedAgentContinuationMessage(item, placements));
2675
+ }
2676
+ function hasTrailingAwaitableResult(items) {
2677
+ const last = items.at(-1);
2678
+ return last !== void 0 && last.type === "message" && isEmbeddedAgentResultMessage(last);
2679
+ }
2680
+ function hasPendingBackgroundWork(items, state) {
2681
+ return items.some((item) => item.type === "tool" && item.backgroundTaskId !== void 0 && state.backgroundTasksById[item.backgroundTaskId]?.status === "running");
2682
+ }
2683
+ function canonicalId(kind, sourceId) {
2684
+ return `${kind}:${encodeURIComponent(sourceId)}`;
2685
+ }
2686
+
2687
+ // packages/herd-transcript/dist/interactive/canonical-attempt-lifecycle.js
2688
+ function attemptLifecycleStatus(attempt) {
2689
+ if (attempt.detached === true && (attempt.status === "running" || attempt.status === "pending")) {
2690
+ return "succeeded";
2691
+ }
2692
+ return attempt.status;
2693
+ }
2694
+
2695
+ // packages/herd-transcript/dist/interactive/canonical-recovery.js
2696
+ function failureOwner(block) {
2697
+ if (block.kind === "provisional_response" || block.kind === "final_answer")
2698
+ return block.status === "failed" ? block.sourceMessageId : void 0;
2699
+ if (block.kind === "custom_message")
2700
+ return block.message.failure === void 0 ? void 0 : block.message.id;
2701
+ return void 0;
2702
+ }
2703
+ function isReply(block) {
2704
+ return block.kind === "provisional_response" || block.kind === "final_answer";
2705
+ }
2706
+ function failedSources(blocks) {
2707
+ const sources = /* @__PURE__ */ new Set();
2708
+ for (const block of blocks) {
2709
+ if ((block.kind === "narration" || block.kind === "provisional_response" || block.kind === "final_answer") && block.status === "failed")
2710
+ sources.add(block.sourceMessageId);
2711
+ }
2712
+ return sources;
2713
+ }
2714
+ function isSettled(attempt) {
2715
+ const status = attemptLifecycleStatus(attempt);
2716
+ return status === "succeeded" || status === "failed";
2717
+ }
2718
+ function attemptsOf(block) {
2719
+ if (block.kind === "work_episode")
2720
+ return block.waves.flatMap((wave) => wave.attempts);
2721
+ return block.kind === "tool_surface" ? [block.attempt] : [];
2722
+ }
2723
+ function isTextProgress(block) {
2724
+ return (block.kind === "narration" || block.kind === "provisional_response" || block.kind === "final_answer") && block.status === "succeeded" && block.text.trim() !== "";
2725
+ }
2726
+ function showsProgress(blocks, failed) {
2727
+ return blocks.some((block) => isTextProgress(block) || attemptsOf(block).some((attempt) => isSettled(attempt) && (attempt.sourceMessageId === void 0 ? failed.size === 0 : !failed.has(attempt.sourceMessageId))));
2728
+ }
2729
+ function stretchFlags(blocks, from, to, status, recoveredAnyway, flags) {
2730
+ const stretch = blocks.slice(from, to);
2731
+ const failed = failedSources(stretch);
2732
+ let textFollows = false;
2733
+ const askers = [];
2734
+ const recovered = /* @__PURE__ */ new Map();
2735
+ for (let index = to - 1; index >= from; index -= 1) {
2736
+ const block = blocks[index];
2737
+ const owner = failureOwner(block);
2738
+ if (owner !== void 0) {
2739
+ recovered.set(index, recoveredAnyway || textFollows || askers.some((asker) => asker !== owner));
2740
+ }
2741
+ if (isTextProgress(block))
2742
+ textFollows = true;
2743
+ for (const attempt of attemptsOf(block)) {
2744
+ const asker = attempt.sourceMessageId;
2745
+ if (asker === void 0 || !isSettled(attempt) || failed.has(asker) || askers.includes(asker) || askers.length === 2)
2746
+ continue;
2747
+ askers.push(asker);
2748
+ }
2749
+ }
2750
+ let lastReply = -1;
2751
+ for (let index = to - 1; index >= from; index -= 1) {
2752
+ if (isReply(blocks[index])) {
2753
+ lastReply = index;
2754
+ break;
2755
+ }
2756
+ }
2757
+ for (const [index, isRecovered] of recovered) {
2758
+ flags.set(index, {
2759
+ recovered: isRecovered,
2760
+ terminal: index === lastReply && status === "failed" && blocks[index].kind !== "custom_message" && !isRecovered
2761
+ });
2762
+ }
2763
+ }
2764
+ function isPending(status) {
2765
+ return status === "running" || status === "pending";
2766
+ }
2767
+ function withFlags(turn, laterTurnProgress) {
2768
+ const { blocks } = turn;
2769
+ if (!blocks.some((block) => failureOwner(block) !== void 0))
2770
+ return turn;
2771
+ const flags = /* @__PURE__ */ new Map();
2772
+ const prefix = turn.settledBlockCount ?? 0;
2773
+ if (isPending(turn.status) && prefix > 0) {
2774
+ const continuation = blocks.slice(prefix);
2775
+ stretchFlags(blocks, 0, prefix, turn.settledStatus ?? "succeeded", laterTurnProgress || showsProgress(continuation, failedSources(blocks)), flags);
2776
+ stretchFlags(blocks, prefix, blocks.length, turn.status, laterTurnProgress, flags);
2777
+ } else {
2778
+ stretchFlags(blocks, 0, blocks.length, turn.status, laterTurnProgress, flags);
2779
+ }
2780
+ let changed = false;
2781
+ const flagged = blocks.map((block, index) => {
2782
+ const flag = flags.get(index);
2783
+ if (flag === void 0 || !flag.recovered && !flag.terminal)
2784
+ return block;
2785
+ changed = true;
2786
+ return {
2787
+ ...block,
2788
+ ...flag.recovered ? { recovered: true } : {},
2789
+ ...flag.terminal ? { terminal: true } : {}
2790
+ };
2791
+ });
2792
+ return changed ? { ...turn, blocks: flagged } : turn;
2793
+ }
2794
+ function withRecoveryFlags(turns) {
2795
+ let laterTurnProgress = false;
2796
+ let result;
2797
+ for (let index = turns.length - 1; index >= 0; index -= 1) {
2798
+ const turn = turns[index];
2799
+ if (turn.kind !== "agent")
2800
+ continue;
2801
+ const flagged = withFlags(turn, laterTurnProgress);
2802
+ if (flagged !== turn) {
2803
+ result ??= [...turns];
2804
+ result[index] = flagged;
2805
+ }
2806
+ laterTurnProgress ||= showsProgress(turn.blocks, failedSources(turn.blocks));
2807
+ }
2808
+ return result ?? turns;
2809
+ }
2810
+
2811
+ // packages/herd-transcript/dist/interactive/canonical-transcript.js
2812
+ var UNKNOWN_ACTIVITY_CUSTOM_TYPE2 = "herd.unknown_activity";
2813
+ function isSteerContinuation(items, index, completedRunBoundaryItemIds) {
2814
+ const item = items[index];
2815
+ const stamped = item?.type === "message" ? item.deliveredVia : void 0;
2816
+ if (stamped === "steer")
2817
+ return true;
2818
+ if (stamped === "prompt" || stamped === "next_turn")
2819
+ return false;
2820
+ let lastAssistantIndex = -1;
2821
+ for (let scan = index - 1; scan >= 0; scan -= 1) {
2822
+ const candidate = items[scan];
2823
+ if (candidate?.type === "message" && candidate.role === "assistant") {
2824
+ lastAssistantIndex = scan;
2825
+ break;
2826
+ }
2827
+ }
2828
+ if (lastAssistantIndex === -1)
2829
+ return false;
2830
+ const lastAssistant = items[lastAssistantIndex];
2831
+ if (completedRunBoundaryItemIds !== void 0) {
2832
+ for (let scan = lastAssistantIndex; scan < index; scan += 1) {
2833
+ const candidate = items[scan];
2834
+ if (candidate !== void 0 && completedRunBoundaryItemIds.has(boundaryAnchorKey(candidate)))
2835
+ return false;
2836
+ }
2837
+ }
2838
+ if (lastAssistant.runAborted)
2839
+ return false;
2840
+ if (lastAssistant.status === "streaming")
2841
+ return true;
2842
+ if (lastAssistant.finishReason === "tool_use") {
2843
+ if (hasTerminalFinalOutputInRange(items, lastAssistantIndex, index)) {
2844
+ return false;
2845
+ }
2846
+ if (hasInterruptedWorkInRange(items, lastAssistantIndex, index)) {
2847
+ return false;
2848
+ }
2849
+ return true;
2850
+ }
2851
+ if (lastAssistant.finishReason !== void 0)
2852
+ return false;
2853
+ for (let scan = 0; scan < index; scan += 1) {
2854
+ const candidate = items[scan];
2855
+ if (candidate?.type === "tool" && candidate.backgroundTaskId === void 0 && (candidate.status === "running" || candidate.status === "declared" || candidate.status === "arguments_complete")) {
2856
+ return true;
2857
+ }
2858
+ }
2859
+ return false;
2860
+ }
2861
+ function hasInterruptedWorkInRange(items, from, to) {
2862
+ for (let scan = from; scan < to; scan += 1) {
2863
+ const item = items[scan];
2864
+ if (item?.type === "tool" && item.backgroundTaskId === void 0 && (item.status === "interrupted" || item.status === "cancelled")) {
2865
+ return true;
2866
+ }
2867
+ }
2868
+ return false;
2869
+ }
2870
+ function companionIntentId(item) {
2871
+ const details = item.details;
2872
+ if (details === null || typeof details !== "object")
2873
+ return void 0;
2874
+ const value = details["clientIntentId"];
2875
+ return typeof value === "string" && value.length > 0 ? value : void 0;
2876
+ }
2877
+ function indexUserMessages(items) {
2878
+ let indexById;
2879
+ return (id) => {
2880
+ if (indexById === void 0) {
2881
+ indexById = /* @__PURE__ */ new Map();
2882
+ for (const [index, item] of items.entries()) {
2883
+ if (item.type === "message" && item.role === "user" && !indexById.has(item.id))
2884
+ indexById.set(item.id, index);
2885
+ }
2886
+ }
2887
+ return indexById.get(id) ?? -1;
2888
+ };
2889
+ }
2890
+ function isSendCompanion(item, placements) {
2891
+ return item.role === "custom" && placementOfCustomMessage(item, placements) === "companion-of-send";
2892
+ }
2893
+ function companionOwnerIndex(items, index, completedRunBoundaryItemIds, userMessageIndexOf, placements) {
2894
+ const item = items[index];
2895
+ if (item?.type !== "message")
2896
+ return void 0;
2897
+ const intentId = companionIntentId(item);
2898
+ if (intentId !== void 0) {
2899
+ const owner = userMessageIndexOf(intentId);
2900
+ return owner < 0 ? void 0 : owner;
2901
+ }
2902
+ const neighbors = [];
2903
+ for (const step of [1, -1]) {
2904
+ for (let scan = index + step; scan >= 0 && scan < items.length; scan += step) {
2905
+ const candidate = items[scan];
2906
+ if (candidate?.type === "message" && (candidate.role === "system" || isSendCompanion(candidate, placements)))
2907
+ continue;
2908
+ if (candidate?.type === "message" && candidate.role === "user")
2909
+ neighbors.push(scan);
2910
+ break;
2911
+ }
2912
+ }
2913
+ return neighbors.find((neighbor) => isSteerContinuation(items, neighbor, completedRunBoundaryItemIds)) ?? neighbors[0];
2914
+ }
2915
+ var attachmentOnlyUsers = /* @__PURE__ */ new WeakMap();
2916
+ function attachmentOnlyUser(item) {
2917
+ const cached = attachmentOnlyUsers.get(item);
2918
+ if (cached !== void 0)
2919
+ return cached;
2920
+ const user = {
2921
+ id: item.id,
2922
+ type: "message",
2923
+ role: "user",
2924
+ status: item.status,
2925
+ text: "",
2926
+ parts: [],
2927
+ ...item.entryId === void 0 ? {} : { entryId: item.entryId },
2928
+ ...item.startedAt === void 0 ? {} : { startedAt: item.startedAt },
2929
+ ...item.completedAt === void 0 ? {} : { completedAt: item.completedAt }
2930
+ };
2931
+ attachmentOnlyUsers.set(item, user);
2932
+ return user;
2933
+ }
2934
+ function isCardAnswerInput(items, index, placements, completedRunBoundaryItemIds) {
2935
+ const item = items[index];
2936
+ if (item?.type !== "message" || item.role !== "custom" || placementOfCustomMessage(item, placements) !== "opens-turn")
2937
+ return false;
2938
+ return !isSteerContinuation(items, index, completedRunBoundaryItemIds);
2939
+ }
2940
+ function attachmentOnlyInput(items, index, completedRunBoundaryItemIds, userMessageIndexOf, placements) {
2941
+ const item = items[index];
2942
+ if (item?.type !== "message" || item.role !== "custom" || item.customType !== ATTACHMENTS_CUSTOM_TYPE)
2943
+ return false;
2944
+ const details = item.details;
2945
+ return Array.isArray(details?.refs) && details.refs.length > 0 && companionOwnerIndex(items, index, completedRunBoundaryItemIds, userMessageIndexOf, placements) === void 0;
2946
+ }
2947
+ function freshPromptCompanions(items, completedRunBoundaryItemIds, userMessageIndexOf, placements) {
2948
+ const byUser = /* @__PURE__ */ new Map();
2949
+ items.forEach((item, index) => {
2950
+ if (item.type === "message" && item.role === "user" && !isSteerContinuation(items, index, completedRunBoundaryItemIds))
2951
+ byUser.set(item.id, {});
2952
+ });
2953
+ const consumed = /* @__PURE__ */ new Set();
2954
+ items.forEach((item, index) => {
2955
+ if (item.type !== "message" || item.role !== "custom")
2956
+ return;
2957
+ const slot = item.customType === ATTACHMENTS_CUSTOM_TYPE ? "attachments" : item.customType === DYNAMIC_CONTEXT_CUSTOM_TYPE ? "dynamicContext" : item.customType === USER_INVOKED_CUSTOM_TYPE ? "invoked" : item.customType === USER_PASTED_CONTENT_CUSTOM_TYPE ? "pastedContent" : void 0;
2958
+ if (slot === void 0)
2959
+ return;
2960
+ const ownerIndex = companionOwnerIndex(items, index, completedRunBoundaryItemIds, userMessageIndexOf, placements);
2961
+ const owner = ownerIndex === void 0 ? void 0 : items[ownerIndex]?.id;
2962
+ const paired = owner === void 0 ? void 0 : byUser.get(owner);
2963
+ if (owner !== void 0 && paired !== void 0 && paired[slot] === void 0) {
2964
+ byUser.set(owner, { ...paired, [slot]: item });
2965
+ consumed.add(item.id);
2966
+ }
2967
+ });
2968
+ return { byUser, consumed };
2969
+ }
2970
+ function projectCanonicalTranscript(state, placements) {
2971
+ const outside = (item) => isOutsideTranscript(item, placements);
2972
+ const items = dropRepeatedDeliveries(state.items.some(outside) ? state.items.filter((item) => !outside(item)) : state.items);
2973
+ const projectedState = items === state.items ? state : { ...state, items };
2974
+ const anchorIndex = indexCompletedRunBoundaryAnchorsOverKeptItems(state.completedRunBoundaryAnchors, state.items, items);
2975
+ const completedRunBoundaryItemIds = anchorIndex?.keys;
2976
+ const userMessageIndexOf = indexUserMessages(items);
2977
+ const promptCompanions = freshPromptCompanions(items, completedRunBoundaryItemIds, userMessageIndexOf, placements);
2978
+ const turns = [];
2979
+ const segments = [];
2980
+ let agentItems = [];
2981
+ let causedByUserMessageId;
2982
+ let causeItem;
2983
+ const flushAgent = () => {
2984
+ if (agentItems[0] === void 0)
2985
+ return false;
2986
+ segments.push({
2987
+ slot: turns.length,
2988
+ items: agentItems,
2989
+ causedByUserMessageId,
2990
+ causeItem
2991
+ });
2992
+ turns.push(void 0);
2993
+ agentItems = [];
2994
+ return true;
2995
+ };
2996
+ for (const [index, item] of items.entries()) {
2997
+ if (item.type === "message" && item.role === "system")
2998
+ continue;
2999
+ if (item.type === "message" && item.role === "user") {
3000
+ if (isSteerContinuation(items, index, completedRunBoundaryItemIds)) {
3001
+ agentItems.push(item);
3002
+ if (causedByUserMessageId === void 0) {
3003
+ causedByUserMessageId = item.id;
3004
+ causeItem = item;
3005
+ }
3006
+ continue;
3007
+ }
3008
+ flushAgent();
3009
+ turns.push({
3010
+ kind: "user",
3011
+ id: canonicalId("user-turn", item.id),
3012
+ sourceMessageId: item.id,
3013
+ text: item.text,
3014
+ message: item,
3015
+ ...promptCompanions.byUser.get(item.id)
3016
+ });
3017
+ causedByUserMessageId = item.id;
3018
+ causeItem = item;
3019
+ continue;
3020
+ }
3021
+ if (attachmentOnlyInput(items, index, completedRunBoundaryItemIds, userMessageIndexOf, placements) && item.type === "message") {
3022
+ const user = attachmentOnlyUser(item);
3023
+ flushAgent();
3024
+ turns.push({
3025
+ kind: "user",
3026
+ id: canonicalId("user-turn", user.id),
3027
+ sourceMessageId: user.id,
3028
+ text: "",
3029
+ message: user,
3030
+ attachments: item
3031
+ });
3032
+ causedByUserMessageId = user.id;
3033
+ causeItem = user;
3034
+ continue;
3035
+ }
3036
+ if (isCardAnswerInput(items, index, placements, completedRunBoundaryItemIds) && item.type === "message") {
3037
+ flushAgent();
3038
+ turns.push({
3039
+ kind: "custom",
3040
+ id: canonicalId("card-answer", item.id),
3041
+ sourceMessageId: item.id,
3042
+ message: item
3043
+ });
3044
+ causedByUserMessageId = item.id;
3045
+ causeItem = item;
3046
+ continue;
3047
+ }
3048
+ if (promptCompanions.consumed.has(item.id))
3049
+ continue;
3050
+ agentItems.push(item);
3051
+ }
3052
+ flushAgent();
3053
+ const latestSegment = segments[segments.length - 1];
3054
+ const transcriptEndsWithAgentSegment = turns[turns.length - 1] === void 0;
3055
+ for (const segment of segments) {
3056
+ turns[segment.slot] = projectAgentTurn(segment.items, segment.causedByUserMessageId, segment.causeItem, transcriptEndsWithAgentSegment && segment === latestSegment, projectedState, anchorIndex, placements);
3057
+ }
3058
+ return {
3059
+ turns: withRecoveryFlags(turns.filter((turn) => turn !== void 0))
3060
+ };
3061
+ }
3062
+ function dropRepeatedDeliveries(items) {
3063
+ const seen = /* @__PURE__ */ new Set();
3064
+ let dropped = false;
3065
+ const kept = items.filter((item) => {
3066
+ if (item.type !== "message" || item.role !== "custom")
3067
+ return true;
3068
+ const details = item.details;
3069
+ if (details === null || typeof details !== "object")
3070
+ return true;
3071
+ const deliveryId = details["deliveryId"];
3072
+ if (typeof deliveryId !== "string" || deliveryId.length === 0)
3073
+ return true;
3074
+ const key = `${item.customType ?? ""}\0${deliveryId}`;
3075
+ if (seen.has(key)) {
3076
+ dropped = true;
3077
+ return false;
3078
+ }
3079
+ seen.add(key);
3080
+ return true;
3081
+ });
3082
+ return dropped ? kept : items;
3083
+ }
3084
+ function isOutsideTranscript(item, placements) {
3085
+ return item.type === "message" && item.role === "custom" && placementOfCustomMessage(item, placements) === "outside-transcript";
3086
+ }
3087
+ function projectAgentTurn(items, causedByUserMessageId, causeItem, isLatestTurn, state, anchorIndex, placements) {
3088
+ const first = items[0];
3089
+ if (first === void 0) {
3090
+ throw new Error("Cannot project an empty agent turn");
3091
+ }
3092
+ const turnId = canonicalId("agent-turn", causedByUserMessageId ?? canonicalSourceId(first));
3093
+ const responseSequence = /* @__PURE__ */ new Map();
3094
+ const thinking = [];
3095
+ let nextResponseSequence = 1;
3096
+ let nextStreamStage = 0;
3097
+ const allocateStreamStage = () => nextStreamStage++;
3098
+ const hasRequiredFinalOutputRepair = items.some((item) => item.type === "message" && isRequiredFinalOutputRepairMessage(item));
3099
+ const boundaryFinalProseMessageKeys = finalProseKeysAtCompletedBoundaries(items, anchorIndex);
3100
+ const finalProseMessageKeys = /* @__PURE__ */ new Set([
3101
+ ...boundaryFinalProseMessageKeys,
3102
+ ...items.flatMap((item, itemIndex) => {
3103
+ if (item.type !== "tool" || item.status !== "complete" || item.name !== RESERVED_FINAL_OUTPUT_TOOL_NAME) {
3104
+ return [];
3105
+ }
3106
+ const capture = finalOutputCaptureFromDetails(item.toolCallId, item.resultDetails);
3107
+ if (capture === void 0 || capture.message !== void 0 || !isTerminalFinalOutput(items, itemIndex))
3108
+ return [];
3109
+ return [item.sourceMessageId, item.responseId].filter((key) => key !== void 0);
3110
+ })
3111
+ ]);
3112
+ for (const item of items) {
3113
+ if (item.type !== "message" || item.role !== "assistant")
3114
+ continue;
3115
+ responseSequence.set(item.id, nextResponseSequence++);
3116
+ thinking.push(...thinkingAnnotations(item));
3117
+ }
3118
+ const blocks = [];
3119
+ const settledItemCount = isLatestTurn ? completedPrefixItemCount(items, anchorIndex?.keys) : 0;
3120
+ let settledBlockCount = 0;
3121
+ let waveBuffer = [];
3122
+ let episodeWaves = [];
3123
+ let episodeHasThinking = false;
3124
+ let episodeStatuses = [];
3125
+ let episodeIdentity;
3126
+ const registerThinkingActivity = (annotations, status2) => {
3127
+ if (annotations.length === 0)
3128
+ return;
3129
+ episodeIdentity ??= annotations[0]?.responseId;
3130
+ episodeHasThinking = true;
3131
+ episodeStatuses.push(status2);
3132
+ };
3133
+ const flushEpisode = () => {
3134
+ if (episodeWaves.length === 0 && !episodeHasThinking)
3135
+ return;
3136
+ const firstWave = episodeWaves[0];
3137
+ const sourceId = episodeIdentity ?? firstWave?.responseId ?? firstWave?.sourceMessageId ?? firstWave?.id ?? turnId;
3138
+ blocks.push({
3139
+ kind: "work_episode",
3140
+ id: canonicalId("work-episode", sourceId),
3141
+ status: aggregateStatus(episodeStatuses),
3142
+ waves: episodeWaves
3143
+ });
3144
+ episodeWaves = [];
3145
+ episodeHasThinking = false;
3146
+ episodeStatuses = [];
3147
+ episodeIdentity = void 0;
3148
+ };
3149
+ const flushWave = () => {
3150
+ const firstAttempt = waveBuffer[0];
3151
+ if (firstAttempt === void 0)
3152
+ return;
3153
+ const wave = projectWave(canonicalToolWaveId(firstAttempt), waveBuffer, responseSequence);
3154
+ episodeIdentity ??= wave.responseId ?? wave.sourceMessageId ?? firstAttempt.responseId;
3155
+ episodeWaves.push(wave);
3156
+ episodeStatuses.push(wave.status);
3157
+ waveBuffer = [];
3158
+ };
3159
+ const pendingAttachments = [];
3160
+ const pendingDynamicContext = [];
3161
+ for (let itemIndex = 0; itemIndex < items.length; itemIndex += 1) {
3162
+ const item = items[itemIndex];
3163
+ if (item === void 0)
3164
+ continue;
3165
+ if (itemIndex === settledItemCount) {
3166
+ flushWave();
3167
+ flushEpisode();
3168
+ settledBlockCount = blocks.length;
3169
+ }
3170
+ if (item.type === "tool") {
3171
+ if (waveBuffer.length > 0 && waveBuffer[0] !== void 0 && canonicalToolWaveId(waveBuffer[0]) !== canonicalToolWaveId(item)) {
3172
+ flushWave();
3173
+ }
3174
+ waveBuffer.push(item);
3175
+ continue;
3176
+ }
3177
+ flushWave();
3178
+ if (item.role === "user") {
3179
+ flushEpisode();
3180
+ let claimedIndex = pendingAttachments.findIndex((pending2) => pending2.intentId === item.id);
3181
+ if (claimedIndex === -1) {
3182
+ claimedIndex = pendingAttachments.findIndex((pending2) => pending2.intentId === void 0);
3183
+ }
3184
+ const claimed = claimedIndex === -1 ? void 0 : pendingAttachments.splice(claimedIndex, 1)[0];
3185
+ let claimedDynamicContextIndex = pendingDynamicContext.findIndex((pending2) => pending2.intentId === item.id);
3186
+ if (claimedDynamicContextIndex === -1) {
3187
+ claimedDynamicContextIndex = pendingDynamicContext.findIndex((pending2) => pending2.intentId === void 0);
3188
+ }
3189
+ const claimedDynamicContext = claimedDynamicContextIndex === -1 ? void 0 : pendingDynamicContext.splice(claimedDynamicContextIndex, 1)[0];
3190
+ blocks.push({
3191
+ kind: "steer_message",
3192
+ id: canonicalId("steer-message", item.id),
3193
+ sourceMessageId: item.id,
3194
+ message: item,
3195
+ ...claimed === void 0 ? {} : { attachments: claimed.item },
3196
+ ...claimedDynamicContext === void 0 ? {} : { dynamicContext: claimedDynamicContext.item }
3197
+ });
3198
+ continue;
3199
+ }
3200
+ if (item.role === "assistant") {
3201
+ const annotations = thinkingAnnotations(item);
3202
+ const response = responseBlocks(item, responseSequence.get(item.id) ?? nextResponseSequence++, allocateStreamStage, hasRequiredFinalOutputRepair, finalProseMessageKeys.has(item.id) || item.responseId !== void 0 && finalProseMessageKeys.has(item.responseId));
3203
+ const narration = response.filter((block) => block.kind === "narration");
3204
+ const following = response.filter((block) => block.kind !== "narration");
3205
+ if (narration.length > 0) {
3206
+ flushEpisode();
3207
+ blocks.push(...narration);
3208
+ registerThinkingActivity(annotations, messageStatus(item));
3209
+ blocks.push(...following);
3210
+ continue;
3211
+ }
3212
+ registerThinkingActivity(annotations, messageStatus(item));
3213
+ if (following.length > 0) {
3214
+ flushEpisode();
3215
+ blocks.push(...following);
3216
+ }
3217
+ continue;
3218
+ }
3219
+ if (isRequiredFinalOutputRepairMessage(item))
3220
+ continue;
3221
+ if (item.role === "custom" && item.customType === DYNAMIC_CONTEXT_CUSTOM_TYPE) {
3222
+ const intentId = companionIntentId(item);
3223
+ if (intentId !== void 0) {
3224
+ const owner = blocks.findLast((block) => block.kind === "steer_message" && block.sourceMessageId === intentId);
3225
+ if (owner !== void 0 && owner.kind === "steer_message") {
3226
+ if (owner.dynamicContext === void 0) {
3227
+ const ownerIndex = blocks.lastIndexOf(owner);
3228
+ blocks[ownerIndex] = { ...owner, dynamicContext: item };
3229
+ continue;
3230
+ }
3231
+ } else if (userItemIndexAfterById(items, itemIndex, intentId) >= 0) {
3232
+ pendingDynamicContext.push({ item, intentId });
3233
+ continue;
3234
+ }
3235
+ } else {
3236
+ const last = blocks[blocks.length - 1];
3237
+ if (last?.kind === "steer_message" && last.dynamicContext === void 0) {
3238
+ blocks[blocks.length - 1] = { ...last, dynamicContext: item };
3239
+ continue;
3240
+ }
3241
+ if (hasUserItemAfter(items, itemIndex) && !pendingDynamicContext.some((pending2) => pending2.intentId === void 0)) {
3242
+ pendingDynamicContext.push({ item, intentId: void 0 });
3243
+ continue;
3244
+ }
3245
+ }
3246
+ }
3247
+ if (item.role === "custom" && item.customType === ATTACHMENTS_CUSTOM_TYPE) {
3248
+ const intentId = companionIntentId(item);
3249
+ if (intentId !== void 0) {
3250
+ const owner = blocks.findLast((block) => block.kind === "steer_message" && block.sourceMessageId === intentId);
3251
+ if (owner !== void 0 && owner.kind === "steer_message") {
3252
+ if (owner.attachments === void 0) {
3253
+ const ownerIndex = blocks.lastIndexOf(owner);
3254
+ blocks[ownerIndex] = { ...owner, attachments: item };
3255
+ continue;
3256
+ }
3257
+ } else if (userItemIndexAfterById(items, itemIndex, intentId) >= 0) {
3258
+ pendingAttachments.push({ item, intentId });
3259
+ continue;
3260
+ }
3261
+ } else if (hasUserItemAfter(items, itemIndex)) {
3262
+ if (!pendingAttachments.some((pending2) => pending2.intentId === void 0)) {
3263
+ pendingAttachments.push({ item, intentId: void 0 });
3264
+ continue;
3265
+ }
3266
+ } else {
3267
+ const last = blocks[blocks.length - 1];
3268
+ if (last?.kind === "steer_message" && last.attachments === void 0) {
3269
+ blocks[blocks.length - 1] = { ...last, attachments: item };
3270
+ continue;
3271
+ }
3272
+ }
3273
+ }
3274
+ if (item.role === "custom" && item.customType !== UNKNOWN_ACTIVITY_CUSTOM_TYPE2) {
3275
+ flushEpisode();
3276
+ blocks.push({
3277
+ kind: "custom_message",
3278
+ id: canonicalId("custom-message", item.id),
3279
+ sourceMessageId: item.id,
3280
+ message: item
3281
+ });
3282
+ continue;
3283
+ }
3284
+ if (!(item.role === "custom" && item.customType === UNKNOWN_ACTIVITY_CUSTOM_TYPE2)) {
3285
+ continue;
3286
+ }
3287
+ flushEpisode();
3288
+ const sequence = responseSequence.get(item.id) ?? nextResponseSequence++;
3289
+ blocks.push(...responseBlocks(item, sequence, allocateStreamStage));
3290
+ }
3291
+ flushWave();
3292
+ flushEpisode();
3293
+ for (const pending2 of pendingAttachments) {
3294
+ blocks.push({
3295
+ kind: "custom_message",
3296
+ id: canonicalId("custom-message", pending2.item.id),
3297
+ sourceMessageId: pending2.item.id,
3298
+ message: pending2.item
3299
+ });
3300
+ }
3301
+ for (const pending2 of pendingDynamicContext) {
3302
+ blocks.push({
3303
+ kind: "custom_message",
3304
+ id: canonicalId("custom-message", pending2.item.id),
3305
+ sourceMessageId: pending2.item.id,
3306
+ message: pending2.item
3307
+ });
3308
+ }
3309
+ const span = turnSpan(causeItem === void 0 ? items : [causeItem, ...items]);
3310
+ const status = agentTurnStatus(blocks, items, state, isLatestTurn, placements);
3311
+ if (settledItemCount === items.length)
3312
+ settledBlockCount = blocks.length;
3313
+ const pending = isLatestTurn && (status === "running" || status === "pending");
3314
+ const hasUnfinishedPrefix = pending && blocks.slice(0, settledBlockCount).some((block) => {
3315
+ const blockStatus = "status" in block ? block.status : "succeeded";
3316
+ return blockStatus === "running" || blockStatus === "pending";
3317
+ });
3318
+ if (hasUnfinishedPrefix)
3319
+ settledBlockCount = 0;
3320
+ const settledItems = pending && settledBlockCount > 0 ? items.slice(0, settledItemCount) : [];
3321
+ const settledStatus = settledItems.length === 0 ? void 0 : agentTurnStatus(blocks.slice(0, settledBlockCount), settledItems, state, false, placements);
3322
+ const settledCompletedAt = turnSpan(settledItems).completedAt;
3323
+ return {
3324
+ kind: "agent",
3325
+ id: turnId,
3326
+ ...causedByUserMessageId === void 0 ? {} : { causedByUserMessageId },
3327
+ status,
3328
+ ...pending ? { settledBlockCount } : {},
3329
+ ...settledStatus === void 0 ? {} : { settledStatus },
3330
+ ...settledCompletedAt === void 0 ? {} : { settledCompletedAt },
3331
+ thinking,
3332
+ blocks,
3333
+ ...span.startedAt === void 0 ? {} : { startedAt: span.startedAt },
3334
+ ...span.completedAt === void 0 ? {} : { completedAt: span.completedAt }
3335
+ };
3336
+ }
3337
+ function turnSpan(items) {
3338
+ let startedAt;
3339
+ let startedAtMs = Infinity;
3340
+ let completedAt;
3341
+ let completedAtMs = -Infinity;
3342
+ const consider = (value) => {
3343
+ if (value === void 0)
3344
+ return;
3345
+ const ms = Date.parse(value);
3346
+ if (Number.isNaN(ms))
3347
+ return;
3348
+ if (ms < startedAtMs) {
3349
+ startedAtMs = ms;
3350
+ startedAt = value;
3351
+ }
3352
+ if (ms > completedAtMs) {
3353
+ completedAtMs = ms;
3354
+ completedAt = value;
3355
+ }
3356
+ };
3357
+ for (const item of items) {
3358
+ consider(item.startedAt);
3359
+ consider(item.completedAt);
3360
+ }
3361
+ return { startedAt, completedAt };
3362
+ }
3363
+ function responseBlocks(message, responseSequence, allocateStreamStage, forceFinalTextProvisional = false, promoteNarrationToFinal = false) {
3364
+ const responseId = message.responseId ?? message.id;
3365
+ const result = [];
3366
+ for (const segment of textBlockSegments(message)) {
3367
+ const effectivePhase = promoteNarrationToFinal && segment.phase === "narration" ? "final" : segment.phase;
3368
+ const phase = forceFinalTextProvisional && !promoteNarrationToFinal && effectivePhase === "final" ? "provisional" : effectivePhase;
3369
+ const blockBase = {
3370
+ id: segment.id,
3371
+ responseId,
3372
+ sourceMessageId: message.id,
3373
+ responseSequence,
3374
+ streamStage: allocateStreamStage(),
3375
+ status: messageStatus(message),
3376
+ text: segment.text,
3377
+ textOffset: segment.textOffset,
3378
+ source: message,
3379
+ ...segment.continuesResponse ? { continuesResponse: true } : {}
3380
+ };
3381
+ switch (phase) {
3382
+ case "narration":
3383
+ result.push({ kind: "narration", ...blockBase, phase: "narration" });
3384
+ break;
3385
+ case "final":
3386
+ result.push({ kind: "final_answer", ...blockBase, phase: "final" });
3387
+ break;
3388
+ case "interrupted":
3389
+ case "error":
3390
+ case "provisional":
3391
+ case void 0:
3392
+ result.push({
3393
+ kind: "provisional_response",
3394
+ ...blockBase,
3395
+ phase: phase ?? "provisional"
3396
+ });
3397
+ break;
3398
+ }
3399
+ }
3400
+ message.parts.forEach((part, index) => {
3401
+ if (part.type !== "unknown")
3402
+ return;
3403
+ result.push({
3404
+ kind: "unknown_activity",
3405
+ id: canonicalId("unknown-activity", `${responseId}:${index}`),
3406
+ responseId,
3407
+ sourceMessageId: message.id,
3408
+ responseSequence,
3409
+ ...part.providerType === void 0 ? {} : { providerType: part.providerType },
3410
+ value: part.value,
3411
+ source: message
3412
+ });
3413
+ });
3414
+ return result;
3415
+ }
3416
+ function textBlockSegments(message) {
3417
+ const responseId = message.responseId ?? message.id;
3418
+ const singleBlockId = canonicalId("response-block", responseId);
3419
+ const textParts = message.parts.filter((part) => part.type === "text");
3420
+ const honorDeclared = message.status !== "streaming" && textParts.some((part) => part.declaredPhase !== void 0);
3421
+ if (!honorDeclared) {
3422
+ const text = message.text !== "" ? message.text : textParts.map((part) => part.text).join("");
3423
+ if (!hasVisibleText(text) && !(message.role === "assistant" && message.status === "streaming" && message.parts.length === 0)) {
3424
+ return [];
3425
+ }
3426
+ return [
3427
+ { id: singleBlockId, phase: message.textPhase, text, textOffset: 0 }
3428
+ ];
3429
+ }
3430
+ const runs = [];
3431
+ let sourceOffset = 0;
3432
+ for (const part of textParts) {
3433
+ const phase = part.declaredPhase ?? message.textPhase;
3434
+ const current = runs.at(-1);
3435
+ if (current !== void 0 && current.phase === phase) {
3436
+ current.text += part.text;
3437
+ } else {
3438
+ runs.push({ phase, text: part.text, textOffset: sourceOffset });
3439
+ }
3440
+ sourceOffset += part.text.length;
3441
+ }
3442
+ return runs.map((run, index) => ({
3443
+ id: index === 0 ? singleBlockId : canonicalId("response-block", `${responseId}:${index}`),
3444
+ phase: run.phase,
3445
+ text: run.text,
3446
+ textOffset: run.textOffset,
3447
+ ...index > 0 ? { continuesResponse: true } : {}
3448
+ })).filter((segment) => hasVisibleText(segment.text));
3449
+ }
3450
+ var VISIBLE_CHARACTER = /[^\p{White_Space}\p{Default_Ignorable_Code_Point}]/u;
3451
+ function hasVisibleText(text) {
3452
+ return VISIBLE_CHARACTER.test(text);
3453
+ }
3454
+ function thinkingAnnotations(message) {
3455
+ const responseId = message.responseId ?? message.id;
3456
+ return message.parts.flatMap((part, index) => part.type === "thinking" ? [
3457
+ {
3458
+ id: canonicalId("thinking", `${responseId}:${index}`),
3459
+ responseId,
3460
+ sourceMessageId: message.id,
3461
+ text: part.text
3462
+ }
3463
+ ] : []);
3464
+ }
3465
+ function projectWave(waveId, tools, responseSequence) {
3466
+ const attempts = tools.map((tool) => projectAttempt(tool, waveId));
3467
+ const first = tools[0];
3468
+ const sequence = first?.sourceMessageId === void 0 ? void 0 : responseSequence.get(first.sourceMessageId);
3469
+ return {
3470
+ id: waveId,
3471
+ ...first?.responseId === void 0 ? {} : { responseId: first.responseId },
3472
+ ...first?.sourceMessageId === void 0 ? {} : { sourceMessageId: first.sourceMessageId },
3473
+ ...sequence === void 0 ? {} : { responseSequence: sequence },
3474
+ status: aggregateStatus(attempts.map(attemptLifecycleStatus)),
3475
+ attempts
3476
+ };
3477
+ }
3478
+ function projectAttempt(tool, canonicalWaveId2) {
3479
+ const attemptId = tool.attemptId ?? canonicalId("tool-attempt", tool.id);
3480
+ return {
3481
+ id: attemptId,
3482
+ waveId: canonicalWaveId2,
3483
+ ...tool.backgroundTaskId === void 0 ? {} : { detached: true },
3484
+ ...tool.responseId === void 0 ? {} : { responseId: tool.responseId },
3485
+ ...tool.sourceMessageId === void 0 ? {} : { sourceMessageId: tool.sourceMessageId },
3486
+ correlationId: tool.toolCallId,
3487
+ generation: tool.attemptGeneration ?? 1,
3488
+ status: toolStatus(tool),
3489
+ ...optional("toolName", tool.name),
3490
+ ...optional("input", tool.argumentsText),
3491
+ ...optional("output", tool.resultText),
3492
+ ...tool.resultDetails === void 0 ? {} : { resultDetails: tool.resultDetails },
3493
+ ...finalOutputOf(tool),
3494
+ ...optional("error", tool.errorText),
3495
+ ...optional("startedAt", tool.startedAt),
3496
+ ...optional("completedAt", tool.completedAt),
3497
+ source: tool
3498
+ };
3499
+ }
3500
+ function finalOutputOf(tool) {
3501
+ if (tool.name !== RESERVED_FINAL_OUTPUT_TOOL_NAME)
3502
+ return {};
3503
+ const capture = finalOutputCaptureFromDetails(tool.toolCallId, tool.resultDetails);
3504
+ return capture === void 0 ? {} : { finalOutput: capture };
3505
+ }
3506
+ function hasUserItemAfter(items, index) {
3507
+ for (let scan = index + 1; scan < items.length; scan += 1) {
3508
+ const candidate = items[scan];
3509
+ if (candidate?.type === "message" && candidate.role === "user") {
3510
+ return true;
3511
+ }
3512
+ }
3513
+ return false;
3514
+ }
3515
+ function userItemIndexAfterById(items, index, id) {
3516
+ for (let scan = index + 1; scan < items.length; scan += 1) {
3517
+ const candidate = items[scan];
3518
+ if (candidate?.type === "message" && candidate.role === "user" && candidate.id === id) {
3519
+ return scan;
3520
+ }
3521
+ }
3522
+ return -1;
3523
+ }
3524
+ function messageStatus(message) {
3525
+ if (message.status === "streaming")
3526
+ return "running";
3527
+ const finishReason = message.finishReason;
3528
+ if (finishReason === void 0) {
3529
+ switch (message.status) {
3530
+ case "interrupted":
3531
+ return "interrupted";
3532
+ case "error":
3533
+ return "failed";
3534
+ case "complete":
3535
+ return "succeeded";
3536
+ }
3537
+ }
3538
+ switch (finishReason) {
3539
+ case "interrupted":
3540
+ return "interrupted";
3541
+ case "cancelled":
3542
+ return "cancelled";
3543
+ case "error":
3544
+ return "failed";
3545
+ case "complete":
3546
+ case "tool_use":
3547
+ case "unknown":
3548
+ return "succeeded";
3549
+ }
3550
+ }
3551
+ function toolStatus(tool) {
3552
+ switch (tool.status) {
3553
+ case "declared":
3554
+ case "arguments_complete":
3555
+ return "pending";
3556
+ case "running":
3557
+ return "running";
3558
+ case "complete":
3559
+ return "succeeded";
3560
+ case "error":
3561
+ return "failed";
3562
+ case "interrupted":
3563
+ return "interrupted";
3564
+ case "cancelled":
3565
+ return "cancelled";
3566
+ }
3567
+ }
3568
+ function aggregateStatus(statuses) {
3569
+ if (statuses.includes("failed"))
3570
+ return "failed";
3571
+ if (statuses.includes("interrupted"))
3572
+ return "interrupted";
3573
+ if (statuses.includes("cancelled"))
3574
+ return "cancelled";
3575
+ if (statuses.includes("running"))
3576
+ return "running";
3577
+ if (statuses.includes("pending"))
3578
+ return "pending";
3579
+ return "succeeded";
3580
+ }
3581
+ function agentTurnStatus(blocks, items, state, isLatestTurn, placements) {
3582
+ const runStatus = isLatestTurn ? state.run.status : void 0;
3583
+ if (runStatus === "aborted")
3584
+ return "interrupted";
3585
+ if (runStatus === "error")
3586
+ return "failed";
3587
+ const lastAssistant = items.findLast((item) => item.type === "message" && item.role === "assistant");
3588
+ if (isLatestTurn && lastAssistant?.status === "streaming")
3589
+ return "running";
3590
+ const hasContinuation = continuationFollowsLastAssistant(items, placements);
3591
+ const hasPendingBackground = isLatestTurn && hasPendingBackgroundWork(items, state);
3592
+ const hasAwaitableResult = isLatestTurn && hasTrailingAwaitableResult(items);
3593
+ if (runStatus === "running") {
3594
+ if (hasContinuation)
3595
+ return "running";
3596
+ if (hasPendingBackground)
3597
+ return "pending";
3598
+ if (lastAssistant !== void 0) {
3599
+ const terminal = terminalAssistantStatus(lastAssistant);
3600
+ if (terminal !== void 0)
3601
+ return terminal;
3602
+ }
3603
+ return "running";
3604
+ }
3605
+ if (lastAssistant?.runAborted)
3606
+ return "interrupted";
3607
+ if (hasPendingBackground || hasAwaitableResult)
3608
+ return "pending";
3609
+ if (hasTerminalFinalOutput(items))
3610
+ return "succeeded";
3611
+ if (hasExhaustedRequiredFinalOutputRepair(items))
3612
+ return "failed";
3613
+ if (lastAssistant !== void 0) {
3614
+ const terminal = terminalAssistantStatus(lastAssistant);
3615
+ if (terminal !== void 0)
3616
+ return terminal;
3617
+ }
3618
+ const finalAnswer = blocks.findLast((block) => block.kind === "final_answer");
3619
+ if (finalAnswer !== void 0)
3620
+ return finalAnswer.status;
3621
+ const statuses = new Set(blocks.flatMap((block) => {
3622
+ switch (block.kind) {
3623
+ case "narration":
3624
+ case "provisional_response":
3625
+ case "work_episode":
3626
+ return [block.status];
3627
+ // tool_surface is never produced; listed so this switch stays exhaustive.
3628
+ case "tool_surface":
3629
+ case "custom_message":
3630
+ case "steer_message":
3631
+ case "unknown_activity":
3632
+ return [];
3633
+ case "final_answer":
3634
+ return [block.status];
3635
+ }
3636
+ }));
3637
+ const responseFailed = blocks.some((block) => (block.kind === "narration" || block.kind === "provisional_response" || block.kind === "final_answer") && block.status === "failed");
3638
+ if (responseFailed)
3639
+ return "failed";
3640
+ if (statuses.has("interrupted"))
3641
+ return "interrupted";
3642
+ if (statuses.has("cancelled"))
3643
+ return "cancelled";
3644
+ if (statuses.has("running"))
3645
+ return "running";
3646
+ if (statuses.has("pending"))
3647
+ return "pending";
3648
+ return "succeeded";
3649
+ }
3650
+ function completedPrefixItemCount(items, completedRunBoundaryItemIds) {
3651
+ let prefixEnd = 0;
3652
+ let endedAt = 0;
3653
+ let endedWaveId;
3654
+ let continuationStart;
3655
+ for (let index = 0; index < items.length; index += 1) {
3656
+ const item = items[index];
3657
+ if (completedRunBoundaryItemIds?.has(boundaryAnchorKey(item)) === true) {
3658
+ endedAt = index + 1;
3659
+ endedWaveId = item.type === "tool" ? canonicalToolWaveId(item) : void 0;
3660
+ continuationStart = void 0;
3661
+ continue;
3662
+ }
3663
+ if (item.type === "tool" && item.backgroundTaskId === void 0 && (toolStatus(item) === "running" || toolStatus(item) === "pending")) {
3664
+ return endedAt > 0 && canonicalToolWaveId(item) !== endedWaveId ? endedAt : prefixEnd;
3665
+ }
3666
+ if (item.type === "message") {
3667
+ if (isRequiredFinalOutputRepairMessage(item)) {
3668
+ endedAt = 0;
3669
+ endedWaveId = void 0;
3670
+ continuationStart = void 0;
3671
+ continue;
3672
+ }
3673
+ if (item.role === "custom" && item.customType === COMPACTION_MARKER_CUSTOM_TYPE) {
3674
+ if (endedAt > 0)
3675
+ endedAt = index + 1;
3676
+ continue;
3677
+ }
3678
+ if (isEmbeddedAgentResultMessage(item) || isDaemonWakeMessage(item)) {
3679
+ continuationStart ??= index;
3680
+ if (endedAt > 0)
3681
+ prefixEnd = endedAt;
3682
+ endedAt = 0;
3683
+ endedWaveId = void 0;
3684
+ if (isDaemonWakeMessage(item))
3685
+ prefixEnd = Math.max(prefixEnd, continuationStart);
3686
+ continue;
3687
+ }
3688
+ if (item.role !== "assistant" && item.role !== "user") {
3689
+ if (endedAt > 0)
3690
+ endedAt = index + 1;
3691
+ continue;
3692
+ }
3693
+ }
3694
+ if (endedAt > 0 && endedWaveId !== void 0 && item.type === "tool" && canonicalToolWaveId(item) === endedWaveId) {
3695
+ endedAt = index + 1;
3696
+ continue;
3697
+ }
3698
+ if (endedAt > 0)
3699
+ prefixEnd = endedAt;
3700
+ endedAt = 0;
3701
+ endedWaveId = void 0;
3702
+ continuationStart = void 0;
3703
+ if (item.type === "message" && item.role === "assistant" && item.status === "complete" && terminalAssistantStatus(item) === "succeeded" || isTerminalFinalOutput(items, index)) {
3704
+ endedAt = index + 1;
3705
+ if (item.type === "tool")
3706
+ endedWaveId = canonicalToolWaveId(item);
3707
+ }
3708
+ }
3709
+ return endedAt > 0 ? items.length : prefixEnd;
3710
+ }
3711
+ function terminalAssistantStatus(message) {
3712
+ const finishReason = message.finishReason;
3713
+ if (finishReason === void 0) {
3714
+ if (message.status === "error")
3715
+ return "failed";
3716
+ if (message.status === "interrupted")
3717
+ return "interrupted";
3718
+ return void 0;
3719
+ }
3720
+ switch (finishReason) {
3721
+ case "error":
3722
+ return "failed";
3723
+ case "interrupted":
3724
+ return "interrupted";
3725
+ case "cancelled":
3726
+ return "cancelled";
3727
+ case "complete":
3728
+ return "succeeded";
3729
+ case "tool_use":
3730
+ case "unknown":
3731
+ return void 0;
3732
+ }
3733
+ }
3734
+ function canonicalSourceId(item) {
3735
+ return item.type === "tool" ? item.attemptId ?? canonicalId("tool-attempt", item.id) : item.id;
3736
+ }
3737
+ function optional(key, value) {
3738
+ return value === void 0 ? {} : { [key]: value };
3739
+ }
3740
+
3741
+ // packages/herd-transcript/dist/interactive/reconstruct.js
3742
+ function eventsForEntry(entry) {
3743
+ if (entry.type === "compaction") {
3744
+ return [
3745
+ {
3746
+ type: "session_compact",
3747
+ compactionEntry: entry,
3748
+ timestamp: entry.timestamp
3749
+ }
3750
+ ];
3751
+ }
3752
+ if (entry.type === "custom") {
3753
+ const boundary = runBoundaryReplayEvent(entry);
3754
+ return boundary === void 0 ? [] : [boundary];
3755
+ }
3756
+ if (entry.type !== void 0 && entry.type !== "message")
3757
+ return [];
3758
+ const body = asRecord3(entry.message);
3759
+ const role = body?.["role"];
3760
+ if (role === TOOL_RESULT_ROLE) {
3761
+ const toolCallId = body?.["toolCallId"];
3762
+ const isError = body?.["isError"] === true;
3763
+ const resultText = contentText(body?.["content"]);
3764
+ return [
3765
+ {
3766
+ type: "tool_execution_end",
3767
+ ...entry.id !== void 0 ? { entryId: entry.id } : {},
3768
+ toolCallId,
3769
+ toolName: body?.["toolName"],
3770
+ content: body?.["content"],
3771
+ details: body?.["details"],
3772
+ isError,
3773
+ timestamp: entry.timestamp,
3774
+ ...isError && resultText !== void 0 ? { error: resultText } : {}
3775
+ }
3776
+ ];
3777
+ }
3778
+ const base = {
3779
+ ...entry.id !== void 0 ? { id: entry.id, entryId: entry.id } : {},
3780
+ message: entry.message,
3781
+ timestamp: entry.timestamp
3782
+ };
3783
+ return [
3784
+ { ...base, type: "message_start" },
3785
+ { ...base, type: "message_end" }
3786
+ ];
3787
+ }
3788
+ function reconstructInteractiveState(entries) {
3789
+ function* replayEvents() {
3790
+ for (const entry of entries) {
3791
+ for (const event of eventsForEntry(entry)) {
3792
+ yield event;
3793
+ }
3794
+ }
3795
+ }
3796
+ return reduceInteractiveModeEventsForReplay(replayEvents());
3797
+ }
3798
+ function runBoundaryReplayEvent(entry) {
3799
+ if (entry.type !== "custom" || entry.customType !== "session_run_state") {
3800
+ return void 0;
3801
+ }
3802
+ const data = asRecord3(entry.data);
3803
+ const runState = data?.["runState"];
3804
+ switch (runState) {
3805
+ case "completed":
3806
+ case "failed":
3807
+ case "interrupted":
3808
+ case "cancelled":
3809
+ return {
3810
+ type: "host_run_status",
3811
+ run: {
3812
+ status: "settled",
3813
+ // Bare cancelled entries predate the interrupt/cancel split.
3814
+ outcome: runState === "cancelled" && data?.["stop"] === void 0 ? "interrupted" : runState
3815
+ }
3816
+ };
3817
+ default:
3818
+ return void 0;
3819
+ }
3820
+ }
3821
+ function contentText(content) {
3822
+ if (typeof content === "string")
3823
+ return content === "" ? void 0 : content;
3824
+ if (!Array.isArray(content))
3825
+ return void 0;
3826
+ const text = content.flatMap((part) => {
3827
+ const record = asRecord3(part);
3828
+ const value = record?.["text"];
3829
+ return typeof value === "string" ? [value] : [];
3830
+ }).join("");
3831
+ return text === "" ? void 0 : text;
3832
+ }
3833
+ function asRecord3(value) {
3834
+ return typeof value === "object" && value !== null ? value : void 0;
3835
+ }
3836
+ export {
3837
+ customMessagePlacement,
3838
+ eventsForEntry,
3839
+ projectCanonicalTranscript,
3840
+ reconstructInteractiveState,
3841
+ runBoundaryReplayEvent
3842
+ };