@belonguniverseai/react-sdk 0.4.1 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/dist/api/agent-grants.d.ts +33 -0
  2. package/dist/api/client.d.ts +154 -10
  3. package/dist/api/retry-fetch.d.ts +3 -1
  4. package/dist/api/task-schedules.d.ts +14 -0
  5. package/dist/browser/agent-link.d.ts +18 -0
  6. package/dist/browser/agent-touch.d.ts +105 -0
  7. package/dist/browser/spa-navigate.d.ts +24 -1
  8. package/dist/component/{arc-Du1-HUt0.js → arc-ByLm_58u.js} +2 -2
  9. package/dist/component/{architectureDiagram-3BPJPVTR-NTFoFNN-.js → architectureDiagram-3BPJPVTR-DcYT4v9Q.js} +3 -3
  10. package/dist/component/{blockDiagram-GPEHLZMM-9LBL4EUV.js → blockDiagram-GPEHLZMM-CHk-YSun.js} +4 -4
  11. package/dist/component/{c4Diagram-AAUBKEIU-C1enIoRg.js → c4Diagram-AAUBKEIU-CEV2fwh-.js} +3 -3
  12. package/dist/component/{channel-CNnOkAN_.js → channel-D67v09ii.js} +2 -2
  13. package/dist/component/{chunk-2J33WTMH-X2Iy3mMD.js → chunk-2J33WTMH-Bsl2GBCp.js} +2 -2
  14. package/dist/component/{chunk-4BX2VUAB-BLlcE09Q.js → chunk-4BX2VUAB-BKmdmdRY.js} +2 -2
  15. package/dist/component/{chunk-55IACEB6-23v_td5T.js → chunk-55IACEB6-DnliqOsL.js} +2 -2
  16. package/dist/component/{chunk-727SXJPM-BC2kAa1t.js → chunk-727SXJPM-O0BgSnK_.js} +6 -6
  17. package/dist/component/{chunk-AQP2D5EJ-CsRFVdwF.js → chunk-AQP2D5EJ-CwBA3VVY.js} +4 -4
  18. package/dist/component/{chunk-FMBD7UC4-CWrggihb.js → chunk-FMBD7UC4-CG5DaKp9.js} +2 -2
  19. package/dist/component/{chunk-ND2GUHAM-Bj78QMsn.js → chunk-ND2GUHAM-COsoTCa0.js} +2 -2
  20. package/dist/component/{chunk-QZHKN3VN-CS_FAlLS.js → chunk-QZHKN3VN-9FjIin4_.js} +2 -2
  21. package/dist/component/{classDiagram-4FO5ZUOK-ci84KOU1.js → classDiagram-4FO5ZUOK-DyQO35S9.js} +3 -3
  22. package/dist/component/{classDiagram-v2-Q7XG4LA2-ci84KOU1.js → classDiagram-v2-Q7XG4LA2-DyQO35S9.js} +3 -3
  23. package/dist/component/{cose-bilkent-S5V4N54A-QLIj0pt2.js → cose-bilkent-S5V4N54A-BTN6Bz9E.js} +2 -2
  24. package/dist/component/{dagre-BM42HDAG-D32wP-VH.js → dagre-BM42HDAG-COU3yvtF.js} +2 -2
  25. package/dist/component/{diagram-2AECGRRQ-Dn47q_hT.js → diagram-2AECGRRQ-r4LO_uyu.js} +3 -3
  26. package/dist/component/{diagram-5GNKFQAL-Df7a_ICg.js → diagram-5GNKFQAL-CraSe8h_.js} +4 -4
  27. package/dist/component/{diagram-KO2AKTUF-CNcoKufc.js → diagram-KO2AKTUF-Dh-L6_aX.js} +3 -3
  28. package/dist/component/{diagram-LMA3HP47-Dq8j6XNs.js → diagram-LMA3HP47-Bv8QREaH.js} +3 -3
  29. package/dist/component/{diagram-OG6HWLK6-CZ1WglbZ.js → diagram-OG6HWLK6-Jf-6CDV4.js} +4 -4
  30. package/dist/component/{erDiagram-TEJ5UH35-CDlHARAu.js → erDiagram-TEJ5UH35-CN8X2drH.js} +5 -5
  31. package/dist/component/{flowDiagram-I6XJVG4X-Cw1mKy8X.js → flowDiagram-I6XJVG4X-CloAsK8k.js} +7 -7
  32. package/dist/component/{ganttDiagram-6RSMTGT7-B3FUForj.js → ganttDiagram-6RSMTGT7-DAlRM4jt.js} +3 -3
  33. package/dist/component/{gitGraphDiagram-PVQCEYII-BgHuuQ27.js → gitGraphDiagram-PVQCEYII-BPVdEwuf.js} +4 -4
  34. package/dist/component/{highlighted-body-OFNGDK62-BTv_Fxf3.js → highlighted-body-OFNGDK62-BEd7ynwt.js} +2 -2
  35. package/dist/component/index.js +2 -2
  36. package/dist/component/{infoDiagram-5YYISTIA-DE9i_OcK.js → infoDiagram-5YYISTIA-CyJi6c7l.js} +2 -2
  37. package/dist/component/{ishikawaDiagram-YF4QCWOH-BDe88Hz2.js → ishikawaDiagram-YF4QCWOH-CNKCQHOP.js} +2 -2
  38. package/dist/component/{journeyDiagram-JHISSGLW-D3t45UC1.js → journeyDiagram-JHISSGLW-DFN0WY5F.js} +5 -5
  39. package/dist/component/{kanban-definition-UN3LZRKU-DfFJIuhU.js → kanban-definition-UN3LZRKU-BT6YDPZA.js} +3 -3
  40. package/dist/component/{linear-AXxuun7R.js → linear-BcyQd0z0.js} +2 -2
  41. package/dist/component/{mermaid-GHXKKRXX-D7NVqIBP.js → mermaid-GHXKKRXX-DiPCfS1n.js} +28526 -27802
  42. package/dist/component/{mindmap-definition-RKZ34NQL-cTac4kYU.js → mindmap-definition-RKZ34NQL-BND7KvId.js} +4 -4
  43. package/dist/component/{pieDiagram-4H26LBE5-B1SubLQb.js → pieDiagram-4H26LBE5-CvDdRFnN.js} +4 -4
  44. package/dist/component/{quadrantDiagram-W4KKPZXB-CzyBW8Cr.js → quadrantDiagram-W4KKPZXB-DMHCLEev.js} +3 -3
  45. package/dist/component/{requirementDiagram-4Y6WPE33-DgS33NcX.js → requirementDiagram-4Y6WPE33-BomcVKb4.js} +4 -4
  46. package/dist/component/{sankeyDiagram-5OEKKPKP-Cp4o_akq.js → sankeyDiagram-5OEKKPKP-D4rmtFCn.js} +2 -2
  47. package/dist/component/{sequenceDiagram-3UESZ5HK-2gf91-2b.js → sequenceDiagram-3UESZ5HK-C0iEDbuE.js} +4 -4
  48. package/dist/component/{stateDiagram-AJRCARHV-BByZezJw.js → stateDiagram-AJRCARHV-x0PonbWT.js} +3 -3
  49. package/dist/component/{stateDiagram-v2-BHNVJYJU-B-IObShO.js → stateDiagram-v2-BHNVJYJU-6Lq1LlSV.js} +3 -3
  50. package/dist/component/{timeline-definition-PNZ67QCA-D_2NG1sj.js → timeline-definition-PNZ67QCA-CIx8lwoQ.js} +3 -3
  51. package/dist/component/{vennDiagram-CIIHVFJN-BjrQUaEs.js → vennDiagram-CIIHVFJN-B27Ya-3D.js} +2 -2
  52. package/dist/component/{wardleyDiagram-YWT4CUSO-DYcvfAeQ.js → wardleyDiagram-YWT4CUSO-efmvFwPj.js} +3 -3
  53. package/dist/component/{xychartDiagram-2RQKCTM6-CtLaJFtQ.js → xychartDiagram-2RQKCTM6-DNJmorKa.js} +3 -3
  54. package/dist/components/ai-elements/dock-link.d.ts +27 -0
  55. package/dist/components/ai-elements/link-safety-modal.d.ts +46 -1
  56. package/dist/components/ai-elements/message.d.ts +29 -2
  57. package/dist/components/ai-elements/prompt-input.d.ts +1 -1
  58. package/dist/components/embed/file-preview-kind.d.ts +6 -1
  59. package/dist/components/embed/parse-csv.d.ts +22 -5
  60. package/dist/components/embed/rail-flags.d.ts +21 -12
  61. package/dist/components/embed/use-preview-bytes.d.ts +12 -0
  62. package/dist/components/embed/use-workspace-preview-file.d.ts +34 -0
  63. package/dist/components/scheduled/ScheduledDetailSurface.d.ts +2 -2
  64. package/dist/components/ui/input-group.d.ts +7 -4
  65. package/dist/embed/slash-commands.d.ts +41 -12
  66. package/dist/embed/use-workspace-file-download.d.ts +10 -2
  67. package/dist/embed/voice/line-dispatch.d.ts +51 -16
  68. package/dist/embed/voice/line-run-reader.d.ts +32 -54
  69. package/dist/embed/voice/line-slots.d.ts +6 -2
  70. package/dist/embed/voice-call-lines.d.ts +38 -11
  71. package/dist/i18n/messages/en.d.ts +16 -5
  72. package/dist/i18n/messages/surfaces/aiElements.d.ts +3 -0
  73. package/dist/i18n/messages/surfaces/scheduled.d.ts +9 -0
  74. package/dist/i18n/messages/surfaces/stream.d.ts +31 -16
  75. package/dist/stream/chat-upload.d.ts +29 -3
  76. package/dist/stream/preview-panel-store.d.ts +8 -0
  77. package/dist/stream/run-line-progress.d.ts +62 -0
  78. package/dist/stream/sandbox-output.d.ts +31 -3
  79. package/dist/stream/stream-state-store.d.ts +56 -0
  80. package/dist/stream/tool-error-copy.d.ts +4 -0
  81. package/dist/test/fetch-stubs.d.ts +16 -0
  82. package/package.json +1 -1
@@ -20,27 +20,62 @@
20
20
  * sessions list names the background conversation.
21
21
  *
22
22
  * BOOT RE-ATTACH (F3/R4): `attachLineReader` below is the ONE seam that wires
23
- * a line-run reader onto a line, shared by a fresh dispatch (this module,
24
- * right after a POST accepts a run) and `reattachPendingLineRuns` (called
25
- * once at boot, after `initAgentLines()` rehydrates the registry) resuming a
26
- * run that was still going when the page reloaded. Both paths persist the
27
- * binding (`persistSlotRun`) and wire the identical phase/approval/navigate/
28
- * artifact/finish/error callbacks — a reload must behave exactly like the
29
- * live dispatch it is standing in for, not a parallel, easier-to-drift copy.
23
+ * a VOICE-dispatched line-run reader onto a line, shared by a fresh dispatch
24
+ * (this module, right after a POST accepts a run) and `reattachPendingLineRuns`
25
+ * (called once at boot, after `initAgentLines()` rehydrates the registry)
26
+ * resuming a run that was still going when the page reloaded. Both paths
27
+ * persist the binding (`persistSlotRun`) and wire the identical phase/approval/
28
+ * navigate/artifact/finish/error callbacks — a reload must behave exactly like
29
+ * the live dispatch it is standing in for, not a parallel, easier-to-drift copy.
30
+ *
31
+ * TWO READER KINDS (BEL-90). This module now attaches two, and which callback
32
+ * set a caller gets is a correctness question, not a style one:
33
+ *
34
+ * - `attachLineReader` — the voice-NARRATION reader. Its callbacks are not
35
+ * plain setters: `deliverLineReply`/`deliverLineFailure` push
36
+ * `conversation.item.create` events into an active voice call and ask the
37
+ * model to respond, `notifyLinePhase` appends timeline rows and nudges
38
+ * spoken progress, `deliverLineArtifact` opens a preview panel. Correct
39
+ * for a run the operator dispatched BY VOICE.
40
+ * - `attachLineProgressReader` — the plain-progress reader, for a run the
41
+ * user started by TYPING that was still in flight at reload. It goes
42
+ * through `reportRunLineProgress` and touches only the registry, so a
43
+ * typed run can never make the agent start talking about background
44
+ * progress mid-call.
30
45
  */
31
46
  /** Abort every live line reader and invalidate their callbacks (call teardown).
32
47
  * Subscribed below to fire whenever a call leaves in_call/connecting. */
33
48
  export declare const abortAllLineReaders: () => void;
49
+ /** Test-only: drop every plain-progress reader (and the active-session latch)
50
+ * so a case never inherits either from the previous case. The narration
51
+ * readers have `abortAllLineReaders`; these deliberately do NOT ride on it — a
52
+ * voice call ending has nothing to do with a typed run still streaming. */
53
+ export declare const __detachLineProgressReadersForTest: () => void;
34
54
  /**
35
- * BOOT RE-ATTACH (F3/R4): call this once, right after `initAgentLines()`
36
- * rehydrates the registry from persisted slots. Every background line (2/3)
37
- * whose slot carried a non-null `runId` already shows `status: "working"`
38
- * (`rehydratedLines()` in voice-call-lines.ts) — this re-attaches its reader
39
- * so the line actually converges to ready/failed via the SAME
40
- * `attachLineReader` a live dispatch uses, instead of sitting at an
41
- * honest-looking but permanently stuck "working". Line 1 never carries a
42
- * registry `runId` (see `AgentLine.runId`'s doc) and is skipped here — its
43
- * own reload-resume path is the stream-state store's, not this one.
55
+ * BOOT RE-ATTACH: call this once, right after `initAgentLines()` rehydrates
56
+ * the registry. A line rehydrated as `status: "working"` has a run that was
57
+ * still going when the page went away (`rehydratedLines()` in
58
+ * voice-call-lines.ts) — this attaches the reader that actually converges it
59
+ * to ready/failed, instead of leaving an honest-looking but permanently stuck
60
+ * "working".
61
+ *
62
+ * TWO paths, because the two dispatch kinds have genuinely different
63
+ * contracts (BEL-90 / B1 see `attachLineProgressReader`'s doc):
64
+ *
65
+ * - F3/R4, UNCHANGED — a line whose durable SLOT carries a runId was
66
+ * dispatched by voice. It gets the narration reader, on every line that has
67
+ * one, INCLUDING when its session is the one on screen. That last part is
68
+ * load-bearing: `persistSlotRun(line, null)` in that reader's terminal
69
+ * callbacks is the durable slot's clearer, and skipping the on-screen line
70
+ * would leave a stale slot runId that rehydrates as "working" on every
71
+ * future reload (§41). The transport's terminal now clears the slot too, so
72
+ * both routes converge.
73
+ * - BEL-90 — a line with NO slot runId but a fresh parked run cursor was
74
+ * started by typing. It gets the plain-progress reader, and it is SKIPPED
75
+ * when its session is the active one: ChatRoute is about to mount for that
76
+ * session and its transport will claim the single reader. Skipping is safe
77
+ * here precisely because a typed run writes no durable slot runId — there
78
+ * is nothing that could get stuck.
44
79
  */
45
80
  export declare const reattachPendingLineRuns: (fetchFn?: typeof fetch) => void;
46
81
  export declare const dispatchToLine: (req: {
@@ -1,56 +1,4 @@
1
- /**
2
- * Minimal SSE consumer for a BACKGROUND line's run stream — the Operator's
3
- * ear on lines the chat surface isn't showing. Reads the AI-SDK data-stream
4
- * protocol from `GET /v1/runs/:runId/stream` and surfaces only what the call
5
- * needs: tool phases, approval-needed, the final text, errors. No `useChat`,
6
- * no rendering, no reconnect/resume (that's `BelongChatTransport`'s job for
7
- * the foreground chat surface — a background line reader just watches once).
8
- * Fetch is injected for tests.
9
- *
10
- * Wire shapes mirror the real protocol pinned in `belong-chat-transport.ts` /
11
- * `belong-data-parts.ts` — NOT the placeholder `text-delta` / `finish` shapes
12
- * from the original task brief:
13
- * - text is a DELTA part: `{ type: "text", id, text }` — accumulate `.text`.
14
- * - `data-tool-call` carries a `state` ("started" | "completed" | "failed");
15
- * only "started" is a phase change worth reporting.
16
- * - `data-approval-request` carries a `state` ("pending" | "approved" |
17
- * "rejected" | "amend_requested" | "expired"); only "pending" means an
18
- * approval is newly needed.
19
- * - `data-navigation` carries `{ routeName, params }` — a background agent
20
- * asking the HOST to navigate. The foreground renderer executes these via
21
- * `peekRouteHandler` (see `route-dispatch.ts`, the shared seam); a
22
- * background line has no renderer to pick it up, so `onNavigate` here
23
- * dispatches through that SAME seam instead. Unlike the foreground's
24
- * reload-replay (guarded by its `historical` flag + `useFireOnce`), this
25
- * reader has no reconnect/replay at all (see the module doc above) — each
26
- * SSE line is parsed and applied exactly once by the read loop below, so
27
- * no separate dedupe is needed here to keep a navigation from re-firing.
28
- * - there is no `finish` / `error` part. The terminal signal is
29
- * `data-status` with `status` ∈ "continuing" | "completed" | "cancelled" |
30
- * "failed" | "throttled". "continuing" is the max-turns auto-continue —
31
- * NOT terminal, keep reading the same stream. "completed" finishes with
32
- * the accumulated text; "cancelled" | "failed" | "throttled" are errors.
33
- *
34
- * BOOT RE-ATTACH (F3/R4): this reader is also opened for a run that already
35
- * finished before the read starts (a persisted `runId` re-attached after a
36
- * reload — see `attachLineReader` in line-dispatch.ts). Two ways that shows
37
- * up on the wire, both a CLEAN convergence rather than a failure:
38
- * - the run is still known server-side and just replays its full history
39
- * (§36 — `GET .../stream` with no cursor replays from the start): the
40
- * already-written terminal `data-status` event arrives like any other
41
- * part and is handled by the SAME "completed"/"cancelled"/"failed"
42
- * branch below — no special-casing needed, this is the ordinary path.
43
- * - the run (or its task) is truly gone server-side — 404/410 — which
44
- * reads identically to "nothing left to report", not an error: `onFinish`
45
- * fires with empty text instead of `onError`, so a boot re-attach never
46
- * paints a stale run as failed just because its record has since expired
47
- * or the session behind it was deleted.
48
- *
49
- * SSE parsing here is LINE-BY-LINE (split on "\n", not "\n\n") — the server
50
- * sends exactly one `data:` line per event. `id:` lines carry the event
51
- * cursor (ignored — v1 has no reconnect/resume) and `:`-prefixed lines are
52
- * keepalive comments.
53
- */
1
+ import { RunStatusKind } from '../../stream/belong-data-parts.ts';
54
2
  export type WatchLineRunInput = {
55
3
  readonly runId: string;
56
4
  readonly onPhase: (toolName: string) => void;
@@ -65,6 +13,36 @@ export type WatchLineRunInput = {
65
13
  mimeType: string;
66
14
  }) => void;
67
15
  readonly onFinish: (finalText: string) => void;
68
- readonly onError: (message: string, kind: "terminal" | "transport") => void;
16
+ /**
17
+ * The run did not finish cleanly. `cause` is a discriminated shape rather
18
+ * than a bare `"terminal" | "transport"` string because the two carry
19
+ * genuinely different data (§21): a TERMINAL knows exactly which non-success
20
+ * status the wire reported, and callers must be able to tell a user-pressed
21
+ * Stop (`cancelled`) from a real breakage (`failed`) — the transport already
22
+ * renders the first as an ordinary finish and only the second as an error,
23
+ * and a rail badge that disagrees is the §42 mistake. A TRANSPORT failure
24
+ * knows nothing about the run's state at all: the server task may well still
25
+ * be running.
26
+ */
27
+ readonly onError: (message: string, cause: {
28
+ readonly kind: "terminal";
29
+ readonly status: Exclude<RunStatusKind, "continuing">;
30
+ } | {
31
+ readonly kind: "transport";
32
+ }) => void;
33
+ /**
34
+ * "The stream just delivered something" — fired once per chunk read off the
35
+ * socket, INCLUDING the server's `: keepalive` comment every 15s (which
36
+ * `parseSseLine` otherwise drops). It carries no payload because its only
37
+ * job is liveness: BEL-90's progress reader is the sole listener on a
38
+ * backgrounded typed run after a reload, and the parked run cursor's
39
+ * age-out gate (`peekLiveParkedRun`) needs a re-stamp from SOMEONE or a run
40
+ * doing two minutes of silent tool work reads as dead (§41).
41
+ *
42
+ * OPTIONAL because only that one caller owns a cursor. The narration reader
43
+ * (`attachLineReader`) rehydrates from the durable slot runId, which has no
44
+ * age gate, so there is nothing for it to keep fresh.
45
+ */
46
+ readonly onTick?: () => void;
69
47
  };
70
48
  export declare const watchLineRun: (input: WatchLineRunInput, fetchFn?: typeof fetch) => (() => void);
@@ -34,8 +34,12 @@
34
34
  * streaming server-side. Back-compatible the same way `line1` is: a bag
35
35
  * written before this field existed has no `runId` key at all, and the
36
36
  * schema defaults it to `null` (nothing was in flight when that bag was
37
- * written). Line 1 never carries a meaningful value hereits `runId` is
38
- * always `null` (see `AgentLine.runId`'s doc in voice-call-lines.ts).
37
+ * written). Line 1's slot `runId` stays `null` in practicenothing dispatches
38
+ * to line 1 and `persistSlotRun` is the only writer — but do not read that as
39
+ * "line 1 has no run": the IN-MEMORY `AgentLine.runId` is no longer always null
40
+ * for line 1, since a reload seeds it from the parked run cursor (BEL-90 — see
41
+ * `AgentLine.runId`'s doc in voice-call-lines.ts). This field is the VOICE
42
+ * dispatch's durable binding specifically, not "the line's run".
39
43
  */
40
44
  /** Every line number that gets a persisted slot — all three agent lines. */
41
45
  declare const SLOT_LINES: readonly [1, 2, 3];
@@ -31,10 +31,16 @@ export type AgentLine = {
31
31
  readonly lastText: string;
32
32
  /** The line's current run, for `stop_agent` to target — bound by the
33
33
  * line-run reader once a background dispatch's POST returns a runId, and
34
- * cleared back to `null` when that run reaches a terminal state. Line 1
35
- * (foreground) never gets this written: its runId is resolved at stop-time
36
- * from the stream-state store instead (the same source the on-screen Stop
37
- * button reads), so this stays `null` for line 1 always. */
34
+ * cleared back to `null` when that run reaches a terminal state.
35
+ *
36
+ * Line 1 never has this WRITTEN by a dispatch (line-dispatch.ts never
37
+ * dispatches to it), and its stop-time runId is still resolved from the
38
+ * stream-state store — the same source the on-screen Stop button reads. It
39
+ * is no longer always `null` for line 1, though: a REHYDRATE seeds it from
40
+ * the parked run cursor on every line alike (BEL-90 — see
41
+ * `inFlightRehydration`), because a run started by typing keeps streaming
42
+ * across a reload and a chip that reads "idle" for it is a lie. Nothing
43
+ * about the stop path changed; only the reload seed did. */
38
44
  readonly runId: string | null;
39
45
  /** The live "what is it doing right now" label (e.g. "writing code"),
40
46
  * written by `setLineStep` as phase notifications arrive while `status`
@@ -114,6 +120,20 @@ export declare const lineBoundToSession: (sessionId: string) => AgentLine | unde
114
120
  * already holds must SWITCH to Agent 1, not adopt (duplicate) it onto whatever
115
121
  * background line the user happens to be viewing. */
116
122
  export declare const lineOwningSession: (sessionId: string) => AgentLine | undefined;
123
+ /**
124
+ * EVERY line bound to `sessionId` — the plural form `markSessionSeen` and
125
+ * `releaseLinesForSession` below already work in, for the same reason they do:
126
+ * more than one line can hold one session (line 1 aliases whatever the chat is
127
+ * showing, so a background line the user opened is held by both), and a legacy
128
+ * `belong:voice-line-slots` bag written before the `isBoundToAnotherLine`
129
+ * guards landed can rehydrate two background lines onto one session.
130
+ *
131
+ * `lineOwningSession` answers a different question — "which ONE agent should a
132
+ * History reopen switch to" — and stays singular. Anything that WRITES per-line
133
+ * state for a session (BEL-90's `reportRunLineProgress`) must use this one, or
134
+ * the second holder freezes at whatever it last said.
135
+ */
136
+ export declare const linesOwningSession: (sessionId: string) => readonly AgentLine[];
117
137
  /** True when `sessionId` is already the session of some line OTHER than line
118
138
  * 1 — chat.tsx's line-1 aliasing guard uses this to skip rebinding line 1
119
139
  * onto a background line's session while the user is viewing it via
@@ -209,14 +229,21 @@ export declare const bindLineRun: (line: number, runId: string | null) => void;
209
229
  * persisted slot together, so the ONE thing a page reload cannot observe by
210
230
  * itself — "is this line's run still going?" — survives the reload instead
211
231
  * of silently reverting to a lying "idle". `line-dispatch.ts`'s
212
- * `attachLineReader` is the ONE seam that calls this, shared by a live
213
- * dispatch and the boot re-attach (`reattachPendingLineRuns`) alike — same
214
- * discipline as `persistSlotBinding`'s ADOPTION seam.
232
+ * `attachLineReader` is the seam that SETS it, shared by a live dispatch and
233
+ * the boot re-attach (`reattachPendingLineRuns`) alike — same discipline as
234
+ * `persistSlotBinding`'s ADOPTION seam.
235
+ *
236
+ * There is a SECOND clearer (BEL-90): `run-line-progress.ts` calls this with
237
+ * `null` on every terminal, including for the session currently on screen.
238
+ * Without it, a background line whose run finished while the user was LOOKING
239
+ * at that line never reached `attachLineReader`'s terminal callbacks, so the
240
+ * slot kept a stale runId and every later reload rehydrated the chip as a
241
+ * permanently stuck "working" (§41).
215
242
  *
216
- * Line 1 never goes through this (line-dispatch.ts never dispatches to line
217
- * 1 — see its module doc): its `runId` stays the always-`null` value
218
- * `bindLineRun` already tolerates, and its own run is resolved at stop-time
219
- * from the stream-state store instead (`AgentLine.runId`'s doc).
243
+ * Line 1 never has this SET (line-dispatch.ts never dispatches to line 1 —
244
+ * see its module doc); its own run is resolved at stop-time from the
245
+ * stream-state store instead (`AgentLine.runId`'s doc). Clearing it for line 1
246
+ * is a harmless no-op, which is what keeps the terminal path above uniform.
220
247
  */
221
248
  export declare const persistSlotRun: (line: number, runId: string | null) => void;
222
249
  export declare const setLineStatus: (line: number, status: AgentLineStatus, lastText?: string) => void;
@@ -53,17 +53,22 @@ export declare const en: {
53
53
  readonly browserResolveResource: "Looked up a resource";
54
54
  readonly browserAwaitProcessed: "Waited for processing";
55
55
  readonly browserAssertCreated: "Checked for an existing resource";
56
+ readonly browserRefreshView: "Refreshed the page";
56
57
  readonly failedBadge: "failed";
57
58
  readonly executingTasks: "Working on it…";
58
59
  readonly workedSteps_one: "Worked · {{count}} step";
59
60
  readonly workedSteps_other: "Worked · {{count}} steps";
61
+ readonly cliAuthStop: {
62
+ readonly noGrant: "Connect to Simetrik to continue";
63
+ readonly reconnectFailed: "Couldn't connect to Simetrik";
64
+ readonly cliAuthRequired: "Reconnecting to Simetrik…";
65
+ readonly reconnecting: "Reconnecting to Simetrik…";
66
+ };
67
+ readonly reconnectingBadge: "reconnecting";
60
68
  readonly resumingAfterPause: "Taking longer than expected — picking it back up…";
61
69
  readonly open: "Open";
62
- readonly reconnectNeeded: "The {{provider}} session needs reconnecting to continue.";
63
- readonly reconnect: "Reconnect";
64
- readonly reconnecting: "Reconnecting…";
65
- readonly reconnected: "Reconnected";
66
- readonly retry: "Retry";
70
+ readonly reconnectRateLimited: "{{provider}} is busy trying again automatically in {{seconds}}s.";
71
+ readonly reconnectRateLimitedStill: "{{provider}} is still busy. We'll keep trying on our own.";
67
72
  };
68
73
  readonly stats: {
69
74
  readonly title: "Session stats";
@@ -128,6 +133,9 @@ export declare const en: {
128
133
  readonly customEmailLabel: "Custom email enabled";
129
134
  readonly customEmailDescription: "Each run reads the latest version of this template and sends an email only when its condition matches.";
130
135
  readonly customEmailTemplate: "HTML template";
136
+ readonly emailNotificationLabel: "Completion email enabled";
137
+ readonly emailRecipients: "Recipients";
138
+ readonly emailAccountRecipient: "Schedule owner's account email";
131
139
  readonly summaryOnce: "Once on {{time}}";
132
140
  readonly summaryDaily: "Daily at {{time}}";
133
141
  readonly summaryWeekdays: "Weekdays at {{time}}";
@@ -372,6 +380,7 @@ export declare const en: {
372
380
  readonly copy: "Copy";
373
381
  readonly copied: "Copied";
374
382
  readonly openExternalLink: "Open external link?";
383
+ readonly openInAppLink: "Open this page?";
375
384
  readonly openLinkDescriptionPrefix: "This will open";
376
385
  readonly openLinkDescriptionSuffix: "in a new tab.";
377
386
  readonly cancel: "Cancel";
@@ -527,6 +536,8 @@ export declare const en: {
527
536
  readonly notDelivered: "Not delivered — please resend";
528
537
  readonly runFailed: "Run failed";
529
538
  readonly uploadFailed: "Attachment upload failed — remove it or try again.";
539
+ readonly uploadRejectedType: "“{{filename}}” isn’t a file type the assistant can read — remove it. Text, data, config, code, document and image files work; archives and compiled binaries don’t.";
540
+ readonly uploadRejectedSecret: "“{{filename}}” looks like an environment/secrets file — it can’t be attached. Remove it and paste only the values you need.";
530
541
  readonly authExpired: "Your session expired — please sign in to {{name}} again, then retry.";
531
542
  readonly backendUnavailable: "Can't reach the assistant service — check your connection.";
532
543
  readonly streamError: "Stream error — {{message}}";
@@ -33,6 +33,7 @@ export declare const aiElementsEn: {
33
33
  readonly copy: "Copy";
34
34
  readonly copied: "Copied";
35
35
  readonly openExternalLink: "Open external link?";
36
+ readonly openInAppLink: "Open this page?";
36
37
  readonly openLinkDescriptionPrefix: "This will open";
37
38
  readonly openLinkDescriptionSuffix: "in a new tab.";
38
39
  readonly cancel: "Cancel";
@@ -84,6 +85,7 @@ export declare const aiElementsEs: {
84
85
  copy: string;
85
86
  copied: string;
86
87
  openExternalLink: string;
88
+ openInAppLink: string;
87
89
  openLinkDescriptionPrefix: string;
88
90
  openLinkDescriptionSuffix: string;
89
91
  cancel: string;
@@ -135,6 +137,7 @@ export declare const aiElementsPt: {
135
137
  copy: string;
136
138
  copied: string;
137
139
  openExternalLink: string;
140
+ openInAppLink: string;
138
141
  openLinkDescriptionPrefix: string;
139
142
  openLinkDescriptionSuffix: string;
140
143
  cancel: string;
@@ -26,6 +26,9 @@ export declare const scheduledEn: {
26
26
  readonly customEmailLabel: "Custom email enabled";
27
27
  readonly customEmailDescription: "Each run reads the latest version of this template and sends an email only when its condition matches.";
28
28
  readonly customEmailTemplate: "HTML template";
29
+ readonly emailNotificationLabel: "Completion email enabled";
30
+ readonly emailRecipients: "Recipients";
31
+ readonly emailAccountRecipient: "Schedule owner's account email";
29
32
  readonly summaryOnce: "Once on {{time}}";
30
33
  readonly summaryDaily: "Daily at {{time}}";
31
34
  readonly summaryWeekdays: "Weekdays at {{time}}";
@@ -120,6 +123,9 @@ export declare const scheduledEs: {
120
123
  customEmailLabel: string;
121
124
  customEmailDescription: string;
122
125
  customEmailTemplate: string;
126
+ emailNotificationLabel: string;
127
+ emailRecipients: string;
128
+ emailAccountRecipient: string;
123
129
  summaryOnce: string;
124
130
  summaryDaily: string;
125
131
  summaryWeekdays: string;
@@ -214,6 +220,9 @@ export declare const scheduledPt: {
214
220
  customEmailLabel: string;
215
221
  customEmailDescription: string;
216
222
  customEmailTemplate: string;
223
+ emailNotificationLabel: string;
224
+ emailRecipients: string;
225
+ emailAccountRecipient: string;
217
226
  summaryOnce: string;
218
227
  summaryDaily: string;
219
228
  summaryWeekdays: string;
@@ -2,7 +2,7 @@
2
2
  * Stream part-renderer strings (`src/stream/ai-sdk-part-renderers.tsx`): the
3
3
  * cards the assistant's live stream renders — approval + choice widgets, tool
4
4
  * activity tasks, browser step labels, consolidated terminal groups, artifact
5
- * cards, and the CLI reconnect chip. Status-code badges (`ok` / `no_handler` /
5
+ * cards, and the CLI reconnect note. Status-code badges (`ok` / `no_handler` /
6
6
  * wire `data.status`) are technical chrome and stay verbatim, per the same
7
7
  * rule as `embed/copy.ts`.
8
8
  */
@@ -53,17 +53,22 @@ export declare const streamEn: {
53
53
  readonly browserResolveResource: "Looked up a resource";
54
54
  readonly browserAwaitProcessed: "Waited for processing";
55
55
  readonly browserAssertCreated: "Checked for an existing resource";
56
+ readonly browserRefreshView: "Refreshed the page";
56
57
  readonly failedBadge: "failed";
57
58
  readonly executingTasks: "Working on it…";
58
59
  readonly workedSteps_one: "Worked · {{count}} step";
59
60
  readonly workedSteps_other: "Worked · {{count}} steps";
61
+ readonly cliAuthStop: {
62
+ readonly noGrant: "Connect to Simetrik to continue";
63
+ readonly reconnectFailed: "Couldn't connect to Simetrik";
64
+ readonly cliAuthRequired: "Reconnecting to Simetrik…";
65
+ readonly reconnecting: "Reconnecting to Simetrik…";
66
+ };
67
+ readonly reconnectingBadge: "reconnecting";
60
68
  readonly resumingAfterPause: "Taking longer than expected — picking it back up…";
61
69
  readonly open: "Open";
62
- readonly reconnectNeeded: "The {{provider}} session needs reconnecting to continue.";
63
- readonly reconnect: "Reconnect";
64
- readonly reconnecting: "Reconnecting…";
65
- readonly reconnected: "Reconnected";
66
- readonly retry: "Retry";
70
+ readonly reconnectRateLimited: "{{provider}} is busy trying again automatically in {{seconds}}s.";
71
+ readonly reconnectRateLimitedStill: "{{provider}} is still busy. We'll keep trying on our own.";
67
72
  };
68
73
  };
69
74
  export declare const streamEs: {
@@ -113,17 +118,22 @@ export declare const streamEs: {
113
118
  browserResolveResource: string;
114
119
  browserAwaitProcessed: string;
115
120
  browserAssertCreated: string;
121
+ browserRefreshView: string;
116
122
  failedBadge: string;
117
123
  executingTasks: string;
118
124
  workedSteps_one: string;
119
125
  workedSteps_other: string;
126
+ cliAuthStop: {
127
+ noGrant: string;
128
+ reconnectFailed: string;
129
+ cliAuthRequired: string;
130
+ reconnecting: string;
131
+ };
132
+ reconnectingBadge: string;
120
133
  resumingAfterPause: string;
121
134
  open: string;
122
- reconnectNeeded: string;
123
- reconnect: string;
124
- reconnecting: string;
125
- reconnected: string;
126
- retry: string;
135
+ reconnectRateLimited: string;
136
+ reconnectRateLimitedStill: string;
127
137
  };
128
138
  };
129
139
  export declare const streamPt: {
@@ -173,16 +183,21 @@ export declare const streamPt: {
173
183
  browserResolveResource: string;
174
184
  browserAwaitProcessed: string;
175
185
  browserAssertCreated: string;
186
+ browserRefreshView: string;
176
187
  failedBadge: string;
177
188
  executingTasks: string;
178
189
  workedSteps_one: string;
179
190
  workedSteps_other: string;
191
+ cliAuthStop: {
192
+ noGrant: string;
193
+ reconnectFailed: string;
194
+ cliAuthRequired: string;
195
+ reconnecting: string;
196
+ };
197
+ reconnectingBadge: string;
180
198
  resumingAfterPause: string;
181
199
  open: string;
182
- reconnectNeeded: string;
183
- reconnect: string;
184
- reconnecting: string;
185
- reconnected: string;
186
- retry: string;
200
+ reconnectRateLimited: string;
201
+ reconnectRateLimitedStill: string;
187
202
  };
188
203
  };
@@ -1,8 +1,34 @@
1
1
  import { FileUIPart } from 'ai';
2
- /** Normalise to the server's allow-list by extension (browsers report .md/.csv inconsistently). */
2
+ /**
3
+ * Normalise to the server's allow-list by extension (browsers report .md/.csv/
4
+ * .yaml inconsistently). An unknown extension keeps whatever the browser said,
5
+ * and an unknown extension with NO browser type reports `application/octet-
6
+ * stream` — deliberately NOT `text/plain`, which used to smuggle `.pyc`/`.pkl`
7
+ * and other typeless binaries onto the text allow-list where they were inlined
8
+ * to the model as mojibake. The server refuses those with a named reason.
9
+ */
3
10
  export declare const resolveMimeType: (file: File) => string;
4
- /** Upload one file to the server, returning its fileId (or null on failure). */
5
- export declare const uploadOneFile: (apiBaseUrl: string, file: File) => Promise<string | null>;
11
+ /** Why an attachment upload failed — a named reason, not a bare null (§19/§20). */
12
+ export type AttachmentUploadReason = "workspace_scope_missing" | "secrets_by_convention" | "unsupported_file_type" | "upload_failed";
13
+ /**
14
+ * A failed attachment upload, carrying the filename + reason so the composer can
15
+ * tell the user WHICH file was refused and WHY instead of a generic banner
16
+ * (007-plan C6 — a silent/anonymous upload failure is the known defect class).
17
+ */
18
+ export declare class AttachmentUploadError extends Error {
19
+ readonly filename: string;
20
+ readonly reason: AttachmentUploadReason;
21
+ constructor(filename: string, reason: AttachmentUploadReason);
22
+ }
23
+ export type UploadOneFileResult = {
24
+ readonly ok: true;
25
+ readonly fileId: string;
26
+ } | {
27
+ readonly ok: false;
28
+ readonly reason: AttachmentUploadReason;
29
+ };
30
+ /** Upload one file to the server, returning its fileId or a named refusal. */
31
+ export declare const uploadOneFile: (apiBaseUrl: string, file: File) => Promise<UploadOneFileResult>;
6
32
  /**
7
33
  * Bridge the PromptInput's `file` parts (data-url FileUIParts) to the
8
34
  * upload-first wire: upload each, in order, and return the server fileIds.
@@ -21,6 +21,12 @@ export declare const DEFAULT_PREVIEW_PANEL_WIDTH_PX = 480;
21
21
  * What the panel is previewing. A published artifact is fetched by id; a
22
22
  * workspace file by its workspace-relative path. Both resolve to an auth'd
23
23
  * bytes URL in `PreviewPanel`.
24
+ *
25
+ * A workspace target PINS the workspace it was opened from. The path is
26
+ * relative to `ws-<id>/`, so it is only meaningful together with that id —
27
+ * reading the live scope later instead would silently repoint an open preview
28
+ * at a different workspace's file (or, when the scope goes `missing`, at the
29
+ * unscoped root) the next time the panel re-renders.
24
30
  */
25
31
  export type PreviewTarget = {
26
32
  readonly kind: "artifact";
@@ -32,6 +38,8 @@ export type PreviewTarget = {
32
38
  readonly path: string;
33
39
  readonly title: string;
34
40
  readonly mimeType: string;
41
+ /** The workspace this path belongs to; null when the host configures none. */
42
+ readonly workspaceExternalId: string | null;
35
43
  };
36
44
  export type PreviewPanelState = {
37
45
  readonly open: boolean;
@@ -0,0 +1,62 @@
1
+ import { RunStatusKind } from './belong-data-parts.ts';
2
+ /**
3
+ * What a run reported, reduced to the only four things a rail chip can show.
4
+ *
5
+ * `activity` is the tool-LESS turn's path to a truthful "working" badge: a
6
+ * turn that only writes text calls no tools, so `tool_started` never fires and
7
+ * the chip would otherwise sit at "idle" through the whole answer.
8
+ *
9
+ * There is deliberately NO `text` variant. An accumulator feeding
10
+ * `AgentLine.lastText` was specified and dropped: nothing in the dock renders
11
+ * `lastText`, and because this seam no-ops while the session is on screen the
12
+ * accumulator could only ever have collected the post-switch TAIL of an
13
+ * answer. Re-add it when something renders it.
14
+ *
15
+ * `terminal` carries the run's OWN id, and it is not decoration: the durable
16
+ * slot runId this seam clears is shared with the voice dispatch, and a line can
17
+ * hold a live voice run at the same moment a DIFFERENT (typed) run on the same
18
+ * session finishes. Clearing by session alone unbinds `stop_agent`'s target for
19
+ * a run that is still going. `status` is spelled from the wire union rather
20
+ * than by hand so a new `RunStatusKind` fails CI here (§21).
21
+ */
22
+ export type RunLineProgressEvent = {
23
+ readonly kind: "activity";
24
+ } | {
25
+ readonly kind: "tool_started";
26
+ readonly toolName: string;
27
+ } | {
28
+ readonly kind: "approval_pending";
29
+ } | {
30
+ readonly kind: "terminal";
31
+ readonly runId: string;
32
+ readonly status: Exclude<RunStatusKind, "continuing">;
33
+ };
34
+ /**
35
+ * Report one run event for `sessionId`. Silently does nothing when no agent
36
+ * line owns that session.
37
+ *
38
+ * Two writes with two different scopes, in this order:
39
+ *
40
+ * 1. A TERMINAL clears the line's durable slot runId — including for the
41
+ * session on screen — but ONLY when the slot still names the run that just
42
+ * ended. `attachLineReader`'s terminal callbacks used to be the only code
43
+ * in the tree that ever cleared it, so a background line's run that
44
+ * finished while the user was LOOKING at that line left a stale runId
45
+ * behind, and every later reload rehydrated the chip as a permanently
46
+ * stuck "working" (§41 violation). The id check is what keeps that fix
47
+ * from becoming its own bug: the slot is also `stop_agent`'s target, and a
48
+ * line can hold a LIVE voice run at the moment an older typed run on the
49
+ * same session terminates. Clearing that would leave a running agent
50
+ * unstoppable and its chip claiming "done" mid-run.
51
+ * 2. The BADGE writes are skipped for the session on screen. That line's
52
+ * status is chat.tsx's exclusive business — it is mounted, it has the real
53
+ * stream status, and it drives the call narration. Leaving the foreground
54
+ * byte-for-byte unchanged is what makes this seam safe to add.
55
+ *
56
+ * Applied to EVERY line bound to the session, not the first match — same
57
+ * reasoning as `markSessionSeen` / `releaseLinesForSession`, which have always
58
+ * iterated: line 1 aliases whatever the chat is showing, so a background line
59
+ * the user opened is held by both, and a legacy slots bag can rehydrate two
60
+ * lines onto one session. Writing only the first left the other frozen.
61
+ */
62
+ export declare const reportRunLineProgress: (sessionId: string, event: RunLineProgressEvent) => void;
@@ -1,7 +1,23 @@
1
- import { SandboxCommandData, ToolCallData } from './belong-data-parts.ts';
1
+ import { SandboxCommandData, ToolCallData, ToolErrorSeverity } from './belong-data-parts.ts';
2
2
  /** The shell tools across runtimes; both carry `input.command` + `output.exitCode`. */
3
3
  export declare const SHELL_TOOL_NAMES: ReadonlySet<string>;
4
4
  export declare const isShellToolName: (toolName: string) => boolean;
5
+ /**
6
+ * The ONE place that decides whether a wire severity means "SURFACES on the
7
+ * collapsed activity line".
8
+ *
9
+ * It used to mean "red". BEL-96 dropped red from the execution surfaces
10
+ * entirely — every failure now reads orange, stopping or not — so severity no
11
+ * longer picks a colour. What it still picks is whether the user is shown the
12
+ * failure at all: an ordinary one stays folded inside "Worked · N steps", a
13
+ * stopping one is lifted onto the collapsed line.
14
+ *
15
+ * Every consumer used to be a bare `=== "stop"`, so a third member added to
16
+ * `ToolErrorSeverity` would have compiled clean everywhere and silently
17
+ * rendered as non-stop. `.exhaustive()` turns that into a CI failure at this
18
+ * single site.
19
+ */
20
+ export declare const isStoppingSeverity: (severity: ToolErrorSeverity | undefined) => boolean;
5
21
  /**
6
22
  * BEL-97 — how a finished shell command's outcome should be coloured.
7
23
  *
@@ -9,12 +25,24 @@ export declare const isShellToolName: (toolName: string) => boolean;
9
25
  * failed with exit 0 (successful execution despite wrapper error),
10
26
  * or timed out (still running in the sandbox).
11
27
  * - `"notice"` — an ORDINARY failure (non-zero exit, or a tool error with no
12
- * stop-severity). Orange, NOT red: the agent kept going.
28
+ * stop-severity). Orange, and folded away.
13
29
  * - `"stop"` — an agent-execution-STOPPING failure (a denied permission, an
14
- * aborting error: `error.severity === "stop"`). Red.
30
+ * aborting error: `error.severity === "stop"`). Also orange
31
+ * since BEL-96 — what sets it apart is that it SURFACES on
32
+ * the collapsed line, not that it is a different colour.
15
33
  *
16
34
  * One source of truth shared by `TerminalTask` (its status badge) and
17
35
  * `ActivityGroup` (its aggregate failure badge).
36
+ *
37
+ * BEL-96 — ORDER MATTERS, and the two observable-outcome guards go FIRST.
38
+ * §42 words both as absolutes ("`exit 0` is ALWAYS a success regardless of wire
39
+ * state"; a timed-out command "reads 'still running', not 'failed'"), and a
40
+ * `severity` check ahead of them defeated both: `exit0 + stop` measured "stop",
41
+ * `timeout + stop` measured "stop". That was unreachable while nothing on the
42
+ * server emitted a stop severity, but `tool-executor.ts` now forwards
43
+ * `error.severity` for ANY registry tool including `run_shell`. Observable
44
+ * outcome beats declared state — the same rule the exit-0 guard already
45
+ * encoded, now applied consistently.
18
46
  */
19
47
  export type TerminalSeverity = "none" | "notice" | "stop";
20
48
  export declare const terminalCommandSeverity: (command: ToolCallData) => TerminalSeverity;