@chrok/dsh-braid 0.3.2 → 0.3.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.
package/README.md CHANGED
@@ -44,6 +44,7 @@ agent's model captured at submission.
44
44
  | Read a job | `braid_status({ jobId })` |
45
45
  | Read a specific invocation | `braid_status({ jobId, executionId })` |
46
46
  | Read a node's latest invocation | `braid_status({ jobId, nodeId })` |
47
+ | Page earlier activity of an invocation | `braid_status({ jobId, executionId, activityBefore })` |
47
48
  | Atomically edit/resume | `braid_update({ jobId, expectedRevision, ...patch })` |
48
49
  | Resume without edits | `braid_resume({ jobId, expectedRevision, executionIds })` |
49
50
  | Cancel | `braid_cancel({ jobId })` or `/braid cancel <jobId>` |
@@ -87,6 +88,14 @@ floating and fullscreen. It follows the session that owns the tab.
87
88
  - Click a node to select an exact execution, including earlier loop iterations.
88
89
  Inspect output, decisions, errors, context usage, tool counts, latency, workspace
89
90
  details and recovery refs. Output is paged in 32,768-character chunks.
91
+ - Watch a running execution's live activity: phase and time in phase, time since
92
+ the last observed signal, total time, the in-flight model request (awaiting its
93
+ first stream event or streaming text/reasoning/tool-call arguments), and running
94
+ tools with arguments and latest shell output. The chronological history shows
95
+ model requests/responses, assistant text, tool calls/results, workspace changes,
96
+ and completion; expand an entry for its bounded detail preview, or load earlier
97
+ entries 50 at a time. Missing host signals are listed as unavailable; quiet
98
+ periods are shown as elapsed time, not as a stall.
90
99
  - View the latest 80 lifecycle events and input/output/cache token totals.
91
100
  - Cancel the job, resume one paused execution, or resume all paused executions.
92
101
  Resume submits the revision currently displayed; stale revisions are rejected
@@ -94,8 +103,9 @@ floating and fullscreen. It follows the session that owns the tab.
94
103
 
95
104
  The Host sends structured snapshots through DSH's authenticated Remote transport,
96
105
  coalesced to at most one update per 150 ms per observer. Prompts, provider messages
97
- and node outputs are excluded from that stream; selected outputs are read
98
- separately. Switching sessions or closing the tab stops observation, while jobs
106
+ and node outputs are excluded from that stream; selected outputs and activity
107
+ history are read separately. Running executions carry a compact activity summary;
108
+ stream and tool-output activity refreshes it at most once per second. Switching sessions or closing the tab stops observation, while jobs
99
109
  continue. Disconnected controls are disabled; the panel retries the stream, then
100
110
  offers manual reconnect if retries fail.
101
111
 
@@ -107,7 +117,9 @@ Unloading the plugin removes its tab type, slots, styles and Remote methods.
107
117
 
108
118
  The generic Jobs panel also streams a text flow diagram, node states, elapsed times, context
109
119
  token estimates/provider reports, context capacity when available, tool counts,
110
- and recent events. Its own stop action cancels the Braid run. Closing the panel
120
+ and recent events; its progress line names the first running node's activity
121
+ phase, and `/braid` adds an activity line for each running node. Its own stop
122
+ action cancels the Braid run. Closing the panel
111
123
  leaves it running. `/braid` returns a snapshot in the command UI; it does not open
112
124
  Pi's terminal overlay or bind Pi's keyboard shortcuts. Headless profiles can use
113
125
  the tools and commands without a Web UI.
@@ -1,3 +1,3 @@
1
1
  /** Scoped styles share the Host's fonts and honor both system and DSH dark themes. */
2
2
  export declare const styles = "\n.braid-panel{--br-bg:var(--dsw-alias-bg-base,#fff);--br-fg:var(--dsw-alias-label-primary,#222b38);--br-soft:var(--dsw-alias-bg-module-platform,#f4f6f8);--br-line:var(--dsw-alias-border-l2,#dce2e8);--br-muted:var(--dsw-alias-label-secondary,#667384);--br-accent:#336dbe;--br-green:var(--dsw-alias-state-success-primary,#18794e);--br-red:var(--dsw-alias-state-error-primary,#ba3340);color:var(--br-fg);background:var(--br-bg);font:inherit;font-size:13px;line-height:1.5;box-sizing:border-box;height:100%;overflow:auto;min-width:0;container-type:inline-size}\n.braid-panel *{box-sizing:border-box}.braid-panel button,.braid-panel select{font:inherit;color:inherit}.braid-panel button,.braid-panel select{border:1px solid var(--br-line);border-radius:7px;background:var(--br-bg);padding:6px 10px}.braid-panel button{cursor:pointer}.braid-panel button:hover:not(:disabled){border-color:var(--br-accent)}.braid-panel button:focus-visible,.braid-panel select:focus-visible{outline:2px solid var(--br-accent);outline-offset:2px}.braid-panel button:disabled{opacity:.45;cursor:default}.braid-panel .br-primary{background:var(--br-accent);color:white;border-color:transparent}.braid-panel .br-danger{color:var(--br-red)}\n.br-header{padding:20px 18px 12px;border-bottom:1px solid var(--br-line)}.br-heading{display:flex;align-items:center;gap:9px}.br-heading h2{font-size:18px;letter-spacing:-.4px;margin:0}.br-heading small{margin-left:auto;color:var(--br-muted)}.br-eyebrow{text-transform:uppercase;letter-spacing:1.4px;font-size:10px;color:var(--br-muted);margin-bottom:5px}.br-select{width:100%;margin:14px 0 8px}.br-goal{margin:8px 0;overflow-wrap:anywhere}.br-muted{color:var(--br-muted)}.br-toolbar{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.br-status{display:inline-flex;align-items:center;gap:5px;font-size:11px;white-space:nowrap}.br-status:before{content:'';width:6px;height:6px;border-radius:50%;background:var(--br-muted)}.br-status[data-status=running]:before,.br-status[data-status=runnable]:before{background:var(--br-accent)}.br-status[data-status=completed]:before{background:var(--br-green)}.br-status[data-status=failed]:before,.br-status[data-status=cancelled]:before{background:var(--br-red)}.br-status[data-status=waiting]:before{background:#ba861a}\n.br-stats{display:grid;grid-template-columns:repeat(4,1fr);padding:14px 18px;gap:8px;border-bottom:1px solid var(--br-line)}.br-stats strong{display:block;font-size:16px;font-variant-numeric:tabular-nums}.br-stats span{font-size:10px;color:var(--br-muted)}.br-section{padding:14px 18px;border-bottom:1px solid var(--br-line)}.br-section h3{font-size:12px;margin:0 0 10px}.br-section-head{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:10px}.br-section-head h3{margin:0}.br-section-head button{padding:2px 8px}.br-graph{overflow:auto;background:var(--br-soft);border:1px solid var(--br-line);border-radius:9px;max-height:420px}.br-graph-canvas{position:relative}.br-graph svg{position:absolute;inset:0;overflow:visible}.br-graph path{fill:none;stroke:var(--br-muted);stroke-width:1.2}.br-graph text{font-size:10px;fill:var(--br-muted)}.br-node{position:absolute;display:flex;flex-direction:column;align-items:flex-start;justify-content:center;width:154px;height:72px;text-align:left;gap:2px;box-shadow:0 2px 5px #00000006}.br-node[aria-pressed=true]{outline:2px solid var(--br-accent);outline-offset:2px}.br-node strong{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.br-node small{font-size:10px;color:var(--br-muted)}.br-legend{display:flex;gap:12px;flex-wrap:wrap;font-size:10px;color:var(--br-muted);margin-top:8px}.br-note{font-size:11px;color:var(--br-muted);margin:8px 0 0;overflow-wrap:anywhere}\n.br-notice{margin:12px 18px;padding:10px 12px;border:1px solid var(--br-line);border-radius:8px;background:var(--br-soft);overflow-wrap:anywhere}.br-notice[role=alert]{color:var(--br-red)}.br-empty{padding:48px 24px;text-align:center}.br-empty h3{font-size:15px}.br-empty p{color:var(--br-muted);max-width:36em;margin:12px auto}.br-detail-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px 16px;font-size:11px;margin:12px 0}.br-detail-grid span{color:var(--br-muted);display:block}.br-output{white-space:pre-wrap;overflow-wrap:anywhere;background:var(--br-soft);border:1px solid var(--br-line);padding:12px;border-radius:8px;max-height:340px;overflow:auto;font:11px/1.65 ui-monospace,SFMono-Regular,monospace;margin:8px 0}.br-tabs{display:flex;gap:5px;margin:14px 0 10px}.br-tabs button[aria-pressed=true]{border-color:var(--br-accent);color:var(--br-accent)}.br-events{list-style:none;padding:0;margin:0;max-height:320px;overflow:auto}.br-events li{padding:8px 0;display:grid;grid-template-columns:64px 1fr;gap:8px;border-bottom:1px solid var(--br-line);font-size:11px}.br-events time{color:var(--br-muted);font-variant-numeric:tabular-nums}.br-events p{margin:0;overflow-wrap:anywhere}.br-events small{color:var(--br-muted)}.br-header-action{font:inherit;border:0;border-radius:6px;padding:5px 9px;background:transparent;color:inherit;cursor:pointer}.br-header-action:hover{background:#8882}\n@container (max-width:330px){.br-stats{grid-template-columns:repeat(2,1fr)}.br-header,.br-section{padding-left:12px;padding-right:12px}}\n@media(prefers-color-scheme:dark){.braid-panel{--br-bg:var(--dsw-alias-bg-base,#171b22);--br-fg:var(--dsw-alias-label-primary,#e0e6ee);--br-soft:var(--dsw-alias-bg-module-platform,#202630);--br-line:var(--dsw-alias-border-l2,#354050);--br-muted:var(--dsw-alias-label-secondary,#a0adbe);--br-accent:#80b6ff;--br-green:var(--dsw-alias-state-success-primary,#69d6a0);--br-red:var(--dsw-alias-state-error-primary,#ff919a)}.braid-panel .br-primary{color:#162336}}\n[data-theme=dark] .braid-panel,.dark .braid-panel{--br-bg:var(--dsw-alias-bg-base,#171b22);--br-fg:var(--dsw-alias-label-primary,#e0e6ee);--br-soft:var(--dsw-alias-bg-module-platform,#202630);--br-line:var(--dsw-alias-border-l2,#354050);--br-muted:var(--dsw-alias-label-secondary,#a0adbe);--br-accent:#80b6ff;--br-green:var(--dsw-alias-state-success-primary,#69d6a0);--br-red:var(--dsw-alias-state-error-primary,#ff919a)}\n";
3
- export declare const toolStyles = "\n.br-tool-call{font:inherit;font-size:12px;color:var(--dsw-alias-label-primary,inherit);border:1px solid var(--dsw-alias-border-l2,#8884);border-radius:9px;margin:8px 0;overflow:hidden}\n.br-tool-call button{font:inherit;color:inherit;cursor:pointer}.br-tool-call button:focus-visible{outline:2px solid #639be6;outline-offset:-2px}.br-tool-call button:disabled{cursor:default;opacity:.6}\n.br-tool-open{display:flex;width:100%;align-items:center;gap:10px;padding:12px;border:0;background:var(--dsw-alias-bg-module-platform,#8881);text-align:left}.br-tool-open:hover:not(:disabled){background:var(--dsw-alias-fill-l1,#8882)}.br-tool-open>span:last-child{margin-left:auto}\n.br-tool-main{display:flex;flex-wrap:wrap;align-items:baseline;gap:3px 8px;min-width:0}.br-tool-target{overflow-wrap:anywhere;color:var(--dsw-alias-label-secondary,inherit)}.br-tool-summary{flex-basis:100%;font-size:11px}.br-tool-call[data-state=failed] .br-tool-summary,.br-tool-error{color:var(--dsw-alias-state-error-primary,#c34e59)}\n.br-tool-actions{display:flex;gap:8px;padding:6px 12px}.br-tool-actions button{border:0;background:transparent;font-size:11px;text-decoration:underline;text-underline-offset:3px;padding:3px 0}.br-tool-details{padding:8px 12px;border-top:1px solid var(--dsw-alias-border-l2,#8884)}.br-tool-details pre{font:11px/1.6 ui-monospace,monospace;white-space:pre-wrap;overflow-wrap:anywhere;max-height:220px;overflow:auto}.br-tool-error{padding:0 12px;white-space:pre-wrap;overflow-wrap:anywhere;font-size:11px}\n.br-tool-note{margin:4px 12px;color:var(--dsw-alias-label-secondary,inherit);font-size:10px;opacity:.8}.br-tool-changes{display:flex;flex-wrap:wrap;gap:5px;padding:8px 12px}.br-tool-changes span{padding:3px 6px;border-radius:4px;background:var(--dsw-alias-bg-module-platform,#8881);font-size:10px;overflow-wrap:anywhere}.br-tool-jobs{list-style:none;margin:0;padding:6px 12px;max-height:230px;overflow:auto}.br-tool-jobs button{display:flex;gap:12px;width:100%;padding:6px 0;border:0;background:transparent;text-align:left}.br-tool-jobs span{margin-left:auto}\n";
3
+ export declare const toolStyles = "\n.br-tool-call{font:inherit;font-size:12px;color:var(--dsw-alias-label-primary,inherit);border:1px solid var(--dsw-alias-border-l2,#8884);border-radius:9px;margin:8px 0;overflow:hidden}\n.br-tool-call button{font:inherit;color:inherit;cursor:pointer}.br-tool-call button:focus-visible{outline:2px solid #639be6;outline-offset:-2px}.br-tool-call button:disabled{cursor:default;opacity:.6}\n.br-tool-open{display:flex;width:100%;align-items:center;gap:10px;padding:12px;border:0;background:var(--dsw-alias-bg-module-platform,#8881);text-align:left}.br-tool-open:hover:not(:disabled){background:var(--dsw-alias-fill-l1,#8882)}.br-tool-open>span:last-child{margin-left:auto}\n.br-tool-main{display:flex;flex-wrap:wrap;align-items:baseline;gap:3px 8px;min-width:0}.br-tool-target{overflow-wrap:anywhere;color:var(--dsw-alias-label-secondary,inherit)}.br-tool-summary{flex-basis:100%;font-size:11px}.br-tool-call[data-state=failed] .br-tool-summary,.br-tool-error{color:var(--dsw-alias-state-error-primary,#c34e59)}\n.br-tool-actions{display:flex;gap:8px;padding:6px 12px}.br-tool-actions button{border:0;background:transparent;font-size:11px;text-decoration:underline;text-underline-offset:3px;padding:3px 0}.br-tool-details{padding:8px 12px;border-top:1px solid var(--dsw-alias-border-l2,#8884)}.br-tool-details pre{font:11px/1.6 ui-monospace,monospace;white-space:pre-wrap;overflow-wrap:anywhere;max-height:220px;overflow:auto}.br-tool-error{padding:0 12px;white-space:pre-wrap;overflow-wrap:anywhere;font-size:11px}\n.br-activity{margin:0 0 12px}.br-activity .br-detail-grid{margin-bottom:8px}.br-activity .br-tail{max-height:120px}.br-activity-log{max-height:420px}.br-activity-log li[data-error] p{color:var(--br-red)}.br-activity-log details summary{cursor:pointer;color:var(--br-muted)}\n.br-tool-note{margin:4px 12px;color:var(--dsw-alias-label-secondary,inherit);font-size:10px;opacity:.8}.br-tool-changes{display:flex;flex-wrap:wrap;gap:5px;padding:8px 12px}.br-tool-changes span{padding:3px 6px;border-radius:4px;background:var(--dsw-alias-bg-module-platform,#8881);font-size:10px;overflow-wrap:anywhere}.br-tool-jobs{list-style:none;margin:0;padding:6px 12px;max-height:230px;overflow:auto}.br-tool-jobs button{display:flex;gap:12px;width:100%;padding:6px 0;border:0;background:transparent;text-align:left}.br-tool-jobs span{margin-left:auto}\n";
package/dist/client.js CHANGED
@@ -36,7 +36,7 @@ function parseRequest(value, method) {
36
36
  if (r.createdBefore !== void 0 && (!Number.isSafeInteger(r.createdBefore) || Number(r.createdBefore) < 0)) throw new Error("Invalid call timestamp");
37
37
  if (method !== "watch" && !id2("jobId")) throw new Error("A job ID is required");
38
38
  if (method === "control" && (!["cancel", "resume"].includes(String(r.action)) || !Number.isSafeInteger(r.revision) || Number(r.revision) < 0 || !Array.isArray(r.executionIds) || r.executionIds.length > 1e4 || r.executionIds.some((v) => typeof v !== "string" || !v || v.length > 1024))) throw new Error("Invalid Braid control request");
39
- if (method === "detail" && (!id2("executionId") || !Number.isSafeInteger(r.offset) || Number(r.offset) < 0)) throw new Error("Invalid execution or offset");
39
+ if (method === "detail" && (!id2("executionId") || !Number.isSafeInteger(r.offset) || Number(r.offset) < 0 || r.activityBefore !== void 0 && (!Number.isSafeInteger(r.activityBefore) || Number(r.activityBefore) < 1))) throw new Error("Invalid execution, offset, or activity page");
40
40
  return value;
41
41
  }
42
42
  var panelDescriptors = ["watch", "control", "detail"].map((method) => ({
@@ -90,6 +90,111 @@ function layoutGraph(nodes, edges) {
90
90
  var import_jsx_runtime = require("react/jsx-runtime");
91
91
  var number = (n) => n.toLocaleString();
92
92
  var message = (error) => error instanceof Error ? error.message : String(error);
93
+ var duration = (ms) => {
94
+ const value = Math.max(0, ms);
95
+ return value < 6e4 ? `${(value / 1e3).toFixed(1)}s` : `${Math.floor(value / 6e4)}m ${Math.floor(value % 6e4 / 1e3)}s`;
96
+ };
97
+ function useHostClock(job, live) {
98
+ const receivedAt = (0, import_react.useMemo)(() => Date.now(), [job]);
99
+ const [clock, setClock] = (0, import_react.useState)(() => Date.now());
100
+ (0, import_react.useEffect)(() => {
101
+ setClock(Date.now());
102
+ if (!live) return;
103
+ const timer = setInterval(() => setClock(Date.now()), 1e3);
104
+ return () => clearInterval(timer);
105
+ }, [job, live]);
106
+ return job.observedAt + Math.max(0, clock - receivedAt);
107
+ }
108
+ function ActivityView({ activity, entries, now, loadEarlier }) {
109
+ const end = activity.finishedAt ?? now;
110
+ const model = activity.model;
111
+ const running = activity.finishedAt === void 0;
112
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "br-activity", "aria-label": "Live activity", children: [
113
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "br-detail-grid", children: [
114
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
115
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Phase" }),
116
+ activity.phase,
117
+ " \xB7 ",
118
+ duration(end - activity.phaseStartedAt)
119
+ ] }),
120
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
121
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Last activity" }),
122
+ running ? `${duration(now - activity.lastActivityAt)} ago` : "\u2014",
123
+ " \xB7 ",
124
+ activity.lastActivity
125
+ ] }),
126
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
127
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Total" }),
128
+ duration(end - activity.startedAt)
129
+ ] }),
130
+ model && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
131
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
132
+ "Model request #",
133
+ model.round
134
+ ] }),
135
+ model.completedAt !== void 0 ? `returned after ${duration(model.completedAt - model.startedAt)}` : model.firstStreamAt === void 0 ? `sent ${duration(now - model.startedAt)} ago \xB7 no stream events yet` : `streaming ${model.receiving ?? "output"}${model.toolName ? ` (${model.toolName})` : ""} \xB7 ${number(model.receivedChars)} chars \xB7 last ${duration(now - (model.lastStreamAt ?? model.firstStreamAt))} ago`
136
+ ] }),
137
+ activity.tools.map((tool) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
138
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Running tool" }),
139
+ tool.name,
140
+ " \xB7 ",
141
+ duration(now - tool.startedAt),
142
+ " \xB7 ",
143
+ tool.lastOutputAt === void 0 ? "no output yet" : `last output ${duration(now - tool.lastOutputAt)} ago`
144
+ ] }, tool.callId))
145
+ ] }),
146
+ model?.completedAt === void 0 && model?.tail && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("pre", { className: "br-output br-tail", "aria-label": "Latest streamed output", children: [
147
+ "\u2026",
148
+ model.tail
149
+ ] }),
150
+ activity.tools.map((tool) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { children: [
151
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("summary", { children: [
152
+ tool.name,
153
+ " arguments",
154
+ tool.outputTail ? " and latest output" : ""
155
+ ] }),
156
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("pre", { className: "br-output", children: [
157
+ tool.arguments,
158
+ tool.outputTail ? `
159
+
160
+ \u2026${tool.outputTail}` : ""
161
+ ] })
162
+ ] }, tool.callId)),
163
+ activity.limitations.map((text) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "br-note", children: [
164
+ "Unavailable: ",
165
+ text
166
+ ] }, text)),
167
+ running && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "br-note", children: "Times since the last observed signal are diagnostic; a quiet worker is not necessarily stalled." }),
168
+ entries && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { open: running, children: [
169
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("summary", { children: [
170
+ "Activity history (",
171
+ activity.sequence,
172
+ ")"
173
+ ] }),
174
+ (entries[0]?.sequence ?? activity.sequence + 1) > activity.droppedEntries + 1 && loadEarlier && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: loadEarlier, children: "Load earlier activity" }),
175
+ activity.droppedEntries > 0 && (entries[0]?.sequence ?? 0) <= activity.droppedEntries + 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "br-note", children: [
176
+ activity.droppedEntries,
177
+ " earlier entries were trimmed to bound memory."
178
+ ] }),
179
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", { className: "br-events br-activity-log", children: entries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { "data-error": entry.isError ? "" : void 0, children: [
180
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("time", { children: [
181
+ "+",
182
+ duration(entry.timestamp - activity.startedAt)
183
+ ] }),
184
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
185
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: entry.summary }),
186
+ entry.detail && entry.detail !== entry.summary && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { children: [
187
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("summary", { children: [
188
+ "Details",
189
+ entry.detailLength ? ` (${number(entry.detailLength)} characters, preview)` : ""
190
+ ] }),
191
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", { className: "br-output", children: entry.detail })
192
+ ] })
193
+ ] })
194
+ ] }, entry.sequence)) })
195
+ ] })
196
+ ] });
197
+ }
93
198
  function Status({ status }) {
94
199
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "br-status", "data-status": status, children: status });
95
200
  }
@@ -164,9 +269,11 @@ function ExecutionDetail({ api, sessionId, job, execution }) {
164
269
  const [error, setError] = (0, import_react.useState)("");
165
270
  const [offset, setOffset] = (0, import_react.useState)(0);
166
271
  const [retry, setRetry] = (0, import_react.useState)(0);
272
+ const [activityBefore, setActivityBefore] = (0, import_react.useState)();
273
+ const [earlier, setEarlier] = (0, import_react.useState)([]);
274
+ const sequence = execution.activity?.sequence;
167
275
  (0, import_react.useEffect)(() => {
168
276
  let active = true;
169
- setDetail(void 0);
170
277
  setError("");
171
278
  void api.detail({ sessionId, jobId: job.jobId, executionId: execution.executionId, offset }).then((value) => {
172
279
  if (active) setDetail(value);
@@ -176,8 +283,28 @@ function ExecutionDetail({ api, sessionId, job, execution }) {
176
283
  return () => {
177
284
  active = false;
178
285
  };
179
- }, [api, sessionId, job.jobId, job.status, execution.executionId, execution.status, offset, retry]);
286
+ }, [api, sessionId, job.jobId, job.status, execution.executionId, execution.status, offset, retry, sequence]);
287
+ (0, import_react.useEffect)(() => {
288
+ if (activityBefore === void 0) return;
289
+ let active = true;
290
+ void api.detail({ sessionId, jobId: job.jobId, executionId: execution.executionId, offset: 0, activityBefore }).then((value) => {
291
+ if (active) setEarlier((previous) => [...value.activity?.entries ?? [], ...previous]);
292
+ }, (e) => {
293
+ if (active) setError(message(e));
294
+ });
295
+ return () => {
296
+ active = false;
297
+ };
298
+ }, [api, sessionId, job.jobId, execution.executionId, activityBefore]);
180
299
  const p = execution.progress;
300
+ const activity = execution.activity ?? detail?.activity;
301
+ const now = useHostClock(job, execution.status === "running");
302
+ const seen = (0, import_react.useRef)(/* @__PURE__ */ new Map());
303
+ const latest = detail?.activity?.entries ?? [];
304
+ const from = earlier[0]?.sequence ?? latest[0]?.sequence ?? Infinity;
305
+ for (const entry of [...earlier, ...latest]) seen.current.set(entry.sequence, entry);
306
+ for (const sequence2 of seen.current.keys()) if (sequence2 < from) seen.current.delete(sequence2);
307
+ const entries = [...seen.current.values()].sort((a, b) => a.sequence - b.sequence);
181
308
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
182
309
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "br-detail-grid", children: [
183
310
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
@@ -212,6 +339,17 @@ function ExecutionDetail({ api, sessionId, job, execution }) {
212
339
  p ? `${p.toolCalls} / ${p.toolRounds}` : "\u2014"
213
340
  ] })
214
341
  ] }),
342
+ activity ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
343
+ ActivityView,
344
+ {
345
+ activity,
346
+ now,
347
+ ...detail?.activity ? { entries } : {},
348
+ loadEarlier: () => {
349
+ if (entries[0]) setActivityBefore(entries[0].sequence);
350
+ }
351
+ }
352
+ ) : execution.status === "running" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "br-muted", role: "status", children: "No worker activity observed yet." }),
215
353
  error && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { role: "alert", children: [
216
354
  error,
217
355
  " ",
@@ -492,6 +630,7 @@ var toolStyles = `
492
630
  .br-tool-open{display:flex;width:100%;align-items:center;gap:10px;padding:12px;border:0;background:var(--dsw-alias-bg-module-platform,#8881);text-align:left}.br-tool-open:hover:not(:disabled){background:var(--dsw-alias-fill-l1,#8882)}.br-tool-open>span:last-child{margin-left:auto}
493
631
  .br-tool-main{display:flex;flex-wrap:wrap;align-items:baseline;gap:3px 8px;min-width:0}.br-tool-target{overflow-wrap:anywhere;color:var(--dsw-alias-label-secondary,inherit)}.br-tool-summary{flex-basis:100%;font-size:11px}.br-tool-call[data-state=failed] .br-tool-summary,.br-tool-error{color:var(--dsw-alias-state-error-primary,#c34e59)}
494
632
  .br-tool-actions{display:flex;gap:8px;padding:6px 12px}.br-tool-actions button{border:0;background:transparent;font-size:11px;text-decoration:underline;text-underline-offset:3px;padding:3px 0}.br-tool-details{padding:8px 12px;border-top:1px solid var(--dsw-alias-border-l2,#8884)}.br-tool-details pre{font:11px/1.6 ui-monospace,monospace;white-space:pre-wrap;overflow-wrap:anywhere;max-height:220px;overflow:auto}.br-tool-error{padding:0 12px;white-space:pre-wrap;overflow-wrap:anywhere;font-size:11px}
633
+ .br-activity{margin:0 0 12px}.br-activity .br-detail-grid{margin-bottom:8px}.br-activity .br-tail{max-height:120px}.br-activity-log{max-height:420px}.br-activity-log li[data-error] p{color:var(--br-red)}.br-activity-log details summary{cursor:pointer;color:var(--br-muted)}
495
634
  .br-tool-note{margin:4px 12px;color:var(--dsw-alias-label-secondary,inherit);font-size:10px;opacity:.8}.br-tool-changes{display:flex;flex-wrap:wrap;gap:5px;padding:8px 12px}.br-tool-changes span{padding:3px 6px;border-radius:4px;background:var(--dsw-alias-bg-module-platform,#8881);font-size:10px;overflow-wrap:anywhere}.br-tool-jobs{list-style:none;margin:0;padding:6px 12px;max-height:230px;overflow:auto}.br-tool-jobs button{display:flex;gap:12px;width:100%;padding:6px 0;border:0;background:transparent;text-align:left}.br-tool-jobs span{margin-left:auto}
496
635
  `;
497
636
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../client/index.tsx", "../panel-contract.ts", "../client/Panel.tsx", "../client/layout.ts", "../client/styles.ts", "../client/navigation.ts", "../client/ToolCall.tsx"],
4
- "sourcesContent": ["import * as React from \"react\";\nimport type { Context } from \"@deepseek-ai/cordis\";\nimport type {} from \"@deepseek-ai/dsh-api-gateway/client\";\nimport type {} from \"@deepseek-ai/dsh-client-ui-renderer/client\";\nimport type {} from \"@deepseek-ai/dsh-client-ui-conversation/client\";\nimport type {} from \"@deepseek-ai/dsh-client-ui-sidebar-right/client\";\nimport type {} from \"@deepseek-ai/dsh-client-ui-tool/client\";\nimport type { PropsRuntime } from \"@deepseek-ai/dsh-client-ui-slots\";\nimport type { SessionId } from \"@deepseek-ai/dsh-session/types\";\nimport type { PanelApi } from \"../panel-types.js\";\nimport { PANEL_PACKAGE, panelDescriptors } from \"../panel-contract.js\";\nimport { BraidPanelView } from \"./Panel.js\";\nimport { styles, toolStyles } from \"./styles.js\";\nimport { BraidToolCall } from \"./ToolCall.js\";\nimport { braidToolNames, readNavigation, type BraidNavigation } from \"./navigation.js\";\n\ndeclare module \"@deepseek-ai/dsh-client-ui-sidebar-right/client\" {\n interface SidebarRightTabParamsMap { braid: BraidNavigation }\n}\n\nexport const inject = [\"remote\", \"slots\", \"sidebarRight\", \"sidebarRightTabs\"];\nexport async function apply(ctx: Context): Promise<void> {\n await ctx.remote.$mount({ package: PANEL_PACKAGE, descriptors: panelDescriptors });\n ctx.inject([\"remote.braidPanel\"], ctx => {\n // Capture traced services inside their declared Cordis scope, not React event stacks.\n const remote = ctx.remote.braidPanel;\n const sidebar = ctx.sidebarRight;\n const api: PanelApi = {\n watch: (request, signal) => remote.watch(request, signal),\n control: async request => { const result = await remote.control(request); if (!result.ok) throw result.error; return result.value; },\n detail: async request => { const result = await remote.detail(request); if (!result.ok) throw result.error; return result.value; },\n };\n ctx.effect(() => {\n const style = document.createElement(\"style\"); style.dataset.plugin = PANEL_PACKAGE; style.textContent = styles + toolStyles;\n document.head.append(style); return () => { style.remove(); };\n });\n ctx.effect(() => ctx.sidebarRightTabs.register({ id: PANEL_PACKAGE, kind: \"braid\", title: () => \"Braid\",\n guide: [{ id: \"braid\", order: 50, title: () => \"Braid\", description: () => \"Live agent graphs, execution details and controls\" }],\n }));\n ctx.effect(() => ctx.slots.inject(\"sidebar.right.pane.tab\", () => ctx.slots.register({\n name: \"sidebar.right.pane.tab\", key: PANEL_PACKAGE, inject: sessionId => ({ api, sessionId }),\n }, PanelSeat)));\n ctx.effect(() => ctx.slots.inject(\"conversation.session.header.actions\", () => ctx.slots.register({\n name: \"conversation.session.header.actions\", id: \"braid\", order: 25,\n inject: () => ({ open: () => { sidebar.openTab(\"braid\"); } }),\n }, HeaderAction)));\n for (const key of braidToolNames) ctx.effect(() => ctx.slots.inject(\"tool.call.toolview\", () => ctx.slots.register({\n name: \"tool.call.toolview\", key,\n inject: sessionId => ({ openBraid: (target: BraidNavigation) => { sidebar.openTabIn(sessionId as SessionId, \"braid\", { params: target }); } }),\n }, BraidToolCall)));\n });\n}\nfunction HeaderAction({ open }: { open: () => void }) {\n return <button className=\"br-header-action\" onClick={open} title=\"Open Braid graph and execution details\" aria-label=\"Open Braid panel\">\u2387 Braid</button>;\n}\nfunction PanelSeat({ sessionId, api, useTabInfo }: PropsRuntime<\"sidebar.right.pane.tab\"> & { sessionId: string; api: PanelApi }) {\n const { tab: { navigation } } = useTabInfo();\n return <BraidPanelView key={navigation.revision} sessionId={sessionId} api={api} target={readNavigation(navigation.params)}/>;\n}\n", "import type { InvocationDescriptor, RemoteResult } from \"@deepseek-ai/dsh-typert-protocol\";\nimport type { ControlRequest, DetailRequest, PanelDetail, PanelFrame, PanelRequest } from \"./panel-types.js\";\n\n/** One descriptor table shared by Host registration and Client Remote mounting. */\nexport const PANEL_PACKAGE = \"@chrok/dsh-braid\";\nfunction parseRequest(value: unknown, method: string): unknown {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) throw new Error(\"Invalid Braid panel request\");\n const r = value as Record<string, unknown>;\n const id = (key: string) => typeof r[key] === \"string\" && (r[key] as string).length > 0 && (r[key] as string).length <= 1024;\n if (!id(\"sessionId\") || (r.jobId !== undefined && !id(\"jobId\"))) throw new Error(\"Invalid session or job ID\");\n if (r.createdBefore !== undefined && (!Number.isSafeInteger(r.createdBefore) || Number(r.createdBefore) < 0)) throw new Error(\"Invalid call timestamp\");\n if (method !== \"watch\" && !id(\"jobId\")) throw new Error(\"A job ID is required\");\n if (method === \"control\" && (\n ![\"cancel\", \"resume\"].includes(String(r.action)) || !Number.isSafeInteger(r.revision) || Number(r.revision) < 0 ||\n !Array.isArray(r.executionIds) || r.executionIds.length > 10000 || r.executionIds.some(v => typeof v !== \"string\" || !v || v.length > 1024)\n )) throw new Error(\"Invalid Braid control request\");\n if (method === \"detail\" && (!id(\"executionId\") || !Number.isSafeInteger(r.offset) || Number(r.offset) < 0)) throw new Error(\"Invalid execution or offset\");\n return value;\n}\nexport const panelDescriptors: InvocationDescriptor[] = [\"watch\", \"control\", \"detail\"].map(method => ({\n id: `${PANEL_PACKAGE}#braidPanel/${method}`, service: \"braidPanel\", namespace: \"braidPanel\", method,\n invocation: { kind: \"direct\" },\n parameters: [{ name: \"request\", wire: \"request\", source: \"json\", codec: {\n mode: \"strict\", typeSymbol: `${PANEL_PACKAGE}/${method}Request`, create: () => ({ parse: value => parseRequest(value, method) }),\n } }],\n result: { mode: \"src-json\" },\n ...(method === \"watch\" ? { mode: \"stream\" as const, cancellation: { parameter: \"signal\" as const } } : {}),\n}));\nexport interface PanelRemote {\n watch(request: PanelRequest, signal?: AbortSignal): AsyncIterable<PanelFrame>;\n control(request: ControlRequest): Promise<RemoteResult<PanelFrame>>;\n detail(request: DetailRequest): Promise<RemoteResult<PanelDetail>>;\n}\ndeclare module \"@deepseek-ai/dsh-typert-protocol\" {\n interface TypertRemoteNamespaceMap { braidPanel: PanelRemote }\n interface RemoteErrorDetailsMap { \"braid/panel\": { sessionId: string } }\n}\n", "import * as React from \"react\";\nimport { useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport type { PanelApi, PanelDetail, PanelExecution, PanelFrame, PanelJob } from \"../panel-types.js\";\nimport { layoutGraph } from \"./layout.js\";\nimport type { BraidNavigation } from \"./navigation.js\";\n\nconst number = (n: number) => n.toLocaleString();\nconst message = (error: unknown) => error instanceof Error ? error.message : String(error);\nexport function Status({ status }: { status: string }) {\n return <span className=\"br-status\" data-status={status}>{status}</span>;\n}\n\nexport function Graph({ job, selected, select }: { job: PanelJob; selected: string; select: (id: string) => void }) {\n const layout = useMemo(() => layoutGraph(job.nodes, job.edges), [job.nodes, job.edges]);\n const [zoom, setZoom] = useState(1);\n const arrow = useId().replaceAll(\":\", \"\");\n const selectedButton = useRef<HTMLButtonElement>(null);\n useEffect(() => { selectedButton.current?.scrollIntoView?.({ block: \"nearest\", inline: \"nearest\" }); }, [selected]);\n return <section className=\"br-section\" aria-label=\"Execution graph\">\n <div className=\"br-section-head\"><h3>Execution graph</h3><div className=\"br-toolbar\">\n <button aria-label=\"Zoom out\" disabled={zoom <= .5} onClick={() => setZoom(v => Math.max(.5, v - .25))}>\u2212</button>\n <button aria-label=\"Reset zoom\" onClick={() => setZoom(1)}>{Math.round(zoom * 100)}%</button>\n <button aria-label=\"Zoom in\" disabled={zoom >= 1.5} onClick={() => setZoom(v => Math.min(1.5, v + .25))}>+</button>\n </div></div>\n <div className=\"br-graph\"><div style={{ width: layout.width * zoom, height: layout.height * zoom }}>\n <div className=\"br-graph-canvas\" style={{ width: layout.width, height: layout.height, transform: `scale(${zoom})`, transformOrigin: \"top left\" }}>\n <svg width={layout.width} height={layout.height} aria-hidden=\"true\"><defs><marker id={arrow} viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"5\" markerHeight=\"5\" orient=\"auto-start-reverse\"><path d=\"M 0 0 L 10 5 L 0 10 z\" style={{ fill: \"var(--br-muted)\" }}/></marker></defs>\n {job.edges.map((edge, i) => {\n const a = layout.positions.get(edge.from), b = layout.positions.get(edge.to);\n if (!a || !b) return null;\n const x = a.x + 77, y = a.y + 72, endX = b.x + 77, endY = b.y;\n const d = edge.feedback ? `M ${a.x} ${a.y + 36} C 6 ${a.y + 36}, 6 ${b.y + 36}, ${b.x} ${b.y + 36}` : `M ${x} ${y} C ${x} ${y + 26}, ${endX} ${endY - 26}, ${endX} ${endY}`;\n return <g key={i}><path d={d} strokeDasharray={edge.feedback ? \"4 4\" : undefined} markerEnd={`url(#${arrow})`}><title>{edge.from} \u2192 {edge.to}{edge.choice ? ` (${edge.choice})` : \"\"}{edge.feedback ? ` \u00B7 loop ${edge.feedback}` : \"\"}{edge.executionId ? ` \u00B7 ${edge.executionId}` : \"\"}</title></path>\n {edge.choice && !edge.feedback && <text x={(x + endX) / 2 + 5} y={(y + endY) / 2 - 4}>{edge.choice.slice(0, 22)}</text>}</g>;\n })}\n </svg>\n {job.nodes.map(node => { const p = layout.positions.get(node.id)!; return <button key={node.id} ref={selected === node.id ? selectedButton : undefined} className=\"br-node\" style={{ left: p.x, top: p.y }} aria-pressed={selected === node.id} onClick={() => select(node.id)} title={`${node.id} \u00B7 ${node.type} \u00B7 ${node.status}`}>\n <small>{node.type}</small><strong>{node.id}</strong><Status status={node.status}/>\n </button>; })}\n </div>\n </div></div>\n <div className=\"br-legend\"><span>Solid \u00B7 dependency</span><span>Dashed \u00B7 loop feedback</span><span>Click a node to inspect</span></div>\n {job.loops.map(loop => <p className=\"br-note\" key={loop.id}>Loop {loop.id} \u00B7 entry {loop.entry} \u00B7 maximum {loop.maxIterations} iterations</p>)}\n </section>;\n}\n\nfunction ExecutionDetail({ api, sessionId, job, execution }: { api: PanelApi; sessionId: string; job: PanelJob; execution: PanelExecution }) {\n const [detail, setDetail] = useState<PanelDetail>();\n const [error, setError] = useState(\"\");\n const [offset, setOffset] = useState(0);\n const [retry, setRetry] = useState(0);\n useEffect(() => {\n let active = true;\n setDetail(undefined); setError(\"\");\n void api.detail({ sessionId, jobId: job.jobId, executionId: execution.executionId, offset }).then(value => {\n if (active) setDetail(value);\n }, e => { if (active) setError(message(e)); });\n return () => { active = false; };\n }, [api, sessionId, job.jobId, job.status, execution.executionId, execution.status, offset, retry]);\n const p = execution.progress;\n return <>\n <div className=\"br-detail-grid\">\n <div><span>Execution</span>{execution.executionId}</div><div><span>Revision / iteration</span>r{execution.revision} / {execution.iteration ?? \"\u2014\"}</div>\n <div><span>Elapsed</span>{execution.latencyMs === undefined ? \"\u2014\" : `${(execution.latencyMs / 1000).toFixed(1)}s`}</div>\n <div><span>Worker</span>{p?.phase ?? execution.status}</div>\n <div><span>Context ({p?.contextSource ?? \"unreported\"})</span>{p ? `${number(p.contextTokens)}${p.contextWindow ? ` / ${number(p.contextWindow)}` : \"\"}` : \"\u2014\"}</div>\n <div><span>Tool calls / rounds</span>{p ? `${p.toolCalls} / ${p.toolRounds}` : \"\u2014\"}</div>\n </div>\n {error && <div role=\"alert\">{error} <button onClick={() => setRetry(v => v + 1)}>Retry output</button></div>}\n {!detail && !error && <p className=\"br-muted\" role=\"status\">Loading output\u2026</p>}\n {detail && <>\n {detail.error && <p role=\"alert\">{detail.error}</p>}\n {detail.decision && <p>Decision: <strong>{detail.decision}</strong></p>}\n <pre className=\"br-output\" aria-label=\"Execution output\">{detail.output || (execution.status === \"running\" ? \"Output will appear when this execution finishes.\" : \"No output for this execution.\")}</pre>\n {detail.total > 32768 && <div className=\"br-toolbar\"><button disabled={offset === 0} onClick={() => setOffset(Math.max(0, offset - 32768))}>Previous output</button><small className=\"br-muted\">{number(detail.offset)}\u2013{number(detail.next)} / {number(detail.total)} characters</small><button disabled={detail.next >= detail.total} onClick={() => setOffset(detail.next)}>Next output</button></div>}\n {detail.workspace && <details><summary>Workspace and recovery refs</summary><pre className=\"br-output\">{detail.workspace}</pre></details>}\n </>}\n </>;\n}\n\nfunction JobView({ job, api, sessionId, connected, act, busy, target }: { job: PanelJob; api: PanelApi; sessionId: string; connected: boolean; act: (action: \"cancel\" | \"resume\", ids: string[]) => void; busy: boolean; target: BraidNavigation | undefined }) {\n const [selected, setSelected] = useState(() => job.executions.find(e => e.executionId === target?.executionId)?.id\n ?? target?.nodeId ?? (target?.executionId ? \"\" : job.nodes[0]?.id ?? \"\"));\n const [chosenExecution, setChosenExecution] = useState(target?.executionId ?? \"\");\n const [tab, setTab] = useState(\"output\");\n const executions = job.executions.filter(e => e.id === selected);\n const execution = chosenExecution ? executions.find(e => e.executionId === chosenExecution) : executions.at(-1);\n const paused = execution && job.pausedExecutionIds.includes(execution.executionId);\n return <>\n <div className=\"br-stats\"><div><strong>{job.executions.filter(e => e.status === \"completed\").length}/{job.executions.length}</strong><span>Executions complete</span></div><div><strong>{number(job.usage.inputTokens)}</strong><span>Input tokens</span></div><div><strong>{number(job.usage.outputTokens)}</strong><span>Output tokens</span></div><div><strong>{number(job.usage.cacheReadTokens + job.usage.cacheWriteTokens)}</strong><span>Cache tokens</span></div></div>\n {job.error && <div className=\"br-notice\" role=\"alert\">{job.error}</div>}\n {job.pausedExecutionIds.length > 0 && <div className=\"br-notice\"><strong>{job.pausedExecutionIds.length} execution(s) paused</strong><p className=\"br-note\">Inspect the output, then resume outgoing scheduling. Job deadlines continue while paused.</p><button className=\"br-primary\" disabled={!connected || busy || job.status !== \"running\"} onClick={() => act(\"resume\", job.pausedExecutionIds)}>Resume all paused</button></div>}\n <Graph job={job} selected={selected} select={id => { setSelected(id); setChosenExecution(\"\"); setTab(\"output\"); }}/>\n <section className=\"br-section\" aria-label=\"Execution details\"><div className=\"br-section-head\"><h3>{selected || \"Execution details\"}</h3>{execution && <Status status={paused ? \"waiting\" : execution.status}/>}</div>\n {chosenExecution && !execution && <p role=\"status\">The requested execution ({chosenExecution}) is no longer available. Select a node to inspect its current history.</p>}\n {executions.length > 0 ? <label><span className=\"br-muted\">Execution history</span><select className=\"br-select\" aria-label=\"Execution history\" value={execution?.executionId ?? \"\"} onChange={e => setChosenExecution(e.target.value)}>{executions.map(e => <option key={e.executionId} value={e.executionId}>{e.executionId} \u00B7 {e.status}{e.iteration === undefined ? \"\" : ` \u00B7 iteration ${e.iteration}`}</option>)}</select></label> : <p className=\"br-muted\">This node has not run yet.</p>}\n {paused && <button className=\"br-primary\" disabled={!connected || busy || job.status !== \"running\"} onClick={() => act(\"resume\", [execution!.executionId])}>Resume this execution</button>}\n <div className=\"br-tabs\"><button aria-pressed={tab === \"output\"} onClick={() => setTab(\"output\")}>Output & details</button><button aria-pressed={tab === \"events\"} onClick={() => setTab(\"events\")}>Event log ({job.events.length})</button></div>\n {tab === \"output\" && execution && <ExecutionDetail key={execution.executionId} api={api} sessionId={sessionId} job={job} execution={execution}/>}\n {tab === \"events\" && <><p className=\"br-note\">Latest 80 lifecycle events. Full results remain available through braid_status.</p><ol className=\"br-events\">{[...job.events].reverse().map(event => <li key={event.sequence}><time>{new Date(event.timestamp).toLocaleTimeString([], { hour12: false })}</time><div><p>{event.message}</p><small>#{event.sequence}{event.nodeId ? ` \u00B7 ${event.nodeId}` : \"\"}{event.executionId ? ` \u00B7 ${event.executionId}` : \"\"}</small></div></li>)}</ol></>}\n <p className=\"br-note\">Cache read {number(job.usage.cacheReadTokens)} \u00B7 cache write {number(job.usage.cacheWriteTokens)}. Usage is reported by DSH; monetary cost is not estimated.</p>\n </section>\n </>;\n}\n\n/** The session key deliberately resets every local selection and request generation. */\nexport function BraidPanelView(props: { sessionId: string; api: PanelApi; target?: BraidNavigation }) {\n return <SessionPanel key={props.sessionId} {...props}/>;\n}\nfunction SessionPanel({ sessionId, api, target }: { sessionId: string; api: PanelApi; target?: BraidNavigation }) {\n const [jobId, setJobId] = useState<string | undefined>(target?.jobId);\n const [createdBefore, setCreatedBefore] = useState<number | undefined>(target?.createdBefore);\n const [frame, setFrame] = useState<PanelFrame>();\n const [connected, setConnected] = useState(false);\n const [error, setError] = useState(\"\");\n const [actionError, setActionError] = useState(\"\");\n const [busy, setBusy] = useState(false);\n const [retry, setRetry] = useState(0);\n useEffect(() => {\n const controller = new AbortController();\n setConnected(false); setFrame(undefined); setError(\"\"); setActionError(\"\");\n void (async () => {\n for (let attempt = 0; !controller.signal.aborted; attempt++) {\n try {\n for await (const value of api.watch({ sessionId, ...(jobId ? { jobId } : {}), ...(createdBefore === undefined ? {} : { createdBefore }) }, controller.signal)) {\n if (controller.signal.aborted) return;\n setFrame(value); setConnected(true); setError(\"\"); attempt = 0;\n }\n if (!controller.signal.aborted) throw new Error(\"Braid connection closed\");\n } catch (e) {\n if (controller.signal.aborted) return;\n setConnected(false); setError(`${message(e)}${attempt < 2 ? \" \u00B7 reconnecting\u2026\" : \"\"}`);\n if (attempt >= 2) return;\n await new Promise<void>(resolve => {\n const done = () => { clearTimeout(timer); controller.signal.removeEventListener(\"abort\", done); resolve(); };\n const timer = setTimeout(done, 1000 * 2 ** attempt);\n controller.signal.addEventListener(\"abort\", done, { once: true });\n });\n }\n }\n })();\n return () => { controller.abort(); };\n }, [api, sessionId, jobId, createdBefore, retry]);\n const job = frame?.job;\n // In-flight mutations only affect their mounted job view; stream frames remain authoritative.\n const [actionOwner, setActionOwner] = useState(\"\");\n const act = async (action: \"cancel\" | \"resume\", executionIds: string[]) => {\n if (!job || !connected || busy) return;\n const owner = job.jobId;\n setBusy(true); setActionOwner(owner); setActionError(\"\");\n try { await api.control({ sessionId, jobId: owner, action, executionIds, revision: job.revision }); }\n catch (e) { setActionError(message(e)); }\n finally { setBusy(false); }\n };\n return <div className=\"braid-panel\">\n <header className=\"br-header\"><div className=\"br-eyebrow\">Agent orchestration</div><div className=\"br-heading\"><h2>Braid</h2><small role=\"status\">{connected ? \"\u25CF Live\" : error ? \"\u25CB Disconnected\" : \"Connecting\u2026\"}</small></div>\n {frame && frame.rows.length > 0 && <><select className=\"br-select\" aria-label=\"Braid job\" disabled={busy} value={job?.jobId ?? \"\"} onChange={e => { setJobId(e.target.value); setCreatedBefore(undefined); setActionError(\"\"); }}>{frame.rows.map(row => <option key={row.jobId} value={row.jobId}>{row.handle} \u00B7 {row.status} \u00B7 {row.goal.slice(0, 70)}</option>)}</select>\n {job && <><p className=\"br-goal\">{job.goal}</p><div className=\"br-toolbar\"><Status status={job.phase === \"waiting\" ? \"waiting\" : job.status}/><small className=\"br-muted\">r{job.revision} \u00B7 {job.nodes.length} nodes</small><button className=\"br-danger\" style={{ marginLeft: \"auto\" }} disabled={!connected || busy || job.status !== \"running\"} onClick={() => void act(\"cancel\", [])}>{busy ? \"Working\u2026\" : \"Cancel job\"}</button></div></>}\n </>}\n </header>\n {error && <div className=\"br-notice\" role=\"alert\">{error}<div className=\"br-toolbar\"><button onClick={() => setRetry(v => v + 1)}>Reconnect</button><button onClick={() => { setJobId(undefined); setCreatedBefore(undefined); setRetry(v => v + 1); }}>Latest job</button></div></div>}\n {actionError && actionOwner === job?.jobId && <div className=\"br-notice\" role=\"alert\">{actionError}</div>}\n {connected && frame?.rows.length === 0 && <div className=\"br-empty\"><h3>No Braid jobs in this session</h3><p>Ask the agent to use Braid for a parallel or multi-step task. Its graph, execution history and results will appear here.</p></div>}\n {job && <JobView key={job.jobId} job={job} api={api} sessionId={sessionId} connected={connected} act={(action, ids) => void act(action, ids)} busy={busy}\n target={target?.jobId && [job.jobId, job.handle].includes(target.jobId) ? target : undefined}/>}\n </div>;\n}\n", "import type { PanelJob } from \"../panel-types.js\";\n\n/** Longest-path ranks in the forward DAG. Feedback is drawn separately. */\nexport function layoutGraph(nodes: PanelJob[\"nodes\"], edges: PanelJob[\"edges\"]) {\n const rank = new Map(nodes.map(node => [node.id, 0]));\n const incoming = new Map(nodes.map(node => [node.id, 0]));\n const outgoing = new Map(nodes.map(node => [node.id, [] as string[]]));\n for (const edge of edges) {\n if (edge.feedback || !rank.has(edge.from) || !rank.has(edge.to)) continue;\n incoming.set(edge.to, incoming.get(edge.to)! + 1);\n outgoing.get(edge.from)!.push(edge.to);\n }\n const queue = nodes.filter(node => incoming.get(node.id) === 0).map(node => node.id);\n for (let i = 0; i < queue.length; i++) for (const to of outgoing.get(queue[i]!)!) {\n rank.set(to, Math.max(rank.get(to)!, rank.get(queue[i]!)! + 1));\n incoming.set(to, incoming.get(to)! - 1);\n if (incoming.get(to) === 0) queue.push(to);\n }\n const columns = new Map<number, number>();\n const positions = new Map(nodes.map(node => {\n const row = rank.get(node.id)!, column = columns.get(row) ?? 0;\n columns.set(row, column + 1);\n return [node.id, { x: 32 + column * 186, y: 28 + row * 124 }];\n }));\n return { positions, width: Math.max(280, ...[...columns.values()].map(count => count * 186 + 32)),\n height: Math.max(160, ...[...rank.values()].map(row => (row + 1) * 124 + 28)) };\n}\n", "/** Scoped styles share the Host's fonts and honor both system and DSH dark themes. */\nexport const styles = `\n.braid-panel{--br-bg:var(--dsw-alias-bg-base,#fff);--br-fg:var(--dsw-alias-label-primary,#222b38);--br-soft:var(--dsw-alias-bg-module-platform,#f4f6f8);--br-line:var(--dsw-alias-border-l2,#dce2e8);--br-muted:var(--dsw-alias-label-secondary,#667384);--br-accent:#336dbe;--br-green:var(--dsw-alias-state-success-primary,#18794e);--br-red:var(--dsw-alias-state-error-primary,#ba3340);color:var(--br-fg);background:var(--br-bg);font:inherit;font-size:13px;line-height:1.5;box-sizing:border-box;height:100%;overflow:auto;min-width:0;container-type:inline-size}\n.braid-panel *{box-sizing:border-box}.braid-panel button,.braid-panel select{font:inherit;color:inherit}.braid-panel button,.braid-panel select{border:1px solid var(--br-line);border-radius:7px;background:var(--br-bg);padding:6px 10px}.braid-panel button{cursor:pointer}.braid-panel button:hover:not(:disabled){border-color:var(--br-accent)}.braid-panel button:focus-visible,.braid-panel select:focus-visible{outline:2px solid var(--br-accent);outline-offset:2px}.braid-panel button:disabled{opacity:.45;cursor:default}.braid-panel .br-primary{background:var(--br-accent);color:white;border-color:transparent}.braid-panel .br-danger{color:var(--br-red)}\n.br-header{padding:20px 18px 12px;border-bottom:1px solid var(--br-line)}.br-heading{display:flex;align-items:center;gap:9px}.br-heading h2{font-size:18px;letter-spacing:-.4px;margin:0}.br-heading small{margin-left:auto;color:var(--br-muted)}.br-eyebrow{text-transform:uppercase;letter-spacing:1.4px;font-size:10px;color:var(--br-muted);margin-bottom:5px}.br-select{width:100%;margin:14px 0 8px}.br-goal{margin:8px 0;overflow-wrap:anywhere}.br-muted{color:var(--br-muted)}.br-toolbar{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.br-status{display:inline-flex;align-items:center;gap:5px;font-size:11px;white-space:nowrap}.br-status:before{content:'';width:6px;height:6px;border-radius:50%;background:var(--br-muted)}.br-status[data-status=running]:before,.br-status[data-status=runnable]:before{background:var(--br-accent)}.br-status[data-status=completed]:before{background:var(--br-green)}.br-status[data-status=failed]:before,.br-status[data-status=cancelled]:before{background:var(--br-red)}.br-status[data-status=waiting]:before{background:#ba861a}\n.br-stats{display:grid;grid-template-columns:repeat(4,1fr);padding:14px 18px;gap:8px;border-bottom:1px solid var(--br-line)}.br-stats strong{display:block;font-size:16px;font-variant-numeric:tabular-nums}.br-stats span{font-size:10px;color:var(--br-muted)}.br-section{padding:14px 18px;border-bottom:1px solid var(--br-line)}.br-section h3{font-size:12px;margin:0 0 10px}.br-section-head{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:10px}.br-section-head h3{margin:0}.br-section-head button{padding:2px 8px}.br-graph{overflow:auto;background:var(--br-soft);border:1px solid var(--br-line);border-radius:9px;max-height:420px}.br-graph-canvas{position:relative}.br-graph svg{position:absolute;inset:0;overflow:visible}.br-graph path{fill:none;stroke:var(--br-muted);stroke-width:1.2}.br-graph text{font-size:10px;fill:var(--br-muted)}.br-node{position:absolute;display:flex;flex-direction:column;align-items:flex-start;justify-content:center;width:154px;height:72px;text-align:left;gap:2px;box-shadow:0 2px 5px #00000006}.br-node[aria-pressed=true]{outline:2px solid var(--br-accent);outline-offset:2px}.br-node strong{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.br-node small{font-size:10px;color:var(--br-muted)}.br-legend{display:flex;gap:12px;flex-wrap:wrap;font-size:10px;color:var(--br-muted);margin-top:8px}.br-note{font-size:11px;color:var(--br-muted);margin:8px 0 0;overflow-wrap:anywhere}\n.br-notice{margin:12px 18px;padding:10px 12px;border:1px solid var(--br-line);border-radius:8px;background:var(--br-soft);overflow-wrap:anywhere}.br-notice[role=alert]{color:var(--br-red)}.br-empty{padding:48px 24px;text-align:center}.br-empty h3{font-size:15px}.br-empty p{color:var(--br-muted);max-width:36em;margin:12px auto}.br-detail-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px 16px;font-size:11px;margin:12px 0}.br-detail-grid span{color:var(--br-muted);display:block}.br-output{white-space:pre-wrap;overflow-wrap:anywhere;background:var(--br-soft);border:1px solid var(--br-line);padding:12px;border-radius:8px;max-height:340px;overflow:auto;font:11px/1.65 ui-monospace,SFMono-Regular,monospace;margin:8px 0}.br-tabs{display:flex;gap:5px;margin:14px 0 10px}.br-tabs button[aria-pressed=true]{border-color:var(--br-accent);color:var(--br-accent)}.br-events{list-style:none;padding:0;margin:0;max-height:320px;overflow:auto}.br-events li{padding:8px 0;display:grid;grid-template-columns:64px 1fr;gap:8px;border-bottom:1px solid var(--br-line);font-size:11px}.br-events time{color:var(--br-muted);font-variant-numeric:tabular-nums}.br-events p{margin:0;overflow-wrap:anywhere}.br-events small{color:var(--br-muted)}.br-header-action{font:inherit;border:0;border-radius:6px;padding:5px 9px;background:transparent;color:inherit;cursor:pointer}.br-header-action:hover{background:#8882}\n@container (max-width:330px){.br-stats{grid-template-columns:repeat(2,1fr)}.br-header,.br-section{padding-left:12px;padding-right:12px}}\n@media(prefers-color-scheme:dark){.braid-panel{--br-bg:var(--dsw-alias-bg-base,#171b22);--br-fg:var(--dsw-alias-label-primary,#e0e6ee);--br-soft:var(--dsw-alias-bg-module-platform,#202630);--br-line:var(--dsw-alias-border-l2,#354050);--br-muted:var(--dsw-alias-label-secondary,#a0adbe);--br-accent:#80b6ff;--br-green:var(--dsw-alias-state-success-primary,#69d6a0);--br-red:var(--dsw-alias-state-error-primary,#ff919a)}.braid-panel .br-primary{color:#162336}}\n[data-theme=dark] .braid-panel,.dark .braid-panel{--br-bg:var(--dsw-alias-bg-base,#171b22);--br-fg:var(--dsw-alias-label-primary,#e0e6ee);--br-soft:var(--dsw-alias-bg-module-platform,#202630);--br-line:var(--dsw-alias-border-l2,#354050);--br-muted:var(--dsw-alias-label-secondary,#a0adbe);--br-accent:#80b6ff;--br-green:var(--dsw-alias-state-success-primary,#69d6a0);--br-red:var(--dsw-alias-state-error-primary,#ff919a)}\n`;\n\nexport const toolStyles = `\n.br-tool-call{font:inherit;font-size:12px;color:var(--dsw-alias-label-primary,inherit);border:1px solid var(--dsw-alias-border-l2,#8884);border-radius:9px;margin:8px 0;overflow:hidden}\n.br-tool-call button{font:inherit;color:inherit;cursor:pointer}.br-tool-call button:focus-visible{outline:2px solid #639be6;outline-offset:-2px}.br-tool-call button:disabled{cursor:default;opacity:.6}\n.br-tool-open{display:flex;width:100%;align-items:center;gap:10px;padding:12px;border:0;background:var(--dsw-alias-bg-module-platform,#8881);text-align:left}.br-tool-open:hover:not(:disabled){background:var(--dsw-alias-fill-l1,#8882)}.br-tool-open>span:last-child{margin-left:auto}\n.br-tool-main{display:flex;flex-wrap:wrap;align-items:baseline;gap:3px 8px;min-width:0}.br-tool-target{overflow-wrap:anywhere;color:var(--dsw-alias-label-secondary,inherit)}.br-tool-summary{flex-basis:100%;font-size:11px}.br-tool-call[data-state=failed] .br-tool-summary,.br-tool-error{color:var(--dsw-alias-state-error-primary,#c34e59)}\n.br-tool-actions{display:flex;gap:8px;padding:6px 12px}.br-tool-actions button{border:0;background:transparent;font-size:11px;text-decoration:underline;text-underline-offset:3px;padding:3px 0}.br-tool-details{padding:8px 12px;border-top:1px solid var(--dsw-alias-border-l2,#8884)}.br-tool-details pre{font:11px/1.6 ui-monospace,monospace;white-space:pre-wrap;overflow-wrap:anywhere;max-height:220px;overflow:auto}.br-tool-error{padding:0 12px;white-space:pre-wrap;overflow-wrap:anywhere;font-size:11px}\n.br-tool-note{margin:4px 12px;color:var(--dsw-alias-label-secondary,inherit);font-size:10px;opacity:.8}.br-tool-changes{display:flex;flex-wrap:wrap;gap:5px;padding:8px 12px}.br-tool-changes span{padding:3px 6px;border-radius:4px;background:var(--dsw-alias-bg-module-platform,#8881);font-size:10px;overflow-wrap:anywhere}.br-tool-jobs{list-style:none;margin:0;padding:6px 12px;max-height:230px;overflow:auto}.br-tool-jobs button{display:flex;gap:12px;width:100%;padding:6px 0;border:0;background:transparent;text-align:left}.br-tool-jobs span{margin-left:auto}\n`;\n", "import type { ToolCallPhaseProps } from \"@deepseek-ai/dsh-client-ui-tool/client\";\n\nexport interface BraidNavigation { jobId?: string; nodeId?: string; executionId?: string; createdBefore?: number }\nexport const braidToolNames = [\"braid\", \"braid_status\", \"braid_update\", \"braid_resume\", \"braid_cancel\"] as const;\n\nfunction record(value: unknown): Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value) ? value as Record<string, unknown> : {};\n}\nfunction json(raw: string): Record<string, unknown> {\n try { return record(JSON.parse(raw)); } catch { return {}; }\n}\nconst id = (value: unknown): string | undefined => typeof value === \"string\" && value.trim() && value.length <= 1024 ? value : undefined;\n\n/** Sidebar navigation also survives layout restoration, so validate its loose JSON boundary. */\nexport function readNavigation(value: unknown): BraidNavigation {\n const source = record(value), target: BraidNavigation = {};\n for (const key of [\"jobId\", \"nodeId\", \"executionId\"] as const) {\n const text = id(source[key]); if (text !== undefined) target[key] = text;\n }\n if (typeof source.createdBefore === \"number\" && Number.isSafeInteger(source.createdBefore) && source.createdBefore >= 0)\n target.createdBefore = source.createdBefore;\n return target;\n}\n\nfunction toolData(props: ToolCallPhaseProps) {\n const args = json(props.phase === \"result\" ? props.block.call?.argsRaw ?? \"\" : props.phase === \"start\" ? props.block.argsRaw : \"\");\n let result: Record<string, unknown> = {};\n if (props.phase === \"result\" && !props.block.isError) for (const content of props.block.content) {\n if (content.type !== \"text\") continue;\n const value = json(content.text);\n if (Object.keys(value).length > 0) { result = value; break; }\n }\n return { args, result };\n}\n\n/** Read only envelope identifiers, never the result preview, prompts, or worker output. */\nexport function toolNavigation(toolName: string, props: ToolCallPhaseProps): BraidNavigation | null {\n if (!braidToolNames.some(name => name === toolName) || props.phase === \"preparing\") return null;\n const { args, result } = toolData(props);\n const jobId = id(result.canonicalJobId) ?? id(result.jobId) ?? id(args.jobId);\n // A submission has no target until its receipt arrives. A list call opens the roster.\n if (!jobId) return toolName === \"braid_status\" && !(\"jobId\" in args || \"nodeId\" in args || \"executionId\" in args) ? {} : null;\n const target: BraidNavigation = { jobId };\n const node = record(result.node);\n const executionId = id(args.executionId) ?? id(node.executionId)\n ?? (toolName === \"braid_resume\" && Array.isArray(args.executionIds) && args.executionIds.length === 1 ? id(args.executionIds[0]) : undefined);\n const nodeId = id(args.nodeId) ?? id(node.id);\n if (executionId) target.executionId = executionId;\n if (nodeId) target.nodeId = nodeId;\n const time = props.block.time;\n if (Number.isSafeInteger(time) && time >= 0) target.createdBefore = time;\n return target;\n}\n\nexport interface ToolPresentation {\n label: string;\n summary: string;\n changes: string[];\n jobs: { label: string; status: string; target: BraidNavigation }[];\n}\nconst array = (value: unknown): unknown[] => Array.isArray(value) ? value : [];\nconst revision = (value: unknown): string => typeof value === \"number\" && Number.isSafeInteger(value) ? `r${value}` : \"\";\nconst names = (values: unknown[]): string => {\n const ids = values.map(value => id(value) ?? id(record(value).id)).filter(Boolean);\n return ids.slice(0, 8).join(\", \") + (ids.length > 8 ? ` \u2026 (+${ids.length - 8})` : \"\");\n};\n\n/** Each tool card describes its recorded operation; the sidebar is explicitly live. */\nexport function toolPresentation(toolName: string, props: ToolCallPhaseProps): ToolPresentation {\n const { args, result } = toolData(props);\n const label = id(result.handle) ?? id(args.jobId) ?? id(result.jobId) ?? \"\";\n const model: ToolPresentation = { label, summary: \"\", changes: [], jobs: [] };\n const failed = props.phase === \"result\" && props.block.isError;\n const settled = props.phase === \"result\";\n if (toolName === \"braid_update\") {\n const revisions = [revision(args.expectedRevision), revision(result.revision)].filter(Boolean).join(\" \u2192 \");\n model.summary = `${failed ? \"Update rejected \u00B7 not applied\" : settled ? \"Graph updated\" : \"Updating graph\"}${revisions ? ` \u00B7 ${revisions}` : \"\"}`;\n for (const [key, title] of [[\"upsertNodes\", \"Upsert nodes\"], [\"removeNodeIds\", \"Remove nodes\"], [\"resume\", \"Resume executions\"]] as const) {\n const values = array(args[key]); if (values.length) model.changes.push(`${title}: ${names(values)}`);\n }\n for (const [key, title] of [[\"addEdges\", \"Add edges\"], [\"removeEdges\", \"Remove edges\"]] as const) {\n const values = array(args[key]); if (values.length) model.changes.push(`${title}: ${values.length}`);\n }\n if (\"loops\" in args) model.changes.push(`Replace loops: ${array(args.loops).length}`);\n if (\"promptTemplates\" in args) model.changes.push(`Prompt templates: ${Object.keys(record(args.promptTemplates)).length}`);\n } else if (toolName === \"braid_resume\") {\n model.summary = failed ? \"Resume rejected\" : `${settled ? \"Resumed\" : \"Resuming\"} ${array(args.executionIds).length} execution(s)`;\n const ids = names(array(args.executionIds)); if (ids) model.changes.push(ids);\n if (Array.isArray(result.pausedExecutionIds)) model.changes.push(`${result.pausedExecutionIds.length} still paused \u00B7 ${revision(result.revision)}`);\n } else if (toolName === \"braid_cancel\") {\n model.summary = failed ? \"Cancellation failed\" : !settled ? \"Requesting cancellation\" : result.cancelled === false ? \"Job already finished\" : \"Cancellation requested\";\n } else if (toolName === \"braid_status\" && Array.isArray(result.jobs)) {\n model.summary = `${result.jobs.length} job(s) at this call`;\n model.jobs = result.jobs.flatMap(value => {\n const row = record(value), jobId = id(row.jobId);\n return jobId ? [{ label: id(row.handle) ?? jobId, status: id(row.status) ?? \"\", target: { jobId, createdBefore: props.block.time } }] : [];\n });\n } else if (toolName === \"braid_status\") {\n const execution = record(result.execution), node = record(result.node);\n const executions = Object.values(record(execution.executions));\n const details = id(node.status)\n ? [`execution ${id(node.status)}`, id(execution.status) ? `graph ${id(execution.status)}` : undefined, revision(execution.revision)]\n : [id(execution.status) ?? id(result.status), revision(execution.revision)];\n if (executions.length) details.push(`${executions.filter(value => record(value).status === \"completed\").length}/${executions.length} executions complete`);\n if (Array.isArray(execution.pausedExecutionIds) && execution.pausedExecutionIds.length) details.push(`${execution.pausedExecutionIds.length} paused`);\n model.summary = failed ? \"Status query failed\" : details.filter(Boolean).join(\" \u00B7 \") || (settled ? \"Recorded status\" : \"Reading status\");\n } else {\n const graph = record(result.graph), nodes = array(graph.nodes).length || array(args.nodes).length;\n model.summary = failed ? \"Submission failed\" : `${settled ? \"Graph submitted\" : \"Starting graph\"}${nodes ? ` \u00B7 ${nodes} nodes` : \"\"}`;\n }\n if (result.truncated === true) model.changes.push(\"Large result saved to file; view fullOutputPath in tool details\");\n return model;\n}\n", "import * as React from \"react\";\nimport type { ToolCallOwnerProps } from \"@deepseek-ai/dsh-client-ui-tool/client\";\nimport { toolNavigation, toolPresentation, type BraidNavigation } from \"./navigation.js\";\n\nexport type BraidToolCallProps = ToolCallOwnerProps & { openBraid: (target: BraidNavigation) => void };\n\n/** The main row opens the graph; a separate disclosure preserves the raw tool evidence. */\nexport function BraidToolCall(props: BraidToolCallProps) {\n const { toolName, phase, block, openBraid, useDisclosure, inspect } = props;\n const { expanded, toggle } = useDisclosure();\n const target = toolNavigation(toolName, props);\n const model = toolPresentation(toolName, props);\n const failed = phase === \"result\" && block.isError;\n const state = failed ? \"failed\" : phase === \"result\" ? \"completed\" : phase === \"preparing\" ? \"preparing\" : \"running\";\n const raw = phase === \"result\" ? block.call?.argsRaw : phase === \"start\" ? block.argsRaw : undefined;\n const output = phase === \"result\" ? block.content.filter(c => c.type === \"text\").map(c => c.text).join(\"\\n\") : \"\";\n return <div className=\"br-tool-call\" data-state={state}>\n <button type=\"button\" className=\"br-tool-open\" disabled={!target} onClick={() => { if (target) openBraid(target); }}\n aria-label={`Open Braid view for ${toolName}`} title={target ? \"Open Braid graph and execution details\" : \"Waiting for a Braid job receipt\"}>\n <span aria-hidden=\"true\">\u2387</span><span className=\"br-tool-main\"><strong>{toolName}</strong>\n <span className=\"br-tool-target\">{model.label}{target?.executionId ? ` / ${target.executionId}` : target?.nodeId ? ` / ${target.nodeId}` : \"\"}</span>\n <span className=\"br-tool-summary\">{model.summary}</span></span><span aria-hidden=\"true\">\u2197</span>\n </button>\n {model.changes.length > 0 && <div className=\"br-tool-changes\" aria-label={failed ? \"Changes not applied\" : \"Operation details\"}>{model.changes.map((change, i) => <span key={i}>{change}</span>)}</div>}\n {model.jobs.length > 0 && <ul className=\"br-tool-jobs\">{model.jobs.map(job => <li key={job.target.jobId}><button type=\"button\" onClick={() => openBraid(job.target)} aria-label={`View ${job.label}`}>{job.label} <span>{job.status}</span> \u2197</button></li>)}</ul>}\n {phase === \"result\" && target && <p className=\"br-tool-note\">Recorded result \u00B7 open the graph for live state</p>}\n {failed && <p role=\"alert\" className=\"br-tool-error\">{block.error?.reason ?? block.error?.code ?? (output.slice(0, 600) || \"Braid tool call failed. Expand the result for details.\")}</p>}\n <div className=\"br-tool-actions\"><button type=\"button\" aria-expanded={expanded} onClick={toggle}>{expanded ? \"Hide\" : \"Show\"} tool details</button>\n {inspect && <button type=\"button\" onClick={inspect}>Inspect call</button>}\n </div>\n {expanded && <div className=\"br-tool-details\"><strong>Arguments</strong><pre>{raw ?? \"Arguments are being prepared\u2026\"}</pre>\n {phase === \"result\" && <><strong>Result</strong><pre>{output || \"No text result.\"}</pre></>}\n </div>}\n </div>;\n}\n"],
5
- "mappings": "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",
6
- "names": ["id", "id", "import_jsx_runtime", "import_jsx_runtime", "ctx"]
4
+ "sourcesContent": ["import * as React from \"react\";\nimport type { Context } from \"@deepseek-ai/cordis\";\nimport type {} from \"@deepseek-ai/dsh-api-gateway/client\";\nimport type {} from \"@deepseek-ai/dsh-client-ui-renderer/client\";\nimport type {} from \"@deepseek-ai/dsh-client-ui-conversation/client\";\nimport type {} from \"@deepseek-ai/dsh-client-ui-sidebar-right/client\";\nimport type {} from \"@deepseek-ai/dsh-client-ui-tool/client\";\nimport type { PropsRuntime } from \"@deepseek-ai/dsh-client-ui-slots\";\nimport type { SessionId } from \"@deepseek-ai/dsh-session/types\";\nimport type { PanelApi } from \"../panel-types.js\";\nimport { PANEL_PACKAGE, panelDescriptors } from \"../panel-contract.js\";\nimport { BraidPanelView } from \"./Panel.js\";\nimport { styles, toolStyles } from \"./styles.js\";\nimport { BraidToolCall } from \"./ToolCall.js\";\nimport { braidToolNames, readNavigation, type BraidNavigation } from \"./navigation.js\";\n\ndeclare module \"@deepseek-ai/dsh-client-ui-sidebar-right/client\" {\n interface SidebarRightTabParamsMap { braid: BraidNavigation }\n}\n\nexport const inject = [\"remote\", \"slots\", \"sidebarRight\", \"sidebarRightTabs\"];\nexport async function apply(ctx: Context): Promise<void> {\n await ctx.remote.$mount({ package: PANEL_PACKAGE, descriptors: panelDescriptors });\n ctx.inject([\"remote.braidPanel\"], ctx => {\n // Capture traced services inside their declared Cordis scope, not React event stacks.\n const remote = ctx.remote.braidPanel;\n const sidebar = ctx.sidebarRight;\n const api: PanelApi = {\n watch: (request, signal) => remote.watch(request, signal),\n control: async request => { const result = await remote.control(request); if (!result.ok) throw result.error; return result.value; },\n detail: async request => { const result = await remote.detail(request); if (!result.ok) throw result.error; return result.value; },\n };\n ctx.effect(() => {\n const style = document.createElement(\"style\"); style.dataset.plugin = PANEL_PACKAGE; style.textContent = styles + toolStyles;\n document.head.append(style); return () => { style.remove(); };\n });\n ctx.effect(() => ctx.sidebarRightTabs.register({ id: PANEL_PACKAGE, kind: \"braid\", title: () => \"Braid\",\n guide: [{ id: \"braid\", order: 50, title: () => \"Braid\", description: () => \"Live agent graphs, execution details and controls\" }],\n }));\n ctx.effect(() => ctx.slots.inject(\"sidebar.right.pane.tab\", () => ctx.slots.register({\n name: \"sidebar.right.pane.tab\", key: PANEL_PACKAGE, inject: sessionId => ({ api, sessionId }),\n }, PanelSeat)));\n ctx.effect(() => ctx.slots.inject(\"conversation.session.header.actions\", () => ctx.slots.register({\n name: \"conversation.session.header.actions\", id: \"braid\", order: 25,\n inject: () => ({ open: () => { sidebar.openTab(\"braid\"); } }),\n }, HeaderAction)));\n for (const key of braidToolNames) ctx.effect(() => ctx.slots.inject(\"tool.call.toolview\", () => ctx.slots.register({\n name: \"tool.call.toolview\", key,\n inject: sessionId => ({ openBraid: (target: BraidNavigation) => { sidebar.openTabIn(sessionId as SessionId, \"braid\", { params: target }); } }),\n }, BraidToolCall)));\n });\n}\nfunction HeaderAction({ open }: { open: () => void }) {\n return <button className=\"br-header-action\" onClick={open} title=\"Open Braid graph and execution details\" aria-label=\"Open Braid panel\">\u2387 Braid</button>;\n}\nfunction PanelSeat({ sessionId, api, useTabInfo }: PropsRuntime<\"sidebar.right.pane.tab\"> & { sessionId: string; api: PanelApi }) {\n const { tab: { navigation } } = useTabInfo();\n return <BraidPanelView key={navigation.revision} sessionId={sessionId} api={api} target={readNavigation(navigation.params)}/>;\n}\n", "import type { InvocationDescriptor, RemoteResult } from \"@deepseek-ai/dsh-typert-protocol\";\nimport type { ControlRequest, DetailRequest, PanelDetail, PanelFrame, PanelRequest } from \"./panel-types.js\";\n\n/** One descriptor table shared by Host registration and Client Remote mounting. */\nexport const PANEL_PACKAGE = \"@chrok/dsh-braid\";\nfunction parseRequest(value: unknown, method: string): unknown {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) throw new Error(\"Invalid Braid panel request\");\n const r = value as Record<string, unknown>;\n const id = (key: string) => typeof r[key] === \"string\" && (r[key] as string).length > 0 && (r[key] as string).length <= 1024;\n if (!id(\"sessionId\") || (r.jobId !== undefined && !id(\"jobId\"))) throw new Error(\"Invalid session or job ID\");\n if (r.createdBefore !== undefined && (!Number.isSafeInteger(r.createdBefore) || Number(r.createdBefore) < 0)) throw new Error(\"Invalid call timestamp\");\n if (method !== \"watch\" && !id(\"jobId\")) throw new Error(\"A job ID is required\");\n if (method === \"control\" && (\n ![\"cancel\", \"resume\"].includes(String(r.action)) || !Number.isSafeInteger(r.revision) || Number(r.revision) < 0 ||\n !Array.isArray(r.executionIds) || r.executionIds.length > 10000 || r.executionIds.some(v => typeof v !== \"string\" || !v || v.length > 1024)\n )) throw new Error(\"Invalid Braid control request\");\n if (method === \"detail\" && (!id(\"executionId\") || !Number.isSafeInteger(r.offset) || Number(r.offset) < 0 ||\n (r.activityBefore !== undefined && (!Number.isSafeInteger(r.activityBefore) || Number(r.activityBefore) < 1)))) throw new Error(\"Invalid execution, offset, or activity page\");\n return value;\n}\nexport const panelDescriptors: InvocationDescriptor[] = [\"watch\", \"control\", \"detail\"].map(method => ({\n id: `${PANEL_PACKAGE}#braidPanel/${method}`, service: \"braidPanel\", namespace: \"braidPanel\", method,\n invocation: { kind: \"direct\" },\n parameters: [{ name: \"request\", wire: \"request\", source: \"json\", codec: {\n mode: \"strict\", typeSymbol: `${PANEL_PACKAGE}/${method}Request`, create: () => ({ parse: value => parseRequest(value, method) }),\n } }],\n result: { mode: \"src-json\" },\n ...(method === \"watch\" ? { mode: \"stream\" as const, cancellation: { parameter: \"signal\" as const } } : {}),\n}));\nexport interface PanelRemote {\n watch(request: PanelRequest, signal?: AbortSignal): AsyncIterable<PanelFrame>;\n control(request: ControlRequest): Promise<RemoteResult<PanelFrame>>;\n detail(request: DetailRequest): Promise<RemoteResult<PanelDetail>>;\n}\ndeclare module \"@deepseek-ai/dsh-typert-protocol\" {\n interface TypertRemoteNamespaceMap { braidPanel: PanelRemote }\n interface RemoteErrorDetailsMap { \"braid/panel\": { sessionId: string } }\n}\n", "import * as React from \"react\";\nimport { useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport type { PanelActivity, PanelActivityEntry, PanelApi, PanelDetail, PanelExecution, PanelFrame, PanelJob } from \"../panel-types.js\";\nimport { layoutGraph } from \"./layout.js\";\nimport type { BraidNavigation } from \"./navigation.js\";\n\nconst number = (n: number) => n.toLocaleString();\nconst message = (error: unknown) => error instanceof Error ? error.message : String(error);\nconst duration = (ms: number) => {\n const value = Math.max(0, ms);\n return value < 60_000 ? `${(value / 1000).toFixed(1)}s` : `${Math.floor(value / 60_000)}m ${Math.floor((value % 60_000) / 1000)}s`;\n};\n\n/** Host time for this frame, advanced locally so idle times keep counting between frames. */\nfunction useHostClock(job: PanelJob, live: boolean): number {\n const receivedAt = useMemo(() => Date.now(), [job]);\n const [clock, setClock] = useState(() => Date.now());\n useEffect(() => {\n setClock(Date.now());\n if (!live) return;\n const timer = setInterval(() => setClock(Date.now()), 1000);\n return () => clearInterval(timer);\n }, [job, live]);\n return job.observedAt + Math.max(0, clock - receivedAt);\n}\n\nfunction ActivityView({ activity, entries, now, loadEarlier }: { activity: PanelActivity; entries?: PanelActivityEntry[]; now: number; loadEarlier?: () => void }) {\n const end = activity.finishedAt ?? now;\n const model = activity.model;\n const running = activity.finishedAt === undefined;\n return <div className=\"br-activity\" aria-label=\"Live activity\">\n <div className=\"br-detail-grid\">\n <div><span>Phase</span>{activity.phase} \u00B7 {duration(end - activity.phaseStartedAt)}</div>\n <div><span>Last activity</span>{running ? `${duration(now - activity.lastActivityAt)} ago` : \"\u2014\"} \u00B7 {activity.lastActivity}</div>\n <div><span>Total</span>{duration(end - activity.startedAt)}</div>\n {model && <div><span>Model request #{model.round}</span>{model.completedAt !== undefined\n ? `returned after ${duration(model.completedAt - model.startedAt)}`\n : model.firstStreamAt === undefined\n ? `sent ${duration(now - model.startedAt)} ago \u00B7 no stream events yet`\n : `streaming ${model.receiving ?? \"output\"}${model.toolName ? ` (${model.toolName})` : \"\"} \u00B7 ${number(model.receivedChars)} chars \u00B7 last ${duration(now - (model.lastStreamAt ?? model.firstStreamAt))} ago`}</div>}\n {activity.tools.map(tool => <div key={tool.callId}><span>Running tool</span>{tool.name} \u00B7 {duration(now - tool.startedAt)} \u00B7 {tool.lastOutputAt === undefined ? \"no output yet\" : `last output ${duration(now - tool.lastOutputAt)} ago`}</div>)}\n </div>\n {model?.completedAt === undefined && model?.tail && <pre className=\"br-output br-tail\" aria-label=\"Latest streamed output\">\u2026{model.tail}</pre>}\n {activity.tools.map(tool => <details key={tool.callId}><summary>{tool.name} arguments{tool.outputTail ? \" and latest output\" : \"\"}</summary><pre className=\"br-output\">{tool.arguments}{tool.outputTail ? `\\n\\n\u2026${tool.outputTail}` : \"\"}</pre></details>)}\n {activity.limitations.map(text => <p className=\"br-note\" key={text}>Unavailable: {text}</p>)}\n {running && <p className=\"br-note\">Times since the last observed signal are diagnostic; a quiet worker is not necessarily stalled.</p>}\n {entries && <details open={running}><summary>Activity history ({activity.sequence})</summary>\n {(entries[0]?.sequence ?? activity.sequence + 1) > activity.droppedEntries + 1 && loadEarlier && <button onClick={loadEarlier}>Load earlier activity</button>}\n {activity.droppedEntries > 0 && (entries[0]?.sequence ?? 0) <= activity.droppedEntries + 1 && <p className=\"br-note\">{activity.droppedEntries} earlier entries were trimmed to bound memory.</p>}\n <ol className=\"br-events br-activity-log\">{entries.map(entry => <li key={entry.sequence} data-error={entry.isError ? \"\" : undefined}>\n <time>+{duration(entry.timestamp - activity.startedAt)}</time>\n <div><p>{entry.summary}</p>{entry.detail && entry.detail !== entry.summary && <details><summary>Details{entry.detailLength ? ` (${number(entry.detailLength)} characters, preview)` : \"\"}</summary><pre className=\"br-output\">{entry.detail}</pre></details>}</div>\n </li>)}</ol>\n </details>}\n </div>;\n}\nexport function Status({ status }: { status: string }) {\n return <span className=\"br-status\" data-status={status}>{status}</span>;\n}\n\nexport function Graph({ job, selected, select }: { job: PanelJob; selected: string; select: (id: string) => void }) {\n const layout = useMemo(() => layoutGraph(job.nodes, job.edges), [job.nodes, job.edges]);\n const [zoom, setZoom] = useState(1);\n const arrow = useId().replaceAll(\":\", \"\");\n const selectedButton = useRef<HTMLButtonElement>(null);\n useEffect(() => { selectedButton.current?.scrollIntoView?.({ block: \"nearest\", inline: \"nearest\" }); }, [selected]);\n return <section className=\"br-section\" aria-label=\"Execution graph\">\n <div className=\"br-section-head\"><h3>Execution graph</h3><div className=\"br-toolbar\">\n <button aria-label=\"Zoom out\" disabled={zoom <= .5} onClick={() => setZoom(v => Math.max(.5, v - .25))}>\u2212</button>\n <button aria-label=\"Reset zoom\" onClick={() => setZoom(1)}>{Math.round(zoom * 100)}%</button>\n <button aria-label=\"Zoom in\" disabled={zoom >= 1.5} onClick={() => setZoom(v => Math.min(1.5, v + .25))}>+</button>\n </div></div>\n <div className=\"br-graph\"><div style={{ width: layout.width * zoom, height: layout.height * zoom }}>\n <div className=\"br-graph-canvas\" style={{ width: layout.width, height: layout.height, transform: `scale(${zoom})`, transformOrigin: \"top left\" }}>\n <svg width={layout.width} height={layout.height} aria-hidden=\"true\"><defs><marker id={arrow} viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"5\" markerHeight=\"5\" orient=\"auto-start-reverse\"><path d=\"M 0 0 L 10 5 L 0 10 z\" style={{ fill: \"var(--br-muted)\" }}/></marker></defs>\n {job.edges.map((edge, i) => {\n const a = layout.positions.get(edge.from), b = layout.positions.get(edge.to);\n if (!a || !b) return null;\n const x = a.x + 77, y = a.y + 72, endX = b.x + 77, endY = b.y;\n const d = edge.feedback ? `M ${a.x} ${a.y + 36} C 6 ${a.y + 36}, 6 ${b.y + 36}, ${b.x} ${b.y + 36}` : `M ${x} ${y} C ${x} ${y + 26}, ${endX} ${endY - 26}, ${endX} ${endY}`;\n return <g key={i}><path d={d} strokeDasharray={edge.feedback ? \"4 4\" : undefined} markerEnd={`url(#${arrow})`}><title>{edge.from} \u2192 {edge.to}{edge.choice ? ` (${edge.choice})` : \"\"}{edge.feedback ? ` \u00B7 loop ${edge.feedback}` : \"\"}{edge.executionId ? ` \u00B7 ${edge.executionId}` : \"\"}</title></path>\n {edge.choice && !edge.feedback && <text x={(x + endX) / 2 + 5} y={(y + endY) / 2 - 4}>{edge.choice.slice(0, 22)}</text>}</g>;\n })}\n </svg>\n {job.nodes.map(node => { const p = layout.positions.get(node.id)!; return <button key={node.id} ref={selected === node.id ? selectedButton : undefined} className=\"br-node\" style={{ left: p.x, top: p.y }} aria-pressed={selected === node.id} onClick={() => select(node.id)} title={`${node.id} \u00B7 ${node.type} \u00B7 ${node.status}`}>\n <small>{node.type}</small><strong>{node.id}</strong><Status status={node.status}/>\n </button>; })}\n </div>\n </div></div>\n <div className=\"br-legend\"><span>Solid \u00B7 dependency</span><span>Dashed \u00B7 loop feedback</span><span>Click a node to inspect</span></div>\n {job.loops.map(loop => <p className=\"br-note\" key={loop.id}>Loop {loop.id} \u00B7 entry {loop.entry} \u00B7 maximum {loop.maxIterations} iterations</p>)}\n </section>;\n}\n\nfunction ExecutionDetail({ api, sessionId, job, execution }: { api: PanelApi; sessionId: string; job: PanelJob; execution: PanelExecution }) {\n const [detail, setDetail] = useState<PanelDetail>();\n const [error, setError] = useState(\"\");\n const [offset, setOffset] = useState(0);\n const [retry, setRetry] = useState(0);\n const [activityBefore, setActivityBefore] = useState<number>();\n const [earlier, setEarlier] = useState<PanelActivityEntry[]>([]);\n // New activity refreshes the detail in place; the view is keyed by execution.\n const sequence = execution.activity?.sequence;\n useEffect(() => {\n let active = true;\n setError(\"\");\n void api.detail({ sessionId, jobId: job.jobId, executionId: execution.executionId, offset }).then(value => {\n if (active) setDetail(value);\n }, e => { if (active) setError(message(e)); });\n return () => { active = false; };\n }, [api, sessionId, job.jobId, job.status, execution.executionId, execution.status, offset, retry, sequence]);\n useEffect(() => {\n if (activityBefore === undefined) return;\n let active = true;\n void api.detail({ sessionId, jobId: job.jobId, executionId: execution.executionId, offset: 0, activityBefore }).then(value => {\n if (active) setEarlier(previous => [...(value.activity?.entries ?? []), ...previous]);\n }, e => { if (active) setError(message(e)); });\n return () => { active = false; };\n }, [api, sessionId, job.jobId, execution.executionId, activityBefore]);\n const p = execution.progress;\n const activity = execution.activity ?? detail?.activity;\n const now = useHostClock(job, execution.status === \"running\");\n // Keep the view contiguous: once earlier pages load, live refreshes extend the\n // range instead of sliding the latest-entries window away from them.\n const seen = useRef(new Map<number, PanelActivityEntry>());\n const latest = detail?.activity?.entries ?? [];\n const from = earlier[0]?.sequence ?? latest[0]?.sequence ?? Infinity;\n for (const entry of [...earlier, ...latest]) seen.current.set(entry.sequence, entry);\n for (const sequence of seen.current.keys()) if (sequence < from) seen.current.delete(sequence);\n const entries = [...seen.current.values()].sort((a, b) => a.sequence - b.sequence);\n return <>\n <div className=\"br-detail-grid\">\n <div><span>Execution</span>{execution.executionId}</div><div><span>Revision / iteration</span>r{execution.revision} / {execution.iteration ?? \"\u2014\"}</div>\n <div><span>Elapsed</span>{execution.latencyMs === undefined ? \"\u2014\" : `${(execution.latencyMs / 1000).toFixed(1)}s`}</div>\n <div><span>Worker</span>{p?.phase ?? execution.status}</div>\n <div><span>Context ({p?.contextSource ?? \"unreported\"})</span>{p ? `${number(p.contextTokens)}${p.contextWindow ? ` / ${number(p.contextWindow)}` : \"\"}` : \"\u2014\"}</div>\n <div><span>Tool calls / rounds</span>{p ? `${p.toolCalls} / ${p.toolRounds}` : \"\u2014\"}</div>\n </div>\n {activity ? <ActivityView activity={activity} now={now} {...(detail?.activity ? { entries } : {})}\n loadEarlier={() => { if (entries[0]) setActivityBefore(entries[0].sequence); }}/>\n : execution.status === \"running\" && <p className=\"br-muted\" role=\"status\">No worker activity observed yet.</p>}\n {error && <div role=\"alert\">{error} <button onClick={() => setRetry(v => v + 1)}>Retry output</button></div>}\n {!detail && !error && <p className=\"br-muted\" role=\"status\">Loading output\u2026</p>}\n {detail && <>\n {detail.error && <p role=\"alert\">{detail.error}</p>}\n {detail.decision && <p>Decision: <strong>{detail.decision}</strong></p>}\n <pre className=\"br-output\" aria-label=\"Execution output\">{detail.output || (execution.status === \"running\" ? \"Output will appear when this execution finishes.\" : \"No output for this execution.\")}</pre>\n {detail.total > 32768 && <div className=\"br-toolbar\"><button disabled={offset === 0} onClick={() => setOffset(Math.max(0, offset - 32768))}>Previous output</button><small className=\"br-muted\">{number(detail.offset)}\u2013{number(detail.next)} / {number(detail.total)} characters</small><button disabled={detail.next >= detail.total} onClick={() => setOffset(detail.next)}>Next output</button></div>}\n {detail.workspace && <details><summary>Workspace and recovery refs</summary><pre className=\"br-output\">{detail.workspace}</pre></details>}\n </>}\n </>;\n}\n\nfunction JobView({ job, api, sessionId, connected, act, busy, target }: { job: PanelJob; api: PanelApi; sessionId: string; connected: boolean; act: (action: \"cancel\" | \"resume\", ids: string[]) => void; busy: boolean; target: BraidNavigation | undefined }) {\n const [selected, setSelected] = useState(() => job.executions.find(e => e.executionId === target?.executionId)?.id\n ?? target?.nodeId ?? (target?.executionId ? \"\" : job.nodes[0]?.id ?? \"\"));\n const [chosenExecution, setChosenExecution] = useState(target?.executionId ?? \"\");\n const [tab, setTab] = useState(\"output\");\n const executions = job.executions.filter(e => e.id === selected);\n const execution = chosenExecution ? executions.find(e => e.executionId === chosenExecution) : executions.at(-1);\n const paused = execution && job.pausedExecutionIds.includes(execution.executionId);\n return <>\n <div className=\"br-stats\"><div><strong>{job.executions.filter(e => e.status === \"completed\").length}/{job.executions.length}</strong><span>Executions complete</span></div><div><strong>{number(job.usage.inputTokens)}</strong><span>Input tokens</span></div><div><strong>{number(job.usage.outputTokens)}</strong><span>Output tokens</span></div><div><strong>{number(job.usage.cacheReadTokens + job.usage.cacheWriteTokens)}</strong><span>Cache tokens</span></div></div>\n {job.error && <div className=\"br-notice\" role=\"alert\">{job.error}</div>}\n {job.pausedExecutionIds.length > 0 && <div className=\"br-notice\"><strong>{job.pausedExecutionIds.length} execution(s) paused</strong><p className=\"br-note\">Inspect the output, then resume outgoing scheduling. Job deadlines continue while paused.</p><button className=\"br-primary\" disabled={!connected || busy || job.status !== \"running\"} onClick={() => act(\"resume\", job.pausedExecutionIds)}>Resume all paused</button></div>}\n <Graph job={job} selected={selected} select={id => { setSelected(id); setChosenExecution(\"\"); setTab(\"output\"); }}/>\n <section className=\"br-section\" aria-label=\"Execution details\"><div className=\"br-section-head\"><h3>{selected || \"Execution details\"}</h3>{execution && <Status status={paused ? \"waiting\" : execution.status}/>}</div>\n {chosenExecution && !execution && <p role=\"status\">The requested execution ({chosenExecution}) is no longer available. Select a node to inspect its current history.</p>}\n {executions.length > 0 ? <label><span className=\"br-muted\">Execution history</span><select className=\"br-select\" aria-label=\"Execution history\" value={execution?.executionId ?? \"\"} onChange={e => setChosenExecution(e.target.value)}>{executions.map(e => <option key={e.executionId} value={e.executionId}>{e.executionId} \u00B7 {e.status}{e.iteration === undefined ? \"\" : ` \u00B7 iteration ${e.iteration}`}</option>)}</select></label> : <p className=\"br-muted\">This node has not run yet.</p>}\n {paused && <button className=\"br-primary\" disabled={!connected || busy || job.status !== \"running\"} onClick={() => act(\"resume\", [execution!.executionId])}>Resume this execution</button>}\n <div className=\"br-tabs\"><button aria-pressed={tab === \"output\"} onClick={() => setTab(\"output\")}>Output & details</button><button aria-pressed={tab === \"events\"} onClick={() => setTab(\"events\")}>Event log ({job.events.length})</button></div>\n {tab === \"output\" && execution && <ExecutionDetail key={execution.executionId} api={api} sessionId={sessionId} job={job} execution={execution}/>}\n {tab === \"events\" && <><p className=\"br-note\">Latest 80 lifecycle events. Full results remain available through braid_status.</p><ol className=\"br-events\">{[...job.events].reverse().map(event => <li key={event.sequence}><time>{new Date(event.timestamp).toLocaleTimeString([], { hour12: false })}</time><div><p>{event.message}</p><small>#{event.sequence}{event.nodeId ? ` \u00B7 ${event.nodeId}` : \"\"}{event.executionId ? ` \u00B7 ${event.executionId}` : \"\"}</small></div></li>)}</ol></>}\n <p className=\"br-note\">Cache read {number(job.usage.cacheReadTokens)} \u00B7 cache write {number(job.usage.cacheWriteTokens)}. Usage is reported by DSH; monetary cost is not estimated.</p>\n </section>\n </>;\n}\n\n/** The session key deliberately resets every local selection and request generation. */\nexport function BraidPanelView(props: { sessionId: string; api: PanelApi; target?: BraidNavigation }) {\n return <SessionPanel key={props.sessionId} {...props}/>;\n}\nfunction SessionPanel({ sessionId, api, target }: { sessionId: string; api: PanelApi; target?: BraidNavigation }) {\n const [jobId, setJobId] = useState<string | undefined>(target?.jobId);\n const [createdBefore, setCreatedBefore] = useState<number | undefined>(target?.createdBefore);\n const [frame, setFrame] = useState<PanelFrame>();\n const [connected, setConnected] = useState(false);\n const [error, setError] = useState(\"\");\n const [actionError, setActionError] = useState(\"\");\n const [busy, setBusy] = useState(false);\n const [retry, setRetry] = useState(0);\n useEffect(() => {\n const controller = new AbortController();\n setConnected(false); setFrame(undefined); setError(\"\"); setActionError(\"\");\n void (async () => {\n for (let attempt = 0; !controller.signal.aborted; attempt++) {\n try {\n for await (const value of api.watch({ sessionId, ...(jobId ? { jobId } : {}), ...(createdBefore === undefined ? {} : { createdBefore }) }, controller.signal)) {\n if (controller.signal.aborted) return;\n setFrame(value); setConnected(true); setError(\"\"); attempt = 0;\n }\n if (!controller.signal.aborted) throw new Error(\"Braid connection closed\");\n } catch (e) {\n if (controller.signal.aborted) return;\n setConnected(false); setError(`${message(e)}${attempt < 2 ? \" \u00B7 reconnecting\u2026\" : \"\"}`);\n if (attempt >= 2) return;\n await new Promise<void>(resolve => {\n const done = () => { clearTimeout(timer); controller.signal.removeEventListener(\"abort\", done); resolve(); };\n const timer = setTimeout(done, 1000 * 2 ** attempt);\n controller.signal.addEventListener(\"abort\", done, { once: true });\n });\n }\n }\n })();\n return () => { controller.abort(); };\n }, [api, sessionId, jobId, createdBefore, retry]);\n const job = frame?.job;\n // In-flight mutations only affect their mounted job view; stream frames remain authoritative.\n const [actionOwner, setActionOwner] = useState(\"\");\n const act = async (action: \"cancel\" | \"resume\", executionIds: string[]) => {\n if (!job || !connected || busy) return;\n const owner = job.jobId;\n setBusy(true); setActionOwner(owner); setActionError(\"\");\n try { await api.control({ sessionId, jobId: owner, action, executionIds, revision: job.revision }); }\n catch (e) { setActionError(message(e)); }\n finally { setBusy(false); }\n };\n return <div className=\"braid-panel\">\n <header className=\"br-header\"><div className=\"br-eyebrow\">Agent orchestration</div><div className=\"br-heading\"><h2>Braid</h2><small role=\"status\">{connected ? \"\u25CF Live\" : error ? \"\u25CB Disconnected\" : \"Connecting\u2026\"}</small></div>\n {frame && frame.rows.length > 0 && <><select className=\"br-select\" aria-label=\"Braid job\" disabled={busy} value={job?.jobId ?? \"\"} onChange={e => { setJobId(e.target.value); setCreatedBefore(undefined); setActionError(\"\"); }}>{frame.rows.map(row => <option key={row.jobId} value={row.jobId}>{row.handle} \u00B7 {row.status} \u00B7 {row.goal.slice(0, 70)}</option>)}</select>\n {job && <><p className=\"br-goal\">{job.goal}</p><div className=\"br-toolbar\"><Status status={job.phase === \"waiting\" ? \"waiting\" : job.status}/><small className=\"br-muted\">r{job.revision} \u00B7 {job.nodes.length} nodes</small><button className=\"br-danger\" style={{ marginLeft: \"auto\" }} disabled={!connected || busy || job.status !== \"running\"} onClick={() => void act(\"cancel\", [])}>{busy ? \"Working\u2026\" : \"Cancel job\"}</button></div></>}\n </>}\n </header>\n {error && <div className=\"br-notice\" role=\"alert\">{error}<div className=\"br-toolbar\"><button onClick={() => setRetry(v => v + 1)}>Reconnect</button><button onClick={() => { setJobId(undefined); setCreatedBefore(undefined); setRetry(v => v + 1); }}>Latest job</button></div></div>}\n {actionError && actionOwner === job?.jobId && <div className=\"br-notice\" role=\"alert\">{actionError}</div>}\n {connected && frame?.rows.length === 0 && <div className=\"br-empty\"><h3>No Braid jobs in this session</h3><p>Ask the agent to use Braid for a parallel or multi-step task. Its graph, execution history and results will appear here.</p></div>}\n {job && <JobView key={job.jobId} job={job} api={api} sessionId={sessionId} connected={connected} act={(action, ids) => void act(action, ids)} busy={busy}\n target={target?.jobId && [job.jobId, job.handle].includes(target.jobId) ? target : undefined}/>}\n </div>;\n}\n", "import type { PanelJob } from \"../panel-types.js\";\n\n/** Longest-path ranks in the forward DAG. Feedback is drawn separately. */\nexport function layoutGraph(nodes: PanelJob[\"nodes\"], edges: PanelJob[\"edges\"]) {\n const rank = new Map(nodes.map(node => [node.id, 0]));\n const incoming = new Map(nodes.map(node => [node.id, 0]));\n const outgoing = new Map(nodes.map(node => [node.id, [] as string[]]));\n for (const edge of edges) {\n if (edge.feedback || !rank.has(edge.from) || !rank.has(edge.to)) continue;\n incoming.set(edge.to, incoming.get(edge.to)! + 1);\n outgoing.get(edge.from)!.push(edge.to);\n }\n const queue = nodes.filter(node => incoming.get(node.id) === 0).map(node => node.id);\n for (let i = 0; i < queue.length; i++) for (const to of outgoing.get(queue[i]!)!) {\n rank.set(to, Math.max(rank.get(to)!, rank.get(queue[i]!)! + 1));\n incoming.set(to, incoming.get(to)! - 1);\n if (incoming.get(to) === 0) queue.push(to);\n }\n const columns = new Map<number, number>();\n const positions = new Map(nodes.map(node => {\n const row = rank.get(node.id)!, column = columns.get(row) ?? 0;\n columns.set(row, column + 1);\n return [node.id, { x: 32 + column * 186, y: 28 + row * 124 }];\n }));\n return { positions, width: Math.max(280, ...[...columns.values()].map(count => count * 186 + 32)),\n height: Math.max(160, ...[...rank.values()].map(row => (row + 1) * 124 + 28)) };\n}\n", "/** Scoped styles share the Host's fonts and honor both system and DSH dark themes. */\nexport const styles = `\n.braid-panel{--br-bg:var(--dsw-alias-bg-base,#fff);--br-fg:var(--dsw-alias-label-primary,#222b38);--br-soft:var(--dsw-alias-bg-module-platform,#f4f6f8);--br-line:var(--dsw-alias-border-l2,#dce2e8);--br-muted:var(--dsw-alias-label-secondary,#667384);--br-accent:#336dbe;--br-green:var(--dsw-alias-state-success-primary,#18794e);--br-red:var(--dsw-alias-state-error-primary,#ba3340);color:var(--br-fg);background:var(--br-bg);font:inherit;font-size:13px;line-height:1.5;box-sizing:border-box;height:100%;overflow:auto;min-width:0;container-type:inline-size}\n.braid-panel *{box-sizing:border-box}.braid-panel button,.braid-panel select{font:inherit;color:inherit}.braid-panel button,.braid-panel select{border:1px solid var(--br-line);border-radius:7px;background:var(--br-bg);padding:6px 10px}.braid-panel button{cursor:pointer}.braid-panel button:hover:not(:disabled){border-color:var(--br-accent)}.braid-panel button:focus-visible,.braid-panel select:focus-visible{outline:2px solid var(--br-accent);outline-offset:2px}.braid-panel button:disabled{opacity:.45;cursor:default}.braid-panel .br-primary{background:var(--br-accent);color:white;border-color:transparent}.braid-panel .br-danger{color:var(--br-red)}\n.br-header{padding:20px 18px 12px;border-bottom:1px solid var(--br-line)}.br-heading{display:flex;align-items:center;gap:9px}.br-heading h2{font-size:18px;letter-spacing:-.4px;margin:0}.br-heading small{margin-left:auto;color:var(--br-muted)}.br-eyebrow{text-transform:uppercase;letter-spacing:1.4px;font-size:10px;color:var(--br-muted);margin-bottom:5px}.br-select{width:100%;margin:14px 0 8px}.br-goal{margin:8px 0;overflow-wrap:anywhere}.br-muted{color:var(--br-muted)}.br-toolbar{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.br-status{display:inline-flex;align-items:center;gap:5px;font-size:11px;white-space:nowrap}.br-status:before{content:'';width:6px;height:6px;border-radius:50%;background:var(--br-muted)}.br-status[data-status=running]:before,.br-status[data-status=runnable]:before{background:var(--br-accent)}.br-status[data-status=completed]:before{background:var(--br-green)}.br-status[data-status=failed]:before,.br-status[data-status=cancelled]:before{background:var(--br-red)}.br-status[data-status=waiting]:before{background:#ba861a}\n.br-stats{display:grid;grid-template-columns:repeat(4,1fr);padding:14px 18px;gap:8px;border-bottom:1px solid var(--br-line)}.br-stats strong{display:block;font-size:16px;font-variant-numeric:tabular-nums}.br-stats span{font-size:10px;color:var(--br-muted)}.br-section{padding:14px 18px;border-bottom:1px solid var(--br-line)}.br-section h3{font-size:12px;margin:0 0 10px}.br-section-head{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:10px}.br-section-head h3{margin:0}.br-section-head button{padding:2px 8px}.br-graph{overflow:auto;background:var(--br-soft);border:1px solid var(--br-line);border-radius:9px;max-height:420px}.br-graph-canvas{position:relative}.br-graph svg{position:absolute;inset:0;overflow:visible}.br-graph path{fill:none;stroke:var(--br-muted);stroke-width:1.2}.br-graph text{font-size:10px;fill:var(--br-muted)}.br-node{position:absolute;display:flex;flex-direction:column;align-items:flex-start;justify-content:center;width:154px;height:72px;text-align:left;gap:2px;box-shadow:0 2px 5px #00000006}.br-node[aria-pressed=true]{outline:2px solid var(--br-accent);outline-offset:2px}.br-node strong{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.br-node small{font-size:10px;color:var(--br-muted)}.br-legend{display:flex;gap:12px;flex-wrap:wrap;font-size:10px;color:var(--br-muted);margin-top:8px}.br-note{font-size:11px;color:var(--br-muted);margin:8px 0 0;overflow-wrap:anywhere}\n.br-notice{margin:12px 18px;padding:10px 12px;border:1px solid var(--br-line);border-radius:8px;background:var(--br-soft);overflow-wrap:anywhere}.br-notice[role=alert]{color:var(--br-red)}.br-empty{padding:48px 24px;text-align:center}.br-empty h3{font-size:15px}.br-empty p{color:var(--br-muted);max-width:36em;margin:12px auto}.br-detail-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px 16px;font-size:11px;margin:12px 0}.br-detail-grid span{color:var(--br-muted);display:block}.br-output{white-space:pre-wrap;overflow-wrap:anywhere;background:var(--br-soft);border:1px solid var(--br-line);padding:12px;border-radius:8px;max-height:340px;overflow:auto;font:11px/1.65 ui-monospace,SFMono-Regular,monospace;margin:8px 0}.br-tabs{display:flex;gap:5px;margin:14px 0 10px}.br-tabs button[aria-pressed=true]{border-color:var(--br-accent);color:var(--br-accent)}.br-events{list-style:none;padding:0;margin:0;max-height:320px;overflow:auto}.br-events li{padding:8px 0;display:grid;grid-template-columns:64px 1fr;gap:8px;border-bottom:1px solid var(--br-line);font-size:11px}.br-events time{color:var(--br-muted);font-variant-numeric:tabular-nums}.br-events p{margin:0;overflow-wrap:anywhere}.br-events small{color:var(--br-muted)}.br-header-action{font:inherit;border:0;border-radius:6px;padding:5px 9px;background:transparent;color:inherit;cursor:pointer}.br-header-action:hover{background:#8882}\n@container (max-width:330px){.br-stats{grid-template-columns:repeat(2,1fr)}.br-header,.br-section{padding-left:12px;padding-right:12px}}\n@media(prefers-color-scheme:dark){.braid-panel{--br-bg:var(--dsw-alias-bg-base,#171b22);--br-fg:var(--dsw-alias-label-primary,#e0e6ee);--br-soft:var(--dsw-alias-bg-module-platform,#202630);--br-line:var(--dsw-alias-border-l2,#354050);--br-muted:var(--dsw-alias-label-secondary,#a0adbe);--br-accent:#80b6ff;--br-green:var(--dsw-alias-state-success-primary,#69d6a0);--br-red:var(--dsw-alias-state-error-primary,#ff919a)}.braid-panel .br-primary{color:#162336}}\n[data-theme=dark] .braid-panel,.dark .braid-panel{--br-bg:var(--dsw-alias-bg-base,#171b22);--br-fg:var(--dsw-alias-label-primary,#e0e6ee);--br-soft:var(--dsw-alias-bg-module-platform,#202630);--br-line:var(--dsw-alias-border-l2,#354050);--br-muted:var(--dsw-alias-label-secondary,#a0adbe);--br-accent:#80b6ff;--br-green:var(--dsw-alias-state-success-primary,#69d6a0);--br-red:var(--dsw-alias-state-error-primary,#ff919a)}\n`;\n\nexport const toolStyles = `\n.br-tool-call{font:inherit;font-size:12px;color:var(--dsw-alias-label-primary,inherit);border:1px solid var(--dsw-alias-border-l2,#8884);border-radius:9px;margin:8px 0;overflow:hidden}\n.br-tool-call button{font:inherit;color:inherit;cursor:pointer}.br-tool-call button:focus-visible{outline:2px solid #639be6;outline-offset:-2px}.br-tool-call button:disabled{cursor:default;opacity:.6}\n.br-tool-open{display:flex;width:100%;align-items:center;gap:10px;padding:12px;border:0;background:var(--dsw-alias-bg-module-platform,#8881);text-align:left}.br-tool-open:hover:not(:disabled){background:var(--dsw-alias-fill-l1,#8882)}.br-tool-open>span:last-child{margin-left:auto}\n.br-tool-main{display:flex;flex-wrap:wrap;align-items:baseline;gap:3px 8px;min-width:0}.br-tool-target{overflow-wrap:anywhere;color:var(--dsw-alias-label-secondary,inherit)}.br-tool-summary{flex-basis:100%;font-size:11px}.br-tool-call[data-state=failed] .br-tool-summary,.br-tool-error{color:var(--dsw-alias-state-error-primary,#c34e59)}\n.br-tool-actions{display:flex;gap:8px;padding:6px 12px}.br-tool-actions button{border:0;background:transparent;font-size:11px;text-decoration:underline;text-underline-offset:3px;padding:3px 0}.br-tool-details{padding:8px 12px;border-top:1px solid var(--dsw-alias-border-l2,#8884)}.br-tool-details pre{font:11px/1.6 ui-monospace,monospace;white-space:pre-wrap;overflow-wrap:anywhere;max-height:220px;overflow:auto}.br-tool-error{padding:0 12px;white-space:pre-wrap;overflow-wrap:anywhere;font-size:11px}\n.br-activity{margin:0 0 12px}.br-activity .br-detail-grid{margin-bottom:8px}.br-activity .br-tail{max-height:120px}.br-activity-log{max-height:420px}.br-activity-log li[data-error] p{color:var(--br-red)}.br-activity-log details summary{cursor:pointer;color:var(--br-muted)}\n.br-tool-note{margin:4px 12px;color:var(--dsw-alias-label-secondary,inherit);font-size:10px;opacity:.8}.br-tool-changes{display:flex;flex-wrap:wrap;gap:5px;padding:8px 12px}.br-tool-changes span{padding:3px 6px;border-radius:4px;background:var(--dsw-alias-bg-module-platform,#8881);font-size:10px;overflow-wrap:anywhere}.br-tool-jobs{list-style:none;margin:0;padding:6px 12px;max-height:230px;overflow:auto}.br-tool-jobs button{display:flex;gap:12px;width:100%;padding:6px 0;border:0;background:transparent;text-align:left}.br-tool-jobs span{margin-left:auto}\n`;\n", "import type { ToolCallPhaseProps } from \"@deepseek-ai/dsh-client-ui-tool/client\";\n\nexport interface BraidNavigation { jobId?: string; nodeId?: string; executionId?: string; createdBefore?: number }\nexport const braidToolNames = [\"braid\", \"braid_status\", \"braid_update\", \"braid_resume\", \"braid_cancel\"] as const;\n\nfunction record(value: unknown): Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value) ? value as Record<string, unknown> : {};\n}\nfunction json(raw: string): Record<string, unknown> {\n try { return record(JSON.parse(raw)); } catch { return {}; }\n}\nconst id = (value: unknown): string | undefined => typeof value === \"string\" && value.trim() && value.length <= 1024 ? value : undefined;\n\n/** Sidebar navigation also survives layout restoration, so validate its loose JSON boundary. */\nexport function readNavigation(value: unknown): BraidNavigation {\n const source = record(value), target: BraidNavigation = {};\n for (const key of [\"jobId\", \"nodeId\", \"executionId\"] as const) {\n const text = id(source[key]); if (text !== undefined) target[key] = text;\n }\n if (typeof source.createdBefore === \"number\" && Number.isSafeInteger(source.createdBefore) && source.createdBefore >= 0)\n target.createdBefore = source.createdBefore;\n return target;\n}\n\nfunction toolData(props: ToolCallPhaseProps) {\n const args = json(props.phase === \"result\" ? props.block.call?.argsRaw ?? \"\" : props.phase === \"start\" ? props.block.argsRaw : \"\");\n let result: Record<string, unknown> = {};\n if (props.phase === \"result\" && !props.block.isError) for (const content of props.block.content) {\n if (content.type !== \"text\") continue;\n const value = json(content.text);\n if (Object.keys(value).length > 0) { result = value; break; }\n }\n return { args, result };\n}\n\n/** Read only envelope identifiers, never the result preview, prompts, or worker output. */\nexport function toolNavigation(toolName: string, props: ToolCallPhaseProps): BraidNavigation | null {\n if (!braidToolNames.some(name => name === toolName) || props.phase === \"preparing\") return null;\n const { args, result } = toolData(props);\n const jobId = id(result.canonicalJobId) ?? id(result.jobId) ?? id(args.jobId);\n // A submission has no target until its receipt arrives. A list call opens the roster.\n if (!jobId) return toolName === \"braid_status\" && !(\"jobId\" in args || \"nodeId\" in args || \"executionId\" in args) ? {} : null;\n const target: BraidNavigation = { jobId };\n const node = record(result.node);\n const executionId = id(args.executionId) ?? id(node.executionId)\n ?? (toolName === \"braid_resume\" && Array.isArray(args.executionIds) && args.executionIds.length === 1 ? id(args.executionIds[0]) : undefined);\n const nodeId = id(args.nodeId) ?? id(node.id);\n if (executionId) target.executionId = executionId;\n if (nodeId) target.nodeId = nodeId;\n const time = props.block.time;\n if (Number.isSafeInteger(time) && time >= 0) target.createdBefore = time;\n return target;\n}\n\nexport interface ToolPresentation {\n label: string;\n summary: string;\n changes: string[];\n jobs: { label: string; status: string; target: BraidNavigation }[];\n}\nconst array = (value: unknown): unknown[] => Array.isArray(value) ? value : [];\nconst revision = (value: unknown): string => typeof value === \"number\" && Number.isSafeInteger(value) ? `r${value}` : \"\";\nconst names = (values: unknown[]): string => {\n const ids = values.map(value => id(value) ?? id(record(value).id)).filter(Boolean);\n return ids.slice(0, 8).join(\", \") + (ids.length > 8 ? ` \u2026 (+${ids.length - 8})` : \"\");\n};\n\n/** Each tool card describes its recorded operation; the sidebar is explicitly live. */\nexport function toolPresentation(toolName: string, props: ToolCallPhaseProps): ToolPresentation {\n const { args, result } = toolData(props);\n const label = id(result.handle) ?? id(args.jobId) ?? id(result.jobId) ?? \"\";\n const model: ToolPresentation = { label, summary: \"\", changes: [], jobs: [] };\n const failed = props.phase === \"result\" && props.block.isError;\n const settled = props.phase === \"result\";\n if (toolName === \"braid_update\") {\n const revisions = [revision(args.expectedRevision), revision(result.revision)].filter(Boolean).join(\" \u2192 \");\n model.summary = `${failed ? \"Update rejected \u00B7 not applied\" : settled ? \"Graph updated\" : \"Updating graph\"}${revisions ? ` \u00B7 ${revisions}` : \"\"}`;\n for (const [key, title] of [[\"upsertNodes\", \"Upsert nodes\"], [\"removeNodeIds\", \"Remove nodes\"], [\"resume\", \"Resume executions\"]] as const) {\n const values = array(args[key]); if (values.length) model.changes.push(`${title}: ${names(values)}`);\n }\n for (const [key, title] of [[\"addEdges\", \"Add edges\"], [\"removeEdges\", \"Remove edges\"]] as const) {\n const values = array(args[key]); if (values.length) model.changes.push(`${title}: ${values.length}`);\n }\n if (\"loops\" in args) model.changes.push(`Replace loops: ${array(args.loops).length}`);\n if (\"promptTemplates\" in args) model.changes.push(`Prompt templates: ${Object.keys(record(args.promptTemplates)).length}`);\n } else if (toolName === \"braid_resume\") {\n model.summary = failed ? \"Resume rejected\" : `${settled ? \"Resumed\" : \"Resuming\"} ${array(args.executionIds).length} execution(s)`;\n const ids = names(array(args.executionIds)); if (ids) model.changes.push(ids);\n if (Array.isArray(result.pausedExecutionIds)) model.changes.push(`${result.pausedExecutionIds.length} still paused \u00B7 ${revision(result.revision)}`);\n } else if (toolName === \"braid_cancel\") {\n model.summary = failed ? \"Cancellation failed\" : !settled ? \"Requesting cancellation\" : result.cancelled === false ? \"Job already finished\" : \"Cancellation requested\";\n } else if (toolName === \"braid_status\" && Array.isArray(result.jobs)) {\n model.summary = `${result.jobs.length} job(s) at this call`;\n model.jobs = result.jobs.flatMap(value => {\n const row = record(value), jobId = id(row.jobId);\n return jobId ? [{ label: id(row.handle) ?? jobId, status: id(row.status) ?? \"\", target: { jobId, createdBefore: props.block.time } }] : [];\n });\n } else if (toolName === \"braid_status\") {\n const execution = record(result.execution), node = record(result.node);\n const executions = Object.values(record(execution.executions));\n const details = id(node.status)\n ? [`execution ${id(node.status)}`, id(execution.status) ? `graph ${id(execution.status)}` : undefined, revision(execution.revision)]\n : [id(execution.status) ?? id(result.status), revision(execution.revision)];\n if (executions.length) details.push(`${executions.filter(value => record(value).status === \"completed\").length}/${executions.length} executions complete`);\n if (Array.isArray(execution.pausedExecutionIds) && execution.pausedExecutionIds.length) details.push(`${execution.pausedExecutionIds.length} paused`);\n model.summary = failed ? \"Status query failed\" : details.filter(Boolean).join(\" \u00B7 \") || (settled ? \"Recorded status\" : \"Reading status\");\n } else {\n const graph = record(result.graph), nodes = array(graph.nodes).length || array(args.nodes).length;\n model.summary = failed ? \"Submission failed\" : `${settled ? \"Graph submitted\" : \"Starting graph\"}${nodes ? ` \u00B7 ${nodes} nodes` : \"\"}`;\n }\n if (result.truncated === true) model.changes.push(\"Large result saved to file; view fullOutputPath in tool details\");\n return model;\n}\n", "import * as React from \"react\";\nimport type { ToolCallOwnerProps } from \"@deepseek-ai/dsh-client-ui-tool/client\";\nimport { toolNavigation, toolPresentation, type BraidNavigation } from \"./navigation.js\";\n\nexport type BraidToolCallProps = ToolCallOwnerProps & { openBraid: (target: BraidNavigation) => void };\n\n/** The main row opens the graph; a separate disclosure preserves the raw tool evidence. */\nexport function BraidToolCall(props: BraidToolCallProps) {\n const { toolName, phase, block, openBraid, useDisclosure, inspect } = props;\n const { expanded, toggle } = useDisclosure();\n const target = toolNavigation(toolName, props);\n const model = toolPresentation(toolName, props);\n const failed = phase === \"result\" && block.isError;\n const state = failed ? \"failed\" : phase === \"result\" ? \"completed\" : phase === \"preparing\" ? \"preparing\" : \"running\";\n const raw = phase === \"result\" ? block.call?.argsRaw : phase === \"start\" ? block.argsRaw : undefined;\n const output = phase === \"result\" ? block.content.filter(c => c.type === \"text\").map(c => c.text).join(\"\\n\") : \"\";\n return <div className=\"br-tool-call\" data-state={state}>\n <button type=\"button\" className=\"br-tool-open\" disabled={!target} onClick={() => { if (target) openBraid(target); }}\n aria-label={`Open Braid view for ${toolName}`} title={target ? \"Open Braid graph and execution details\" : \"Waiting for a Braid job receipt\"}>\n <span aria-hidden=\"true\">\u2387</span><span className=\"br-tool-main\"><strong>{toolName}</strong>\n <span className=\"br-tool-target\">{model.label}{target?.executionId ? ` / ${target.executionId}` : target?.nodeId ? ` / ${target.nodeId}` : \"\"}</span>\n <span className=\"br-tool-summary\">{model.summary}</span></span><span aria-hidden=\"true\">\u2197</span>\n </button>\n {model.changes.length > 0 && <div className=\"br-tool-changes\" aria-label={failed ? \"Changes not applied\" : \"Operation details\"}>{model.changes.map((change, i) => <span key={i}>{change}</span>)}</div>}\n {model.jobs.length > 0 && <ul className=\"br-tool-jobs\">{model.jobs.map(job => <li key={job.target.jobId}><button type=\"button\" onClick={() => openBraid(job.target)} aria-label={`View ${job.label}`}>{job.label} <span>{job.status}</span> \u2197</button></li>)}</ul>}\n {phase === \"result\" && target && <p className=\"br-tool-note\">Recorded result \u00B7 open the graph for live state</p>}\n {failed && <p role=\"alert\" className=\"br-tool-error\">{block.error?.reason ?? block.error?.code ?? (output.slice(0, 600) || \"Braid tool call failed. Expand the result for details.\")}</p>}\n <div className=\"br-tool-actions\"><button type=\"button\" aria-expanded={expanded} onClick={toggle}>{expanded ? \"Hide\" : \"Show\"} tool details</button>\n {inspect && <button type=\"button\" onClick={inspect}>Inspect call</button>}\n </div>\n {expanded && <div className=\"br-tool-details\"><strong>Arguments</strong><pre>{raw ?? \"Arguments are being prepared\u2026\"}</pre>\n {phase === \"result\" && <><strong>Result</strong><pre>{output || \"No text result.\"}</pre></>}\n </div>}\n </div>;\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["id", "sequence", "id", "import_jsx_runtime", "import_jsx_runtime", "ctx"]
7
7
  }
package/dist/display.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { type ExecutionActivity } from "@chrok/braid";
1
2
  import type { JobSnapshot } from "./jobs.js";
2
3
  /** Plain text works in both DSH's native job panel and human command results. */
3
- export declare function renderPanel(job: JobSnapshot): string;
4
+ export declare function renderPanel(job: JobSnapshot, activity?: (executionId: string) => ExecutionActivity | undefined, now?: number): string;
package/dist/display.js CHANGED
@@ -1,5 +1,6 @@
1
+ import { formatActivityStatus } from "@chrok/braid";
1
2
  /** Plain text works in both DSH's native job panel and human command results. */
2
- export function renderPanel(job) {
3
+ export function renderPanel(job, activity = () => undefined, now = Date.now()) {
3
4
  const state = job.execution;
4
5
  const lines = [`Braid ${job.handle} · ${job.status} · revision ${state.revision}`, job.goal,
5
6
  `Paused: ${state.pausedExecutionIds.join(", ") || "none"}`, ""];
@@ -11,6 +12,9 @@ export function renderPanel(job) {
11
12
  (result?.startedAt ? ` · ${Math.max(0, (result.finishedAt ?? Date.now()) - result.startedAt)} ms` : ""));
12
13
  for (const edge of state.graph.edges.filter(edge => edge.from === node.id))
13
14
  lines.push(` └─${edge.choice ? ` ${edge.choice}` : ""}${edge.feedback ? ` ↻ ${edge.feedback}` : ""} → ${edge.to}`);
15
+ const live = result?.status === "running" && result.executionId ? activity(result.executionId) : undefined;
16
+ if (live)
17
+ lines.push(` activity: ${formatActivityStatus(live, now)} · ${live.lastActivity.slice(0, 160)}`);
14
18
  if (result?.error)
15
19
  lines.push(` ${result.error.code}: ${result.error.message}`);
16
20
  }
package/dist/index.js CHANGED
@@ -84,12 +84,16 @@ export function apply(ctx) {
84
84
  const refresh = () => {
85
85
  timer = undefined;
86
86
  const job = jobs.get(handle);
87
+ // The log records lifecycle changes; ticking activity belongs in the replaceable progress line.
87
88
  const panel = renderPanel(job);
88
89
  if (panel !== previous) {
89
90
  previous = panel;
90
91
  native.append("\n" + panel + "\n", { channel: "log" });
91
92
  }
92
- native.updateProgress(`${handle} · ${job.execution.status} · ${Object.keys(job.execution.executions).length} executions`);
93
+ const running = Object.values(job.execution.executions).find(execution => execution.status === "running");
94
+ const live = running && jobs.getActivity(handle, running.executionId, { limit: 0 });
95
+ native.updateProgress(`${handle} · ${job.execution.status} · ${Object.keys(job.execution.executions).length} executions` +
96
+ (live ? ` · ${running.id}: ${live.phase}${live.tools[0] ? ` (${live.tools[0].name})` : ""}` : ""));
93
97
  };
94
98
  const unsubscribe = jobs.subscribe(() => { timer ??= setTimeout(refresh, 250); });
95
99
  return {
@@ -123,7 +127,7 @@ export function apply(ctx) {
123
127
  if (parts[0] === "list")
124
128
  return { kind: "success", text: JSON.stringify(jobs.list(), null, 2) };
125
129
  const id = parts[0] ?? jobs.list()[0]?.handle;
126
- return { kind: "success", text: id ? renderPanel(jobs.get(id)) : "No Braid jobs in this session." };
130
+ return { kind: "success", text: id ? renderPanel(jobs.get(id), executionId => jobs.getActivity(id, executionId, { limit: 0 })) : "No Braid jobs in this session." };
127
131
  }
128
132
  catch (error) {
129
133
  return { kind: "error", text: error instanceof Error ? error.message : String(error) };
package/dist/jobs.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type BraidInput, type BraidResult, type BraidSnapshot, type GraphUpdate, type ExecutionEvent, type NodeResult } from "@chrok/braid";
1
+ import { type BraidInput, type ExecutionActivity, type ExecutionActivityPage, type BraidResult, type BraidSnapshot, type GraphUpdate, type ExecutionEvent, type NodeResult } from "@chrok/braid";
2
2
  import type { TokenUsage } from "@deepseek-ai/dsh-llm";
3
3
  import { type NodeProgress, type DshLlm } from "./runner.js";
4
4
  export interface JobOptions {
@@ -53,6 +53,8 @@ export declare class BraidJobs {
53
53
  private lookup;
54
54
  get(id: string): JobSnapshot;
55
55
  getNode(id: string, nodeId?: string, executionId?: string): NodeResult;
56
+ /** Live activity for one exact execution; undefined until it is first observed. */
57
+ getActivity(id: string, executionId: string, page?: ExecutionActivityPage): ExecutionActivity | undefined;
56
58
  list(): {
57
59
  jobId: string;
58
60
  handle: string;
package/dist/jobs.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { setImmediate as nextTurn } from "node:timers/promises";
3
- import { startBraid, validateGraph } from "@chrok/braid";
3
+ import { ExecutionActivityTracker, startBraid, validateGraph } from "@chrok/braid";
4
4
  import { createDshRunner, sumUsage, validateBudgets } from "./runner.js";
5
5
  /** One manager per live DSH agent; foreground cancellation never owns these runs. */
6
6
  export class BraidJobs {
@@ -36,7 +36,8 @@ export class BraidJobs {
36
36
  const reports = [];
37
37
  const events = [];
38
38
  const progress = Object.create(null);
39
- const invoke = createDshRunner(this.llm, { cwd: context.cwd,
39
+ const activity = new ExecutionActivityTracker({ onChange: () => this.changed() });
40
+ const invoke = createDshRunner(this.llm, { cwd: context.cwd, activity,
40
41
  ...(options.maxToolRounds === undefined ? {} : { maxToolRounds: options.maxToolRounds }),
41
42
  ...(options.maxToolCalls === undefined ? {} : { maxToolCalls: options.maxToolCalls }),
42
43
  onUsage: usage => { reports.push(usage); },
@@ -47,8 +48,17 @@ export class BraidJobs {
47
48
  cwd: context.cwd, ...options,
48
49
  nodeTimeoutMs: options.nodeTimeoutMs ?? Infinity, graphTimeoutMs: options.graphTimeoutMs ?? Infinity,
49
50
  ...(context.model ? { defaultModel: context.model } : {}),
50
- runner: async (request) => { await nextTurn(); return invoke(request); },
51
+ runner: async (request) => {
52
+ try {
53
+ await nextTurn();
54
+ return await invoke(request);
55
+ }
56
+ finally {
57
+ activity.workerFinished(request.execution.executionId);
58
+ }
59
+ },
51
60
  onEvent: event => {
61
+ activity.observe(event);
52
62
  events.push(structuredClone(event));
53
63
  if (events.length > 80)
54
64
  events.shift();
@@ -56,7 +66,7 @@ export class BraidJobs {
56
66
  this.onEvent(jobId, handle, event);
57
67
  },
58
68
  });
59
- const job = { jobId, handle, goal: input.goal, status: "running", createdAt: Date.now(), run, reports, progress, events, done: Promise.resolve() };
69
+ const job = { jobId, handle, goal: input.goal, status: "running", createdAt: Date.now(), run, reports, progress, events, activity, done: Promise.resolve() };
60
70
  this.nextHandle++;
61
71
  this.jobs.set(jobId, job);
62
72
  this.handles.set(handle, jobId);
@@ -103,7 +113,7 @@ export class BraidJobs {
103
113
  return job;
104
114
  }
105
115
  get(id) {
106
- const { run, done: _done, reports, ...job } = this.lookup(id);
116
+ const { run, done: _done, reports, activity: _activity, ...job } = this.lookup(id);
107
117
  return structuredClone({ ...job, execution: run.snapshot(), usage: sumUsage(reports) });
108
118
  }
109
119
  getNode(id, nodeId, executionId) {
@@ -115,6 +125,10 @@ export class BraidJobs {
115
125
  throw new Error("Unknown Braid node or execution; inspect braid_status with only jobId");
116
126
  return structuredClone(node);
117
127
  }
128
+ /** Live activity for one exact execution; undefined until it is first observed. */
129
+ getActivity(id, executionId, page) {
130
+ return this.lookup(id).activity.get(executionId, page);
131
+ }
118
132
  list() {
119
133
  return [...this.jobs.values()].reverse().map(({ jobId, handle, goal, status, createdAt }) => ({ jobId, handle, goal, status, createdAt }));
120
134
  }
@@ -14,8 +14,9 @@ function parseRequest(value, method) {
14
14
  if (method === "control" && (!["cancel", "resume"].includes(String(r.action)) || !Number.isSafeInteger(r.revision) || Number(r.revision) < 0 ||
15
15
  !Array.isArray(r.executionIds) || r.executionIds.length > 10000 || r.executionIds.some(v => typeof v !== "string" || !v || v.length > 1024)))
16
16
  throw new Error("Invalid Braid control request");
17
- if (method === "detail" && (!id("executionId") || !Number.isSafeInteger(r.offset) || Number(r.offset) < 0))
18
- throw new Error("Invalid execution or offset");
17
+ if (method === "detail" && (!id("executionId") || !Number.isSafeInteger(r.offset) || Number(r.offset) < 0 ||
18
+ (r.activityBefore !== undefined && (!Number.isSafeInteger(r.activityBefore) || Number(r.activityBefore) < 1))))
19
+ throw new Error("Invalid execution, offset, or activity page");
19
20
  return value;
20
21
  }
21
22
  export const panelDescriptors = ["watch", "control", "detail"].map(method => ({
@@ -10,10 +10,12 @@ export interface ControlRequest extends PanelRequest {
10
10
  revision: number;
11
11
  executionIds: string[];
12
12
  }
13
+ /** activityBefore pages earlier activity entries by sequence. */
13
14
  export interface DetailRequest extends PanelRequest {
14
15
  jobId: string;
15
16
  executionId: string;
16
17
  offset: number;
18
+ activityBefore?: number;
17
19
  }
18
20
  export interface PanelRow {
19
21
  jobId: string;
@@ -22,6 +24,53 @@ export interface PanelRow {
22
24
  status: string;
23
25
  createdAt: number;
24
26
  }
27
+ /** Live state of one execution; phase timings are host epoch milliseconds. */
28
+ export interface PanelActivity {
29
+ phase: string;
30
+ phaseStartedAt: number;
31
+ startedAt: number;
32
+ finishedAt?: number;
33
+ lastActivityAt: number;
34
+ lastActivity: string;
35
+ modelRequests: number;
36
+ toolCalls: number;
37
+ model?: {
38
+ round: number;
39
+ startedAt: number;
40
+ completedAt?: number;
41
+ firstStreamAt?: number;
42
+ lastStreamAt?: number;
43
+ streamEvents: number;
44
+ receivedChars: number;
45
+ receiving?: string;
46
+ toolName?: string;
47
+ tail?: string;
48
+ };
49
+ tools: {
50
+ callId: string;
51
+ name: string;
52
+ startedAt: number;
53
+ arguments: string;
54
+ lastOutputAt?: number;
55
+ outputChars: number;
56
+ outputTail?: string;
57
+ }[];
58
+ limitations: string[];
59
+ /** Latest entry sequence; changes whenever history grows. */
60
+ sequence: number;
61
+ droppedEntries: number;
62
+ }
63
+ export interface PanelActivityEntry {
64
+ sequence: number;
65
+ timestamp: number;
66
+ kind: string;
67
+ summary: string;
68
+ detail?: string;
69
+ detailLength?: number;
70
+ toolName?: string;
71
+ durationMs?: number;
72
+ isError?: boolean;
73
+ }
25
74
  export interface PanelExecution {
26
75
  id: string;
27
76
  executionId: string;
@@ -39,11 +88,15 @@ export interface PanelExecution {
39
88
  toolRounds: number;
40
89
  phase: string;
41
90
  };
91
+ /** Present while running; detail returns history for any execution. */
92
+ activity?: PanelActivity;
42
93
  }
43
94
  export interface PanelJob extends PanelRow {
44
95
  revision: number;
45
96
  phase: string;
46
97
  error?: string;
98
+ /** Host clock when this frame was built, for elapsed and idle times. */
99
+ observedAt: number;
47
100
  nodes: {
48
101
  id: string;
49
102
  type: string;
@@ -92,6 +145,10 @@ export interface PanelDetail {
92
145
  decision?: string;
93
146
  error?: string;
94
147
  workspace?: string;
148
+ /** Up to 50 entries before activityBefore (or the latest), chronological. */
149
+ activity?: PanelActivity & {
150
+ entries: PanelActivityEntry[];
151
+ };
95
152
  }
96
153
  export interface PanelApi {
97
154
  watch(request: PanelRequest, signal: AbortSignal): AsyncIterable<PanelFrame>;
package/dist/panel.d.ts CHANGED
@@ -1,8 +1,11 @@
1
1
  import type { Context } from "@deepseek-ai/cordis";
2
2
  import { TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
3
3
  import type { BraidJobs, JobSnapshot } from "./jobs.js";
4
+ import type { ExecutionActivity } from "@chrok/braid";
4
5
  import type { ControlRequest, DetailRequest, PanelDetail, PanelFrame, PanelJob, PanelRequest } from "./panel-types.js";
5
- export declare function panelJob(job: JobSnapshot): PanelJob;
6
+ export declare const DETAIL_ACTIVITY_ENTRIES = 50;
7
+ /** activity supplies live summaries for running executions; history stays in detail reads. */
8
+ export declare function panelJob(job: JobSnapshot, activity?: (executionId: string) => ExecutionActivity | undefined): PanelJob;
6
9
  /** Session managers are borrowed; viewing a panel never creates an Agent or starts model work. */
7
10
  export declare class BraidPanel extends TypertRemoteService {
8
11
  private readonly find;
package/dist/panel.js CHANGED
@@ -34,12 +34,17 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
34
34
  };
35
35
  import { Remote, RemoteError, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
36
36
  import { PANEL_PACKAGE, panelDescriptors } from "./panel-contract.js";
37
+ export const DETAIL_ACTIVITY_ENTRIES = 50;
37
38
  const clip = (text, limit = 2000) => text.length > limit ? text.slice(0, limit) + "…" : text;
38
- export function panelJob(job) {
39
+ function panelActivity({ entries: _entries, executionId: _executionId, nodeId: _nodeId, ...activity }) {
40
+ return activity;
41
+ }
42
+ /** activity supplies live summaries for running executions; history stays in detail reads. */
43
+ export function panelJob(job, activity = () => undefined) {
39
44
  const state = job.execution;
40
45
  return {
41
46
  jobId: job.jobId, handle: job.handle, goal: clip(job.goal), status: job.status, createdAt: job.createdAt,
42
- revision: state.revision, phase: state.status,
47
+ revision: state.revision, phase: state.status, observedAt: Date.now(),
43
48
  ...(job.error || state.error ? { error: clip(job.error ?? state.error.message) } : {}),
44
49
  nodes: state.graph.nodes.map(node => ({ id: node.id, type: node.type, status: state.nodes[node.id]?.status ?? "pending" })),
45
50
  edges: state.graph.edges.map(edge => ({ ...edge })), loops: [...state.graph.loops ?? []],
@@ -49,6 +54,10 @@ export function panelJob(job) {
49
54
  ...(e.loopId === undefined ? {} : { loopId: e.loopId }),
50
55
  ...(e.latencyMs === undefined ? {} : { latencyMs: e.latencyMs }),
51
56
  ...(job.progress[e.executionId] ? { progress: job.progress[e.executionId] } : {}),
57
+ ...(() => {
58
+ const live = e.status === "running" ? activity(e.executionId) : undefined;
59
+ return live ? { activity: panelActivity(live) } : {};
60
+ })(),
52
61
  })),
53
62
  pausedExecutionIds: [...state.pausedExecutionIds],
54
63
  usage: { inputTokens: job.usage.inputTokens ?? 0, outputTokens: job.usage.outputTokens ?? 0,
@@ -95,7 +104,7 @@ let BraidPanel = (() => {
95
104
  if (request.jobId && !selected)
96
105
  throw new Error("Braid job is no longer available in this session");
97
106
  const id = selected?.jobId;
98
- return { rows, job: id && jobs ? panelJob(jobs.get(id)) : null };
107
+ return { rows, job: id && jobs ? panelJob(jobs.get(id), executionId => jobs.getActivity(id, executionId, { limit: 0 })) : null };
99
108
  }
100
109
  async *watch(request, signal) {
101
110
  let dirty = true, wake;
@@ -148,13 +157,18 @@ let BraidPanel = (() => {
148
157
  detail(request) {
149
158
  try {
150
159
  this.snapshot(request);
151
- const node = this.find(request.sessionId).getNode(request.jobId, undefined, request.executionId);
160
+ const jobs = this.find(request.sessionId);
161
+ const node = jobs.getNode(request.jobId, undefined, request.executionId);
162
+ const activity = jobs.getActivity(request.jobId, request.executionId, {
163
+ limit: DETAIL_ACTIVITY_ENTRIES, ...(request.activityBefore === undefined ? {} : { before: request.activityBefore }),
164
+ });
152
165
  const output = node.output ?? "";
153
166
  const offset = Math.min(request.offset, output.length), next = Math.min(offset + 32768, output.length);
154
167
  return { executionId: request.executionId, status: node.status, output: output.slice(offset, next), offset, next, total: output.length,
155
168
  ...(node.decision === undefined ? {} : { decision: clip(node.decision) }),
156
169
  ...(node.error ? { error: clip(node.error.message) } : {}),
157
170
  ...(node.workspace ? { workspace: clip(JSON.stringify(node.workspace, null, 2), 8000) } : {}),
171
+ ...(activity ? { activity: { ...panelActivity(activity), entries: activity.entries } } : {}),
158
172
  };
159
173
  }
160
174
  catch (error) {
package/dist/runner.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { type LlmRuntime, type TokenUsage } from "@deepseek-ai/dsh-llm";
2
- import { type ModelRunner } from "@chrok/braid";
2
+ import { type ExecutionActivityTracker, type ModelRunner } from "@chrok/braid";
3
3
  export interface NodeProgress {
4
4
  nodeId: string;
5
5
  executionId: string;
@@ -16,6 +16,8 @@ export interface RunnerOptions {
16
16
  maxToolCalls?: number;
17
17
  onUsage?: (usage: TokenUsage) => void;
18
18
  onProgress?: (progress: NodeProgress) => void;
19
+ /** Record model requests, stream chunks, and tool calls for live diagnostics. */
20
+ activity?: ExecutionActivityTracker;
19
21
  }
20
22
  export declare function validateBudgets(options: {
21
23
  maxToolRounds?: number | undefined;
package/dist/runner.js CHANGED
@@ -16,6 +16,7 @@ export function createDshRunner(llm, options) {
16
16
  if (!route || slash < 1 || slash === route.length - 1)
17
17
  throw new Error("Choose a DSH provider/model, or set node.model to an exact provider/model-id");
18
18
  const provider = route.slice(0, slash), model = route.slice(slash + 1);
19
+ const activity = options.activity?.recorder(request);
19
20
  const modelInfo = await llm.resolveModelInfo?.(provider, model, request.signal);
20
21
  const contextWindow = modelInfo?.context?.contextWindow;
21
22
  request.signal.throwIfAborted();
@@ -75,14 +76,25 @@ export function createDshRunner(llm, options) {
75
76
  progress("model");
76
77
  const assembler = new BlockAssembler();
77
78
  let finished = false;
79
+ activity?.modelRequest();
78
80
  try {
79
81
  for await (const chunk of llm.stream({ provider, model, messages, system: prompt, tools: activeTools, signal: request.signal })) {
80
82
  request.signal.throwIfAborted();
81
83
  assembler.push(chunk);
82
84
  if (chunk.type === "finish")
83
85
  finished = true;
86
+ else if (chunk.type === "text-delta")
87
+ activity?.modelStream("text", chunk.text);
88
+ else if (chunk.type === "reasoning-delta")
89
+ activity?.modelStream("reasoning", chunk.text);
90
+ else if (chunk.type === "tool-call-delta")
91
+ activity?.modelStream("tool_call", chunk.argumentsDelta, chunk.name);
84
92
  }
85
93
  }
94
+ catch (error) {
95
+ activity?.modelError(error instanceof Error ? error.message : String(error));
96
+ throw error;
97
+ }
86
98
  finally {
87
99
  if (assembler.usage) {
88
100
  const usage = structuredClone(assembler.usage);
@@ -95,11 +107,22 @@ export function createDshRunner(llm, options) {
95
107
  }
96
108
  request.signal.throwIfAborted();
97
109
  const finish = assembler.finish;
98
- if (!finished)
99
- throw new Error("DSH model stream ended without a finish event");
100
- if (finish.kind !== "stop" && finish.kind !== "tool-calls")
101
- throw new Error("failure" in finish ? finish.failure.message : `DSH model ended with ${finish.kind}`);
110
+ const failure = !finished ? "DSH model stream ended without a finish event"
111
+ : finish.kind !== "stop" && finish.kind !== "tool-calls"
112
+ ? "failure" in finish ? finish.failure.message : `DSH model ended with ${finish.kind}` : undefined;
113
+ if (failure) {
114
+ activity?.modelError(failure);
115
+ throw new Error(failure);
116
+ }
102
117
  const response = assembler.message({ provider, model, ...(assembler.replayState ? { replayState: assembler.replayState } : {}) });
118
+ activity?.modelResponse({
119
+ text: response.content.flatMap(block => block.type === "text" ? [block.text] : []).join("\n\n"),
120
+ reasoning: response.content.flatMap(block => block.type === "reasoning" ? [block.text] : []).join("\n\n"),
121
+ toolCalls: response.content.flatMap(block => block.type === "tool-call" ? [{ id: block.id, name: block.name }] : []),
122
+ stopReason: finish.kind,
123
+ ...(assembler.usage ? { inputTokens: assembler.usage.inputTokens + (assembler.usage.cacheReadTokens ?? 0) + (assembler.usage.cacheWriteTokens ?? 0),
124
+ outputTokens: assembler.usage.outputTokens } : {}),
125
+ });
103
126
  output.push(...response.content.flatMap(block => block.type === "text" ? [block.text] : []));
104
127
  const calls = response.content.filter(block => block.type === "tool-call");
105
128
  if (!calls.length) {
@@ -118,6 +141,7 @@ export function createDshRunner(llm, options) {
118
141
  for (const call of calls) {
119
142
  request.signal.throwIfAborted();
120
143
  let text, isError = false;
144
+ activity?.toolStart(call.id, call.name, call.arguments);
121
145
  try {
122
146
  const args = JSON.parse(call.arguments);
123
147
  if (call.name === "decide" && request.decide) {
@@ -141,18 +165,21 @@ export function createDshRunner(llm, options) {
141
165
  const tool = files.find(tool => tool.name === call.name);
142
166
  if (!tool)
143
167
  throw new Error(`Unavailable tool '${call.name}'. Available: ${activeTools.map(tool => tool.name).join(", ")}`);
144
- const invoke = () => tool.execute(args);
168
+ const invoke = () => tool.execute(args, output => activity?.toolOutput(call.id, output));
145
169
  text = tool.writes && request.withWorkspaceWrite ? await request.withWorkspaceWrite(invoke) : await invoke();
146
170
  }
147
171
  }
148
172
  catch (error) {
149
173
  request.signal.throwIfAborted();
150
- // Invalid or duplicate decisions are terminal, matching core's exactly-once contract.
151
- if (call.name === "decide" && request.decide)
152
- throw error;
153
174
  isError = true;
154
175
  text = error instanceof Error ? error.message : String(error);
176
+ // Invalid or duplicate decisions are terminal, matching core's exactly-once contract.
177
+ if (call.name === "decide" && request.decide) {
178
+ activity?.toolEnd(call.id, text, true);
179
+ throw error;
180
+ }
155
181
  }
182
+ activity?.toolEnd(call.id, text, isError);
156
183
  messages.push(createToolResultMessage({ callId: call.id, content: [{ type: "text", text }], isError }));
157
184
  }
158
185
  }
@@ -1,2 +1,2 @@
1
1
  /** Own the entire process group through completion, cancellation, and timeout. */
2
- export declare function runCommand(shell: string, args: string[], cwd: string, signal: AbortSignal, timeout?: number): Promise<string>;
2
+ export declare function runCommand(shell: string, args: string[], cwd: string, signal: AbortSignal, timeout?: number, onOutput?: (output: string) => void): Promise<string>;
@@ -2,9 +2,16 @@ import { execFile, spawn } from "node:child_process";
2
2
  import { constants } from "node:os";
3
3
  import { join } from "node:path";
4
4
  /** Own the entire process group through completion, cancellation, and timeout. */
5
- export async function runCommand(shell, args, cwd, signal, timeout) {
5
+ export async function runCommand(shell, args, cwd, signal, timeout, onOutput) {
6
6
  let output = "";
7
- const onData = (data) => { output = (output + data.toString()).slice(-50_000); };
7
+ const onData = (data) => {
8
+ const text = data.toString();
9
+ output = (output + text).slice(-50_000);
10
+ try {
11
+ onOutput?.(text);
12
+ }
13
+ catch { /* Observers cannot affect the command. */ }
14
+ };
8
15
  signal?.throwIfAborted();
9
16
  if (timeout !== undefined && (!Number.isFinite(timeout) || timeout <= 0 || timeout * 1000 > 2_147_483_647))
10
17
  throw new Error("Invalid timeout: expected positive seconds within the timer limit");
package/dist/tools.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import type { ToolDefinition, ToolRunContext } from "@deepseek-ai/dsh-tools";
2
2
  import type { BraidJobs, JobSnapshot } from "./jobs.js";
3
+ /** Focused reads return the latest activity entries; activityBefore pages earlier ones. */
4
+ export declare const STATUS_ACTIVITY_ENTRIES = 40;
3
5
  export declare function graphReceipt(job: JobSnapshot): {
4
6
  nodes: ({
5
7
  model?: string;
package/dist/tools.js CHANGED
@@ -6,6 +6,8 @@ import { Value } from "@sinclair/typebox/value";
6
6
  import { braidParameters, nodeParameters, updateEdgeParameters, loopParameters } from "./schema.js";
7
7
  const id = Type.String({ minLength: 1, pattern: "\\S" });
8
8
  const revision = Type.Integer({ minimum: 0 });
9
+ /** Focused reads return the latest activity entries; activityBefore pages earlier ones. */
10
+ export const STATUS_ACTIVITY_ENTRIES = 40;
9
11
  export function graphReceipt(job) {
10
12
  return {
11
13
  nodes: job.execution.graph.nodes.map(({ prompt: _prompt, ...node }) => node),
@@ -39,8 +41,9 @@ export function createBraidTools(getJobs, submit) {
39
41
  }
40
42
  return [
41
43
  tool("braid", "Start a background Braid graph before nontrivial engineering work with independent concerns. Returns jobId immediately. Supports execute/decision/merge/integrate, promptTemplates, bounded loops, worktree isolation, pauseAfter and notifyOnCompletion. Omit workspace on merge/integrate. No automatic integration. Continue independent work; retrieve results after the completion reminder instead of polling.", braidParameters, submit),
42
- tool("braid_status", "Retrieve progress and results by exact jobId handle or UUID. Omit all IDs to list this agent's jobs. executionId selects an exact invocation; nodeId selects its latest invocation. Control fields contain the CURRENT revision and paused IDs. Large results provide a fullOutputPath. usage includes completed provider rounds from failed workers and cache tokens; reads do not add charges.", Type.Object({
44
+ tool("braid_status", "Retrieve progress and results by exact jobId handle or UUID. Omit all IDs to list this agent's jobs. executionId selects an exact invocation; nodeId selects its latest invocation. Focused reads include live activity: phase, time in phase and since the last observed signal, model request/stream state, running tools, and the latest " + STATUS_ACTIVITY_ENTRIES + " history entries; activityBefore pages earlier entries. Lack of observed activity is a diagnostic signal, not proof of a stall. Control fields contain the CURRENT revision and paused IDs. Large results provide a fullOutputPath. usage includes completed provider rounds from failed workers and cache tokens; reads do not add charges.", Type.Object({
43
45
  jobId: Type.Optional(id), nodeId: Type.Optional(id), executionId: Type.Optional(id),
46
+ activityBefore: Type.Optional(Type.Integer({ minimum: 1, maximum: Number.MAX_SAFE_INTEGER })),
44
47
  }, { additionalProperties: false }), (args, context) => {
45
48
  const jobs = getJobs(context);
46
49
  if (!args.jobId) {
@@ -49,11 +52,22 @@ export function createBraidTools(getJobs, submit) {
49
52
  return { jobs: jobs.list() };
50
53
  }
51
54
  const job = jobs.get(args.jobId);
52
- return args.nodeId || args.executionId ? {
55
+ if (args.activityBefore !== undefined && !args.nodeId && !args.executionId)
56
+ throw new Error("activityBefore requires nodeId or executionId");
57
+ if (!args.nodeId && !args.executionId)
58
+ return job;
59
+ const node = jobs.getNode(args.jobId, args.nodeId, args.executionId);
60
+ const activity = node.executionId ? jobs.getActivity(args.jobId, node.executionId, {
61
+ limit: STATUS_ACTIVITY_ENTRIES, ...(args.activityBefore === undefined ? {} : { before: args.activityBefore }),
62
+ }) : undefined;
63
+ // While running, activity is the useful part; afterwards the output is.
64
+ const running = activity && activity.finishedAt === undefined;
65
+ const live = activity ? { observedAt: Date.now(), activity } : {};
66
+ return {
53
67
  jobId: job.jobId, handle: job.handle, status: job.status,
54
68
  execution: { status: job.execution.status, revision: job.execution.revision, pausedExecutionIds: job.execution.pausedExecutionIds },
55
- node: jobs.getNode(args.jobId, args.nodeId, args.executionId),
56
- } : job;
69
+ ...(running ? live : {}), node, ...(running ? {} : live),
70
+ };
57
71
  }),
58
72
  tool("braid_cancel", "Cancel a background job. Foreground cancellation does not stop Braid jobs.", Type.Object({ jobId: id }, { additionalProperties: false }), (args, context) => {
59
73
  const jobs = getJobs(context), job = jobs.get(args.jobId);
@@ -4,6 +4,7 @@ export interface WorkerTool {
4
4
  description: string;
5
5
  parameters: Record<string, unknown>;
6
6
  writes: boolean;
7
- execute(args: unknown): Promise<string>;
7
+ /** onOutput receives incremental command output where a tool produces it. */
8
+ execute(args: unknown, onOutput?: (output: string) => void): Promise<string>;
8
9
  }
9
10
  export declare function createWorkerTools(request: ModelRequest, workspace: NodeWorkspace): Promise<WorkerTool[]>;
@@ -10,11 +10,11 @@ export async function createWorkerTools(request, workspace) {
10
10
  const cwd = workspace.workingDirectory, signal = request.signal;
11
11
  const tools = [];
12
12
  function add(name, description, parameters, writes, execute) {
13
- tools.push({ name, description, parameters, writes, async execute(args) {
13
+ tools.push({ name, description, parameters, writes, async execute(args, onOutput) {
14
14
  signal.throwIfAborted();
15
15
  if (!Value.Check(parameters, args))
16
16
  throw new Error(`Invalid ${name} arguments: ${[...Value.Errors(parameters, args)].map(error => `${error.path} ${error.message}`).join("; ")}`);
17
- const result = await execute(args);
17
+ const result = await execute(args, onOutput);
18
18
  signal.throwIfAborted();
19
19
  return result;
20
20
  } });
@@ -73,9 +73,9 @@ export async function createWorkerTools(request, workspace) {
73
73
  return "File edited.";
74
74
  });
75
75
  const shellParameters = Type.Object({ command: path, timeout: Type.Optional(Type.Number({ exclusiveMinimum: 0, maximum: 2_147_483.647 })) }, { additionalProperties: false });
76
- add("bash", "Run a foreground shell command in the assigned workspace. timeout is seconds. Output retains the last 50 KB. Host permissions apply; do not daemonize.", shellParameters, true, args => runCommand("bash", ["-c", args.command], cwd, signal, args.timeout));
76
+ add("bash", "Run a foreground shell command in the assigned workspace. timeout is seconds. Output retains the last 50 KB. Host permissions apply; do not daemonize.", shellParameters, true, (args, onOutput) => runCommand("bash", ["-c", args.command], cwd, signal, args.timeout, onOutput));
77
77
  if (process.platform === "win32")
78
- add("powershell", "Run a foreground PowerShell command in the assigned workspace. timeout is seconds.", shellParameters, true, args => runCommand("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", args.command], cwd, signal, args.timeout));
78
+ add("powershell", "Run a foreground PowerShell command in the assigned workspace. timeout is seconds.", shellParameters, true, (args, onOutput) => runCommand("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", args.command], cwd, signal, args.timeout, onOutput));
79
79
  }
80
80
  return tools;
81
81
  }
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@chrok/dsh-braid",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "license": "MIT",
5
5
  "description": "DeepSeek Harness plugin for Braid: background agent graphs, bounded loops, live updates, and execution progress",
6
6
  "type": "module",
7
7
  "dependencies": {
8
- "@chrok/braid": "0.3.2",
8
+ "@chrok/braid": "0.3.3",
9
9
  "@sinclair/typebox": "^0.34.41"
10
10
  },
11
11
  "peerDependencies": {