@belonguniverseai/react-sdk 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dist/api/agent-grants.d.ts +33 -0
  2. package/dist/api/client.d.ts +104 -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-COH48Rtu.js → arc-CtyXH_sw.js} +2 -2
  9. package/dist/component/{architectureDiagram-3BPJPVTR-B5qmE5k5.js → architectureDiagram-3BPJPVTR-C6NZifN6.js} +3 -3
  10. package/dist/component/{blockDiagram-GPEHLZMM-lkovkWkX.js → blockDiagram-GPEHLZMM-_-K66LP4.js} +4 -4
  11. package/dist/component/{c4Diagram-AAUBKEIU-CaWDjxTr.js → c4Diagram-AAUBKEIU-DL-K-sZW.js} +3 -3
  12. package/dist/component/{channel-DNnfyuhY.js → channel-scCA9sxi.js} +2 -2
  13. package/dist/component/{chunk-2J33WTMH-I7HgfCPn.js → chunk-2J33WTMH-Dkd9OyM1.js} +2 -2
  14. package/dist/component/{chunk-4BX2VUAB-CZBTp8pg.js → chunk-4BX2VUAB-JbEXcQ3q.js} +2 -2
  15. package/dist/component/{chunk-55IACEB6-C-RnqcTj.js → chunk-55IACEB6-Dg96dHvQ.js} +2 -2
  16. package/dist/component/{chunk-727SXJPM-BFV7YyWV.js → chunk-727SXJPM-Cu3-awqi.js} +6 -6
  17. package/dist/component/{chunk-AQP2D5EJ-BDVikNJT.js → chunk-AQP2D5EJ-DLX62MPh.js} +4 -4
  18. package/dist/component/{chunk-FMBD7UC4-C864-npb.js → chunk-FMBD7UC4-BxU0KQRK.js} +2 -2
  19. package/dist/component/{chunk-ND2GUHAM-DuitYR9A.js → chunk-ND2GUHAM-CEQj3so6.js} +2 -2
  20. package/dist/component/{chunk-QZHKN3VN-B9uI1TYV.js → chunk-QZHKN3VN-BWgwT04-.js} +2 -2
  21. package/dist/component/{classDiagram-4FO5ZUOK-BUdCEjaj.js → classDiagram-4FO5ZUOK-Ton6m2pw.js} +3 -3
  22. package/dist/component/{classDiagram-v2-Q7XG4LA2-BUdCEjaj.js → classDiagram-v2-Q7XG4LA2-Ton6m2pw.js} +3 -3
  23. package/dist/component/{cose-bilkent-S5V4N54A-Dgk__ohs.js → cose-bilkent-S5V4N54A-Dja09hp6.js} +2 -2
  24. package/dist/component/{dagre-BM42HDAG-DGHFHFPf.js → dagre-BM42HDAG-Ch6fODe-.js} +2 -2
  25. package/dist/component/{diagram-2AECGRRQ-DvGSzrwW.js → diagram-2AECGRRQ-DdDr6tHi.js} +3 -3
  26. package/dist/component/{diagram-5GNKFQAL-XebuIyjn.js → diagram-5GNKFQAL-BT2qfjUH.js} +4 -4
  27. package/dist/component/{diagram-KO2AKTUF-slUL6XEO.js → diagram-KO2AKTUF-UcWrBVNK.js} +3 -3
  28. package/dist/component/{diagram-LMA3HP47-BEPY8GOZ.js → diagram-LMA3HP47-D-BCOeIt.js} +3 -3
  29. package/dist/component/{diagram-OG6HWLK6-DHI_0aIk.js → diagram-OG6HWLK6-CJDJgfQO.js} +4 -4
  30. package/dist/component/{erDiagram-TEJ5UH35-D-6DbJr-.js → erDiagram-TEJ5UH35-kY5sdKqg.js} +5 -5
  31. package/dist/component/{flowDiagram-I6XJVG4X-Cw87OG_x.js → flowDiagram-I6XJVG4X-9OddgRiE.js} +7 -7
  32. package/dist/component/{ganttDiagram-6RSMTGT7-B47s5HUB.js → ganttDiagram-6RSMTGT7-Dc9t8llA.js} +3 -3
  33. package/dist/component/{gitGraphDiagram-PVQCEYII-DqFW3uiq.js → gitGraphDiagram-PVQCEYII-DYjn9Ff5.js} +4 -4
  34. package/dist/component/{highlighted-body-OFNGDK62-CBU3EdTE.js → highlighted-body-OFNGDK62-D_TDzrFY.js} +2 -2
  35. package/dist/component/index.js +2 -2
  36. package/dist/component/{infoDiagram-5YYISTIA-_0W78xb_.js → infoDiagram-5YYISTIA-CBPoKi7E.js} +2 -2
  37. package/dist/component/{ishikawaDiagram-YF4QCWOH-CvybNkGE.js → ishikawaDiagram-YF4QCWOH-C3rChBg5.js} +2 -2
  38. package/dist/component/{journeyDiagram-JHISSGLW-DgLrQs9G.js → journeyDiagram-JHISSGLW-DVTybrGG.js} +5 -5
  39. package/dist/component/{kanban-definition-UN3LZRKU-ReYnw5Xl.js → kanban-definition-UN3LZRKU-DNMLC4NQ.js} +3 -3
  40. package/dist/component/{linear-Cih5KQ00.js → linear-B_oPUR6_.js} +2 -2
  41. package/dist/component/{mermaid-GHXKKRXX-B6ix-Z04.js → mermaid-GHXKKRXX-CjZr9GWr.js} +28679 -27638
  42. package/dist/component/{mindmap-definition-RKZ34NQL-hRhkTdF6.js → mindmap-definition-RKZ34NQL-CErhrdm3.js} +4 -4
  43. package/dist/component/{pieDiagram-4H26LBE5-DAAEUZCY.js → pieDiagram-4H26LBE5-Cno02n3_.js} +4 -4
  44. package/dist/component/{quadrantDiagram-W4KKPZXB-Benxdf_G.js → quadrantDiagram-W4KKPZXB-DQV7ytCz.js} +3 -3
  45. package/dist/component/{requirementDiagram-4Y6WPE33-BxvkbDYP.js → requirementDiagram-4Y6WPE33-DBORDX5u.js} +4 -4
  46. package/dist/component/{sankeyDiagram-5OEKKPKP-RPwwVwu3.js → sankeyDiagram-5OEKKPKP-gNBaVNW1.js} +2 -2
  47. package/dist/component/{sequenceDiagram-3UESZ5HK-C-prnAtS.js → sequenceDiagram-3UESZ5HK-BlxJztMa.js} +4 -4
  48. package/dist/component/{stateDiagram-AJRCARHV-BEIQAx9e.js → stateDiagram-AJRCARHV-2ziF_Zes.js} +3 -3
  49. package/dist/component/{stateDiagram-v2-BHNVJYJU-BD5dkY8l.js → stateDiagram-v2-BHNVJYJU-BWmzKTMS.js} +3 -3
  50. package/dist/component/{timeline-definition-PNZ67QCA-DQJPMkfL.js → timeline-definition-PNZ67QCA-OcHhxXWM.js} +3 -3
  51. package/dist/component/{vennDiagram-CIIHVFJN-CreOqXMc.js → vennDiagram-CIIHVFJN-Fl9VlPVe.js} +2 -2
  52. package/dist/component/{wardleyDiagram-YWT4CUSO--dbQqySn.js → wardleyDiagram-YWT4CUSO-BNHUW0Ex.js} +3 -3
  53. package/dist/component/{xychartDiagram-2RQKCTM6-BOSkmQiX.js → xychartDiagram-2RQKCTM6-Bog3Ddue.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/use-preview-bytes.d.ts +12 -0
  61. package/dist/components/embed/use-workspace-preview-file.d.ts +34 -0
  62. package/dist/components/scheduled/ScheduledDetailSurface.d.ts +2 -2
  63. package/dist/components/ui/input-group.d.ts +7 -4
  64. package/dist/embed/approval-bus.d.ts +5 -0
  65. package/dist/embed/slash-commands.d.ts +41 -12
  66. package/dist/embed/voice/agent-queue.d.ts +106 -0
  67. package/dist/embed/voice/call-roster-store.d.ts +110 -0
  68. package/dist/embed/voice/line-dispatch.d.ts +57 -18
  69. package/dist/embed/voice/line-run-reader.d.ts +35 -55
  70. package/dist/embed/voice/line-slots.d.ts +6 -2
  71. package/dist/embed/voice-call-lines.d.ts +58 -11
  72. package/dist/embed/voice-call-pacing.d.ts +47 -9
  73. package/dist/embed/voice-call.d.ts +70 -14
  74. package/dist/i18n/messages/en.d.ts +30 -20
  75. package/dist/i18n/messages/surfaces/aiElements.d.ts +3 -0
  76. package/dist/i18n/messages/surfaces/scheduled.d.ts +9 -0
  77. package/dist/i18n/messages/surfaces/stream.d.ts +31 -16
  78. package/dist/stream/chat-upload.d.ts +29 -3
  79. package/dist/stream/run-line-progress.d.ts +62 -0
  80. package/dist/stream/sandbox-output.d.ts +31 -3
  81. package/dist/stream/stream-state-store.d.ts +56 -0
  82. package/dist/stream/tool-error-copy.d.ts +4 -0
  83. package/dist/test/fetch-stubs.d.ts +16 -0
  84. package/dist/types/public.d.ts +1 -1
  85. package/package.json +1 -1
@@ -12,8 +12,12 @@ export type CallTimelineEntry = {
12
12
  readonly atMs: number;
13
13
  readonly kind: "user" | "agent" | "step" | "success" | "error" | "skill" | "schedule";
14
14
  readonly text: string;
15
- /** Agent tag for Operator-mode rows (e.g. "A2"); absent for foreground rows. */
16
- readonly lineTag?: string;
15
+ /** The switchboard line this row concerns; `null` for a foreground (line 1)
16
+ * row. CallScreen's `labelFor` resolves `line ?? 1` to look up the agent's
17
+ * short board label for `step`/`success`/`error` rows (X2b) — the label
18
+ * column names the agent, so `text` itself never repeats a title prefix or
19
+ * an "A2"-style tag. */
20
+ readonly line: number | null;
17
21
  };
18
22
  export type CallState = {
19
23
  readonly status: CallStatus;
@@ -112,14 +116,55 @@ declare let lineDispatcher: ((req: {
112
116
  readonly isNewLine: boolean;
113
117
  }) => void) | null;
114
118
  export declare const registerCallLineDispatcher: (dispatcher: NonNullable<typeof lineDispatcher>) => (() => void);
119
+ /**
120
+ * Last-resort delivery for `flushLineQueuesOnCallEnd` when no `lineDispatcher`
121
+ * is wired (the M7 gap — ChatRoute unmounted). Self-registered by
122
+ * line-dispatch.ts (see the bottom of that file) with the real
123
+ * `dispatchToLine` — deliberately NOT imported here directly. `line-dispatch.ts`
124
+ * already imports six functions FROM this module (buildCallContextDigest,
125
+ * the deliver/notify callbacks, peekCallState, subscribeCallState), so a
126
+ * static import the other way would close a two-way cycle between
127
+ * voice-call.ts and line-dispatch.ts — forbidden outright by
128
+ * `.dependency-cruiser.cjs`'s `no-circular` rule (severity: error, applies
129
+ * everywhere, not just the hexagonal backend layers). Registering FROM
130
+ * line-dispatch.ts, in the SAME direction its existing dependency already
131
+ * runs, avoids the cycle entirely; that file's own `subscribeCallState`
132
+ * self-subscribe (its module doc, right above `abortAllLineReaders`) is the
133
+ * identical idiom already established there.
134
+ *
135
+ * Investigated and confirmed SOUND as a fallback: chat.tsx's own
136
+ * `registerCallLineDispatcher` wrapper does nothing beyond routing line 1 to
137
+ * `sendCallText` and calling this exact function, unmodified, for any other
138
+ * line — see that effect in chat.tsx. Held/queued items only ever exist for
139
+ * background lines (line 1 never enqueues — see the busy-line branch above),
140
+ * so every item this fallback ever sees is exactly the shape ChatRoute's
141
+ * wrapper would have passed through unchanged. No ChatRoute-specific
142
+ * behavior is lost by calling it directly.
143
+ *
144
+ * Deliberately SEPARATE from `lineDispatcher` — not folded into
145
+ * `releaseHeldRequest` itself — so `pumpLineQueue`'s live-queue draining is
146
+ * UNAFFECTED: it must keep checking `lineDispatcher` and leaving an item
147
+ * queued (not popped) when nothing is wired, per its own doc. Only the
148
+ * end-of-call flush, which has nothing left to leave a drained item queued
149
+ * IN, reaches for this.
150
+ */
151
+ declare let lineDispatchFallback: ((req: {
152
+ readonly line: number;
153
+ readonly request: string;
154
+ readonly isNewLine: boolean;
155
+ }) => Promise<void>) | null;
156
+ export declare const registerLineDispatchFallback: (dispatcher: NonNullable<typeof lineDispatchFallback>) => (() => void);
115
157
  export declare const registerCallLineViewSwitcher: (switcher: (sessionId: string) => void) => (() => void);
116
158
  export declare const registerCallClearNotifier: (notifier: (sessionId: string) => void) => (() => void);
117
159
  /**
118
160
  * ChatRoute calls this when a tool-approval card appears while a call is
119
161
  * live: the ask lands on the timeline and the voice model asks the user to
120
- * approve or reject out loud.
162
+ * approve or reject out loud. `reason` is the approval part's own `reason`
163
+ * field (via the approval bus's `PendingApproval.reason`) — on a phone call
164
+ * the user cannot see the card, so WHAT it wants to do has to travel in the
165
+ * prompt, not stay something only "open the chat view" could answer.
121
166
  */
122
- export declare const notifyCallApprovalRequired: (timelineText: string) => void;
167
+ export declare const notifyCallApprovalRequired: (timelineText: string, reason: string) => void;
123
168
  /** Live speech level, 0..1 (max of agent voice + user mic). */
124
169
  export declare const peekCallAudioLevel: () => number;
125
170
  /** ChatRoute reports a tool-phase change on the delegated run — the strongest
@@ -129,7 +174,7 @@ export declare const notifyCallProgress: (hint: string) => void;
129
174
  * small work badge while the agent is busy. */
130
175
  export declare const setCallWorkPhase: (phase: CallState["workPhase"]) => void;
131
176
  /**
132
- * Click-path twin of `show_agent_line`: the lines strip chip on CallScreen
177
+ * Click-path twin of `show_agent`: the lines strip chip on CallScreen
133
178
  * calls this directly (no tool-call round trip, no ack). No-op when the line
134
179
  * is unknown, never bound to a session, or no view switcher is registered
135
180
  * (e.g. ChatRoute hasn't mounted).
@@ -173,7 +218,8 @@ export declare const deliverAgentReply: (text: string) => void;
173
218
  * must tell the user something went wrong and offer to retry.
174
219
  */
175
220
  export declare const deliverAgentFailure: (message: string) => void;
176
- /** A background line finished: relay its final text, naming the line. */
221
+ /** A background line finished: relay its final text, naming the agent by
222
+ * role. */
177
223
  export declare const deliverLineReply: (line: number, text: string) => void;
178
224
  /**
179
225
  * A background line published an artifact: OPEN it on screen, mirroring
@@ -188,16 +234,26 @@ export declare const deliverLineArtifact: (line: number, artifact: {
188
234
  readonly title: string;
189
235
  readonly mimeType: string;
190
236
  }) => void;
191
- /** A background line failed: tell the user, naming the agent. */
237
+ /** A background line failed: tell the user, naming the agent by role. */
192
238
  export declare const deliverLineFailure: (line: number, message: string) => void;
193
- /** A background line is blocked on a tool approval — steer the user to it. */
194
- export declare const notifyLineApprovalNeeded: (line: number, timelineText: string) => void;
239
+ /** A background line is blocked on a tool approval — steer the user to it,
240
+ * by role, and tell the model WHAT it wants to do. W3: the old text asked
241
+ * the user to say a magic phrase ("show <title>") and never said what was
242
+ * being approved — unanswerable on a phone call, where there is no screen to
243
+ * "go look at". `reason` is the approval part's own `reason` field, threaded
244
+ * from the run stream via `onApprovalNeeded` (line-run-reader.ts). */
245
+ export declare const notifyLineApprovalNeeded: (line: number, timelineText: string, reason: string) => void;
195
246
  /** A background line advanced a phase — record it as the line's live step
196
- * (CallScreen's agent board), land a tagged timeline row, and nudge a spoken
197
- * update. The registry write is unconditional (line-dispatch's own `isStale`
247
+ * (CallScreen's agent board reads `currentStepLabel`/`currentPhase` off the
248
+ * registry) and nudge a spoken update. X2a: deliberately NO timeline row per
249
+ * phase change any more — the board's own card already shows the identical
250
+ * string live, and a 12-step run used to write 12 near-identical Activity
251
+ * rows that buried the actual results; the durable Activity-log row for a
252
+ * background line's work is the ONE `dispatchToBackgroundLine` appends up
253
+ * front. The registry write is unconditional (line-dispatch's own `isStale`
198
254
  * guard already keeps a stale-call phase from ever reaching here); the
199
- * timeline/spoken half stays guarded like its delivery siblings so a phase
200
- * that DOES arrive with no live call just updates the board silently. */
255
+ * spoken nudge stays guarded like its delivery siblings so a phase that DOES
256
+ * arrive with no live call just updates the board silently. */
201
257
  export declare const notifyLinePhase: (line: number, phaseLabel: string, phase?: WorkPhase | null) => void;
202
258
  /** True while a call holds the audio path — ChatRoute gates TTS autoplay on it. */
203
259
  export declare const isCallActive: () => boolean;
@@ -209,7 +265,7 @@ export declare const isCallActive: () => boolean;
209
265
  */
210
266
  export declare const __forceCallState: (patch: Partial<CallState>) => void;
211
267
  /** TEST-ONLY companion: append a timeline row while in a forced state. */
212
- export declare const __forceCallTimelineEntry: (kind: CallTimelineEntry["kind"], text: string, lineTag?: string) => void;
268
+ export declare const __forceCallTimelineEntry: (kind: CallTimelineEntry["kind"], text: string, line?: number | null) => void;
213
269
  /** TEST-ONLY companion: drive the orb's audio level without Web Audio. */
214
270
  export declare const __forceCallAudioLevel: (level: number) => void;
215
271
  /**
@@ -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";
@@ -471,9 +480,6 @@ export declare const en: {
471
480
  readonly muted: "Mic muted";
472
481
  readonly youSaid: "You said";
473
482
  readonly agentSaid: "Agent";
474
- readonly step: "Working";
475
- readonly done: "Done";
476
- readonly failed: "Failed";
477
483
  readonly speakHint: "Speak to the agent…";
478
484
  readonly readyHint: "I'm listening — speak when you're ready.";
479
485
  readonly thinkingHint: "Thinking…";
@@ -492,22 +498,24 @@ export declare const en: {
492
498
  readonly skillNotFound: "No exact skill match for “{{query}}”";
493
499
  readonly skillCatalogUnavailable: "Skill catalog unavailable — retrying";
494
500
  readonly noSkillsConfigured: "No skills configured in this workspace";
495
- readonly phaseCoding: "Writing code";
496
- readonly phaseFiles: "Working with files";
497
- readonly phaseActions: "Taking actions";
501
+ readonly phaseCoding: "Putting the steps together";
502
+ readonly phaseFiles: "Going through your data";
503
+ readonly phaseActions: "Running the steps";
498
504
  readonly lines: "Agents";
499
505
  readonly lineLabel: "Agent {{line}}";
500
506
  readonly mainAgentLabel: "Main agent";
501
- readonly lineNeedsApproval: "needs approval";
502
- readonly lineWorking: "working";
503
- readonly lineReady: "ready";
504
- readonly lineFailed: "failed";
505
- readonly lineIdle: "idle";
506
- readonly lineNotStarted: "not started";
507
- readonly lineNoChat: "no chat yet";
507
+ readonly roleLabelMain: "Main agent";
508
+ readonly roleLabelData: "{{product}} data agent";
509
+ readonly roleLabelDataGeneric: "Data agent";
510
+ readonly roleLabelAnalyst: "Analyst";
511
+ readonly lineNeedsApproval: "Needs your OK";
512
+ readonly lineWorking: "Working…";
513
+ readonly lineReady: "Done";
514
+ readonly lineFailed: "Couldn't finish";
515
+ readonly lineIdle: "Ready";
508
516
  readonly activity: "Activity";
509
- readonly showConversationLog: "Show conversation log";
510
- readonly hideConversationLog: "Hide conversation log";
517
+ readonly showConversationLog: "Show what was said";
518
+ readonly hideConversationLog: "Hide what was said";
511
519
  readonly ambientTypingCode: "Typing code…";
512
520
  readonly ambientReviewingDiff: "Reviewing the diff…";
513
521
  readonly ambientRunningChecks: "Running checks…";
@@ -527,6 +535,8 @@ export declare const en: {
527
535
  readonly notDelivered: "Not delivered — please resend";
528
536
  readonly runFailed: "Run failed";
529
537
  readonly uploadFailed: "Attachment upload failed — remove it or try again.";
538
+ 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.";
539
+ readonly uploadRejectedSecret: "“{{filename}}” looks like an environment/secrets file — it can’t be attached. Remove it and paste only the values you need.";
530
540
  readonly authExpired: "Your session expired — please sign in to {{name}} again, then retry.";
531
541
  readonly backendUnavailable: "Can't reach the assistant service — check your connection.";
532
542
  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.
@@ -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;
@@ -92,6 +92,62 @@ export declare const clearStreamState: (workspaceId?: string | null) => void;
92
92
  * message overwrites the cursor via {@link writeStreamState}.
93
93
  */
94
94
  export declare const readResumableStreamState: (workspaceId?: string | null) => PersistedStreamState | null;
95
+ /**
96
+ * Was a run still in flight for `sessionId` when this page last looked — the
97
+ * ONE query behind "a reload must not lie about a backgrounded agent"
98
+ * (BEL-90 / §41). The parked-cursor map already carries exactly this truth
99
+ * for every session this tab drove: it lives in `sessionStorage`, so it
100
+ * survives a genuine reload and is correctly absent in a brand-new tab, which
101
+ * owns no reader for the run.
102
+ *
103
+ * Gated on the same {@link RESUME_MAX_AGE_MS} window {@link setActiveSessionId}
104
+ * and {@link readResumableStreamState} use, so a run abandoned by a worker
105
+ * restart ages out into `null` instead of pinning a badge at "working"
106
+ * forever. Non-throwing and null-returning like its neighbours.
107
+ *
108
+ * That gate is only honest while SOMETHING re-stamps the cursor for a live but
109
+ * silent run — see {@link touchParkedRun}. The transport does it from its
110
+ * `: keepalive` handler; a reader that adopts a run WITHOUT a transport (the
111
+ * boot re-attach in `line-dispatch.ts`) must do it too, or a genuinely
112
+ * streaming run reads "idle" on the next reload.
113
+ *
114
+ * NOTE the boundary this does NOT cover: a line's DURABLE slot runId
115
+ * (`line-slots.ts`) is written by voice dispatch and is not consulted here,
116
+ * so a slot runId left behind by a reader torn down mid-flight
117
+ * (`abortAllLineReaders`) bypasses this freshness gate entirely — that path is
118
+ * `resetForCallStart`'s to clean up, not this one's.
119
+ */
120
+ export declare const peekLiveParkedRun: (sessionId: string) => string | null;
121
+ /**
122
+ * Prove `runId` is still alive: re-stamp `sessionId`'s parked cursor's
123
+ * `updatedAt` so the {@link RESUME_MAX_AGE_MS} gate in
124
+ * {@link peekLiveParkedRun} keeps returning it (BEL-90 / §41).
125
+ *
126
+ * This is the SAME job the transport's `onKeepalive` → `#persist()` does, made
127
+ * callable by the one reader that has no transport behind it: after a reload
128
+ * `line-dispatch.ts`'s progress reader is the only listener on a backgrounded
129
+ * typed run's stream, so without this a run doing 2 minutes of silent tool work
130
+ * ages out of the cursor map and the next reload paints its chip "idle" while
131
+ * it is still streaming.
132
+ *
133
+ * Deliberately touches ONLY the parked map, never the selected pointer: the
134
+ * caller attaches exclusively to sessions that are NOT on screen, and moving
135
+ * the selection would hijack the user's chat. No-op unless the cursor still
136
+ * names `runId` — a cursor that moved on belongs to a newer run, and the
137
+ * caller has no claim on it.
138
+ */
139
+ export declare const touchParkedRun: (sessionId: string, runId: string) => void;
140
+ /**
141
+ * `runId` reached a terminal state — drop `sessionId`'s parked cursor so
142
+ * nothing rehydrates the line as "working" for a run that is already done
143
+ * (BEL-90 / §41, the mirror of {@link touchParkedRun}).
144
+ *
145
+ * The transport gets this for free from `onStreamTerminal` → `#persist()` with
146
+ * a null `#runId`; the progress reader has no transport, so it calls this. Same
147
+ * ownership guard: a cursor naming a DIFFERENT run is someone else's live run
148
+ * and is left alone.
149
+ */
150
+ export declare const releaseParkedRun: (sessionId: string, runId: string) => void;
95
151
  /**
96
152
  * Select one Session (sessions menu switch / new). A Session with a live cursor
97
153
  * parked by this tab restores that cursor so the next ChatRoute mount resumes
@@ -0,0 +1,4 @@
1
+ import { TFunction } from 'i18next';
2
+ import { ToolCallData } from './belong-data-parts.ts';
3
+ /** Localised copy for a tool error, or the server's message when unmapped. */
4
+ export declare const toolErrorText: (t: TFunction, error: ToolCallData["error"]) => string | undefined;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Shared fetch-stub bodies for the preview surfaces.
3
+ *
4
+ * `usePreviewBytes` reads a text preview as BYTES (`res.arrayBuffer()`) rather
5
+ * than `res.text()`, so it can fall back to windows-1252 when a file isn't
6
+ * valid UTF-8 — a stub that only implements `text()` therefore no longer models
7
+ * a Response the hook can consume. `textResponseStub` implements both, so a
8
+ * test can stay agnostic about which one the code under test reaches for.
9
+ */
10
+ export type TextResponseStub = {
11
+ readonly ok: true;
12
+ readonly status: 200;
13
+ readonly text: () => Promise<string>;
14
+ readonly arrayBuffer: () => Promise<ArrayBuffer>;
15
+ };
16
+ export declare const textResponseStub: (text: string) => TextResponseStub;
@@ -252,7 +252,7 @@ export type BelongGlobal = {
252
252
  errorMessage?: string;
253
253
  }) => void;
254
254
  /** TEST-ONLY: append a live-call timeline row. */
255
- readonly __forceCallTimelineEntry?: (kind: "user" | "agent" | "step" | "success" | "error" | "skill" | "schedule", text: string, lineTag?: string) => void;
255
+ readonly __forceCallTimelineEntry?: (kind: "user" | "agent" | "step" | "success" | "error" | "skill" | "schedule", text: string, line?: number | null) => void;
256
256
  /** TEST-ONLY: drive the call orb's audio level (0..1) without Web Audio. */
257
257
  readonly __forceCallAudioLevel?: (level: number) => void;
258
258
  /** TEST-ONLY: force the agent-lines switchboard state without HTTP dispatch. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@belonguniverseai/react-sdk",
3
- "version": "0.4.2",
3
+ "version": "0.5.0",
4
4
  "description": "Belong — embeddable React AI assistant dock. Mount <BelongWidget> in your app tree with getToken dependency-injection auth.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",