@belonguniverseai/react-sdk 0.3.5 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -8
- package/dist/api/client.d.ts +40 -1
- package/dist/api/report-client-error.d.ts +1 -1
- package/dist/browser/dom-bridge.d.ts +7 -0
- package/dist/browser/spa-navigate.d.ts +11 -2
- package/dist/component/BelongWidget.d.ts +12 -7
- package/dist/component/{arc-6I9bTNTk.js → arc-BhIvhaIH.js} +2 -2
- package/dist/component/{architectureDiagram-3BPJPVTR-DecTtp8M.js → architectureDiagram-3BPJPVTR-BWNCirdr.js} +3 -3
- package/dist/component/{blockDiagram-GPEHLZMM-D0ShJEdc.js → blockDiagram-GPEHLZMM-BnslF4z5.js} +4 -4
- package/dist/component/{c4Diagram-AAUBKEIU-D-N4NLkS.js → c4Diagram-AAUBKEIU-ByIoAzxn.js} +3 -3
- package/dist/component/{channel-BTRAV_iV.js → channel-BSkI2ZMQ.js} +2 -2
- package/dist/component/{chunk-2J33WTMH-Chgh4n6n.js → chunk-2J33WTMH-DdP5frJt.js} +2 -2
- package/dist/component/{chunk-4BX2VUAB-BR7BZW6m.js → chunk-4BX2VUAB-DlsylVfZ.js} +2 -2
- package/dist/component/{chunk-55IACEB6-D0_e3QRv.js → chunk-55IACEB6-CcJHjxtI.js} +2 -2
- package/dist/component/{chunk-727SXJPM-Cooz66Ae.js → chunk-727SXJPM-IzRNu9Aj.js} +6 -6
- package/dist/component/{chunk-AQP2D5EJ-CAz4YEpg.js → chunk-AQP2D5EJ-DmcGMHHV.js} +4 -4
- package/dist/component/{chunk-FMBD7UC4-C8n0NV45.js → chunk-FMBD7UC4-T7thtdBK.js} +2 -2
- package/dist/component/{chunk-ND2GUHAM-Di6RJblt.js → chunk-ND2GUHAM-Dm_d0Ags.js} +2 -2
- package/dist/component/{chunk-QZHKN3VN-Cii0zOyK.js → chunk-QZHKN3VN-D2PGEfVN.js} +2 -2
- package/dist/component/{classDiagram-4FO5ZUOK-BIqkynKR.js → classDiagram-4FO5ZUOK-Bn7KwDp9.js} +3 -3
- package/dist/component/{classDiagram-v2-Q7XG4LA2-BIqkynKR.js → classDiagram-v2-Q7XG4LA2-Bn7KwDp9.js} +3 -3
- package/dist/component/{cose-bilkent-S5V4N54A-Dq3K4Kak.js → cose-bilkent-S5V4N54A-BtDuNpUN.js} +2 -2
- package/dist/component/{dagre-BM42HDAG-KdRn-NQ2.js → dagre-BM42HDAG-BknZdIOQ.js} +2 -2
- package/dist/component/{diagram-2AECGRRQ-CeJVj827.js → diagram-2AECGRRQ-ISHN0dHe.js} +3 -3
- package/dist/component/{diagram-5GNKFQAL-ceCtRhc4.js → diagram-5GNKFQAL-7gWbpLCQ.js} +4 -4
- package/dist/component/{diagram-KO2AKTUF-CU9xKIPR.js → diagram-KO2AKTUF-B63ZLzkh.js} +3 -3
- package/dist/component/{diagram-LMA3HP47-CRZuMr0r.js → diagram-LMA3HP47-hhw0MjoS.js} +3 -3
- package/dist/component/{diagram-OG6HWLK6-DdO8bLrY.js → diagram-OG6HWLK6-D_L9Gvuh.js} +4 -4
- package/dist/component/{erDiagram-TEJ5UH35-BnPlE6-i.js → erDiagram-TEJ5UH35-BAg27ZHd.js} +5 -5
- package/dist/component/{flowDiagram-I6XJVG4X-Bi70muwl.js → flowDiagram-I6XJVG4X-DDYjK7xG.js} +7 -7
- package/dist/component/{ganttDiagram-6RSMTGT7-FjDKlQ-F.js → ganttDiagram-6RSMTGT7-CDNAiKQG.js} +3 -3
- package/dist/component/{gitGraphDiagram-PVQCEYII-B9GAxjPJ.js → gitGraphDiagram-PVQCEYII-CY1N7jOJ.js} +4 -4
- package/dist/component/{highlighted-body-OFNGDK62-DEhmLiFe.js → highlighted-body-OFNGDK62-DHwLnkF_.js} +2 -2
- package/dist/component/index.js +2 -2
- package/dist/component/{infoDiagram-5YYISTIA-D_z8khpb.js → infoDiagram-5YYISTIA-Cbgk6g6j.js} +2 -2
- package/dist/component/{ishikawaDiagram-YF4QCWOH-DHUQHc7h.js → ishikawaDiagram-YF4QCWOH-BUfiorJj.js} +2 -2
- package/dist/component/{journeyDiagram-JHISSGLW-BdPxTkII.js → journeyDiagram-JHISSGLW-Bh4IizEm.js} +5 -5
- package/dist/component/{kanban-definition-UN3LZRKU-CXo8cG6_.js → kanban-definition-UN3LZRKU-CgWqLfFM.js} +3 -3
- package/dist/component/{linear-azN-TF0f.js → linear-D1rJivs3.js} +2 -2
- package/dist/component/{mermaid-GHXKKRXX-P_Te0BTc.js → mermaid-GHXKKRXX-iO2IZZUN.js} +31615 -30317
- package/dist/component/{mindmap-definition-RKZ34NQL-CVTlgpwY.js → mindmap-definition-RKZ34NQL-DeQED-9b.js} +4 -4
- package/dist/component/{pieDiagram-4H26LBE5-BBqlJN3M.js → pieDiagram-4H26LBE5-CZ5Zt_mz.js} +4 -4
- package/dist/component/{quadrantDiagram-W4KKPZXB-Cq8G5gg8.js → quadrantDiagram-W4KKPZXB-Dib1AukJ.js} +3 -3
- package/dist/component/{requirementDiagram-4Y6WPE33-DE8meVq8.js → requirementDiagram-4Y6WPE33-DubjTJYS.js} +4 -4
- package/dist/component/{sankeyDiagram-5OEKKPKP-rGv9060J.js → sankeyDiagram-5OEKKPKP-Cq2S3XKs.js} +2 -2
- package/dist/component/{sequenceDiagram-3UESZ5HK-CYZCqSg5.js → sequenceDiagram-3UESZ5HK-BUo5k0zn.js} +4 -4
- package/dist/component/{stateDiagram-AJRCARHV-7PfYQio8.js → stateDiagram-AJRCARHV-DJwQp0D7.js} +3 -3
- package/dist/component/{stateDiagram-v2-BHNVJYJU-Bc8Y618M.js → stateDiagram-v2-BHNVJYJU-BX77P5aq.js} +3 -3
- package/dist/component/{timeline-definition-PNZ67QCA-DDLIgmb4.js → timeline-definition-PNZ67QCA-DnQ481VI.js} +3 -3
- package/dist/component/{vennDiagram-CIIHVFJN-BPKi69Hn.js → vennDiagram-CIIHVFJN-BQ0X92lQ.js} +2 -2
- package/dist/component/{wardleyDiagram-YWT4CUSO-Dumz_-ib.js → wardleyDiagram-YWT4CUSO-CMTnjVTA.js} +3 -3
- package/dist/component/{xychartDiagram-2RQKCTM6-DQGacrwk.js → xychartDiagram-2RQKCTM6-BLSiRWug.js} +3 -3
- package/dist/components/embed/AgentChatIcon.d.ts +16 -0
- package/dist/components/embed/AgentPhaseIcon.d.ts +17 -0
- package/dist/components/embed/EmbedAvatar.d.ts +14 -2
- package/dist/components/embed/EmbedRail.d.ts +12 -1
- package/dist/components/embed/EmbedSessions.d.ts +22 -8
- package/dist/embed/adoption-notice.d.ts +22 -0
- package/dist/embed/auth0-cache.d.ts +32 -0
- package/dist/embed/auth0-refresh.d.ts +8 -5
- package/dist/embed/copy.d.ts +2 -0
- package/dist/embed/dock-state.d.ts +16 -0
- package/dist/embed/global.d.ts +6 -0
- package/dist/embed/host-layout-vars.d.ts +24 -0
- package/dist/embed/host-push-controller.d.ts +67 -0
- package/dist/embed/host-surface.d.ts +57 -0
- package/dist/embed/voice/agent-spawn.d.ts +38 -0
- package/dist/embed/voice/audio-utils.d.ts +6 -0
- package/dist/embed/voice/call-active-marker.d.ts +67 -0
- package/dist/embed/voice/line-dispatch.d.ts +13 -4
- package/dist/embed/voice/line-run-reader.d.ts +13 -0
- package/dist/embed/voice/line-slots.d.ts +61 -0
- package/dist/embed/voice/reconnect-offer.d.ts +29 -0
- package/dist/embed/voice/session-create.d.ts +26 -0
- package/dist/embed/voice/voice-http.d.ts +12 -0
- package/dist/embed/voice-bus.d.ts +2 -0
- package/dist/embed/voice-call-lines.d.ts +211 -14
- package/dist/embed/voice-call.d.ts +34 -6
- package/dist/i18n/messages/en.d.ts +12 -0
- package/dist/i18n/messages/surfaces/embedMisc.d.ts +3 -0
- package/dist/i18n/messages/surfaces/header.d.ts +6 -0
- package/dist/i18n/messages/surfaces/sessions.d.ts +3 -0
- package/dist/i18n/messages/surfaces/stream.d.ts +3 -0
- package/dist/stream/belong-chat-transport.d.ts +26 -0
- package/dist/stream/belong-data-parts.d.ts +8 -0
- package/dist/stream/route-dispatch.d.ts +17 -0
- package/dist/stream/stream-state-store.d.ts +7 -6
- package/dist/types/public.d.ts +3 -1
- package/package.json +1 -1
- package/dist/embed/universe-origin.d.ts +0 -24
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rail "+": spawn a brand-new agent slot. Reuses the exact seams the voice
|
|
3
|
+
* background-line dispatch already established rather than hand-rolling a
|
|
4
|
+
* second "mint a session" flow — `createVoiceSession` (session-create.ts) is
|
|
5
|
+
* the ONE place that mints a Belong session over plain HTTP, and
|
|
6
|
+
* `persistSlotBinding` (voice-call-lines.ts) is the ONE seam that keeps the
|
|
7
|
+
* in-memory registry and the durable slot moving together (see that module's
|
|
8
|
+
* ADOPTION doc). This is the rail-initiated counterpart to
|
|
9
|
+
* `line-dispatch.ts`'s find-or-create — but a spawn has no message to send
|
|
10
|
+
* yet, so it stops once the session exists instead of posting anything.
|
|
11
|
+
*
|
|
12
|
+
* No label prompt in v1 (product ask): the new line's label stays "" and its
|
|
13
|
+
* rail tooltip falls back to "Agent N" — a labeled spawn is a followup.
|
|
14
|
+
*
|
|
15
|
+
* `openAgentLine` starts a fresh line at status "working" (its usual meaning
|
|
16
|
+
* elsewhere: a voice request is about to dispatch to it). A rail spawn has no
|
|
17
|
+
* work pending, so a successful mint clears the line back to "idle" instead of
|
|
18
|
+
* leaving a misleading spinner badge on an agent that isn't actually doing
|
|
19
|
+
* anything yet — and a FAILED mint releases the line outright
|
|
20
|
+
* (`closeAgentLine`), because a slot with no session behind it is not an agent.
|
|
21
|
+
*/
|
|
22
|
+
export type SpawnAgentLineResult = {
|
|
23
|
+
readonly ok: true;
|
|
24
|
+
readonly line: number;
|
|
25
|
+
readonly sessionId: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* `line_released` is the QUIET outcome — the user closed the freshly-spawned
|
|
29
|
+
* chip (or a workspace switch re-read the slots) while the mint was still in
|
|
30
|
+
* flight. It is not an error: the user asked for that agent to go away, and
|
|
31
|
+
* they got exactly that. The caller must not navigate and must not surface a
|
|
32
|
+
* message. Distinct from `create_failed` precisely so it can be told apart.
|
|
33
|
+
*/
|
|
34
|
+
| {
|
|
35
|
+
readonly ok: false;
|
|
36
|
+
readonly reason: "cap_reached" | "create_failed" | "line_released";
|
|
37
|
+
};
|
|
38
|
+
export declare const spawnAgentLine: (fetchFn?: typeof fetch) => Promise<SpawnAgentLineResult>;
|
|
@@ -36,3 +36,9 @@ export declare function arrayBufferToBase64(buf: ArrayBuffer): string;
|
|
|
36
36
|
* @returns An ArrayBuffer containing the decoded bytes.
|
|
37
37
|
*/
|
|
38
38
|
export declare function base64ToArrayBuffer(b64: string): ArrayBuffer;
|
|
39
|
+
/**
|
|
40
|
+
* Join captured little-endian PCM16 frames and wrap them in a mono WAV file.
|
|
41
|
+
* The microphone capture engine emits 16 kHz frames; a WAV container lets the
|
|
42
|
+
* belong-cloud STT proxy forward one provider-compatible audio file.
|
|
43
|
+
*/
|
|
44
|
+
export declare function pcm16FramesToWav(frames: readonly ArrayBuffer[], sampleRate: number): ArrayBuffer;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
declare const callActiveMarkerSchema: z.ZodObject<{
|
|
3
|
+
active: z.ZodLiteral<true>;
|
|
4
|
+
startedAtMs: z.ZodNumber;
|
|
5
|
+
/** Recap of the call so far, same shape/cap as `buildCallContextDigest()`.
|
|
6
|
+
* Empty until the first user/agent timeline row lands. */
|
|
7
|
+
contextDigest: z.ZodString;
|
|
8
|
+
}, "strip", z.ZodTypeAny, {
|
|
9
|
+
active: true;
|
|
10
|
+
startedAtMs: number;
|
|
11
|
+
contextDigest: string;
|
|
12
|
+
}, {
|
|
13
|
+
active: true;
|
|
14
|
+
startedAtMs: number;
|
|
15
|
+
contextDigest: string;
|
|
16
|
+
}>;
|
|
17
|
+
export type CallActiveMarker = z.infer<typeof callActiveMarkerSchema>;
|
|
18
|
+
/** The tab's persisted call marker, or null when absent/malformed — a
|
|
19
|
+
* corrupted or pre-this-feature record just means "nothing to redial". */
|
|
20
|
+
export declare const readCallActiveMarker: () => CallActiveMarker | null;
|
|
21
|
+
/** Mark the call live — called on the `in_call` transition. Starts with an
|
|
22
|
+
* empty digest; {@link refreshCallActiveMarkerContext} fills it in as the
|
|
23
|
+
* call progresses. */
|
|
24
|
+
export declare const writeCallActiveMarker: () => void;
|
|
25
|
+
/** Update the persisted digest of an already-active marker. No-op when no
|
|
26
|
+
* marker is active — a digest has nothing to attach itself to once the call
|
|
27
|
+
* has ended. */
|
|
28
|
+
export declare const refreshCallActiveMarkerContext: (contextDigest: string) => void;
|
|
29
|
+
/** Call ended (explicit hangup or terminal error) — no reload should redial. */
|
|
30
|
+
export declare const clearCallActiveMarker: () => void;
|
|
31
|
+
export type ReconnectOfferDecision = "offer" | "skip";
|
|
32
|
+
/**
|
|
33
|
+
* How long after the interrupted call started we still OFFER to reconnect. A
|
|
34
|
+
* reload lands in seconds; a tab the browser restored from a much older session
|
|
35
|
+
* should come back to a plain idle dock, not a stale "Reconnect" affordance
|
|
36
|
+
* pointing at a conversation the user has long since moved on from.
|
|
37
|
+
*/
|
|
38
|
+
export declare const RECONNECT_OFFER_MAX_AGE_MS = 600000;
|
|
39
|
+
/**
|
|
40
|
+
* Whether the dock's boot effect should OFFER to reconnect an interrupted call.
|
|
41
|
+
*
|
|
42
|
+
* This deliberately decides an offer, never a dial. Auto-dialing on load opens
|
|
43
|
+
* the MICROPHONE with no user gesture: the origin already holds mic permission
|
|
44
|
+
* (a call was live moments ago), so the browser does not re-prompt and the mic
|
|
45
|
+
* would come back silently on the next page load — on hosts that receive the
|
|
46
|
+
* SDK through an unpinnable bundle, with no opt-in of their own. Requiring one
|
|
47
|
+
* click to redial is both the honest consent story and what browsers' autoplay/
|
|
48
|
+
* gesture rules expect; the marker is kept either way so the redial can still
|
|
49
|
+
* carry the interrupted call's `contextDigest`.
|
|
50
|
+
*
|
|
51
|
+
* Pure so the branching is unit-testable without React or WebRTC: a marker
|
|
52
|
+
* means a call was live when the page went away; `tokenReady` mirrors the same
|
|
53
|
+
* auth-readiness gate the login screen polls; `alreadyOffered` is the one-shot
|
|
54
|
+
* guard (the offer is raised at most once per page load); and `startedAtMs` is
|
|
55
|
+
* consumed against `nowMs` so a stale marker cannot offer forever.
|
|
56
|
+
*/
|
|
57
|
+
export declare const decideReconnectOffer: (input: {
|
|
58
|
+
readonly marker: CallActiveMarker | null;
|
|
59
|
+
readonly tokenReady: boolean;
|
|
60
|
+
readonly alreadyOffered: boolean;
|
|
61
|
+
readonly nowMs: number;
|
|
62
|
+
}) => ReconnectOfferDecision;
|
|
63
|
+
export declare const peekReconnectOffered: () => boolean;
|
|
64
|
+
export declare const markReconnectOffered: () => void;
|
|
65
|
+
/** Test-only: forget the one-shot guard between test cases. */
|
|
66
|
+
export declare const __resetReconnectOfferedForTest: () => void;
|
|
67
|
+
export {};
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Background-line dispatch: create the line's session
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* Background-line dispatch: find-or-create the line's session (plain HTTP —
|
|
3
|
+
* the same endpoints the chat transport uses), post the message, and attach
|
|
4
|
+
* the line-run reader so results/failures/phases/approvals flow back into the
|
|
5
|
+
* call. Line 1 (the foreground chat) never comes through here.
|
|
6
|
+
*
|
|
7
|
+
* Persistent slots: a line's session, once created, is adopted via
|
|
8
|
+
* `persistSlotBinding` (`voice-call-lines.ts`), which persists it to
|
|
9
|
+
* `line-slots.ts` so the NEXT call's `resetAgentLines()` rehydrates onto the
|
|
10
|
+
* SAME session — "Agent 2" keeps its identity across calls instead of
|
|
11
|
+
* starting a fresh conversation every time. A persisted session can go stale
|
|
12
|
+
* between calls (deleted from another surface, tenant reset, …): the message
|
|
13
|
+
* POST below treats 404/410 as "the bound session is gone", recreates one,
|
|
14
|
+
* updates the binding, and retries once.
|
|
6
15
|
*
|
|
7
16
|
* Workspace isolation (§28): a background line opened while the host is inside
|
|
8
17
|
* a workspace must land in THAT workspace, not the shared legacy root — so the
|
|
@@ -16,6 +16,15 @@
|
|
|
16
16
|
* - `data-approval-request` carries a `state` ("pending" | "approved" |
|
|
17
17
|
* "rejected" | "amend_requested" | "expired"); only "pending" means an
|
|
18
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.
|
|
19
28
|
* - there is no `finish` / `error` part. The terminal signal is
|
|
20
29
|
* `data-status` with `status` ∈ "continuing" | "completed" | "cancelled" |
|
|
21
30
|
* "failed" | "throttled". "continuing" is the max-turns auto-continue —
|
|
@@ -31,6 +40,10 @@ export type WatchLineRunInput = {
|
|
|
31
40
|
readonly runId: string;
|
|
32
41
|
readonly onPhase: (toolName: string) => void;
|
|
33
42
|
readonly onApprovalNeeded: () => void;
|
|
43
|
+
readonly onNavigate: (data: {
|
|
44
|
+
readonly routeName: string;
|
|
45
|
+
readonly params: Readonly<Record<string, string>>;
|
|
46
|
+
}) => void;
|
|
34
47
|
readonly onArtifact: (artifact: {
|
|
35
48
|
artifactId: string;
|
|
36
49
|
title: string;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persisted agent-line slot bindings — the durable identity behind
|
|
3
|
+
* "Agent 1" / "Agent 2" / "Agent 3" across DIFFERENT calls (and, for line 1,
|
|
4
|
+
* across page reloads with no call at all). The in-memory switchboard
|
|
5
|
+
* (`voice-call-lines.ts`) is wiped and rebuilt on every call start/end
|
|
6
|
+
* (`resetAgentLines`); this module is what lets that rebuild REHYDRATE every
|
|
7
|
+
* line onto the same session it pointed to last time, instead of starting
|
|
8
|
+
* from a blank switchboard.
|
|
9
|
+
*
|
|
10
|
+
* Line 1 is no longer special-cased: the ADOPTION rule (see
|
|
11
|
+
* `persistSlotBinding` in `voice-call-lines.ts`) is that whichever session
|
|
12
|
+
* last became a slot's ACTIVE session — including the foreground chat — gets
|
|
13
|
+
* written here, so "Agent 1" means the same session across reloads and
|
|
14
|
+
* calls, same as 2/3 always have.
|
|
15
|
+
*
|
|
16
|
+
* Workspace isolation (§28): keyed the same way `stream-state-store.ts`
|
|
17
|
+
* namespaces the session pointer (`belong:voice-line-slots:ws:<id>`, the
|
|
18
|
+
* legacy un-suffixed key when no workspace is in effect) — a host workspace
|
|
19
|
+
* switch must not hand a slot from workspace A to a session that actually
|
|
20
|
+
* belongs to workspace B.
|
|
21
|
+
*
|
|
22
|
+
* localStorage is a perimeter: the persisted bag is zod-validated on read and
|
|
23
|
+
* any junk (corrupted JSON, wrong shape, storage disabled) degrades to "no
|
|
24
|
+
* slots" — the switchboard just starts fresh, same as a first-ever call. The
|
|
25
|
+
* schema is back-compatible with the pre-line-1 bag: a persisted object with
|
|
26
|
+
* only `line2`/`line3` still parses fine, `line1` just defaults to `null`.
|
|
27
|
+
*/
|
|
28
|
+
/** Every line number that gets a persisted slot — all three agent lines. */
|
|
29
|
+
declare const SLOT_LINES: readonly [1, 2, 3];
|
|
30
|
+
type SlotLine = (typeof SLOT_LINES)[number];
|
|
31
|
+
export type LineSlot = {
|
|
32
|
+
readonly sessionId: string;
|
|
33
|
+
readonly label: string;
|
|
34
|
+
};
|
|
35
|
+
/** The persisted binding for line 1/2/3, or `null` when never set (or `line`
|
|
36
|
+
* isn't a valid agent line at all). */
|
|
37
|
+
export declare const readLineSlot: (line: number) => LineSlot | null;
|
|
38
|
+
/** Persist a line's current `{ sessionId, label }` so the NEXT rehydration
|
|
39
|
+
* (`resetAgentLines()`, or a plain reload for line 1) rebinds onto the same
|
|
40
|
+
* session. No-op for a line number that isn't 1/2/3, and no-op when the slot
|
|
41
|
+
* already holds this exact `{ sessionId, label }` — callers (e.g. chat.tsx's
|
|
42
|
+
* per-render bind effect) call this on every render, so an unchanged binding
|
|
43
|
+
* must not touch storage. */
|
|
44
|
+
export declare const writeLineSlot: (line: number, slot: LineSlot) => void;
|
|
45
|
+
/** Drop a line's persisted binding — the durable half of `closeAgentLine`
|
|
46
|
+
* (voice-call-lines.ts). Called when a slot is RELEASED rather than rebound: a
|
|
47
|
+
* spawn whose session mint failed, or a session the user deleted. Without this
|
|
48
|
+
* the slot would rehydrate on the next boot onto a session that no longer
|
|
49
|
+
* exists (a dangling agent the rail keeps offering). No-op for a line number
|
|
50
|
+
* that isn't 1/2/3, and no-op when the slot is already empty. */
|
|
51
|
+
export declare const clearLineSlot: (line: number) => void;
|
|
52
|
+
/** Every persisted line slot, in ascending line order (1, then 2, then 3),
|
|
53
|
+
* skipping lines that were never bound. What `resetAgentLines()` reads to
|
|
54
|
+
* rebuild the switchboard. */
|
|
55
|
+
export declare const readAllLineSlots: () => readonly {
|
|
56
|
+
readonly line: SlotLine;
|
|
57
|
+
readonly slot: LineSlot;
|
|
58
|
+
}[];
|
|
59
|
+
/** Test-only: drop every persisted slot for the current workspace scope. */
|
|
60
|
+
export declare const __clearLineSlotsForTest: () => void;
|
|
61
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* "A call was interrupted — tap to reconnect" — the one-bit store that turns a
|
|
3
|
+
* surviving call marker (`call-active-marker.ts`) into a USER-DRIVEN redial.
|
|
4
|
+
*
|
|
5
|
+
* The dock's boot effect raises the offer; the rail's CallButton reads it and,
|
|
6
|
+
* while it stands, dials with `{ isReconnect: true }` (carrying the interrupted
|
|
7
|
+
* call's context digest) and labels itself "Reconnect" instead of "Start voice
|
|
8
|
+
* call". That is the whole mechanism: ONE user click, on a control that is
|
|
9
|
+
* already always visible in the rail — no new surface, and crucially no
|
|
10
|
+
* microphone access without a gesture.
|
|
11
|
+
*
|
|
12
|
+
* Why a separate store rather than a field on `CallState`: the call state is
|
|
13
|
+
* rebuilt from `IDLE` on every dial and every terminal error, which would wipe
|
|
14
|
+
* a pending offer mid-flight. This flag's lifetime is the page load, not the
|
|
15
|
+
* call's, so it lives on its own — and stays trivially testable without WebRTC.
|
|
16
|
+
*
|
|
17
|
+
* External-store singleton, same idiom as `voice-bus.ts` / `voice-call-lines.ts`.
|
|
18
|
+
*/
|
|
19
|
+
export declare const peekReconnectOffer: () => boolean;
|
|
20
|
+
export declare const subscribeReconnectOffer: (listener: () => void) => (() => void);
|
|
21
|
+
/** Raise the offer (dock boot, when `decideReconnectOffer` says so). */
|
|
22
|
+
export declare const offerReconnect: () => void;
|
|
23
|
+
/**
|
|
24
|
+
* Take the offer down. Called when the user acts on it (the reconnect click),
|
|
25
|
+
* and on any other dial or hang-up — once a call is being started or has been
|
|
26
|
+
* deliberately ended, "reconnect the previous one" is no longer the thing to
|
|
27
|
+
* show. No-op when no offer stands.
|
|
28
|
+
*/
|
|
29
|
+
export declare const consumeReconnectOffer: () => void;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ONE place that mints a Belong session over plain HTTP for the voice
|
|
3
|
+
* call surface — shared by `line-dispatch.ts` (background lines 2/3, which
|
|
4
|
+
* additionally persist the slot) and `voice-call.ts` (the foreground line 1
|
|
5
|
+
* eager-bind at call start). Both need "create a session, same endpoint the
|
|
6
|
+
* chat transport uses" with no message attached yet; this is that seam, so
|
|
7
|
+
* neither call site hand-rolls its own `POST /v1/sessions` fetch.
|
|
8
|
+
*
|
|
9
|
+
* Workspace isolation (§28) mirrors `line-dispatch.ts`'s existing behavior:
|
|
10
|
+
* the create body carries the effective `workspaceExternalId` (absent when
|
|
11
|
+
* the host runs unscoped) so a background OR foreground line opened while the
|
|
12
|
+
* host is inside a workspace lands in THAT workspace.
|
|
13
|
+
*/
|
|
14
|
+
export type CreateSessionOutcome = {
|
|
15
|
+
readonly status: "created";
|
|
16
|
+
readonly sessionId: string;
|
|
17
|
+
} | {
|
|
18
|
+
readonly status: "failed";
|
|
19
|
+
readonly httpStatus: number;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* `title` seeds the session's row in the Chats switcher (e.g. an agent
|
|
23
|
+
* line's label) — pass `null` (or `""`) to omit it, matching
|
|
24
|
+
* `createSessionSchema`'s optional title.
|
|
25
|
+
*/
|
|
26
|
+
export declare const createVoiceSession: (title: string | null, fetchFn?: typeof fetch) => Promise<CreateSessionOutcome>;
|
|
@@ -6,3 +6,15 @@
|
|
|
6
6
|
export declare function voiceJsonHeaders(): Promise<Record<string, string>>;
|
|
7
7
|
/** Absolute URL for a voice endpoint path (e.g. "/v1/voice/tts"). */
|
|
8
8
|
export declare function voiceUrl(path: string): string;
|
|
9
|
+
export type VoiceTranscriptionResult = {
|
|
10
|
+
readonly ok: true;
|
|
11
|
+
readonly text: string;
|
|
12
|
+
} | {
|
|
13
|
+
readonly ok: false;
|
|
14
|
+
readonly reason: "unconfigured" | "error";
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Send one captured WAV clip to belong-cloud's authenticated STT proxy.
|
|
18
|
+
* Gemini/OpenAI keys stay server-side; the SDK receives only transcript text.
|
|
19
|
+
*/
|
|
20
|
+
export declare function transcribeVoiceAudio(audio: ArrayBuffer, contentType: string): Promise<VoiceTranscriptionResult>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { fetchVoiceTokens } from './voice/voice-token.ts';
|
|
2
2
|
import { createDeepgramStt } from './voice/deepgram-stt.ts';
|
|
3
3
|
import { createMicCapture } from './voice/mic-capture.ts';
|
|
4
|
+
import { transcribeVoiceAudio } from './voice/voice-http.ts';
|
|
4
5
|
export type VoiceStatus = "idle" | "requesting" | "listening" | "transcribing" | "error";
|
|
5
6
|
/**
|
|
6
7
|
* Capture state. `status` is the single source of truth; `interim` is the live
|
|
@@ -32,6 +33,7 @@ type VoiceEngineFactories = {
|
|
|
32
33
|
fetchTokens: typeof fetchVoiceTokens;
|
|
33
34
|
createStt: typeof createDeepgramStt;
|
|
34
35
|
createMic: typeof createMicCapture;
|
|
36
|
+
transcribeAudio: typeof transcribeVoiceAudio;
|
|
35
37
|
};
|
|
36
38
|
/**
|
|
37
39
|
* Test-only: override one or more engine factories. Pass `null` to restore the
|
|
@@ -1,31 +1,228 @@
|
|
|
1
|
+
import { WorkPhase } from './voice-narration.ts';
|
|
2
|
+
export declare const MAX_AGENT_LINES = 3;
|
|
1
3
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* "idle" is the not-busy resting state — no work in flight, and nothing
|
|
5
|
+
* completed/failed yet worth reporting (a fresh call, or a line rebound onto
|
|
6
|
+
* a persisted session with no activity this call). "ready" is the DISTINCT
|
|
7
|
+
* terminal state after a run actually finished successfully — it carries a
|
|
8
|
+
* result (`lastText`) worth showing, unlike "idle" which never conflates the
|
|
9
|
+
* two anymore (pre-CallScreen-board, both were folded into "ready").
|
|
6
10
|
*/
|
|
7
|
-
export
|
|
8
|
-
export type AgentLineStatus = "working" | "ready" | "failed" | "needs_approval";
|
|
11
|
+
export type AgentLineStatus = "idle" | "working" | "ready" | "failed" | "needs_approval";
|
|
9
12
|
export type AgentLine = {
|
|
10
13
|
readonly line: number;
|
|
14
|
+
/**
|
|
15
|
+
* Monotonic stamp identifying THIS occupancy of the slot — bumped every time
|
|
16
|
+
* a line entry is CREATED (`openAgentLine`, a line-1 reset, a rehydrate), and
|
|
17
|
+
* carried unchanged through every later write (they all spread `...l`).
|
|
18
|
+
*
|
|
19
|
+
* The line NUMBER is not an identity: `closeAgentLine(2)` frees it and the
|
|
20
|
+
* very next `openAgentLine` hands the same number to a different reservation.
|
|
21
|
+
* Anything holding a line across an await (`spawnAgentLine`'s session mint,
|
|
22
|
+
* line-dispatch's find-or-create) must therefore re-check the epoch, not just
|
|
23
|
+
* that "line 2 exists" — otherwise a spawn whose chip the user closed
|
|
24
|
+
* mid-mint binds its session onto the NEXT spawn's line. Compare via
|
|
25
|
+
* `isLineReservation` below.
|
|
26
|
+
*/
|
|
27
|
+
readonly epoch: number;
|
|
11
28
|
readonly sessionId: string | null;
|
|
12
29
|
readonly label: string;
|
|
13
30
|
readonly status: AgentLineStatus;
|
|
14
31
|
readonly lastText: string;
|
|
32
|
+
/** The line's current run, for `stop_agent` to target — bound by the
|
|
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. */
|
|
38
|
+
readonly runId: string | null;
|
|
39
|
+
/** The live "what is it doing right now" label (e.g. "writing code"),
|
|
40
|
+
* written by `setLineStep` as phase notifications arrive while `status`
|
|
41
|
+
* is `"working"`. Cleared back to `null` once the line reaches a terminal
|
|
42
|
+
* status (ready/failed) or starts a fresh dispatch — CallScreen's agent
|
|
43
|
+
* board reads this to show a step under the status dot instead of just a
|
|
44
|
+
* bare "working" chip. */
|
|
45
|
+
readonly currentStepLabel: string | null;
|
|
46
|
+
/** The step's phase classification — what KIND of work the line is doing
|
|
47
|
+
* right now (`classifyToolPhase`), so a working card wears the same phase
|
|
48
|
+
* icon the orb's work badge does (code / files / actions; spinner while
|
|
49
|
+
* unknown). Written and cleared together with `currentStepLabel` by
|
|
50
|
+
* `setLineStep`. */
|
|
51
|
+
readonly currentPhase: WorkPhase | null;
|
|
52
|
+
/** True when this line reached a terminal status (ready/failed) while its
|
|
53
|
+
* session was NOT the one on screen — a finished result the user hasn't
|
|
54
|
+
* looked at yet (product vision: the rail's green "unseen" dot). Written by
|
|
55
|
+
* `deliverLineReply`/`deliverLineFailure` (voice-call.ts) for background
|
|
56
|
+
* lines; line 1's own terminal writes never set it (the foreground chat IS
|
|
57
|
+
* what's on screen, so its own results are seen by definition). Cleared by
|
|
58
|
+
* `markLineSeen` once the user actually views that line's session. */
|
|
59
|
+
readonly unseenResult: boolean;
|
|
15
60
|
};
|
|
16
61
|
export declare const peekAgentLines: () => readonly AgentLine[];
|
|
17
62
|
export declare const subscribeAgentLines: (listener: () => void) => (() => void);
|
|
63
|
+
/** Hard reset: rebuilds every line from its persisted slot, ephemeral fields
|
|
64
|
+
* clean. Used by `initAgentLines()`, a host workspace switch, and the
|
|
65
|
+
* `__forceAgentLines` test/E2E harness —
|
|
66
|
+
* NOT on a call boundary any more (see the module doc's "CALL BOUNDARY"
|
|
67
|
+
* section); a live call uses `resetForCallStart()` below instead. */
|
|
18
68
|
export declare const resetAgentLines: () => void;
|
|
69
|
+
/**
|
|
70
|
+
* The registry's FIRST read of the durable slots, and the one that binds it to
|
|
71
|
+
* the host's workspace. The dock calls this once on mount — i.e. after
|
|
72
|
+
* `configureWorkspaceScope` / `setWorkspace` have run — so the boot rehydrate
|
|
73
|
+
* uses the workspace-suffixed storage key that every later write also uses
|
|
74
|
+
* (a module-eval read would have used the legacy unsuffixed one).
|
|
75
|
+
*
|
|
76
|
+
* It also subscribes to the workspace-scope store: a host workspace switch
|
|
77
|
+
* hard-resets the registry and re-reads the slots under the NEW key, so the
|
|
78
|
+
* rail can never keep offering the previous workspace's sessions. Idempotent —
|
|
79
|
+
* a second call just re-reads; only one subscription is ever held.
|
|
80
|
+
*/
|
|
81
|
+
export declare const initAgentLines: () => void;
|
|
82
|
+
/** Test-only: drop the workspace subscription so each case starts unsubscribed. */
|
|
83
|
+
export declare const __resetAgentLinesInitForTest: () => void;
|
|
84
|
+
/**
|
|
85
|
+
* Call-boundary reset — narrower than `resetAgentLines()`. A call ENDING no
|
|
86
|
+
* longer touches the registry at all (a finished result and its
|
|
87
|
+
* `unseenResult` flag must survive the hang-up). By the time the NEXT call
|
|
88
|
+
* starts, the only genuinely stale ephemera left behind is a line stuck at
|
|
89
|
+
* "working": its reader was torn down mid-flight when the previous call ended
|
|
90
|
+
* (`abortAllLineReaders` in line-dispatch.ts) without the run ever reaching a
|
|
91
|
+
* terminal status. Everything else — bindings, terminal statuses,
|
|
92
|
+
* `unseenResult` — is left exactly as it is. No-op (no emit) when nothing was
|
|
93
|
+
* actually "working".
|
|
94
|
+
*/
|
|
95
|
+
export declare const resetForCallStart: () => void;
|
|
19
96
|
export declare const getLine: (line: number) => AgentLine | undefined;
|
|
20
97
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
|
|
98
|
+
* Is the slot `line` STILL held by the reservation stamped `epoch`? The check
|
|
99
|
+
* every holder of a line across an await owes the registry before it adopts a
|
|
100
|
+
* session into that line (see `AgentLine.epoch`). False means the reservation
|
|
101
|
+
* is gone — released outright, or already replaced by a different one that
|
|
102
|
+
* happens to wear the same number.
|
|
103
|
+
*/
|
|
104
|
+
export declare const isLineReservation: (line: number, epoch: number) => boolean;
|
|
105
|
+
/** The line (other than 1) currently bound to `sessionId`, or `undefined` when
|
|
106
|
+
* no background line holds it — the shared scan behind `isBoundToAnotherLine`
|
|
107
|
+
* (the boolean chat.tsx's aliasing guard needs) and `markLineSeen`'s callers
|
|
108
|
+
* (which need the actual line number to mark seen). */
|
|
109
|
+
export declare const lineBoundToSession: (sessionId: string) => AgentLine | undefined;
|
|
110
|
+
/** True when `sessionId` is already the session of some line OTHER than line
|
|
111
|
+
* 1 — chat.tsx's line-1 aliasing guard uses this to skip rebinding line 1
|
|
112
|
+
* onto a background line's session while the user is viewing it via
|
|
113
|
+
* `show_agent_line` (rebinding would overwrite line 1's own identity). */
|
|
114
|
+
export declare const isBoundToAnotherLine: (sessionId: string) => boolean;
|
|
115
|
+
/**
|
|
116
|
+
* The line number the FOREGROUND chat's registry writes belong to. The visible
|
|
117
|
+
* chat is NOT always line 1: the rail's spawn flow and `show_agent_line` both
|
|
118
|
+
* put a BACKGROUND line's session on screen, and work done there must light
|
|
119
|
+
* that line's badge — not line 1's, which would leave the agent the user is
|
|
120
|
+
* actually watching sitting idle. Falls back to line 1 when the on-screen
|
|
121
|
+
* session is line 1's own (or unknown), which is the common case.
|
|
122
|
+
*
|
|
123
|
+
* This SUPERSEDED the old `findAliasedLine()` helper, which served the INVERSE
|
|
124
|
+
* premise: line 1 having ADOPTED a background line's session, so a line-1 write
|
|
125
|
+
* had to be mirrored onto the aliased background line. The aliasing guards
|
|
126
|
+
* (`isBoundToAnotherLine`, in chat.tsx's line-1 bind effect and voice-call.ts's
|
|
127
|
+
* eager foreground mint) now stop line 1 from ever adopting another line's
|
|
128
|
+
* session, so that premise can no longer hold in production — the helper was
|
|
129
|
+
* permanently `undefined`, i.e. dead code that read as live, and was deleted.
|
|
130
|
+
* Every foreground write resolves its ONE target through this function instead.
|
|
27
131
|
*/
|
|
28
|
-
export declare const
|
|
132
|
+
export declare const foregroundLineNumber: (sessionId: string | null) => number;
|
|
29
133
|
export declare const openAgentLine: (label: string) => AgentLine | null;
|
|
30
|
-
|
|
134
|
+
/**
|
|
135
|
+
* RELEASE a line — the mirror of `persistSlotBinding`'s adoption: clears the
|
|
136
|
+
* in-memory entry AND its durable slot together, so the freed number is
|
|
137
|
+
* immediately re-mintable by `openAgentLine` and does not rehydrate on the next
|
|
138
|
+
* boot. Called when a spawn's session mint fails (otherwise the slot is burned
|
|
139
|
+
* until reload) and when the user deletes a session a line was bound to
|
|
140
|
+
* (otherwise the rail keeps offering a chip that opens a session that is gone).
|
|
141
|
+
*
|
|
142
|
+
* Line 1 is the foreground chat and is never REMOVED — releasing it resets it
|
|
143
|
+
* to the familiar fresh/unbound line 1 instead. No-op on an unknown line.
|
|
144
|
+
*/
|
|
145
|
+
export declare const closeAgentLine: (line: number) => void;
|
|
146
|
+
/**
|
|
147
|
+
* TEST/HARNESS-ONLY memory-only bind — the `__` prefix is load-bearing. This
|
|
148
|
+
* writes the in-memory registry WITHOUT the durable slot, which is precisely
|
|
149
|
+
* the divergence `persistSlotBinding` exists to eliminate: a line bound only in
|
|
150
|
+
* memory looks right until the next rehydrate, then silently reverts (or, after
|
|
151
|
+
* a workspace switch, rehydrates onto the OTHER workspace's session). Production
|
|
152
|
+
* adoption has exactly one seam and it is `persistSlotBinding`.
|
|
153
|
+
*
|
|
154
|
+
* It stays exported solely so unit tests, the rail stories, and the
|
|
155
|
+
* `__forceAgentLines` E2E hook can construct a registry state without writing
|
|
156
|
+
* durable slots that would then leak across cases (and, for `__forceAgentLines`,
|
|
157
|
+
* survive an E2E reload as phantom agents). Renamed from the old public
|
|
158
|
+
* `bindLineSession` so no production writer can reach for it by accident.
|
|
159
|
+
*/
|
|
160
|
+
export declare const __bindLineSessionForTest: (line: number, sessionId: string) => void;
|
|
161
|
+
/**
|
|
162
|
+
* The ADOPTION seam (the one rule for what "Agent N" means): call this
|
|
163
|
+
* whenever `sessionId` becomes the ACTIVE session for `line` — line 1's
|
|
164
|
+
* foreground bind effect, the eager foreground mint at call start, and a
|
|
165
|
+
* background line's find-or-create dispatch. Updates the in-memory registry
|
|
166
|
+
* and the durable slot together, so a slot's identity never drifts between
|
|
167
|
+
* the two. No-ops on an unchanged binding, so calling this on every render
|
|
168
|
+
* (chat.tsx's bind effect has no dep array) is cheap.
|
|
169
|
+
*
|
|
170
|
+
* The two halves must move TOGETHER — both of these were real divergences:
|
|
171
|
+
*
|
|
172
|
+
* - An UNKNOWN line writes nothing. Every adoption site has an async gap
|
|
173
|
+
* between reserving the line and minting its session (`spawnAgentLine`,
|
|
174
|
+
* line-dispatch's find-or-create), and the line can be released inside that
|
|
175
|
+
* gap — a failed sibling spawn, a deleted session, a workspace switch that
|
|
176
|
+
* re-reads the slots. Writing the slot anyway left a durable binding for a
|
|
177
|
+
* line the registry does not hold, which rehydrates on the next boot as a
|
|
178
|
+
* phantom agent (and, after a workspace switch, one pointing at the OTHER
|
|
179
|
+
* workspace's session).
|
|
180
|
+
* - The `label` is written to memory too, not only to storage. Adopting under
|
|
181
|
+
* a new label with an unchanged `sessionId` used to update the durable slot
|
|
182
|
+
* while the in-memory line kept the old label, so the rail's chip and the
|
|
183
|
+
* label that survives a reload disagreed until the next rehydration.
|
|
184
|
+
*/
|
|
185
|
+
export declare const persistSlotBinding: (line: number, sessionId: string, label: string) => void;
|
|
186
|
+
/** `stop_agent`'s target: bound by the line-run reader once a background
|
|
187
|
+
* dispatch's POST returns a runId, and cleared to `null` when that run
|
|
188
|
+
* finishes/fails/errors — a stopped or finished run must not look stoppable
|
|
189
|
+
* again. No-op on an unknown line or an unchanged value (mirrors
|
|
190
|
+
* `setLineStatus`'s re-write-on-every-render tolerance). */
|
|
191
|
+
export declare const bindLineRun: (line: number, runId: string | null) => void;
|
|
31
192
|
export declare const setLineStatus: (line: number, status: AgentLineStatus, lastText?: string) => void;
|
|
193
|
+
/** CallScreen's agent board reads this as the live "what is it doing right
|
|
194
|
+
* now" line under a working line's status dot — written on every phase
|
|
195
|
+
* notification (`notifyLinePhase`) and cleared (`null`) once the line's run
|
|
196
|
+
* reaches a terminal state. `phase` rides along so the working card can wear
|
|
197
|
+
* the matching phase icon (omitted/null = kind unknown → spinner); a `null`
|
|
198
|
+
* label always clears both. No-op on an unknown line or unchanged values
|
|
199
|
+
* (mirrors `setLineStatus`'s tolerance). */
|
|
200
|
+
export declare const setLineStep: (line: number, label: string | null, phase?: WorkPhase | null) => void;
|
|
201
|
+
/** Write a line's `unseenResult` flag directly — `deliverLineReply`/
|
|
202
|
+
* `deliverLineFailure` (voice-call.ts) call this alongside `setLineStatus` to
|
|
203
|
+
* mark a background line's finish/failure unseen when its session isn't the
|
|
204
|
+
* one on screen. No-op on an unknown line or an unchanged value (mirrors
|
|
205
|
+
* `setLineStatus`'s tolerance). Most callers want `markLineSeen` below rather
|
|
206
|
+
* than calling this with `false` directly. */
|
|
207
|
+
export declare const setLineUnseenResult: (line: number, unseenResult: boolean) => void;
|
|
208
|
+
/** The user is now looking at this line's session — clear its unseen-result
|
|
209
|
+
* flag. Called from BelongDock's `onSelectSession` (any surface that opens a
|
|
210
|
+
* session — the sessions list, `show_agent_line`, a notification click) once
|
|
211
|
+
* it resolves which line, if any, owns the opened session. */
|
|
212
|
+
export declare const markLineSeen: (line: number) => void;
|
|
213
|
+
/**
|
|
214
|
+
* The user opened `sessionId` — clear the unseen-result flag on EVERY line
|
|
215
|
+
* bound to it. More than one line can share a session: line 1 aliases whatever
|
|
216
|
+
* the chat is showing, so a background line the user opened is held by both.
|
|
217
|
+
* Marking only the FIRST match (line 1, which sorts first) left the background
|
|
218
|
+
* agent's green dot lit forever with no way to clear it. No-op when no line
|
|
219
|
+
* owns the session.
|
|
220
|
+
*/
|
|
221
|
+
export declare const markSessionSeen: (sessionId: string) => void;
|
|
222
|
+
/**
|
|
223
|
+
* The session behind `sessionId` is gone (the user deleted it) — RELEASE every
|
|
224
|
+
* line bound to it, in memory and durably. Without this the registry and its
|
|
225
|
+
* reload-surviving slot keep pointing at a session that no longer exists, so
|
|
226
|
+
* the rail goes on offering a chip that opens nothing.
|
|
227
|
+
*/
|
|
228
|
+
export declare const releaseLinesForSession: (sessionId: string) => void;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AgentLineStatus } from './voice-call-lines.ts';
|
|
2
|
+
import { WorkPhase } from './voice-narration.ts';
|
|
2
3
|
export type CallStatus = "idle" | "connecting" | "in_call" | "error";
|
|
3
4
|
/**
|
|
4
5
|
* One row of the call's execution timeline (the CallScreen activity card):
|
|
@@ -112,6 +113,7 @@ declare let lineDispatcher: ((req: {
|
|
|
112
113
|
}) => void) | null;
|
|
113
114
|
export declare const registerCallLineDispatcher: (dispatcher: NonNullable<typeof lineDispatcher>) => (() => void);
|
|
114
115
|
export declare const registerCallLineViewSwitcher: (switcher: (sessionId: string) => void) => (() => void);
|
|
116
|
+
export declare const registerCallClearNotifier: (notifier: (sessionId: string) => void) => (() => void);
|
|
115
117
|
/**
|
|
116
118
|
* ChatRoute calls this when a tool-approval card appears while a call is
|
|
117
119
|
* live: the ask lands on the timeline and the voice model asks the user to
|
|
@@ -133,7 +135,24 @@ export declare const setCallWorkPhase: (phase: CallState["workPhase"]) => void;
|
|
|
133
135
|
* (e.g. ChatRoute hasn't mounted).
|
|
134
136
|
*/
|
|
135
137
|
export declare const showLineOnScreen: (line: number) => void;
|
|
136
|
-
|
|
138
|
+
/**
|
|
139
|
+
* `isReconnect`: set by the dock's boot-time auto-redial (BEL — call survives
|
|
140
|
+
* page reload) when a per-tab {@link readCallActiveMarker} marker says a call
|
|
141
|
+
* was live when the page went away. Everything else about starting the call
|
|
142
|
+
* is identical to a manual dial — a fresh page load already rehydrates every
|
|
143
|
+
* line straight from its persisted slot session at MODULE BOOT (the registry's
|
|
144
|
+
* own initializer, `voice-call-lines.ts`), and `ensureForegroundLineSession`
|
|
145
|
+
* reuses line 1's persisted session pointer (stream-state-store.ts), so no
|
|
146
|
+
* line state is lost either way; `resetForCallStart()` below only clears a
|
|
147
|
+
* line that was genuinely left stuck "working" by an earlier call's teardown.
|
|
148
|
+
* The ONE thing a fresh page load can't recover on its own is the call's
|
|
149
|
+
* spoken timeline (in-memory, wiped by definition) — `resumeDigest`, captured
|
|
150
|
+
* from the marker BEFORE this call's own lifecycle overwrites it, carries that
|
|
151
|
+
* recap into the reconnected realtime session (see `onOpen` below).
|
|
152
|
+
*/
|
|
153
|
+
export declare const startCall: (options?: {
|
|
154
|
+
readonly isReconnect?: boolean;
|
|
155
|
+
}) => Promise<void>;
|
|
137
156
|
export declare const endCall: () => void;
|
|
138
157
|
export declare const toggleCallMuted: () => void;
|
|
139
158
|
/** Dismiss a sticky error state (the overlay's ✕). */
|
|
@@ -173,10 +192,13 @@ export declare const deliverLineArtifact: (line: number, artifact: {
|
|
|
173
192
|
export declare const deliverLineFailure: (line: number, message: string) => void;
|
|
174
193
|
/** A background line is blocked on a tool approval — steer the user to it. */
|
|
175
194
|
export declare const notifyLineApprovalNeeded: (line: number, timelineText: string) => void;
|
|
176
|
-
/** A background line advanced a phase —
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
|
|
195
|
+
/** 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`
|
|
198
|
+
* 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. */
|
|
201
|
+
export declare const notifyLinePhase: (line: number, phaseLabel: string, phase?: WorkPhase | null) => void;
|
|
180
202
|
/** True while a call holds the audio path — ChatRoute gates TTS autoplay on it. */
|
|
181
203
|
export declare const isCallActive: () => boolean;
|
|
182
204
|
/**
|
|
@@ -196,7 +218,7 @@ export declare const __forceCallAudioLevel: (level: number) => void;
|
|
|
196
218
|
* CallScreen lines strip in E2E and sandboxed browsers. Resets the registry,
|
|
197
219
|
* then replays the same store calls a live Operator run makes: `openAgentLine`
|
|
198
220
|
* to create each background line (sequential, mirroring real dispatch),
|
|
199
|
-
* `
|
|
221
|
+
* `__bindLineSessionForTest` + `setLineStatus` to fill it in. Line 1 is the existing
|
|
200
222
|
* foreground line and is updated in place rather than opened. Entries are
|
|
201
223
|
* replayed in ascending `line` order regardless of input order, so lines 2/3
|
|
202
224
|
* always land on their expected slots.
|
|
@@ -206,5 +228,11 @@ export declare const __forceAgentLines: (forced: readonly {
|
|
|
206
228
|
label: string;
|
|
207
229
|
status: AgentLineStatus;
|
|
208
230
|
sessionId?: string;
|
|
231
|
+
/** Optional live step label (CallScreen's agent board) — mirrors what
|
|
232
|
+
* `notifyLinePhase` writes on a real background dispatch. */
|
|
233
|
+
currentStepLabel?: string;
|
|
234
|
+
/** Optional phase classification for the step — drives the working
|
|
235
|
+
* card's phase icon (omitted = spinner). */
|
|
236
|
+
currentPhase?: WorkPhase;
|
|
209
237
|
}[]) => void;
|
|
210
238
|
export {};
|