@elizaos/plugin-task-coordinator 2.0.3-beta.2 → 2.0.3-beta.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.
Files changed (176) hide show
  1. package/assets/hero.png +0 -0
  2. package/dist/AgentTabsSection.d.ts +16 -0
  3. package/dist/AgentTabsSection.d.ts.map +1 -0
  4. package/dist/AgentTabsSection.js +169 -0
  5. package/dist/AgentTabsSection.js.map +1 -0
  6. package/dist/CodingAgentControlChip.d.ts +2 -0
  7. package/dist/CodingAgentControlChip.d.ts.map +1 -0
  8. package/dist/CodingAgentControlChip.js +73 -0
  9. package/dist/CodingAgentControlChip.js.map +1 -0
  10. package/dist/CodingAgentSettingsSection.d.ts +2 -0
  11. package/dist/CodingAgentSettingsSection.d.ts.map +1 -0
  12. package/dist/CodingAgentSettingsSection.js +379 -0
  13. package/dist/CodingAgentSettingsSection.js.map +1 -0
  14. package/dist/CodingAgentTasksPanel.d.ts +4 -0
  15. package/dist/CodingAgentTasksPanel.d.ts.map +1 -0
  16. package/dist/CodingAgentTasksPanel.interact.d.ts +2 -0
  17. package/dist/CodingAgentTasksPanel.interact.d.ts.map +1 -0
  18. package/dist/CodingAgentTasksPanel.interact.js +46 -0
  19. package/dist/CodingAgentTasksPanel.interact.js.map +1 -0
  20. package/dist/CodingAgentTasksPanel.js +740 -0
  21. package/dist/CodingAgentTasksPanel.js.map +1 -0
  22. package/dist/GitHubConnectionCard.d.ts +2 -0
  23. package/dist/GitHubConnectionCard.d.ts.map +1 -0
  24. package/dist/GitHubConnectionCard.js +172 -0
  25. package/dist/GitHubConnectionCard.js.map +1 -0
  26. package/dist/GlobalPrefsSection.d.ts +10 -0
  27. package/dist/GlobalPrefsSection.d.ts.map +1 -0
  28. package/dist/GlobalPrefsSection.js +166 -0
  29. package/dist/GlobalPrefsSection.js.map +1 -0
  30. package/dist/LlmProviderSection.d.ts +10 -0
  31. package/dist/LlmProviderSection.d.ts.map +1 -0
  32. package/dist/LlmProviderSection.js +161 -0
  33. package/dist/LlmProviderSection.js.map +1 -0
  34. package/dist/ModelConfigSection.d.ts +15 -0
  35. package/dist/ModelConfigSection.d.ts.map +1 -0
  36. package/dist/ModelConfigSection.js +86 -0
  37. package/dist/ModelConfigSection.js.map +1 -0
  38. package/dist/OrchestratorView.d.ts +20 -0
  39. package/dist/OrchestratorView.d.ts.map +1 -0
  40. package/dist/OrchestratorView.js +231 -0
  41. package/dist/OrchestratorView.js.map +1 -0
  42. package/dist/OrchestratorWorkbench.d.ts +32 -0
  43. package/dist/OrchestratorWorkbench.d.ts.map +1 -0
  44. package/dist/OrchestratorWorkbench.js +3200 -0
  45. package/dist/OrchestratorWorkbench.js.map +1 -0
  46. package/dist/PtyConsoleBase.d.ts +9 -0
  47. package/dist/PtyConsoleBase.d.ts.map +1 -0
  48. package/dist/PtyConsoleBase.js +174 -0
  49. package/dist/PtyConsoleBase.js.map +1 -0
  50. package/dist/PtyConsoleDrawer.d.ts +10 -0
  51. package/dist/PtyConsoleDrawer.d.ts.map +1 -0
  52. package/dist/PtyConsoleDrawer.js +77 -0
  53. package/dist/PtyConsoleDrawer.js.map +1 -0
  54. package/dist/PtyConsoleSidePanel.d.ts +8 -0
  55. package/dist/PtyConsoleSidePanel.d.ts.map +1 -0
  56. package/dist/PtyConsoleSidePanel.js +9 -0
  57. package/dist/PtyConsoleSidePanel.js.map +1 -0
  58. package/dist/PtyTerminalPane.d.ts +10 -0
  59. package/dist/PtyTerminalPane.d.ts.map +1 -0
  60. package/dist/PtyTerminalPane.js +147 -0
  61. package/dist/PtyTerminalPane.js.map +1 -0
  62. package/dist/TaskCardList.d.ts +76 -0
  63. package/dist/TaskCardList.d.ts.map +1 -0
  64. package/dist/TaskCardList.js +327 -0
  65. package/dist/TaskCardList.js.map +1 -0
  66. package/dist/TaskCoordinatorView.d.ts +20 -0
  67. package/dist/TaskCoordinatorView.d.ts.map +1 -0
  68. package/dist/TaskCoordinatorView.js +146 -0
  69. package/dist/TaskCoordinatorView.js.map +1 -0
  70. package/dist/__e2e__/dashboard-fixture.d.ts +9 -0
  71. package/dist/__e2e__/dashboard-fixture.d.ts.map +1 -0
  72. package/dist/__e2e__/dashboard-fixture.js +123 -0
  73. package/dist/__e2e__/dashboard-fixture.js.map +1 -0
  74. package/dist/api/coding-agents-auth-sanitize.d.ts +23 -0
  75. package/dist/api/coding-agents-auth-sanitize.d.ts.map +1 -0
  76. package/dist/api/coding-agents-auth-sanitize.js +22 -0
  77. package/dist/api/coding-agents-auth-sanitize.js.map +1 -0
  78. package/dist/api/coding-agents-preflight-normalize.d.ts +29 -0
  79. package/dist/api/coding-agents-preflight-normalize.d.ts.map +1 -0
  80. package/dist/api/coding-agents-preflight-normalize.js +20 -0
  81. package/dist/api/coding-agents-preflight-normalize.js.map +1 -0
  82. package/dist/coding-agent-settings-shared.d.ts +42 -0
  83. package/dist/coding-agent-settings-shared.d.ts.map +1 -0
  84. package/dist/coding-agent-settings-shared.js +121 -0
  85. package/dist/coding-agent-settings-shared.js.map +1 -0
  86. package/dist/components/OrchestratorSpatialView.d.ts +56 -0
  87. package/dist/components/OrchestratorSpatialView.d.ts.map +1 -0
  88. package/dist/components/OrchestratorSpatialView.js +501 -0
  89. package/dist/components/OrchestratorSpatialView.js.map +1 -0
  90. package/dist/components/TaskCoordinatorSpatialView.d.ts +59 -0
  91. package/dist/components/TaskCoordinatorSpatialView.d.ts.map +1 -0
  92. package/dist/components/TaskCoordinatorSpatialView.js +294 -0
  93. package/dist/components/TaskCoordinatorSpatialView.js.map +1 -0
  94. package/dist/index.d.ts +5 -0
  95. package/dist/index.d.ts.map +1 -0
  96. package/dist/index.js +286 -0
  97. package/dist/index.js.map +1 -0
  98. package/dist/orchestrator-capabilities.d.ts +3 -0
  99. package/dist/orchestrator-capabilities.d.ts.map +1 -0
  100. package/dist/orchestrator-capabilities.js +136 -0
  101. package/dist/orchestrator-capabilities.js.map +1 -0
  102. package/dist/orchestrator-command.d.ts +39 -0
  103. package/dist/orchestrator-command.d.ts.map +1 -0
  104. package/dist/orchestrator-command.js +52 -0
  105. package/dist/orchestrator-command.js.map +1 -0
  106. package/dist/orchestrator-diff.d.ts +19 -0
  107. package/dist/orchestrator-diff.d.ts.map +1 -0
  108. package/dist/orchestrator-diff.helpers.d.ts +18 -0
  109. package/dist/orchestrator-diff.helpers.d.ts.map +1 -0
  110. package/dist/orchestrator-diff.helpers.js +76 -0
  111. package/dist/orchestrator-diff.helpers.js.map +1 -0
  112. package/dist/orchestrator-diff.js +119 -0
  113. package/dist/orchestrator-diff.js.map +1 -0
  114. package/dist/orchestrator-markdown.d.ts +5 -0
  115. package/dist/orchestrator-markdown.d.ts.map +1 -0
  116. package/dist/orchestrator-markdown.helpers.d.ts +2 -0
  117. package/dist/orchestrator-markdown.helpers.d.ts.map +1 -0
  118. package/dist/orchestrator-markdown.helpers.js +21 -0
  119. package/dist/orchestrator-markdown.helpers.js.map +1 -0
  120. package/dist/orchestrator-markdown.js +199 -0
  121. package/dist/orchestrator-markdown.js.map +1 -0
  122. package/dist/orchestrator-params.d.ts +8 -0
  123. package/dist/orchestrator-params.d.ts.map +1 -0
  124. package/dist/orchestrator-params.js +27 -0
  125. package/dist/orchestrator-params.js.map +1 -0
  126. package/dist/orchestrator-plan.d.ts +5 -0
  127. package/dist/orchestrator-plan.d.ts.map +1 -0
  128. package/dist/orchestrator-plan.js +95 -0
  129. package/dist/orchestrator-plan.js.map +1 -0
  130. package/dist/orchestrator-reasoning.d.ts +21 -0
  131. package/dist/orchestrator-reasoning.d.ts.map +1 -0
  132. package/dist/orchestrator-reasoning.js +105 -0
  133. package/dist/orchestrator-reasoning.js.map +1 -0
  134. package/dist/orchestrator-stream.d.ts +15 -0
  135. package/dist/orchestrator-stream.d.ts.map +1 -0
  136. package/dist/orchestrator-stream.helpers.d.ts +89 -0
  137. package/dist/orchestrator-stream.helpers.d.ts.map +1 -0
  138. package/dist/orchestrator-stream.helpers.js +361 -0
  139. package/dist/orchestrator-stream.helpers.js.map +1 -0
  140. package/dist/orchestrator-stream.js +307 -0
  141. package/dist/orchestrator-stream.js.map +1 -0
  142. package/dist/pty-status-dots.d.ts +2 -0
  143. package/dist/pty-status-dots.d.ts.map +1 -0
  144. package/dist/pty-status-dots.js +6 -0
  145. package/dist/pty-status-dots.js.map +1 -0
  146. package/dist/register-slots.d.ts +20 -0
  147. package/dist/register-slots.d.ts.map +1 -0
  148. package/dist/register-slots.js +50 -0
  149. package/dist/register-slots.js.map +1 -0
  150. package/dist/register-terminal-view.d.ts +21 -0
  151. package/dist/register-terminal-view.d.ts.map +1 -0
  152. package/dist/register-terminal-view.js +46 -0
  153. package/dist/register-terminal-view.js.map +1 -0
  154. package/dist/register.d.ts +2 -0
  155. package/dist/register.d.ts.map +1 -0
  156. package/dist/register.js +23 -0
  157. package/dist/register.js.map +1 -0
  158. package/dist/session-hydration.d.ts +2 -0
  159. package/dist/session-hydration.d.ts.map +1 -0
  160. package/dist/session-hydration.js +9 -0
  161. package/dist/session-hydration.js.map +1 -0
  162. package/dist/task-coordinator-view-bundle.d.ts +4 -0
  163. package/dist/task-coordinator-view-bundle.d.ts.map +1 -0
  164. package/dist/task-coordinator-view-bundle.js +9 -0
  165. package/dist/task-coordinator-view-bundle.js.map +1 -0
  166. package/dist/ui.d.ts +2 -0
  167. package/dist/ui.d.ts.map +1 -0
  168. package/dist/ui.js +13 -0
  169. package/dist/ui.js.map +1 -0
  170. package/dist/view-format.d.ts +25 -0
  171. package/dist/view-format.d.ts.map +1 -0
  172. package/dist/view-format.js +64 -0
  173. package/dist/view-format.js.map +1 -0
  174. package/dist/views/bundle.js +1383 -0
  175. package/dist/views/bundle.js.map +1 -0
  176. package/package.json +7 -6
@@ -0,0 +1,89 @@
1
+ import type { CodingAgentTaskEventRecord, CodingAgentTaskMessageRecord } from "@elizaos/ui";
2
+ import { type LucideIcon } from "lucide-react";
3
+ export type ToolStatus = "running" | "done" | "failed";
4
+ export interface ToolView {
5
+ /** Session-scoped render key; raw tool ids are not globally unique. */
6
+ groupKey: string;
7
+ /** The tool call's raw id from the adapter, preserved for inspection. */
8
+ id: string;
9
+ /** Task event ids merged into this rendered tool call. */
10
+ eventIds: string[];
11
+ sessionId: string | null;
12
+ /** The tool's own name, e.g. `write`, `bash`, `read`. */
13
+ title: string;
14
+ /** ACP tool kind, e.g. `edit`, `execute`, `read`, `search`. */
15
+ kind: string;
16
+ /** The raw adapter status, before UI normalization. */
17
+ rawStatus?: string;
18
+ /** The raw adapter input payload, preserved for operator inspection. */
19
+ rawInput?: Record<string, unknown>;
20
+ /** The raw adapter output payload, preserved for operator inspection. */
21
+ rawOutput?: unknown;
22
+ status: ToolStatus;
23
+ /** Edited/read file, relative to the session workdir when resolvable. */
24
+ filePath?: string;
25
+ /** Shell command for `execute` tools. */
26
+ command?: string;
27
+ /** New file content (write) or replacement text (edit). */
28
+ newText?: string;
29
+ /** Prior text for an edit, enabling a real +/- diff. */
30
+ oldText?: string;
31
+ /** Query/pattern for search-style tools. */
32
+ query?: string;
33
+ /** Tool result/output, ANSI-stripped. */
34
+ output?: string;
35
+ /** Process exit code for `execute` tools (0 = success); null/undefined when
36
+ * the tool is not an exec invocation or is still running. */
37
+ exitCode?: number | null;
38
+ /** Wall-clock duration in ms from the tool's first to last event. */
39
+ durationMs?: number;
40
+ }
41
+ export type ConversationBlock = {
42
+ kind: "user";
43
+ key: string;
44
+ at: number;
45
+ content: string;
46
+ messageIds: string[];
47
+ sessionId: string | null;
48
+ } | {
49
+ kind: "agent";
50
+ key: string;
51
+ at: number;
52
+ senderName: string;
53
+ content: string;
54
+ tone: "normal" | "error";
55
+ messageIds: string[];
56
+ sessionId: string | null;
57
+ } | {
58
+ kind: "tool";
59
+ key: string;
60
+ at: number;
61
+ tool: ToolView;
62
+ } | {
63
+ kind: "reasoning";
64
+ key: string;
65
+ at: number;
66
+ text: string;
67
+ eventIds: string[];
68
+ sessionId: string | null;
69
+ /** Wall-clock span from the first to the last reasoning delta in the
70
+ * coalesced burst; drives the "Thought for Ns" header. */
71
+ durationMs?: number;
72
+ /** True while the owning session is still running, so reasoning may still
73
+ * be arriving — drives the "Thinking…" header and shimmer. */
74
+ streaming?: boolean;
75
+ } | {
76
+ kind: "notice";
77
+ key: string;
78
+ at: number;
79
+ eventId: string;
80
+ eventType: string;
81
+ sessionId: string | null;
82
+ icon: LucideIcon;
83
+ tone: string;
84
+ text: string;
85
+ };
86
+ /** Turn the polled message + event records into the ordered conversation the
87
+ * room renders. */
88
+ export declare function buildConversation(messages: CodingAgentTaskMessageRecord[], events: CodingAgentTaskEventRecord[], resolveSenderName: (message: CodingAgentTaskMessageRecord) => string, finishedSessionIds: ReadonlySet<string>): ConversationBlock[];
89
+ //# sourceMappingURL=orchestrator-stream.helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator-stream.helpers.d.ts","sourceRoot":"","sources":["../src/orchestrator-stream.helpers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,361 @@
1
+ import {
2
+ Check,
3
+ Circle,
4
+ CircleAlert,
5
+ CircleCheck,
6
+ CircleStop,
7
+ CircleX,
8
+ OctagonX
9
+ } from "lucide-react";
10
+ import { stripAnsi } from "./view-format.js";
11
+ const NOISE_EVENT_TYPES = /* @__PURE__ */ new Set([
12
+ "message",
13
+ "usage_update",
14
+ "ready",
15
+ "available_commands_update"
16
+ ]);
17
+ const NOTICE_META = {
18
+ task_registered: { icon: Circle, tone: "text-muted", label: "Task started" },
19
+ task_complete: { icon: CircleCheck, tone: "text-ok", label: "Completed" },
20
+ stopped: { icon: CircleStop, tone: "text-muted", label: "Stopped" },
21
+ blocked: { icon: OctagonX, tone: "text-muted-strong", label: "Blocked" },
22
+ blocked_auto_resolved: {
23
+ icon: Check,
24
+ tone: "text-muted",
25
+ label: "Auto-resolved"
26
+ },
27
+ escalation: { icon: CircleAlert, tone: "text-muted", label: "Escalation" },
28
+ error: { icon: CircleX, tone: "text-red-500", label: "Error" }
29
+ };
30
+ function noticeMeta(eventType) {
31
+ return NOTICE_META[eventType] ?? {
32
+ icon: Circle,
33
+ tone: "text-muted",
34
+ label: eventType.replace(/_/g, " ")
35
+ };
36
+ }
37
+ const TOOL_STATUS_FROM_RAW = {
38
+ in_progress: "running",
39
+ pending: "running",
40
+ running: "running",
41
+ queued: "running",
42
+ completed: "done",
43
+ success: "done",
44
+ done: "done",
45
+ ok: "done",
46
+ failed: "failed",
47
+ error: "failed",
48
+ cancelled: "failed",
49
+ skipped: "failed"
50
+ };
51
+ function asRecord(value) {
52
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
53
+ }
54
+ function pickString(obj, ...keys) {
55
+ if (!obj) return void 0;
56
+ for (const key of keys) {
57
+ const value = obj[key];
58
+ if (typeof value === "string" && value.trim() !== "") return value;
59
+ }
60
+ return void 0;
61
+ }
62
+ function pickNumber(obj, ...keys) {
63
+ if (!obj) return void 0;
64
+ for (const key of keys) {
65
+ const value = obj[key];
66
+ if (typeof value === "number" && Number.isFinite(value)) return value;
67
+ }
68
+ return void 0;
69
+ }
70
+ function normalizeOutput(value) {
71
+ let text;
72
+ if (typeof value === "string") text = value;
73
+ else if (Array.isArray(value)) {
74
+ text = value.map((part) => pickString(asRecord(part), "text", "content") ?? "").join("");
75
+ }
76
+ if (text === void 0) return void 0;
77
+ if (text.length >= 2 && text.startsWith('"') && text.endsWith('"') && !text.includes("\n")) {
78
+ try {
79
+ const decoded = JSON.parse(text);
80
+ if (typeof decoded === "string") text = decoded;
81
+ } catch {
82
+ }
83
+ }
84
+ const clean = stripAnsi(text).trim();
85
+ return clean === "" ? void 0 : clean;
86
+ }
87
+ function parseToolOutput(raw) {
88
+ let value = raw;
89
+ if (typeof value === "string") {
90
+ const trimmed = value.trim();
91
+ if (!trimmed.startsWith("[") && !trimmed.startsWith("{")) {
92
+ return { text: normalizeOutput(raw) };
93
+ }
94
+ try {
95
+ value = JSON.parse(trimmed);
96
+ } catch {
97
+ return { text: normalizeOutput(raw) };
98
+ }
99
+ }
100
+ const blocks = Array.isArray(value) ? value : [value];
101
+ const texts = [];
102
+ let diff;
103
+ let parsedExitCode;
104
+ for (const block of blocks) {
105
+ const record = asRecord(block);
106
+ if (!record) continue;
107
+ if (record.type === "diff") {
108
+ diff = {
109
+ path: pickString(record, "path"),
110
+ oldText: typeof record.oldText === "string" ? record.oldText : void 0,
111
+ newText: typeof record.newText === "string" ? record.newText : void 0
112
+ };
113
+ continue;
114
+ }
115
+ const inner = asRecord(record.content) ?? record;
116
+ const text = pickString(inner, "text", "content", "output") ?? pickString(record, "text", "output");
117
+ if (text) texts.push(text);
118
+ const metadata = asRecord(record.metadata) ?? asRecord(inner.metadata);
119
+ const exitCode = pickNumber(metadata, "exitCode", "exit_code") ?? pickNumber(record, "exitCode", "exit_code") ?? pickNumber(inner, "exitCode", "exit_code");
120
+ if (exitCode !== void 0) parsedExitCode = exitCode;
121
+ }
122
+ const joined = stripAnsi(texts.join("\n")).trim();
123
+ return {
124
+ text: joined === "" ? void 0 : joined,
125
+ diff,
126
+ exitCode: parsedExitCode
127
+ };
128
+ }
129
+ function rawToolCall(event) {
130
+ return asRecord(event.data?.toolCall);
131
+ }
132
+ function toToolView(id, groupKey, events) {
133
+ let title = "tool";
134
+ let kind = "";
135
+ let status = "running";
136
+ let rawStatus;
137
+ let rawInput;
138
+ let rawOutput;
139
+ let output;
140
+ let outputDiff;
141
+ let exitCode;
142
+ for (const event of events) {
143
+ const call = rawToolCall(event);
144
+ if (!call) continue;
145
+ title = pickString(call, "title", "name", "toolName") ?? title;
146
+ kind = pickString(call, "kind") ?? kind;
147
+ const nextRawStatus = pickString(call, "status");
148
+ if (nextRawStatus) {
149
+ rawStatus = nextRawStatus;
150
+ status = TOOL_STATUS_FROM_RAW[nextRawStatus] ?? status;
151
+ }
152
+ const nextInput = asRecord(call.rawInput) ?? asRecord(call.input);
153
+ if (nextInput) rawInput = { ...rawInput, ...nextInput };
154
+ const nextRawOutput = call.output ?? call.rawOutput;
155
+ if (nextRawOutput !== void 0) rawOutput = nextRawOutput;
156
+ const parsed = parseToolOutput(nextRawOutput);
157
+ if (parsed.text) output = parsed.text;
158
+ if (parsed.diff?.oldText !== void 0 || parsed.diff?.newText !== void 0)
159
+ outputDiff = parsed.diff;
160
+ if (parsed.exitCode !== void 0) exitCode = parsed.exitCode;
161
+ const nextExit = pickNumber(asRecord(call.exitStatus), "exitCode") ?? pickNumber(call, "exitCode");
162
+ if (nextExit !== void 0) exitCode = nextExit;
163
+ }
164
+ if (typeof exitCode === "number") status = exitCode === 0 ? "done" : "failed";
165
+ const durationMs = events.length > 1 ? events[events.length - 1].timestamp - events[0].timestamp : void 0;
166
+ return {
167
+ groupKey,
168
+ id,
169
+ eventIds: events.map((event) => event.id),
170
+ sessionId: events[0]?.sessionId ?? null,
171
+ title,
172
+ kind,
173
+ rawStatus,
174
+ rawInput,
175
+ rawOutput,
176
+ status,
177
+ filePath: pickString(rawInput, "filePath", "file_path", "path"),
178
+ command: pickString(rawInput, "command", "cmd", "script"),
179
+ // A pure insertion (`old_string:""`), deletion-only edit (`new_string:""`),
180
+ // or empty-file write (`content:""`) is a real change whose "" must survive
181
+ // — pickString drops empty strings, so check the content keys directly and
182
+ // only fall back to it (then the output diff) for the rest.
183
+ newText: typeof rawInput?.content === "string" ? rawInput.content : typeof rawInput?.new_string === "string" ? rawInput.new_string : typeof rawInput?.newString === "string" ? rawInput.newString : pickString(rawInput, "newText") ?? outputDiff?.newText,
184
+ oldText: typeof rawInput?.old_string === "string" ? rawInput.old_string : typeof rawInput?.oldString === "string" ? rawInput.oldString : pickString(rawInput, "oldText") ?? outputDiff?.oldText,
185
+ query: pickString(rawInput, "pattern", "query", "regex", "glob"),
186
+ output,
187
+ exitCode,
188
+ durationMs: durationMs && durationMs > 0 ? durationMs : void 0
189
+ };
190
+ }
191
+ function messageLane(message) {
192
+ if (message.senderKind === "user") return `user:${message.id}`;
193
+ const stream = message.direction === "stderr" ? "err" : "out";
194
+ return `${message.senderKind}:${message.sessionId ?? message.id}:${stream}`;
195
+ }
196
+ function toolGroupKey(event, toolCallId) {
197
+ return `${event.sessionId ?? event.threadId ?? "sessionless"}:${toolCallId}`;
198
+ }
199
+ function buildConversation(messages, events, resolveSenderName, finishedSessionIds) {
200
+ const toolEvents = /* @__PURE__ */ new Map();
201
+ const toolFirstSeen = /* @__PURE__ */ new Map();
202
+ const atoms = [];
203
+ let order = 0;
204
+ for (const message of messages) {
205
+ if (message.senderKind !== "user" && (message.direction === "stdin" || message.direction === "keys"))
206
+ continue;
207
+ if (stripAnsi(message.content).trim() === "") continue;
208
+ atoms.push({
209
+ at: message.timestamp,
210
+ order: order++,
211
+ type: "message",
212
+ message
213
+ });
214
+ }
215
+ for (const event of events) {
216
+ const call = rawToolCall(event);
217
+ if (call) {
218
+ const id = pickString(call, "id", "toolCallId", "callId") ?? `tool-${event.id}`;
219
+ const groupKey = toolGroupKey(event, id);
220
+ const group = toolEvents.get(groupKey);
221
+ if (group) group.events.push(event);
222
+ else {
223
+ toolEvents.set(groupKey, { id, events: [event] });
224
+ toolFirstSeen.set(groupKey, event.timestamp);
225
+ }
226
+ continue;
227
+ }
228
+ if (event.eventType === "reasoning") {
229
+ const text = typeof event.data?.text === "string" ? event.data.text : "";
230
+ if (text)
231
+ atoms.push({
232
+ at: event.timestamp,
233
+ order: order++,
234
+ type: "reasoning",
235
+ eventId: event.id,
236
+ text,
237
+ sessionId: event.sessionId
238
+ });
239
+ continue;
240
+ }
241
+ if (NOISE_EVENT_TYPES.has(event.eventType)) continue;
242
+ atoms.push({
243
+ at: event.timestamp,
244
+ order: order++,
245
+ type: "notice",
246
+ eventId: event.id,
247
+ sessionId: event.sessionId,
248
+ eventType: event.eventType,
249
+ summary: event.summary
250
+ });
251
+ }
252
+ for (const [groupKey, group] of toolEvents) {
253
+ const list = group.events;
254
+ const tool = toToolView(group.id, groupKey, list);
255
+ const sessionId = list[0].sessionId;
256
+ if (tool.status === "running" && sessionId && finishedSessionIds.has(sessionId)) {
257
+ tool.status = "done";
258
+ }
259
+ atoms.push({
260
+ at: toolFirstSeen.get(groupKey) ?? list[0].timestamp,
261
+ order: order++,
262
+ type: "tool",
263
+ tool
264
+ });
265
+ }
266
+ atoms.sort((a, b) => a.at - b.at || a.order - b.order);
267
+ const blocks = [];
268
+ let openLane = null;
269
+ let openReasoning = null;
270
+ for (const atom of atoms) {
271
+ if (atom.type === "message") {
272
+ openReasoning = null;
273
+ const lane = messageLane(atom.message);
274
+ const text = stripAnsi(atom.message.content);
275
+ if (openLane && openLane.lane === lane) {
276
+ openLane.block.content += text;
277
+ openLane.block.messageIds.push(atom.message.id);
278
+ continue;
279
+ }
280
+ if (atom.message.senderKind === "user") {
281
+ const block = {
282
+ kind: "user",
283
+ key: `msg-${atom.message.id}`,
284
+ at: atom.at,
285
+ content: text,
286
+ messageIds: [atom.message.id],
287
+ sessionId: atom.message.sessionId
288
+ };
289
+ blocks.push(block);
290
+ openLane = { lane, block };
291
+ } else {
292
+ const block = {
293
+ kind: "agent",
294
+ key: `msg-${atom.message.id}`,
295
+ at: atom.at,
296
+ senderName: resolveSenderName(atom.message),
297
+ content: text,
298
+ tone: atom.message.direction === "stderr" ? "error" : "normal",
299
+ messageIds: [atom.message.id],
300
+ sessionId: atom.message.sessionId
301
+ };
302
+ blocks.push(block);
303
+ openLane = { lane, block };
304
+ }
305
+ continue;
306
+ }
307
+ openLane = null;
308
+ if (atom.type === "reasoning") {
309
+ const streaming = atom.sessionId ? !finishedSessionIds.has(atom.sessionId) : false;
310
+ if (openReasoning && openReasoning.sessionId === atom.sessionId) {
311
+ openReasoning.text += atom.text;
312
+ openReasoning.eventIds.push(atom.eventId);
313
+ openReasoning.durationMs = atom.at - openReasoning.at;
314
+ openReasoning.streaming = streaming;
315
+ } else {
316
+ const block = {
317
+ kind: "reasoning",
318
+ key: `reason-${atom.eventId}`,
319
+ at: atom.at,
320
+ text: atom.text,
321
+ eventIds: [atom.eventId],
322
+ sessionId: atom.sessionId,
323
+ // A single-delta burst has no span yet; left undefined so the header
324
+ // reads "Thought" rather than "Thought for 0s".
325
+ durationMs: void 0,
326
+ streaming
327
+ };
328
+ blocks.push(block);
329
+ openReasoning = block;
330
+ }
331
+ continue;
332
+ }
333
+ openReasoning = null;
334
+ if (atom.type === "tool") {
335
+ blocks.push({
336
+ kind: "tool",
337
+ key: `tool-${atom.tool.groupKey}`,
338
+ at: atom.at,
339
+ tool: atom.tool
340
+ });
341
+ } else {
342
+ const meta = noticeMeta(atom.eventType);
343
+ blocks.push({
344
+ kind: "notice",
345
+ key: `evt-${atom.eventId}`,
346
+ at: atom.at,
347
+ eventId: atom.eventId,
348
+ eventType: atom.eventType,
349
+ sessionId: atom.sessionId,
350
+ icon: meta.icon,
351
+ tone: meta.tone,
352
+ text: atom.summary.trim() || meta.label
353
+ });
354
+ }
355
+ }
356
+ return blocks;
357
+ }
358
+ export {
359
+ buildConversation
360
+ };
361
+ //# sourceMappingURL=orchestrator-stream.helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/orchestrator-stream.helpers.ts"],"sourcesContent":["// Pure transform layer for the orchestrator conversation stream, split out of\n// orchestrator-stream.tsx so that file exports only React components and stays\n// Fast-Refresh-compatible. Turns the polled message + event records into the\n// ordered ConversationBlock list the room renders; the .tsx render half consumes\n// the exported types (ToolView, ConversationBlock) and buildConversation.\nimport type {\n CodingAgentTaskEventRecord,\n CodingAgentTaskMessageRecord,\n} from \"@elizaos/ui\";\nimport {\n Check,\n Circle,\n CircleAlert,\n CircleCheck,\n CircleStop,\n CircleX,\n type LucideIcon,\n OctagonX,\n} from \"lucide-react\";\nimport { stripAnsi } from \"./view-format.js\";\n\nexport type ToolStatus = \"running\" | \"done\" | \"failed\";\n\nexport interface ToolView {\n /** Session-scoped render key; raw tool ids are not globally unique. */\n groupKey: string;\n /** The tool call's raw id from the adapter, preserved for inspection. */\n id: string;\n /** Task event ids merged into this rendered tool call. */\n eventIds: string[];\n sessionId: string | null;\n /** The tool's own name, e.g. `write`, `bash`, `read`. */\n title: string;\n /** ACP tool kind, e.g. `edit`, `execute`, `read`, `search`. */\n kind: string;\n /** The raw adapter status, before UI normalization. */\n rawStatus?: string;\n /** The raw adapter input payload, preserved for operator inspection. */\n rawInput?: Record<string, unknown>;\n /** The raw adapter output payload, preserved for operator inspection. */\n rawOutput?: unknown;\n status: ToolStatus;\n /** Edited/read file, relative to the session workdir when resolvable. */\n filePath?: string;\n /** Shell command for `execute` tools. */\n command?: string;\n /** New file content (write) or replacement text (edit). */\n newText?: string;\n /** Prior text for an edit, enabling a real +/- diff. */\n oldText?: string;\n /** Query/pattern for search-style tools. */\n query?: string;\n /** Tool result/output, ANSI-stripped. */\n output?: string;\n /** Process exit code for `execute` tools (0 = success); null/undefined when\n * the tool is not an exec invocation or is still running. */\n exitCode?: number | null;\n /** Wall-clock duration in ms from the tool's first to last event. */\n durationMs?: number;\n}\n\nexport type ConversationBlock =\n | {\n kind: \"user\";\n key: string;\n at: number;\n content: string;\n messageIds: string[];\n sessionId: string | null;\n }\n | {\n kind: \"agent\";\n key: string;\n at: number;\n senderName: string;\n content: string;\n tone: \"normal\" | \"error\";\n messageIds: string[];\n sessionId: string | null;\n }\n | { kind: \"tool\"; key: string; at: number; tool: ToolView }\n | {\n kind: \"reasoning\";\n key: string;\n at: number;\n text: string;\n eventIds: string[];\n sessionId: string | null;\n /** Wall-clock span from the first to the last reasoning delta in the\n * coalesced burst; drives the \"Thought for Ns\" header. */\n durationMs?: number;\n /** True while the owning session is still running, so reasoning may still\n * be arriving — drives the \"Thinking…\" header and shimmer. */\n streaming?: boolean;\n }\n | {\n kind: \"notice\";\n key: string;\n at: number;\n eventId: string;\n eventType: string;\n sessionId: string | null;\n icon: LucideIcon;\n tone: string;\n text: string;\n };\n\n/** Events whose content is already shown elsewhere (prose lives in the message\n * stream; token usage lives in the inspector) and so would only add noise to\n * the conversation. */\nconst NOISE_EVENT_TYPES: ReadonlySet<string> = new Set([\n \"message\",\n \"usage_update\",\n \"ready\",\n \"available_commands_update\",\n]);\n\ninterface NoticeMeta {\n icon: LucideIcon;\n tone: string;\n label: string;\n}\n\nconst NOTICE_META: Record<string, NoticeMeta> = {\n task_registered: { icon: Circle, tone: \"text-muted\", label: \"Task started\" },\n task_complete: { icon: CircleCheck, tone: \"text-ok\", label: \"Completed\" },\n stopped: { icon: CircleStop, tone: \"text-muted\", label: \"Stopped\" },\n blocked: { icon: OctagonX, tone: \"text-muted-strong\", label: \"Blocked\" },\n blocked_auto_resolved: {\n icon: Check,\n tone: \"text-muted\",\n label: \"Auto-resolved\",\n },\n escalation: { icon: CircleAlert, tone: \"text-muted\", label: \"Escalation\" },\n error: { icon: CircleX, tone: \"text-red-500\", label: \"Error\" },\n};\n\nfunction noticeMeta(eventType: string): NoticeMeta {\n return (\n NOTICE_META[eventType] ?? {\n icon: Circle,\n tone: \"text-muted\",\n label: eventType.replace(/_/g, \" \"),\n }\n );\n}\n\nconst TOOL_STATUS_FROM_RAW: Record<string, ToolStatus> = {\n in_progress: \"running\",\n pending: \"running\",\n running: \"running\",\n queued: \"running\",\n completed: \"done\",\n success: \"done\",\n done: \"done\",\n ok: \"done\",\n failed: \"failed\",\n error: \"failed\",\n cancelled: \"failed\",\n skipped: \"failed\",\n};\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\n/** First non-empty string among `keys` on `obj`. */\nfunction pickString(\n obj: Record<string, unknown> | undefined,\n ...keys: string[]\n): string | undefined {\n if (!obj) return undefined;\n for (const key of keys) {\n const value = obj[key];\n if (typeof value === \"string\" && value.trim() !== \"\") return value;\n }\n return undefined;\n}\n\n/** First finite number among `keys` on `obj`. */\nfunction pickNumber(\n obj: Record<string, unknown> | undefined,\n ...keys: string[]\n): number | undefined {\n if (!obj) return undefined;\n for (const key of keys) {\n const value = obj[key];\n if (typeof value === \"number\" && Number.isFinite(value)) return value;\n }\n return undefined;\n}\n\n/** Tool output arrives as a possibly JSON-encoded string (e.g. `\"\\\"\\\"\"` for an\n * empty result); decode one layer, strip ANSI, and drop if empty. */\nfunction normalizeOutput(value: unknown): string | undefined {\n let text: string | undefined;\n if (typeof value === \"string\") text = value;\n else if (Array.isArray(value)) {\n text = value\n .map((part) => pickString(asRecord(part), \"text\", \"content\") ?? \"\")\n .join(\"\");\n }\n if (text === undefined) return undefined;\n if (\n text.length >= 2 &&\n text.startsWith('\"') &&\n text.endsWith('\"') &&\n !text.includes(\"\\n\")\n ) {\n try {\n const decoded = JSON.parse(text);\n if (typeof decoded === \"string\") text = decoded;\n } catch {\n // keep the raw text\n }\n }\n const clean = stripAnsi(text).trim();\n return clean === \"\" ? undefined : clean;\n}\n\ninterface ToolOutput {\n text?: string;\n diff?: { path?: string; oldText?: string; newText?: string };\n exitCode?: number;\n}\n\n/** ACP tool results arrive as a JSON-encoded array of content blocks, e.g.\n * `[{type:\"content\",content:{type:\"text\",text}}, {type:\"diff\",path,oldText,newText}]`.\n * Pull out the human-readable text and any file diff so the card renders real\n * prose + a diff instead of dumping the raw JSON the agent returned. Plain\n * (non-block) strings fall back to {@link normalizeOutput}. */\nfunction parseToolOutput(raw: unknown): ToolOutput {\n let value = raw;\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n if (!trimmed.startsWith(\"[\") && !trimmed.startsWith(\"{\")) {\n return { text: normalizeOutput(raw) };\n }\n try {\n value = JSON.parse(trimmed);\n } catch {\n return { text: normalizeOutput(raw) };\n }\n }\n const blocks = Array.isArray(value) ? value : [value];\n const texts: string[] = [];\n let diff: ToolOutput[\"diff\"];\n let parsedExitCode: number | undefined;\n for (const block of blocks) {\n const record = asRecord(block);\n if (!record) continue;\n if (record.type === \"diff\") {\n diff = {\n path: pickString(record, \"path\"),\n oldText:\n typeof record.oldText === \"string\" ? record.oldText : undefined,\n newText:\n typeof record.newText === \"string\" ? record.newText : undefined,\n };\n continue;\n }\n const inner = asRecord(record.content) ?? record;\n const text =\n pickString(inner, \"text\", \"content\", \"output\") ??\n pickString(record, \"text\", \"output\");\n if (text) texts.push(text);\n const metadata = asRecord(record.metadata) ?? asRecord(inner.metadata);\n const exitCode =\n pickNumber(metadata, \"exitCode\", \"exit_code\") ??\n pickNumber(record, \"exitCode\", \"exit_code\") ??\n pickNumber(inner, \"exitCode\", \"exit_code\");\n if (exitCode !== undefined) parsedExitCode = exitCode;\n }\n const joined = stripAnsi(texts.join(\"\\n\")).trim();\n return {\n text: joined === \"\" ? undefined : joined,\n diff,\n exitCode: parsedExitCode,\n };\n}\n\n/** The raw `data.toolCall` object the ACP service forwards (see its field\n * mapping). Kept as an open record because adapters vary in which fields they\n * populate (`title`/`name`, `rawInput`/`input`, `output`/`rawOutput`, …); every\n * field is read defensively via {@link pickString} / {@link asRecord}. */\nfunction rawToolCall(\n event: CodingAgentTaskEventRecord,\n): Record<string, unknown> | undefined {\n return asRecord(event.data?.toolCall);\n}\n\n/** Merge the ordered `tool_running` events for one call into a single view:\n * inputs from whichever event carried them, the latest status, and the latest\n * non-empty output. */\nfunction toToolView(\n id: string,\n groupKey: string,\n events: CodingAgentTaskEventRecord[],\n): ToolView {\n let title = \"tool\";\n let kind = \"\";\n let status: ToolStatus = \"running\";\n let rawStatus: string | undefined;\n let rawInput: Record<string, unknown> | undefined;\n let rawOutput: unknown;\n let output: string | undefined;\n let outputDiff: ToolOutput[\"diff\"];\n let exitCode: number | undefined;\n for (const event of events) {\n const call = rawToolCall(event);\n if (!call) continue;\n title = pickString(call, \"title\", \"name\", \"toolName\") ?? title;\n kind = pickString(call, \"kind\") ?? kind;\n const nextRawStatus = pickString(call, \"status\");\n if (nextRawStatus) {\n rawStatus = nextRawStatus;\n status = TOOL_STATUS_FROM_RAW[nextRawStatus] ?? status;\n }\n const nextInput = asRecord(call.rawInput) ?? asRecord(call.input);\n if (nextInput) rawInput = { ...rawInput, ...nextInput };\n const nextRawOutput = call.output ?? call.rawOutput;\n if (nextRawOutput !== undefined) rawOutput = nextRawOutput;\n const parsed = parseToolOutput(nextRawOutput);\n if (parsed.text) output = parsed.text;\n if (\n parsed.diff?.oldText !== undefined ||\n parsed.diff?.newText !== undefined\n )\n outputDiff = parsed.diff;\n if (parsed.exitCode !== undefined) exitCode = parsed.exitCode;\n const nextExit =\n pickNumber(asRecord(call.exitStatus), \"exitCode\") ??\n pickNumber(call, \"exitCode\");\n if (nextExit !== undefined) exitCode = nextExit;\n }\n // A finished exec tool's exit code is the authoritative status — opencode tops\n // its tool events out at in_progress, so the code is what distinguishes a\n // success from a failure.\n if (typeof exitCode === \"number\") status = exitCode === 0 ? \"done\" : \"failed\";\n // Wall-clock span from the tool's first to last event.\n const durationMs =\n events.length > 1\n ? events[events.length - 1].timestamp - events[0].timestamp\n : undefined;\n return {\n groupKey,\n id,\n eventIds: events.map((event) => event.id),\n sessionId: events[0]?.sessionId ?? null,\n title,\n kind,\n rawStatus,\n rawInput,\n rawOutput,\n status,\n filePath: pickString(rawInput, \"filePath\", \"file_path\", \"path\"),\n command: pickString(rawInput, \"command\", \"cmd\", \"script\"),\n // A pure insertion (`old_string:\"\"`), deletion-only edit (`new_string:\"\"`),\n // or empty-file write (`content:\"\"`) is a real change whose \"\" must survive\n // — pickString drops empty strings, so check the content keys directly and\n // only fall back to it (then the output diff) for the rest.\n newText:\n typeof rawInput?.content === \"string\"\n ? rawInput.content\n : typeof rawInput?.new_string === \"string\"\n ? rawInput.new_string\n : typeof rawInput?.newString === \"string\"\n ? rawInput.newString\n : (pickString(rawInput, \"newText\") ?? outputDiff?.newText),\n oldText:\n typeof rawInput?.old_string === \"string\"\n ? rawInput.old_string\n : typeof rawInput?.oldString === \"string\"\n ? rawInput.oldString\n : (pickString(rawInput, \"oldText\") ?? outputDiff?.oldText),\n query: pickString(rawInput, \"pattern\", \"query\", \"regex\", \"glob\"),\n output,\n exitCode,\n durationMs: durationMs && durationMs > 0 ? durationMs : undefined,\n };\n}\n\ntype Atom =\n | {\n at: number;\n order: number;\n type: \"message\";\n message: CodingAgentTaskMessageRecord;\n }\n | { at: number; order: number; type: \"tool\"; tool: ToolView }\n | {\n at: number;\n order: number;\n type: \"reasoning\";\n eventId: string;\n text: string;\n sessionId: string | null;\n }\n | {\n at: number;\n order: number;\n type: \"notice\";\n eventId: string;\n sessionId: string | null;\n eventType: string;\n summary: string;\n };\n\n/** The lane an agent/user message coalesces into; messages in the same lane that\n * are adjacent in time merge into one turn. `stderr` stays in its own lane so\n * error output never blends into normal prose. */\nfunction messageLane(message: CodingAgentTaskMessageRecord): string {\n // Each user message is its own turn: key on the id (not a shared \"user\"\n // lane) so consecutive user messages don't coalesce into one run-on bubble\n // under a single (wrong) shared timestamp.\n if (message.senderKind === \"user\") return `user:${message.id}`;\n const stream = message.direction === \"stderr\" ? \"err\" : \"out\";\n // Fall back to the message id, not a shared empty string, so unrelated\n // session-less output never coalesces into one rendered turn.\n return `${message.senderKind}:${message.sessionId ?? message.id}:${stream}`;\n}\n\nfunction toolGroupKey(\n event: CodingAgentTaskEventRecord,\n toolCallId: string,\n): string {\n return `${event.sessionId ?? event.threadId ?? \"sessionless\"}:${toolCallId}`;\n}\n\n/** Turn the polled message + event records into the ordered conversation the\n * room renders. */\nexport function buildConversation(\n messages: CodingAgentTaskMessageRecord[],\n events: CodingAgentTaskEventRecord[],\n resolveSenderName: (message: CodingAgentTaskMessageRecord) => string,\n finishedSessionIds: ReadonlySet<string>,\n): ConversationBlock[] {\n const toolEvents = new Map<\n string,\n { id: string; events: CodingAgentTaskEventRecord[] }\n >();\n const toolFirstSeen = new Map<string, number>();\n const atoms: Atom[] = [];\n let order = 0;\n\n for (const message of messages) {\n // Skip raw stdin/keystroke echoes from sub-agents, but ALWAYS render the\n // user's own typed messages — those are recorded with senderKind \"user\"\n // AND direction \"stdin\", and skipping them hid the user's input entirely.\n if (\n message.senderKind !== \"user\" &&\n (message.direction === \"stdin\" || message.direction === \"keys\")\n )\n continue;\n if (stripAnsi(message.content).trim() === \"\") continue;\n atoms.push({\n at: message.timestamp,\n order: order++,\n type: \"message\",\n message,\n });\n }\n\n for (const event of events) {\n const call = rawToolCall(event);\n if (call) {\n const id =\n pickString(call, \"id\", \"toolCallId\", \"callId\") ?? `tool-${event.id}`;\n const groupKey = toolGroupKey(event, id);\n const group = toolEvents.get(groupKey);\n if (group) group.events.push(event);\n else {\n toolEvents.set(groupKey, { id, events: [event] });\n toolFirstSeen.set(groupKey, event.timestamp);\n }\n continue;\n }\n // Reasoning streams as many small `agent_thought_chunk` deltas; capture the\n // full text from event.data (not the 160-char summary) and let the block\n // pass coalesce consecutive deltas into one collapsible cell — rendering\n // each delta as its own notice would flood the room.\n if (event.eventType === \"reasoning\") {\n const text = typeof event.data?.text === \"string\" ? event.data.text : \"\";\n if (text)\n atoms.push({\n at: event.timestamp,\n order: order++,\n type: \"reasoning\",\n eventId: event.id,\n text,\n sessionId: event.sessionId,\n });\n continue;\n }\n if (NOISE_EVENT_TYPES.has(event.eventType)) continue;\n atoms.push({\n at: event.timestamp,\n order: order++,\n type: \"notice\",\n eventId: event.id,\n sessionId: event.sessionId,\n eventType: event.eventType,\n summary: event.summary,\n });\n }\n\n for (const [groupKey, group] of toolEvents) {\n const list = group.events;\n const tool = toToolView(group.id, groupKey, list);\n // opencode never persists a tool's terminal status — its events top out at\n // `in_progress`. Once the owning session has finished, a still-\"running\"\n // tool has in fact completed, so reflect that instead of a perpetual spinner.\n const sessionId = list[0].sessionId;\n if (\n tool.status === \"running\" &&\n sessionId &&\n finishedSessionIds.has(sessionId)\n ) {\n tool.status = \"done\";\n }\n atoms.push({\n at: toolFirstSeen.get(groupKey) ?? list[0].timestamp,\n order: order++,\n type: \"tool\",\n tool,\n });\n }\n\n atoms.sort((a, b) => a.at - b.at || a.order - b.order);\n\n const blocks: ConversationBlock[] = [];\n let openLane: {\n lane: string;\n block: Extract<ConversationBlock, { kind: \"user\" | \"agent\" }>;\n } | null = null;\n // Consecutive reasoning deltas coalesce into one collapsible cell, the way a\n // message lane coalesces; any non-reasoning atom closes the burst.\n let openReasoning: Extract<ConversationBlock, { kind: \"reasoning\" }> | null =\n null;\n\n for (const atom of atoms) {\n if (atom.type === \"message\") {\n openReasoning = null;\n const lane = messageLane(atom.message);\n const text = stripAnsi(atom.message.content);\n if (openLane && openLane.lane === lane) {\n openLane.block.content += text;\n openLane.block.messageIds.push(atom.message.id);\n continue;\n }\n if (atom.message.senderKind === \"user\") {\n const block: ConversationBlock = {\n kind: \"user\",\n key: `msg-${atom.message.id}`,\n at: atom.at,\n content: text,\n messageIds: [atom.message.id],\n sessionId: atom.message.sessionId,\n };\n blocks.push(block);\n openLane = { lane, block };\n } else {\n const block: ConversationBlock = {\n kind: \"agent\",\n key: `msg-${atom.message.id}`,\n at: atom.at,\n senderName: resolveSenderName(atom.message),\n content: text,\n tone: atom.message.direction === \"stderr\" ? \"error\" : \"normal\",\n messageIds: [atom.message.id],\n sessionId: atom.message.sessionId,\n };\n blocks.push(block);\n openLane = { lane, block };\n }\n continue;\n }\n openLane = null;\n if (atom.type === \"reasoning\") {\n // Reasoning is still arriving as long as its owning session has not\n // finished; a session-less burst can never be marked finished, so it is\n // treated as settled (its last delta is its end).\n const streaming = atom.sessionId\n ? !finishedSessionIds.has(atom.sessionId)\n : false;\n if (openReasoning && openReasoning.sessionId === atom.sessionId) {\n openReasoning.text += atom.text;\n openReasoning.eventIds.push(atom.eventId);\n // Span = last delta's time − the burst's first; recomputed as deltas\n // append so it always reflects the full burst.\n openReasoning.durationMs = atom.at - openReasoning.at;\n openReasoning.streaming = streaming;\n } else {\n const block = {\n kind: \"reasoning\" as const,\n key: `reason-${atom.eventId}`,\n at: atom.at,\n text: atom.text,\n eventIds: [atom.eventId],\n sessionId: atom.sessionId,\n // A single-delta burst has no span yet; left undefined so the header\n // reads \"Thought\" rather than \"Thought for 0s\".\n durationMs: undefined,\n streaming,\n };\n blocks.push(block);\n openReasoning = block;\n }\n continue;\n }\n openReasoning = null;\n if (atom.type === \"tool\") {\n blocks.push({\n kind: \"tool\",\n key: `tool-${atom.tool.groupKey}`,\n at: atom.at,\n tool: atom.tool,\n });\n } else {\n const meta = noticeMeta(atom.eventType);\n blocks.push({\n kind: \"notice\",\n key: `evt-${atom.eventId}`,\n at: atom.at,\n eventId: atom.eventId,\n eventType: atom.eventType,\n sessionId: atom.sessionId,\n icon: meta.icon,\n tone: meta.tone,\n text: atom.summary.trim() || meta.label,\n });\n }\n }\n\n return blocks;\n}\n"],"mappings":"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","names":[]}