@ellipsis-dev/sdk 0.25.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-RMPAMUAE.js → chunk-YJC53TA7.js} +11 -1
- package/dist/index.d.ts +1760 -77
- package/dist/index.js +897 -91
- package/dist/store/index.d.ts +36 -4
- package/dist/store/index.js +452 -85
- package/dist/stream/index.d.ts +2 -2
- package/dist/stream/index.js +1 -1
- package/dist/{types-DJzmFABi.d.ts → types-B-jIFh4_.d.ts} +20476 -9961
- package/package.json +1 -1
- package/schema/collection_frames.schema.json +3623 -0
- package/schema/frames.schema.json +9543 -3114
- package/schema/lifecycle.schema.json +18 -0
- package/schema/openapi.v1.json +25191 -8381
- package/schema/trigger_fields.schema.json +1 -1
package/dist/store/index.js
CHANGED
|
@@ -1,6 +1,107 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SESSION_STREAM_PROTOCOL_VERSION
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-YJC53TA7.js";
|
|
4
|
+
|
|
5
|
+
// src/store/claude.ts
|
|
6
|
+
function claudePayload(record) {
|
|
7
|
+
if (record.kind === "claude_sdk") return record.payload;
|
|
8
|
+
if (record.kind !== "claude_code") return null;
|
|
9
|
+
const event = record.payload;
|
|
10
|
+
switch (event.type) {
|
|
11
|
+
case "assistant":
|
|
12
|
+
return {
|
|
13
|
+
...event.message,
|
|
14
|
+
kind: "assistant",
|
|
15
|
+
message_id: event.message.id,
|
|
16
|
+
parent_tool_use_id: event.parent_tool_use_id
|
|
17
|
+
};
|
|
18
|
+
case "user":
|
|
19
|
+
return {
|
|
20
|
+
kind: "user",
|
|
21
|
+
content: event.message.content,
|
|
22
|
+
uuid: event.uuid,
|
|
23
|
+
parent_tool_use_id: event.parent_tool_use_id
|
|
24
|
+
};
|
|
25
|
+
case "system":
|
|
26
|
+
return {
|
|
27
|
+
kind: "system",
|
|
28
|
+
subtype: event.subtype,
|
|
29
|
+
data: event,
|
|
30
|
+
session_id: event.session_id,
|
|
31
|
+
uuid: event.uuid
|
|
32
|
+
};
|
|
33
|
+
case "result":
|
|
34
|
+
return {
|
|
35
|
+
...event,
|
|
36
|
+
kind: "result",
|
|
37
|
+
cost_usd: event.total_cost_usd,
|
|
38
|
+
model_usage: event.modelUsage
|
|
39
|
+
};
|
|
40
|
+
case "rate_limit_event":
|
|
41
|
+
return {
|
|
42
|
+
kind: "rate_limit",
|
|
43
|
+
status: event.rate_limit_info.status,
|
|
44
|
+
rate_limit_type: event.rate_limit_info.rateLimitType,
|
|
45
|
+
resets_at: event.rate_limit_info.resetsAt,
|
|
46
|
+
utilization: event.rate_limit_info.utilization
|
|
47
|
+
};
|
|
48
|
+
default:
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/store/codexAppServer.ts
|
|
54
|
+
function codexAppServerContent(event) {
|
|
55
|
+
if (event.method === "turn/completed") {
|
|
56
|
+
return { kind: "end", isError: event.params.turn.status !== "completed" };
|
|
57
|
+
}
|
|
58
|
+
if (event.method === "error") {
|
|
59
|
+
return event.params.willRetry ? null : { kind: "error", text: event.params.error.message };
|
|
60
|
+
}
|
|
61
|
+
if (event.method !== "item/completed") return null;
|
|
62
|
+
const item = event.params.item;
|
|
63
|
+
switch (item.type) {
|
|
64
|
+
case "agentMessage":
|
|
65
|
+
case "plan":
|
|
66
|
+
return { kind: "assistant", text: item.text };
|
|
67
|
+
case "reasoning":
|
|
68
|
+
return {
|
|
69
|
+
kind: "thinking",
|
|
70
|
+
text: (item.summary?.length ? item.summary : item.content ?? []).join(
|
|
71
|
+
"\n"
|
|
72
|
+
)
|
|
73
|
+
};
|
|
74
|
+
case "commandExecution":
|
|
75
|
+
return {
|
|
76
|
+
kind: "tool",
|
|
77
|
+
name: "Bash",
|
|
78
|
+
input: { command: item.command },
|
|
79
|
+
summary: item.command,
|
|
80
|
+
result: item.aggregatedOutput?.trim() || "(no output)",
|
|
81
|
+
isError: item.status === "failed" || item.status === "declined" || typeof item.exitCode === "number" && item.exitCode !== 0
|
|
82
|
+
};
|
|
83
|
+
case "fileChange":
|
|
84
|
+
return {
|
|
85
|
+
kind: "tool",
|
|
86
|
+
name: "Edit",
|
|
87
|
+
input: { changes: item.changes },
|
|
88
|
+
summary: item.changes.map((change) => change.path).join(", "),
|
|
89
|
+
result: item.changes.map((change) => change.diff).join("\n"),
|
|
90
|
+
isError: item.status === "failed" || item.status === "declined"
|
|
91
|
+
};
|
|
92
|
+
case "webSearch":
|
|
93
|
+
return {
|
|
94
|
+
kind: "tool",
|
|
95
|
+
name: "WebSearch",
|
|
96
|
+
input: { query: item.query },
|
|
97
|
+
summary: item.query,
|
|
98
|
+
result: null,
|
|
99
|
+
isError: false
|
|
100
|
+
};
|
|
101
|
+
default:
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
4
105
|
|
|
5
106
|
// src/store/lifecycle.ts
|
|
6
107
|
function sandboxOutputStep(payload) {
|
|
@@ -62,11 +163,11 @@ function sandboxPhaseText(payload) {
|
|
|
62
163
|
if (tier) parts.push(tier);
|
|
63
164
|
const duration = durationLabel(payload.duration_ms);
|
|
64
165
|
if (duration) parts.push(duration);
|
|
65
|
-
return parts.join("
|
|
166
|
+
return parts.join(", ");
|
|
66
167
|
}
|
|
67
168
|
case "failed": {
|
|
68
169
|
const duration = durationLabel(payload.duration_ms);
|
|
69
|
-
return duration ? `${label} failed
|
|
170
|
+
return duration ? `${label} failed, ${duration}` : `${label} failed`;
|
|
70
171
|
}
|
|
71
172
|
default:
|
|
72
173
|
return label;
|
|
@@ -76,7 +177,7 @@ function lifecycleText(recordType, payload) {
|
|
|
76
177
|
switch (recordType) {
|
|
77
178
|
case "session_scheduled": {
|
|
78
179
|
const config = typeof payload.config_name === "string" ? payload.config_name : null;
|
|
79
|
-
return config ? `Session scheduled
|
|
180
|
+
return config ? `Session scheduled, ${config}` : "Session scheduled";
|
|
80
181
|
}
|
|
81
182
|
case "session_starting": {
|
|
82
183
|
const attempt = typeof payload.attempt === "number" ? payload.attempt : 0;
|
|
@@ -85,14 +186,14 @@ function lifecycleText(recordType, payload) {
|
|
|
85
186
|
return wakeIndex > 0 ? "Waking the session\u2026" : "Session starting\u2026";
|
|
86
187
|
}
|
|
87
188
|
case "session_retrying":
|
|
88
|
-
return typeof payload.reason === "string" && payload.reason ? `Retrying
|
|
189
|
+
return typeof payload.reason === "string" && payload.reason ? `Retrying, ${payload.reason}` : "Retrying after a transient error\u2026";
|
|
89
190
|
case "sandbox_starting":
|
|
90
191
|
return "Starting sandbox\u2026";
|
|
91
192
|
case "sandbox_phase":
|
|
92
193
|
return sandboxPhaseText(payload);
|
|
93
194
|
case "sandbox_output": {
|
|
94
195
|
const last = sandboxOutputLine(payload);
|
|
95
|
-
return last ? `${sandboxOutputStep(payload)}
|
|
196
|
+
return last ? `${sandboxOutputStep(payload)}, ${last}` : null;
|
|
96
197
|
}
|
|
97
198
|
case "sandbox_ready": {
|
|
98
199
|
const repos = Array.isArray(payload.repositories) ? payload.repositories.filter(
|
|
@@ -102,7 +203,7 @@ function lifecycleText(recordType, payload) {
|
|
|
102
203
|
if (repos.length) parts.push(repos.join(", "));
|
|
103
204
|
const tier = cacheTierLabel(payload.cache_tier);
|
|
104
205
|
if (tier) parts.push(tier);
|
|
105
|
-
return parts.join("
|
|
206
|
+
return parts.join(", ");
|
|
106
207
|
}
|
|
107
208
|
case "session_resumed":
|
|
108
209
|
return "Resumed the conversation";
|
|
@@ -112,7 +213,7 @@ function lifecycleText(recordType, payload) {
|
|
|
112
213
|
return "Conversation closed";
|
|
113
214
|
case "session_cancelled": {
|
|
114
215
|
const reason = typeof payload.reason === "string" ? payload.reason : null;
|
|
115
|
-
return reason ? `Session cancelled
|
|
216
|
+
return reason ? `Session cancelled, ${reason}` : "Session cancelled";
|
|
116
217
|
}
|
|
117
218
|
default:
|
|
118
219
|
return null;
|
|
@@ -182,7 +283,7 @@ function eventToItems(event, keyBase, options = {}) {
|
|
|
182
283
|
const label = event.is_error ? "turn ended with an error" : "turn complete";
|
|
183
284
|
push({
|
|
184
285
|
kind: "summary",
|
|
185
|
-
text: bits.length ? `${label}
|
|
286
|
+
text: bits.length ? `${label}, ${bits.join(", ")}` : label,
|
|
186
287
|
spaceBefore: true,
|
|
187
288
|
isError: event.is_error
|
|
188
289
|
});
|
|
@@ -196,17 +297,17 @@ function eventToItems(event, keyBase, options = {}) {
|
|
|
196
297
|
if (typeof data.cwd === "string") bits.push(data.cwd);
|
|
197
298
|
push({
|
|
198
299
|
kind: "system",
|
|
199
|
-
text: bits.length ? `session started
|
|
300
|
+
text: bits.length ? `session started, ${bits.join(", ")}` : "session started",
|
|
200
301
|
spaceBefore: true
|
|
201
302
|
});
|
|
202
303
|
return items;
|
|
203
304
|
}
|
|
204
305
|
if (event.kind === "rate_limit") return items;
|
|
205
|
-
const blocks = blocksOf(event.content);
|
|
306
|
+
const blocks = blocksOf(event.content ?? []);
|
|
206
307
|
if (event.kind === "user") {
|
|
207
308
|
for (const block of blocks) {
|
|
208
309
|
if (block.type === "tool_result") {
|
|
209
|
-
const body = toolResultText(block.content);
|
|
310
|
+
const body = toolResultText(block.content ?? null);
|
|
210
311
|
push({
|
|
211
312
|
kind: "tool_result",
|
|
212
313
|
gutter: "\u23BF",
|
|
@@ -234,14 +335,14 @@ function eventToItems(event, keyBase, options = {}) {
|
|
|
234
335
|
spaceBefore: true
|
|
235
336
|
});
|
|
236
337
|
} else if (block.type === "tool_use" || block.type === "server_tool_use") {
|
|
237
|
-
const summary = summarizeToolInput(block.name, block.input);
|
|
338
|
+
const summary = summarizeToolInput(block.name, block.input ?? {});
|
|
238
339
|
push({
|
|
239
340
|
kind: "tool",
|
|
240
341
|
gutter: "\u25CF",
|
|
241
342
|
text: block.name,
|
|
242
343
|
detail: summary ? `(${summary})` : void 0,
|
|
243
344
|
spaceBefore: true,
|
|
244
|
-
tool: { name: block.name, input: block.input }
|
|
345
|
+
tool: { name: block.name, input: block.input ?? {} }
|
|
245
346
|
});
|
|
246
347
|
} else if (block.type === "text" && block.text.trim()) {
|
|
247
348
|
push({ kind: "assistant", text: block.text.trim(), spaceBefore: true });
|
|
@@ -276,7 +377,7 @@ function codexEventToItems(event, keyBase) {
|
|
|
276
377
|
const item = event.item;
|
|
277
378
|
switch (item.type) {
|
|
278
379
|
case "agent_message": {
|
|
279
|
-
const text = item.text.trim();
|
|
380
|
+
const text = (item.text ?? "").trim();
|
|
280
381
|
if (text) push({ kind: "assistant", text, spaceBefore: true });
|
|
281
382
|
break;
|
|
282
383
|
}
|
|
@@ -289,7 +390,7 @@ function codexEventToItems(event, keyBase) {
|
|
|
289
390
|
}
|
|
290
391
|
case "command_execution": {
|
|
291
392
|
const c = item;
|
|
292
|
-
const summary = oneLine(c.command, 100);
|
|
393
|
+
const summary = oneLine(c.command ?? "", 100);
|
|
293
394
|
push({
|
|
294
395
|
kind: "tool",
|
|
295
396
|
gutter: "\u25CF",
|
|
@@ -361,12 +462,61 @@ function codexMcpToolName(item) {
|
|
|
361
462
|
return item.server && item.tool ? `mcp__${item.server}__${item.tool}` : item.tool ?? "mcp_tool_call";
|
|
362
463
|
}
|
|
363
464
|
function recordToItems(record, keyBase, options = {}) {
|
|
364
|
-
switch (record.
|
|
365
|
-
case "claude_sdk
|
|
366
|
-
|
|
367
|
-
|
|
465
|
+
switch (record.kind) {
|
|
466
|
+
case "claude_sdk":
|
|
467
|
+
case "claude_code": {
|
|
468
|
+
const payload = claudePayload(record);
|
|
469
|
+
return payload ? eventToItems(payload, keyBase, options) : [];
|
|
470
|
+
}
|
|
471
|
+
case "codex":
|
|
368
472
|
return codexEventToItems(record.payload, keyBase);
|
|
369
|
-
case "
|
|
473
|
+
case "codex_app_server": {
|
|
474
|
+
const content = codexAppServerContent(record.payload);
|
|
475
|
+
if (!content) return [];
|
|
476
|
+
if (content.kind === "end") {
|
|
477
|
+
return content.isError ? [
|
|
478
|
+
{
|
|
479
|
+
key: keyBase,
|
|
480
|
+
kind: "summary",
|
|
481
|
+
text: "turn ended with an error",
|
|
482
|
+
isError: true,
|
|
483
|
+
spaceBefore: true
|
|
484
|
+
}
|
|
485
|
+
] : [];
|
|
486
|
+
}
|
|
487
|
+
if (content.kind === "tool") {
|
|
488
|
+
const summary = oneLine(content.summary, 100);
|
|
489
|
+
return [
|
|
490
|
+
{
|
|
491
|
+
key: `${keyBase}:0`,
|
|
492
|
+
kind: "tool",
|
|
493
|
+
gutter: "\u25CF",
|
|
494
|
+
text: content.name,
|
|
495
|
+
detail: summary ? `(${summary})` : void 0,
|
|
496
|
+
spaceBefore: true,
|
|
497
|
+
tool: { name: content.name, input: content.input ?? void 0 }
|
|
498
|
+
},
|
|
499
|
+
{
|
|
500
|
+
key: `${keyBase}:1`,
|
|
501
|
+
kind: "tool_result",
|
|
502
|
+
gutter: "\u23BF",
|
|
503
|
+
text: content.result || "(completed)",
|
|
504
|
+
isError: content.isError,
|
|
505
|
+
spaceBefore: false
|
|
506
|
+
}
|
|
507
|
+
];
|
|
508
|
+
}
|
|
509
|
+
return content.text.trim() ? [
|
|
510
|
+
{
|
|
511
|
+
key: keyBase,
|
|
512
|
+
kind: content.kind,
|
|
513
|
+
text: content.text.trim(),
|
|
514
|
+
isError: content.kind === "error",
|
|
515
|
+
spaceBefore: true
|
|
516
|
+
}
|
|
517
|
+
] : [];
|
|
518
|
+
}
|
|
519
|
+
case "platform": {
|
|
370
520
|
const text = lifecycleText(record.record_type, record.payload);
|
|
371
521
|
return text ? [{ key: keyBase, kind: "notice", text, spaceBefore: true }] : [];
|
|
372
522
|
}
|
|
@@ -386,42 +536,57 @@ function pendingToolCalls(items) {
|
|
|
386
536
|
}
|
|
387
537
|
return pending;
|
|
388
538
|
}
|
|
389
|
-
function
|
|
539
|
+
function isFoldable(item) {
|
|
540
|
+
return item.kind === "tool" || item.kind === "tool_result" || item.kind === "thinking";
|
|
541
|
+
}
|
|
542
|
+
function foldLabel(group, settled) {
|
|
543
|
+
const work = group.filter((i) => i.kind !== "thinking");
|
|
544
|
+
if (work.length === 0) return settled ? "Thinking\u2026" : "Thinking";
|
|
545
|
+
const names = [
|
|
546
|
+
...new Set(work.filter((i) => i.kind === "tool").map((i) => i.text))
|
|
547
|
+
];
|
|
548
|
+
const n = work.filter((i) => i.kind === "tool").length || work.length;
|
|
549
|
+
const plural = n === 1 ? "" : "s";
|
|
550
|
+
if (names.length === 1 && names[0] === "Bash")
|
|
551
|
+
return `Ran ${n} shell command${plural}`;
|
|
552
|
+
if (names.length === 1 && names[0] === "Read")
|
|
553
|
+
return `Read ${n} file${plural}`;
|
|
554
|
+
if (names.length === 1)
|
|
555
|
+
return n === 1 ? `Ran ${names[0]}` : `Ran ${names[0]} ${n} times`;
|
|
556
|
+
if (names.length === 0) return `Ran ${n} tool call${plural}`;
|
|
557
|
+
const shown = names.slice(0, 3).join(", ") + (names.length > 3 ? ", \u2026" : "");
|
|
558
|
+
return `Ran ${n} tool call${plural} (${shown})`;
|
|
559
|
+
}
|
|
560
|
+
function foldRun(group, loading) {
|
|
561
|
+
const thinkingOnly = group.every((i) => i.kind === "thinking");
|
|
562
|
+
return {
|
|
563
|
+
key: `grp:${group[0].key}`,
|
|
564
|
+
kind: thinkingOnly ? "thinking" : "notice",
|
|
565
|
+
...thinkingOnly ? { gutter: "\u273B" } : {},
|
|
566
|
+
text: foldLabel(group, !loading),
|
|
567
|
+
spaceBefore: true,
|
|
568
|
+
...loading ? { loading } : {}
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
function collapseToolRuns(items, { working = false } = {}) {
|
|
390
572
|
const out = [];
|
|
391
573
|
let group = [];
|
|
392
|
-
const flush = () => {
|
|
574
|
+
const flush = (trailing) => {
|
|
393
575
|
if (group.length === 0) return;
|
|
394
|
-
const
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
const plural = n === 1 ? "" : "s";
|
|
399
|
-
let label;
|
|
400
|
-
if (names.length === 1 && names[0] === "Bash")
|
|
401
|
-
label = `Ran ${n} shell command${plural}`;
|
|
402
|
-
else if (names.length === 1 && names[0] === "Read")
|
|
403
|
-
label = `Read ${n} file${plural}`;
|
|
404
|
-
else if (names.length === 0) label = `Ran ${n} tool call${plural}`;
|
|
405
|
-
else {
|
|
406
|
-
const shown = names.slice(0, 3).join(", ") + (names.length > 3 ? ", \u2026" : "");
|
|
407
|
-
label = `Ran ${n} tool call${plural} (${shown})`;
|
|
408
|
-
}
|
|
409
|
-
out.push({
|
|
410
|
-
key: `grp:${group[0].key}`,
|
|
411
|
-
kind: "notice",
|
|
412
|
-
text: label,
|
|
413
|
-
spaceBefore: true
|
|
414
|
-
});
|
|
576
|
+
const pending = pendingToolCalls(group).length > 0;
|
|
577
|
+
const thinkingOnly = group.every((i) => i.kind === "thinking");
|
|
578
|
+
const loading = pending || trailing && working && thinkingOnly;
|
|
579
|
+
out.push(foldRun(group, loading));
|
|
415
580
|
group = [];
|
|
416
581
|
};
|
|
417
582
|
for (const item of items) {
|
|
418
|
-
if (item
|
|
583
|
+
if (isFoldable(item)) group.push(item);
|
|
419
584
|
else {
|
|
420
|
-
flush();
|
|
585
|
+
flush(false);
|
|
421
586
|
out.push(item);
|
|
422
587
|
}
|
|
423
588
|
}
|
|
424
|
-
flush();
|
|
589
|
+
flush(true);
|
|
425
590
|
return out;
|
|
426
591
|
}
|
|
427
592
|
function clampLines(text, maxLines) {
|
|
@@ -471,6 +636,8 @@ var SANDBOX_RECORD_TYPES = /* @__PURE__ */ new Set([
|
|
|
471
636
|
function groupRecordsToChatTurns(records) {
|
|
472
637
|
const turns = [];
|
|
473
638
|
const toolNodeByUseId = /* @__PURE__ */ new Map();
|
|
639
|
+
const userTurnByMessageId = /* @__PURE__ */ new Map();
|
|
640
|
+
const messageIdByTurnId = /* @__PURE__ */ new Map();
|
|
474
641
|
let seq = 0;
|
|
475
642
|
const nextKey = (base) => `${base}:${seq++}`;
|
|
476
643
|
let openIdx = -1;
|
|
@@ -496,7 +663,39 @@ function groupRecordsToChatTurns(records) {
|
|
|
496
663
|
return turns[openIdx];
|
|
497
664
|
};
|
|
498
665
|
for (const record of records) {
|
|
499
|
-
if (record.
|
|
666
|
+
if (record.kind === "platform") {
|
|
667
|
+
const messageId = typeof record.payload.message_id === "string" ? record.payload.message_id : null;
|
|
668
|
+
if (record.record_type === "message_received" && messageId) {
|
|
669
|
+
const body = typeof record.payload.body === "string" ? record.payload.body : "";
|
|
670
|
+
if (!body.trim() || userTurnByMessageId.has(messageId)) continue;
|
|
671
|
+
const turn2 = {
|
|
672
|
+
resumed: false,
|
|
673
|
+
isError: false,
|
|
674
|
+
key: `msg:${messageId}`,
|
|
675
|
+
role: "user",
|
|
676
|
+
nodes: [{ key: `msg:${messageId}`, kind: "user", text: body.trim() }],
|
|
677
|
+
startedAt: record.created_at,
|
|
678
|
+
completedAt: record.created_at,
|
|
679
|
+
durationMs: null,
|
|
680
|
+
costUsd: null,
|
|
681
|
+
tokens: null
|
|
682
|
+
};
|
|
683
|
+
userTurnByMessageId.set(messageId, turn2);
|
|
684
|
+
turns.push(turn2);
|
|
685
|
+
continue;
|
|
686
|
+
}
|
|
687
|
+
if (record.record_type === "message_delivered" && messageId) {
|
|
688
|
+
if (typeof record.payload.turn_id === "string")
|
|
689
|
+
messageIdByTurnId.set(record.payload.turn_id, messageId);
|
|
690
|
+
continue;
|
|
691
|
+
}
|
|
692
|
+
if (record.record_type === "turn_failed") {
|
|
693
|
+
const turnId = typeof record.payload.turn_id === "string" ? record.payload.turn_id : null;
|
|
694
|
+
const owner = turnId ? messageIdByTurnId.get(turnId) : void 0;
|
|
695
|
+
const userTurn = owner ? userTurnByMessageId.get(owner) : void 0;
|
|
696
|
+
if (userTurn) userTurn.isError = true;
|
|
697
|
+
continue;
|
|
698
|
+
}
|
|
500
699
|
const text = lifecycleText(record.record_type, record.payload);
|
|
501
700
|
if (!text) continue;
|
|
502
701
|
const isSandbox = SANDBOX_RECORD_TYPES.has(record.record_type);
|
|
@@ -559,7 +758,7 @@ function groupRecordsToChatTurns(records) {
|
|
|
559
758
|
});
|
|
560
759
|
continue;
|
|
561
760
|
}
|
|
562
|
-
if (record.
|
|
761
|
+
if (record.kind === "codex") {
|
|
563
762
|
codexEventIntoTurns(record, record.payload, {
|
|
564
763
|
openAgentTurn,
|
|
565
764
|
closeTurn: (completedAt, isError) => {
|
|
@@ -573,7 +772,40 @@ function groupRecordsToChatTurns(records) {
|
|
|
573
772
|
});
|
|
574
773
|
continue;
|
|
575
774
|
}
|
|
576
|
-
|
|
775
|
+
if (record.kind === "codex_app_server") {
|
|
776
|
+
const content = codexAppServerContent(record.payload);
|
|
777
|
+
if (!content) continue;
|
|
778
|
+
if (content.kind === "end") {
|
|
779
|
+
if (openIdx >= 0) {
|
|
780
|
+
turns[openIdx].completedAt = record.created_at;
|
|
781
|
+
if (content.isError) turns[openIdx].isError = true;
|
|
782
|
+
openIdx = -1;
|
|
783
|
+
}
|
|
784
|
+
} else if (content.kind === "tool") {
|
|
785
|
+
openAgentTurn(record).nodes.push({
|
|
786
|
+
key: nextKey(record.id),
|
|
787
|
+
kind: "tool",
|
|
788
|
+
name: content.name,
|
|
789
|
+
input: content.input,
|
|
790
|
+
summary: oneLine(content.summary, 100),
|
|
791
|
+
result: content.result,
|
|
792
|
+
isError: content.isError,
|
|
793
|
+
startedAt: record.created_at,
|
|
794
|
+
completedAt: record.created_at
|
|
795
|
+
});
|
|
796
|
+
} else if (content.text.trim()) {
|
|
797
|
+
const turn2 = openAgentTurn(record);
|
|
798
|
+
if (content.kind === "error") turn2.isError = true;
|
|
799
|
+
turn2.nodes.push({
|
|
800
|
+
key: nextKey(record.id),
|
|
801
|
+
kind: content.kind === "error" ? "assistant" : content.kind,
|
|
802
|
+
text: content.text.trim()
|
|
803
|
+
});
|
|
804
|
+
}
|
|
805
|
+
continue;
|
|
806
|
+
}
|
|
807
|
+
const data = claudePayload(record);
|
|
808
|
+
if (!data) continue;
|
|
577
809
|
if (data.kind === "system") {
|
|
578
810
|
if (isInitEvent(data)) {
|
|
579
811
|
initCount += 1;
|
|
@@ -598,6 +830,8 @@ function groupRecordsToChatTurns(records) {
|
|
|
598
830
|
if (typeof content === "string") {
|
|
599
831
|
if (content.trim()) {
|
|
600
832
|
openIdx = -1;
|
|
833
|
+
if (record.session_message_id != null && userTurnByMessageId.has(record.session_message_id))
|
|
834
|
+
continue;
|
|
601
835
|
turns.push({
|
|
602
836
|
resumed: false,
|
|
603
837
|
isError: false,
|
|
@@ -617,7 +851,7 @@ function groupRecordsToChatTurns(records) {
|
|
|
617
851
|
}
|
|
618
852
|
for (const block of content) {
|
|
619
853
|
if (block.type !== "tool_result") continue;
|
|
620
|
-
const body = toolResultText(block.content) || "(no output)";
|
|
854
|
+
const body = toolResultText(block.content ?? null) || "(no output)";
|
|
621
855
|
const useId = block.tool_use_id;
|
|
622
856
|
const node = toolNodeByUseId.get(useId);
|
|
623
857
|
if (node) {
|
|
@@ -647,7 +881,7 @@ function groupRecordsToChatTurns(records) {
|
|
|
647
881
|
if (data.usage && typeof data.usage.output_tokens === "number") {
|
|
648
882
|
turn.tokens = (turn.tokens ?? 0) + data.usage.output_tokens;
|
|
649
883
|
}
|
|
650
|
-
for (const block of data.content) {
|
|
884
|
+
for (const block of data.content ?? []) {
|
|
651
885
|
if (block.type === "thinking" && block.thinking.trim()) {
|
|
652
886
|
turn.nodes.push({
|
|
653
887
|
key: nextKey(record.id),
|
|
@@ -659,7 +893,7 @@ function groupRecordsToChatTurns(records) {
|
|
|
659
893
|
key: nextKey(record.id),
|
|
660
894
|
kind: "tool",
|
|
661
895
|
name: block.name,
|
|
662
|
-
input: block.input,
|
|
896
|
+
input: block.input ?? null,
|
|
663
897
|
summary: summarizeToolInput(block.name, block.input),
|
|
664
898
|
result: null,
|
|
665
899
|
isError: false,
|
|
@@ -698,7 +932,7 @@ function codexEventIntoTurns(record, event, ops) {
|
|
|
698
932
|
const turn = () => ops.openAgentTurn(record);
|
|
699
933
|
switch (item.type) {
|
|
700
934
|
case "agent_message": {
|
|
701
|
-
const text = item.text.trim();
|
|
935
|
+
const text = (item.text ?? "").trim();
|
|
702
936
|
if (text)
|
|
703
937
|
turn().nodes.push({
|
|
704
938
|
key: ops.nextKey(record.id),
|
|
@@ -725,7 +959,7 @@ function codexEventIntoTurns(record, event, ops) {
|
|
|
725
959
|
kind: "tool",
|
|
726
960
|
name: "Bash",
|
|
727
961
|
input: { command: c.command },
|
|
728
|
-
summary: oneLine(c.command, 100),
|
|
962
|
+
summary: oneLine(c.command ?? "", 100),
|
|
729
963
|
result: (c.aggregated_output ?? "").trim() || "(no output)",
|
|
730
964
|
isError: typeof c.exit_code === "number" && c.exit_code !== 0,
|
|
731
965
|
startedAt: record.created_at,
|
|
@@ -801,6 +1035,7 @@ function humanDuration(seconds) {
|
|
|
801
1035
|
if (s > 0 || bits.length === 0) bits.push(`${s}s`);
|
|
802
1036
|
return bits.join(" ");
|
|
803
1037
|
}
|
|
1038
|
+
var SESSION_WAKING = "Session waking";
|
|
804
1039
|
function sessionLogText(recordType, payload) {
|
|
805
1040
|
const p = payload;
|
|
806
1041
|
switch (recordType) {
|
|
@@ -810,14 +1045,14 @@ function sessionLogText(recordType, payload) {
|
|
|
810
1045
|
const wake = typeof p.wake_index === "number" ? p.wake_index : 0;
|
|
811
1046
|
const attempt = typeof p.attempt === "number" ? p.attempt : 0;
|
|
812
1047
|
if (attempt > 0) return "Restarting the sandbox after a transient error\u2026";
|
|
813
|
-
return wake > 0 ?
|
|
1048
|
+
return wake > 0 ? SESSION_WAKING : null;
|
|
814
1049
|
}
|
|
815
1050
|
case "session_retrying":
|
|
816
|
-
return typeof p.reason === "string" && p.reason ? `Retrying
|
|
1051
|
+
return typeof p.reason === "string" && p.reason ? `Retrying, ${p.reason}` : "Retrying after a transient error\u2026";
|
|
817
1052
|
case "session_resumed":
|
|
818
1053
|
return "Session awake";
|
|
819
1054
|
case "session_cancelled": {
|
|
820
|
-
const reason = typeof p.reason === "string" && p.reason ?
|
|
1055
|
+
const reason = typeof p.reason === "string" && p.reason ? `, ${p.reason}` : "";
|
|
821
1056
|
return `Session cancelled${reason}`;
|
|
822
1057
|
}
|
|
823
1058
|
default:
|
|
@@ -879,6 +1114,7 @@ function deliveredUnechoedSends(records) {
|
|
|
879
1114
|
}
|
|
880
1115
|
return out;
|
|
881
1116
|
}
|
|
1117
|
+
var STARTING_SANDBOX = "Starting sandbox\u2026";
|
|
882
1118
|
function msLabel(ms) {
|
|
883
1119
|
if (typeof ms !== "number" || !isFinite(ms) || ms < 0) return null;
|
|
884
1120
|
return humanDuration(ms / 1e3);
|
|
@@ -920,7 +1156,7 @@ function stepLabel(phase, step) {
|
|
|
920
1156
|
}
|
|
921
1157
|
function deriveSandboxState(records, minFeedSeq) {
|
|
922
1158
|
let seen = false;
|
|
923
|
-
let headline =
|
|
1159
|
+
let headline = STARTING_SANDBOX;
|
|
924
1160
|
let done = false;
|
|
925
1161
|
let sandboxDone = false;
|
|
926
1162
|
let readySeconds = null;
|
|
@@ -955,7 +1191,7 @@ function deriveSandboxState(records, minFeedSeq) {
|
|
|
955
1191
|
case "session_retrying": {
|
|
956
1192
|
seen = true;
|
|
957
1193
|
const text = lifecycleText(record.record_type, p);
|
|
958
|
-
headline = !text || text === "Session starting\u2026" ?
|
|
1194
|
+
headline = !text || text === "Session starting\u2026" ? STARTING_SANDBOX : text;
|
|
959
1195
|
done = false;
|
|
960
1196
|
readySeconds = null;
|
|
961
1197
|
reset();
|
|
@@ -970,7 +1206,6 @@ function deriveSandboxState(records, minFeedSeq) {
|
|
|
970
1206
|
case "sandbox_starting": {
|
|
971
1207
|
seen = true;
|
|
972
1208
|
reset();
|
|
973
|
-
push(record, "step", "Starting sandbox\u2026");
|
|
974
1209
|
break;
|
|
975
1210
|
}
|
|
976
1211
|
case "sandbox_phase": {
|
|
@@ -989,7 +1224,7 @@ function deriveSandboxState(records, minFeedSeq) {
|
|
|
989
1224
|
base,
|
|
990
1225
|
...tier ? [tier] : [],
|
|
991
1226
|
...dur ? [dur] : []
|
|
992
|
-
].join("
|
|
1227
|
+
].join(", ");
|
|
993
1228
|
const line = open.get(key);
|
|
994
1229
|
if (line) {
|
|
995
1230
|
line.kind = failed ? "failed" : "done";
|
|
@@ -1025,7 +1260,7 @@ function deriveSandboxState(records, minFeedSeq) {
|
|
|
1025
1260
|
"Sandbox ready",
|
|
1026
1261
|
...tier ? [tier] : [],
|
|
1027
1262
|
...totalSeconds > 0 ? [humanDuration(totalSeconds)] : []
|
|
1028
|
-
].join("
|
|
1263
|
+
].join(", ")
|
|
1029
1264
|
);
|
|
1030
1265
|
sandboxDone = true;
|
|
1031
1266
|
readySeconds = totalSeconds > 0 ? totalSeconds : null;
|
|
@@ -1036,6 +1271,8 @@ function deriveSandboxState(records, minFeedSeq) {
|
|
|
1036
1271
|
break;
|
|
1037
1272
|
}
|
|
1038
1273
|
}
|
|
1274
|
+
const openLines = [...open.values()];
|
|
1275
|
+
if (openLines.length) openLines[openLines.length - 1].loading = true;
|
|
1039
1276
|
const full = configName ? [
|
|
1040
1277
|
{
|
|
1041
1278
|
key: "config",
|
|
@@ -1054,6 +1291,14 @@ function deriveSandboxState(records, minFeedSeq) {
|
|
|
1054
1291
|
log: full
|
|
1055
1292
|
} : null;
|
|
1056
1293
|
}
|
|
1294
|
+
function startupSettled(sandbox, status) {
|
|
1295
|
+
return (sandbox?.done ?? false) && statusActivityText(status) == null;
|
|
1296
|
+
}
|
|
1297
|
+
function startupHeadline(sandbox, status) {
|
|
1298
|
+
const activity = statusActivityText(status);
|
|
1299
|
+
const text = !sandbox || sandbox.done ? activity ?? STARTING_SANDBOX : sandbox.headline;
|
|
1300
|
+
return `${text.replace(/…$/, "")}\u2026`;
|
|
1301
|
+
}
|
|
1057
1302
|
function sandboxSummary(sandbox) {
|
|
1058
1303
|
const seconds = sandbox?.readySeconds ?? null;
|
|
1059
1304
|
return seconds ? `Sandbox ready in ${humanDuration(seconds)}` : "Sandbox started";
|
|
@@ -1081,20 +1326,33 @@ var SANDBOX_RECORD_TYPES2 = /* @__PURE__ */ new Set([
|
|
|
1081
1326
|
function chatTurnsToItems(turns) {
|
|
1082
1327
|
const items = [];
|
|
1083
1328
|
let wakeAt = -1;
|
|
1329
|
+
const settleWake = () => {
|
|
1330
|
+
if (wakeAt < 0) return;
|
|
1331
|
+
const { loading: _, ...settled } = items[wakeAt];
|
|
1332
|
+
items[wakeAt] = { ...settled, text: "Session awake" };
|
|
1333
|
+
wakeAt = -1;
|
|
1334
|
+
};
|
|
1084
1335
|
for (const turn of turns) {
|
|
1336
|
+
if (turn.role === "assistant") settleWake();
|
|
1085
1337
|
if (turn.role === "lifecycle") {
|
|
1086
1338
|
for (const node of turn.nodes) {
|
|
1087
1339
|
if (node.kind !== "lifecycle") continue;
|
|
1088
1340
|
if (SANDBOX_RECORD_TYPES2.has(node.recordType)) continue;
|
|
1089
|
-
if (node.recordType === "session_resumed"
|
|
1090
|
-
|
|
1091
|
-
wakeAt = -1;
|
|
1341
|
+
if (node.recordType === "session_resumed") {
|
|
1342
|
+
settleWake();
|
|
1092
1343
|
continue;
|
|
1093
1344
|
}
|
|
1094
1345
|
const text = sessionLogText(node.recordType, node.payload ?? {});
|
|
1095
1346
|
if (!text) continue;
|
|
1096
|
-
|
|
1097
|
-
|
|
1347
|
+
const waking = text === SESSION_WAKING;
|
|
1348
|
+
items.push({
|
|
1349
|
+
key: node.key,
|
|
1350
|
+
kind: "notice",
|
|
1351
|
+
text,
|
|
1352
|
+
spaceBefore: true,
|
|
1353
|
+
...waking ? { loading: true } : {}
|
|
1354
|
+
});
|
|
1355
|
+
wakeAt = waking ? items.length - 1 : -1;
|
|
1098
1356
|
}
|
|
1099
1357
|
continue;
|
|
1100
1358
|
}
|
|
@@ -1105,7 +1363,8 @@ function chatTurnsToItems(turns) {
|
|
|
1105
1363
|
key: node.key,
|
|
1106
1364
|
kind: "user",
|
|
1107
1365
|
text: node.text,
|
|
1108
|
-
spaceBefore: true
|
|
1366
|
+
spaceBefore: true,
|
|
1367
|
+
...turn.isError ? { isError: true } : {}
|
|
1109
1368
|
});
|
|
1110
1369
|
}
|
|
1111
1370
|
}
|
|
@@ -1170,21 +1429,8 @@ function isToolFold(item) {
|
|
|
1170
1429
|
function isToolActivity(item) {
|
|
1171
1430
|
return item.kind === "tool" || item.kind === "tool_result" || isToolFold(item);
|
|
1172
1431
|
}
|
|
1173
|
-
function isAgentSpeech(item) {
|
|
1174
|
-
return item.kind === "assistant" || item.kind === "thinking";
|
|
1175
|
-
}
|
|
1176
1432
|
function layOutItems(items) {
|
|
1177
|
-
|
|
1178
|
-
let nestUnder = false;
|
|
1179
|
-
for (const item of items) {
|
|
1180
|
-
if (!isToolActivity(item)) {
|
|
1181
|
-
out.push({ item, nested: false, attach: false });
|
|
1182
|
-
nestUnder = isAgentSpeech(item);
|
|
1183
|
-
continue;
|
|
1184
|
-
}
|
|
1185
|
-
out.push({ item, nested: nestUnder, attach: nestUnder });
|
|
1186
|
-
}
|
|
1187
|
-
return out;
|
|
1433
|
+
return items.map((item) => ({ item, nested: false, attach: false }));
|
|
1188
1434
|
}
|
|
1189
1435
|
function foldGutter(nested) {
|
|
1190
1436
|
return nested ? BRANCH_GLYPH : "\u25CF";
|
|
@@ -1205,13 +1451,125 @@ function toolRunMembers(items) {
|
|
|
1205
1451
|
group = [];
|
|
1206
1452
|
};
|
|
1207
1453
|
for (const item of items) {
|
|
1208
|
-
if (item
|
|
1454
|
+
if (isFoldable(item)) group.push(item);
|
|
1209
1455
|
else flush();
|
|
1210
1456
|
}
|
|
1211
1457
|
flush();
|
|
1212
1458
|
return out;
|
|
1213
1459
|
}
|
|
1214
1460
|
|
|
1461
|
+
// src/store/ledger.ts
|
|
1462
|
+
function splitLedger(turns) {
|
|
1463
|
+
const preamble = [];
|
|
1464
|
+
const entries = [];
|
|
1465
|
+
for (const turn of turns) {
|
|
1466
|
+
if (turn.role === "user") {
|
|
1467
|
+
const node = turn.nodes.find((n) => n.kind === "user");
|
|
1468
|
+
entries.push({
|
|
1469
|
+
key: turn.key,
|
|
1470
|
+
prompt: node?.text ?? "",
|
|
1471
|
+
cancelled: turn.isError,
|
|
1472
|
+
turns: []
|
|
1473
|
+
});
|
|
1474
|
+
continue;
|
|
1475
|
+
}
|
|
1476
|
+
const last = entries[entries.length - 1];
|
|
1477
|
+
if (last) last.turns.push(turn);
|
|
1478
|
+
else preamble.push(turn);
|
|
1479
|
+
}
|
|
1480
|
+
return { preamble, entries };
|
|
1481
|
+
}
|
|
1482
|
+
function entrySeconds(entry, now) {
|
|
1483
|
+
let ms = 0;
|
|
1484
|
+
for (const turn of entry.turns) {
|
|
1485
|
+
if (turn.role !== "assistant" || turn.startedAt == null) continue;
|
|
1486
|
+
if (turn.durationMs != null) ms += turn.durationMs;
|
|
1487
|
+
else {
|
|
1488
|
+
const end = turn.completedAt != null ? Date.parse(turn.completedAt) : now;
|
|
1489
|
+
ms += Math.max(0, end - Date.parse(turn.startedAt));
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
return ms / 1e3;
|
|
1493
|
+
}
|
|
1494
|
+
function foldToolTurn(raw, live, members) {
|
|
1495
|
+
const items = [];
|
|
1496
|
+
let run = [];
|
|
1497
|
+
const flush = () => {
|
|
1498
|
+
if (run.length === 0) return;
|
|
1499
|
+
const fold = foldRun(run, live && pendingToolCalls(run).length > 0);
|
|
1500
|
+
members.set(fold.key, run);
|
|
1501
|
+
items.push(fold);
|
|
1502
|
+
run = [];
|
|
1503
|
+
};
|
|
1504
|
+
for (const item of raw) {
|
|
1505
|
+
if (item.kind === "tool" || item.kind === "tool_result") run.push(item);
|
|
1506
|
+
else {
|
|
1507
|
+
flush();
|
|
1508
|
+
items.push(item);
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
flush();
|
|
1512
|
+
return items;
|
|
1513
|
+
}
|
|
1514
|
+
function entryBody(entry, {
|
|
1515
|
+
live,
|
|
1516
|
+
now,
|
|
1517
|
+
liveText = ""
|
|
1518
|
+
}) {
|
|
1519
|
+
const raw = chatTurnsToItems(entry.turns);
|
|
1520
|
+
const members = /* @__PURE__ */ new Map();
|
|
1521
|
+
const toolRan = raw.some((i) => i.kind === "tool");
|
|
1522
|
+
let items;
|
|
1523
|
+
if (toolRan) {
|
|
1524
|
+
items = foldToolTurn(raw, live, members);
|
|
1525
|
+
} else {
|
|
1526
|
+
const thoughts = raw.filter((i) => i.kind === "thinking");
|
|
1527
|
+
items = raw.filter((i) => i.kind !== "thinking");
|
|
1528
|
+
const key = `grp:thought:${entry.key}`;
|
|
1529
|
+
if (thoughts.length) members.set(key, thoughts);
|
|
1530
|
+
if (live && liveText === "") {
|
|
1531
|
+
items.push({
|
|
1532
|
+
key,
|
|
1533
|
+
kind: "thinking",
|
|
1534
|
+
text: "Thinking",
|
|
1535
|
+
summary: true,
|
|
1536
|
+
spaceBefore: true
|
|
1537
|
+
});
|
|
1538
|
+
} else if (!live && thoughts.length) {
|
|
1539
|
+
items.push({
|
|
1540
|
+
key,
|
|
1541
|
+
kind: "thinking",
|
|
1542
|
+
text: `Thought for ${humanDuration(entrySeconds(entry, now))}`,
|
|
1543
|
+
summary: true,
|
|
1544
|
+
spaceBefore: true
|
|
1545
|
+
});
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
if (live && liveText !== "") {
|
|
1549
|
+
items.push({
|
|
1550
|
+
key: `live:${entry.key}`,
|
|
1551
|
+
kind: "assistant",
|
|
1552
|
+
text: liveText,
|
|
1553
|
+
spaceBefore: true
|
|
1554
|
+
});
|
|
1555
|
+
}
|
|
1556
|
+
const chosen = live ? liveRow(items, members) : -1;
|
|
1557
|
+
items = items.map((item, i) => {
|
|
1558
|
+
const { loading: _, ...rest } = item;
|
|
1559
|
+
return i === chosen ? { ...rest, loading: true } : rest;
|
|
1560
|
+
});
|
|
1561
|
+
return { items, members };
|
|
1562
|
+
}
|
|
1563
|
+
function liveRow(items, members) {
|
|
1564
|
+
if (items.length === 0) return -1;
|
|
1565
|
+
const running = items.findIndex((item) => {
|
|
1566
|
+
const run = members.get(item.key);
|
|
1567
|
+
return run != null && pendingToolCalls(run).length > 0;
|
|
1568
|
+
});
|
|
1569
|
+
if (running >= 0) return running;
|
|
1570
|
+
return items.length - 1;
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1215
1573
|
// src/store/index.ts
|
|
1216
1574
|
var TERMINAL_SESSION_STATUSES = /* @__PURE__ */ new Set([
|
|
1217
1575
|
"completed",
|
|
@@ -1293,6 +1651,7 @@ var SessionTranscriptStore = class {
|
|
|
1293
1651
|
// Fold one lifecycle record into the inbox projection; returns whether the
|
|
1294
1652
|
// pending view changed. Unknown fields/types are ignored (§3.6).
|
|
1295
1653
|
applyMessageRecord = (record) => {
|
|
1654
|
+
if (record.kind !== "platform") return false;
|
|
1296
1655
|
const payload = record.payload;
|
|
1297
1656
|
const messageId = typeof payload.message_id === "string" ? payload.message_id : null;
|
|
1298
1657
|
switch (record.record_type) {
|
|
@@ -1418,12 +1777,14 @@ var SessionTranscriptStore = class {
|
|
|
1418
1777
|
export {
|
|
1419
1778
|
BRANCH_GLYPH,
|
|
1420
1779
|
LIVE_GLYPH,
|
|
1780
|
+
SESSION_WAKING,
|
|
1421
1781
|
SessionTranscriptStore,
|
|
1422
1782
|
USER_BAR,
|
|
1423
1783
|
awaitingAgentPhase,
|
|
1424
1784
|
cacheTierLabel,
|
|
1425
1785
|
chatTurnsToItems,
|
|
1426
1786
|
clampLines,
|
|
1787
|
+
claudePayload,
|
|
1427
1788
|
codexChangedPaths,
|
|
1428
1789
|
codexEventToItems,
|
|
1429
1790
|
codexMcpToolName,
|
|
@@ -1431,17 +1792,20 @@ export {
|
|
|
1431
1792
|
deliveredUnechoedSends,
|
|
1432
1793
|
deriveSandboxState,
|
|
1433
1794
|
emptySessionTranscriptSnapshot,
|
|
1795
|
+
entryBody,
|
|
1796
|
+
entrySeconds,
|
|
1434
1797
|
eventToItems,
|
|
1435
1798
|
foldCosts,
|
|
1436
1799
|
foldGutter,
|
|
1800
|
+
foldRun,
|
|
1437
1801
|
formatDuration,
|
|
1438
1802
|
groupRecordsToChatTurns,
|
|
1439
1803
|
gutterFor,
|
|
1440
1804
|
hookPhrase,
|
|
1441
1805
|
humanDuration,
|
|
1442
|
-
isAgentSpeech,
|
|
1443
1806
|
isConnectVisibleRecord,
|
|
1444
1807
|
isConversationOver,
|
|
1808
|
+
isFoldable,
|
|
1445
1809
|
isToolActivity,
|
|
1446
1810
|
isToolFold,
|
|
1447
1811
|
lastLines,
|
|
@@ -1459,6 +1823,9 @@ export {
|
|
|
1459
1823
|
sandboxSummary,
|
|
1460
1824
|
seedTranscriptStore,
|
|
1461
1825
|
sessionLogText,
|
|
1826
|
+
splitLedger,
|
|
1827
|
+
startupHeadline,
|
|
1828
|
+
startupSettled,
|
|
1462
1829
|
statusActivityText,
|
|
1463
1830
|
summarizeToolInput,
|
|
1464
1831
|
tailLines,
|