@belonguniverseai/react-sdk 0.3.6 → 0.4.1
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/dist/api/client.d.ts +238 -0
- package/dist/api/queries.d.ts +16 -0
- package/dist/api/query-keys.d.ts +1 -0
- package/dist/api/report-client-error.d.ts +1 -1
- package/dist/api/task-schedules.d.ts +3 -3
- package/dist/component/BelongWidget.d.ts +5 -3
- package/dist/component/{arc-6nY2VvBR.js → arc-Du1-HUt0.js} +2 -2
- package/dist/component/{architectureDiagram-3BPJPVTR-8NzFzSu-.js → architectureDiagram-3BPJPVTR-NTFoFNN-.js} +3 -3
- package/dist/component/{blockDiagram-GPEHLZMM-DUEwMafH.js → blockDiagram-GPEHLZMM-9LBL4EUV.js} +4 -4
- package/dist/component/{c4Diagram-AAUBKEIU-CDD_6To7.js → c4Diagram-AAUBKEIU-C1enIoRg.js} +3 -3
- package/dist/component/{channel-B4iaYdVF.js → channel-CNnOkAN_.js} +2 -2
- package/dist/component/{chunk-2J33WTMH-DyOrhFxY.js → chunk-2J33WTMH-X2Iy3mMD.js} +2 -2
- package/dist/component/{chunk-4BX2VUAB-Bc66-Fjy.js → chunk-4BX2VUAB-BLlcE09Q.js} +2 -2
- package/dist/component/{chunk-55IACEB6-CIN0g3JH.js → chunk-55IACEB6-23v_td5T.js} +2 -2
- package/dist/component/{chunk-727SXJPM-BGs-m5or.js → chunk-727SXJPM-BC2kAa1t.js} +6 -6
- package/dist/component/{chunk-AQP2D5EJ-CPlwnVcL.js → chunk-AQP2D5EJ-CsRFVdwF.js} +4 -4
- package/dist/component/{chunk-FMBD7UC4-09viRWEH.js → chunk-FMBD7UC4-CWrggihb.js} +2 -2
- package/dist/component/{chunk-ND2GUHAM-BJo4K53f.js → chunk-ND2GUHAM-Bj78QMsn.js} +2 -2
- package/dist/component/{chunk-QZHKN3VN-DufugBok.js → chunk-QZHKN3VN-CS_FAlLS.js} +2 -2
- package/dist/component/{classDiagram-4FO5ZUOK-DfAygW-7.js → classDiagram-4FO5ZUOK-ci84KOU1.js} +3 -3
- package/dist/component/{classDiagram-v2-Q7XG4LA2-DfAygW-7.js → classDiagram-v2-Q7XG4LA2-ci84KOU1.js} +3 -3
- package/dist/component/{cose-bilkent-S5V4N54A-CUKOuMcm.js → cose-bilkent-S5V4N54A-QLIj0pt2.js} +2 -2
- package/dist/component/{dagre-BM42HDAG-BPRObW6r.js → dagre-BM42HDAG-D32wP-VH.js} +2 -2
- package/dist/component/{diagram-2AECGRRQ-Cxsg-pXz.js → diagram-2AECGRRQ-Dn47q_hT.js} +3 -3
- package/dist/component/{diagram-5GNKFQAL-U6L8NDef.js → diagram-5GNKFQAL-Df7a_ICg.js} +4 -4
- package/dist/component/{diagram-KO2AKTUF-BxN_e8Dk.js → diagram-KO2AKTUF-CNcoKufc.js} +3 -3
- package/dist/component/{diagram-LMA3HP47-Dbkb79LU.js → diagram-LMA3HP47-Dq8j6XNs.js} +3 -3
- package/dist/component/{diagram-OG6HWLK6-SASqlYMy.js → diagram-OG6HWLK6-CZ1WglbZ.js} +4 -4
- package/dist/component/{erDiagram-TEJ5UH35-CDTBM9wY.js → erDiagram-TEJ5UH35-CDlHARAu.js} +5 -5
- package/dist/component/{flowDiagram-I6XJVG4X-DugkNxCw.js → flowDiagram-I6XJVG4X-Cw1mKy8X.js} +7 -7
- package/dist/component/{ganttDiagram-6RSMTGT7-D3FuGu21.js → ganttDiagram-6RSMTGT7-B3FUForj.js} +3 -3
- package/dist/component/{gitGraphDiagram-PVQCEYII-DMKggb_e.js → gitGraphDiagram-PVQCEYII-BgHuuQ27.js} +4 -4
- package/dist/component/{highlighted-body-OFNGDK62-Bnl71RgK.js → highlighted-body-OFNGDK62-BTv_Fxf3.js} +2 -2
- package/dist/component/index.js +2 -2
- package/dist/component/{infoDiagram-5YYISTIA-BaUo1fFU.js → infoDiagram-5YYISTIA-DE9i_OcK.js} +2 -2
- package/dist/component/{ishikawaDiagram-YF4QCWOH-DofOP6uV.js → ishikawaDiagram-YF4QCWOH-BDe88Hz2.js} +2 -2
- package/dist/component/{journeyDiagram-JHISSGLW-D-xl9LqQ.js → journeyDiagram-JHISSGLW-D3t45UC1.js} +5 -5
- package/dist/component/{kanban-definition-UN3LZRKU-Lfcidbpn.js → kanban-definition-UN3LZRKU-DfFJIuhU.js} +3 -3
- package/dist/component/{linear-CtCl_nrs.js → linear-AXxuun7R.js} +2 -2
- package/dist/component/{mermaid-GHXKKRXX-CnzRBGo3.js → mermaid-GHXKKRXX-D7NVqIBP.js} +31181 -29271
- package/dist/component/{mindmap-definition-RKZ34NQL-RZVaz4dV.js → mindmap-definition-RKZ34NQL-cTac4kYU.js} +4 -4
- package/dist/component/{pieDiagram-4H26LBE5-CEwcfNwI.js → pieDiagram-4H26LBE5-B1SubLQb.js} +4 -4
- package/dist/component/{quadrantDiagram-W4KKPZXB-BJBEiTgK.js → quadrantDiagram-W4KKPZXB-CzyBW8Cr.js} +3 -3
- package/dist/component/{requirementDiagram-4Y6WPE33-CVHog8O-.js → requirementDiagram-4Y6WPE33-DgS33NcX.js} +4 -4
- package/dist/component/{sankeyDiagram-5OEKKPKP-Cn1N0qrl.js → sankeyDiagram-5OEKKPKP-Cp4o_akq.js} +2 -2
- package/dist/component/{sequenceDiagram-3UESZ5HK-CRaBqdL0.js → sequenceDiagram-3UESZ5HK-2gf91-2b.js} +4 -4
- package/dist/component/{stateDiagram-AJRCARHV-9q4hv0ii.js → stateDiagram-AJRCARHV-BByZezJw.js} +3 -3
- package/dist/component/{stateDiagram-v2-BHNVJYJU-By7O-5eN.js → stateDiagram-v2-BHNVJYJU-B-IObShO.js} +3 -3
- package/dist/component/{timeline-definition-PNZ67QCA-BWfxZI7f.js → timeline-definition-PNZ67QCA-D_2NG1sj.js} +3 -3
- package/dist/component/{vennDiagram-CIIHVFJN-B_PQ6bU6.js → vennDiagram-CIIHVFJN-BjrQUaEs.js} +2 -2
- package/dist/component/{wardleyDiagram-YWT4CUSO-P7tCzeA0.js → wardleyDiagram-YWT4CUSO-DYcvfAeQ.js} +3 -3
- package/dist/component/{xychartDiagram-2RQKCTM6-B4Z_Zrko.js → xychartDiagram-2RQKCTM6-CtLaJFtQ.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 +21 -2
- package/dist/components/embed/EmbedHeader.d.ts +25 -2
- package/dist/components/embed/EmbedRail.d.ts +20 -1
- package/dist/components/embed/EmbedSessions.d.ts +33 -8
- package/dist/components/embed/MobileNavBar.d.ts +4 -1
- package/dist/components/embed/SessionStatsPanel.d.ts +12 -0
- package/dist/components/embed/rail-flags.d.ts +23 -0
- package/dist/embed/adoption-notice.d.ts +32 -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/presets.d.ts +10 -0
- package/dist/embed/theme.d.ts +13 -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 +34 -4
- package/dist/embed/voice/line-run-reader.d.ts +29 -1
- package/dist/embed/voice/line-slots.d.ts +99 -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 +241 -14
- package/dist/embed/voice-call.d.ts +34 -6
- package/dist/i18n/messages/en.d.ts +33 -0
- package/dist/i18n/messages/surfaces/header.d.ts +18 -0
- package/dist/i18n/messages/surfaces/sessions.d.ts +6 -0
- package/dist/i18n/messages/surfaces/stats.d.ts +55 -0
- package/dist/i18n/messages/surfaces/stream.d.ts +3 -0
- package/dist/stream/belong-chat-transport.d.ts +45 -8
- package/dist/stream/belong-data-parts.d.ts +8 -0
- package/dist/stream/chat-export-store.d.ts +35 -0
- package/dist/stream/route-dispatch.d.ts +17 -0
- package/dist/stream/session-stats-csv.d.ts +52 -0
- package/dist/stream/stream-state-store.d.ts +36 -6
- package/dist/types/public.d.ts +3 -1
- package/package.json +1 -1
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BEL-112 / push layout: keeps HOST `position: fixed` surfaces out from under
|
|
3
|
+
* the dock.
|
|
4
|
+
*
|
|
5
|
+
* `<body>` padding reserves the dock's width for everything in the normal
|
|
6
|
+
* flow. Fixed host UI escapes that flow — a right-anchored Simetrik drawer,
|
|
7
|
+
* a portal-mounted popout, a drawer scrim, a centered modal — so this
|
|
8
|
+
* controller finds those surfaces and writes ONE inline margin per element to
|
|
9
|
+
* shift or shrink them into the free viewport. The geometry lives in
|
|
10
|
+
* embed/host-surface.ts; this file is the DOM adapter around it.
|
|
11
|
+
*
|
|
12
|
+
* Two escape hatches for the failure modes a host can put us in:
|
|
13
|
+
*
|
|
14
|
+
* fight detection a host that repositions its own surface against our
|
|
15
|
+
* margin never converges (customer report: rename dialog
|
|
16
|
+
* shaking left↔right). Writes are budgeted per element
|
|
17
|
+
* within a stable footprint+viewport epoch; past the cap
|
|
18
|
+
* the element is left alone forever.
|
|
19
|
+
* yield a surface too wide to fit beside the dock can't be
|
|
20
|
+
* corrected at all, so the DOCK gives way instead — the
|
|
21
|
+
* owner collapses it to the rail via `onYieldNeeded` and
|
|
22
|
+
* restores on `onYieldCleared`.
|
|
23
|
+
*
|
|
24
|
+
* No React: the owner injects the two callbacks and pushes layout changes in.
|
|
25
|
+
*/
|
|
26
|
+
/** Per-element inline-margin writes allowed inside one stable epoch. */
|
|
27
|
+
export declare const MAX_HOST_SURFACE_SHIFT_WRITES = 4;
|
|
28
|
+
export type HostPushLayout = {
|
|
29
|
+
readonly side: "left" | "right";
|
|
30
|
+
/** Total width the dock reserves: chat dock + plan panel + preview panel. */
|
|
31
|
+
readonly reservePx: number;
|
|
32
|
+
};
|
|
33
|
+
export type HostPushControllerDeps = {
|
|
34
|
+
/**
|
|
35
|
+
* A surface can't fit beside the dock — the owner should collapse. Called
|
|
36
|
+
* once per yield episode, never while a yield is already pending.
|
|
37
|
+
*/
|
|
38
|
+
readonly onYieldNeeded: () => void;
|
|
39
|
+
/** Every surface that forced the yield is gone — the owner may restore. */
|
|
40
|
+
readonly onYieldCleared: () => void;
|
|
41
|
+
};
|
|
42
|
+
export type HostPushController = {
|
|
43
|
+
/** Push new layout inputs and re-evaluate (dock resized, side flipped). */
|
|
44
|
+
readonly setLayout: (layout: HostPushLayout) => void;
|
|
45
|
+
/** Request an evaluation on the next frame (coalesced). */
|
|
46
|
+
readonly schedule: () => void;
|
|
47
|
+
/** Disconnect observers and restore every margin this controller wrote. */
|
|
48
|
+
readonly stop: () => void;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Candidate host surfaces, from three complementary sources:
|
|
52
|
+
*
|
|
53
|
+
* 1. dialog-ish elements anywhere (Radix and friends set one of these);
|
|
54
|
+
* 2. DIRECT CHILDREN of <body> that compute to `position: fixed` — where
|
|
55
|
+
* React and Radix portals land, hit-testable or not;
|
|
56
|
+
* 3. anything currently under the dock, found by hit-testing the reserve
|
|
57
|
+
* band — this is what catches a fixed drawer rendered INLINE deep in the
|
|
58
|
+
* host's own tree, which is how plenty of hosts (Simetrik included) build
|
|
59
|
+
* them.
|
|
60
|
+
*
|
|
61
|
+
* Probing every element's computed style would be far too expensive for a
|
|
62
|
+
* MutationObserver callback; between them these three cost a bounded number of
|
|
63
|
+
* style reads per evaluation. `position: sticky` is deliberately excluded —
|
|
64
|
+
* sticky lives in the normal flow, so the body padding already moves it.
|
|
65
|
+
*/
|
|
66
|
+
export declare const collectHostSurfaces: (side: "left" | "right", reservePx: number) => readonly HTMLElement[];
|
|
67
|
+
export declare const startHostPushController: (initialLayout: HostPushLayout, deps: HostPushControllerDeps) => HostPushController;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure classification + correction geometry for HOST viewport-anchored
|
|
3
|
+
* surfaces (drawers, popouts, side panels, modal backdrops, centered modals).
|
|
4
|
+
*
|
|
5
|
+
* The dock reserves its width with `<body>` padding, which reflows everything
|
|
6
|
+
* in the normal flow. `position: fixed` host UI escapes that flow and would
|
|
7
|
+
* render underneath the dock, so the dock corrects it with one inline margin.
|
|
8
|
+
* Which margin, and how far, is decided here — no DOM, no React.
|
|
9
|
+
*
|
|
10
|
+
* Three correctable shapes:
|
|
11
|
+
*
|
|
12
|
+
* full_bleed an overlay spanning the viewport (a drawer's backdrop, an
|
|
13
|
+
* `inset: 0` scrim). Shifting it would just move it off screen;
|
|
14
|
+
* a margin on the dock side SHRINKS it, which is the fix.
|
|
15
|
+
* anchored a drawer/panel pinned to the dock's own viewport edge.
|
|
16
|
+
* floating a centered modal that merely overlaps the reserve band.
|
|
17
|
+
*
|
|
18
|
+
* `anchored` and `floating` share the legacy `resolveHostModalShiftPx`
|
|
19
|
+
* magnitude; they are distinguished so the classification is explicit and
|
|
20
|
+
* testable, and so a future rule can treat them differently.
|
|
21
|
+
*/
|
|
22
|
+
export type HostSurfaceRect = {
|
|
23
|
+
readonly left: number;
|
|
24
|
+
readonly right: number;
|
|
25
|
+
};
|
|
26
|
+
export type HostSurfaceKind = "clear" | "full_bleed" | "anchored" | "floating";
|
|
27
|
+
/**
|
|
28
|
+
* How far a surface edge may sit from the viewport edge and still count as
|
|
29
|
+
* pinned to it. Generous on purpose: hosts inset drawers and scrims by a few
|
|
30
|
+
* pixels (`right: 8px`, a 1px border, scrollbar-gutter compensation) and those
|
|
31
|
+
* are still edge-anchored — misreading one as a free-floating modal would send
|
|
32
|
+
* it a margin the browser cannot act on.
|
|
33
|
+
*/
|
|
34
|
+
export declare const EDGE_ANCHOR_TOLERANCE_PX = 24;
|
|
35
|
+
/**
|
|
36
|
+
* The inline property a correction writes, the signed DELTA to add to whatever
|
|
37
|
+
* margin the host already set there, and the shape it was derived from — the
|
|
38
|
+
* caller needs the kind to back the correction out of a later measurement (a
|
|
39
|
+
* shift moves the box; a shrink moves one edge).
|
|
40
|
+
*/
|
|
41
|
+
export type HostSurfaceCorrection = {
|
|
42
|
+
readonly property: "margin-left" | "margin-right";
|
|
43
|
+
readonly px: number;
|
|
44
|
+
readonly kind: HostSurfaceKind;
|
|
45
|
+
};
|
|
46
|
+
export declare const classifyHostSurface: (rect: HostSurfaceRect, viewportWidthPx: number, side: "left" | "right", reservePx: number) => HostSurfaceKind;
|
|
47
|
+
/**
|
|
48
|
+
* The inline correction that moves `rect` (its UNSHIFTED position) out from
|
|
49
|
+
* under a dock reserving `reservePx` on `side`. `px: 0` means leave it alone.
|
|
50
|
+
*/
|
|
51
|
+
export declare const resolveHostSurfaceCorrection: (rect: HostSurfaceRect, viewportWidthPx: number, side: "left" | "right", reservePx: number) => HostSurfaceCorrection;
|
|
52
|
+
/**
|
|
53
|
+
* Can this surface be corrected and still sit fully on screen? A full-bleed
|
|
54
|
+
* overlay always can (shrinking it never pushes it off). Shifted surfaces are
|
|
55
|
+
* judged by the legacy fit test. False means the dock must yield instead.
|
|
56
|
+
*/
|
|
57
|
+
export declare const canHostSurfaceFitBesideDock: (rect: HostSurfaceRect, viewportWidthPx: number, side: "left" | "right", reservePx: number) => boolean;
|
package/dist/embed/presets.d.ts
CHANGED
|
@@ -17,6 +17,16 @@ export declare const DEFAULT_PRESET: PresetName;
|
|
|
17
17
|
export declare const isSimetrikHost: (hostname: string) => boolean;
|
|
18
18
|
/** The default preset for a host: `simetrik` on a Simetrik domain, else belong. */
|
|
19
19
|
export declare const defaultPresetForHost: (hostname: string) => PresetName;
|
|
20
|
+
/**
|
|
21
|
+
* The preset the dock boots with, given the user's stored choice and the host
|
|
22
|
+
* it's embedded on. **Brand-as-floor:** on a host that defaults to a tenant
|
|
23
|
+
* brand (a Simetrik domain), a stored *generic* built-in preset (`belong`) must
|
|
24
|
+
* not silently downgrade the brand — a stale `localStorage` preset from QA/dev
|
|
25
|
+
* once wiped Simetrik's brand on the real site. Only the user's explicit Custom
|
|
26
|
+
* theme (or a matching brand choice) overrides the host brand. On a non-branded
|
|
27
|
+
* host there's no floor to enforce, so the stored preference always wins.
|
|
28
|
+
*/
|
|
29
|
+
export declare const resolveInitialPreset: (storedPreset: PresetName | undefined, hostname: string) => PresetName;
|
|
20
30
|
export declare const getPreset: (name: PresetName) => PartialBelongTheme;
|
|
21
31
|
export declare const listPresets: () => readonly {
|
|
22
32
|
name: PresetName;
|
package/dist/embed/theme.d.ts
CHANGED
|
@@ -8,6 +8,19 @@ export declare const setTheme: (partial: PartialBelongTheme) => void;
|
|
|
8
8
|
* the Custom style overlays the user's accent/cssVars stash. */
|
|
9
9
|
export declare const applyPreset: (name: PresetName) => void;
|
|
10
10
|
export declare const peekPreset: () => PresetName;
|
|
11
|
+
/**
|
|
12
|
+
* One-line diagnostic of how the boot theme resolved, logged once at init
|
|
13
|
+
* (see `applyInitConfig`). Pairs with the build-provenance line (plan 007 §B4)
|
|
14
|
+
* so a "the dock isn't showing our brand" report is answerable from the host
|
|
15
|
+
* console alone: it names the winning preset + brand, the host that drove the
|
|
16
|
+
* default, and whether the tenant's *published* theme overrode it on top.
|
|
17
|
+
*/
|
|
18
|
+
export declare const describeThemeResolution: (input: {
|
|
19
|
+
hostname: string;
|
|
20
|
+
preset: PresetName;
|
|
21
|
+
brandName: string;
|
|
22
|
+
remoteThemeApplied: boolean;
|
|
23
|
+
}) => string;
|
|
11
24
|
/**
|
|
12
25
|
* Set (or clear, with `null`) the Custom-style accent. Updates the stash and
|
|
13
26
|
* switches to the Custom style so the change is immediately visible.
|
|
@@ -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,18 +1,48 @@
|
|
|
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
|
|
9
18
|
* create body carries the effective `workspaceExternalId` (absent when the host
|
|
10
19
|
* runs unscoped). The line's registry label seeds the session title, so the
|
|
11
20
|
* sessions list names the background conversation.
|
|
21
|
+
*
|
|
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.
|
|
12
30
|
*/
|
|
13
31
|
/** Abort every live line reader and invalidate their callbacks (call teardown).
|
|
14
32
|
* Subscribed below to fire whenever a call leaves in_call/connecting. */
|
|
15
33
|
export declare const abortAllLineReaders: () => void;
|
|
34
|
+
/**
|
|
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.
|
|
44
|
+
*/
|
|
45
|
+
export declare const reattachPendingLineRuns: (fetchFn?: typeof fetch) => void;
|
|
16
46
|
export declare const dispatchToLine: (req: {
|
|
17
47
|
readonly line: number;
|
|
18
48
|
readonly request: string;
|
|
@@ -16,12 +16,36 @@
|
|
|
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 —
|
|
22
31
|
* NOT terminal, keep reading the same stream. "completed" finishes with
|
|
23
32
|
* the accumulated text; "cancelled" | "failed" | "throttled" are errors.
|
|
24
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
|
+
*
|
|
25
49
|
* SSE parsing here is LINE-BY-LINE (split on "\n", not "\n\n") — the server
|
|
26
50
|
* sends exactly one `data:` line per event. `id:` lines carry the event
|
|
27
51
|
* cursor (ignored — v1 has no reconnect/resume) and `:`-prefixed lines are
|
|
@@ -31,12 +55,16 @@ export type WatchLineRunInput = {
|
|
|
31
55
|
readonly runId: string;
|
|
32
56
|
readonly onPhase: (toolName: string) => void;
|
|
33
57
|
readonly onApprovalNeeded: () => void;
|
|
58
|
+
readonly onNavigate: (data: {
|
|
59
|
+
readonly routeName: string;
|
|
60
|
+
readonly params: Readonly<Record<string, string>>;
|
|
61
|
+
}) => void;
|
|
34
62
|
readonly onArtifact: (artifact: {
|
|
35
63
|
artifactId: string;
|
|
36
64
|
title: string;
|
|
37
65
|
mimeType: string;
|
|
38
66
|
}) => void;
|
|
39
67
|
readonly onFinish: (finalText: string) => void;
|
|
40
|
-
readonly onError: (message: string) => void;
|
|
68
|
+
readonly onError: (message: string, kind: "terminal" | "transport") => void;
|
|
41
69
|
};
|
|
42
70
|
export declare const watchLineRun: (input: WatchLineRunInput, fetchFn?: typeof fetch) => (() => void);
|
|
@@ -0,0 +1,99 @@
|
|
|
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
|
+
* `runId` (F3/R4 — reload must not lie about a still-running background
|
|
29
|
+
* line): the durable half of `bindLineRun`'s in-memory tracking, written by
|
|
30
|
+
* `persistSlotRun` (`voice-call-lines.ts`) alongside every `bindLineRun` call
|
|
31
|
+
* a background dispatch makes. Without it, a page reload has no way to know
|
|
32
|
+
* a line was mid-run — `runId` lives only in JS memory otherwise, and the
|
|
33
|
+
* boot rehydrate would show a lying "idle" line while the run keeps
|
|
34
|
+
* streaming server-side. Back-compatible the same way `line1` is: a bag
|
|
35
|
+
* written before this field existed has no `runId` key at all, and the
|
|
36
|
+
* schema defaults it to `null` (nothing was in flight when that bag was
|
|
37
|
+
* written). Line 1 never carries a meaningful value here — its `runId` is
|
|
38
|
+
* always `null` (see `AgentLine.runId`'s doc in voice-call-lines.ts).
|
|
39
|
+
*/
|
|
40
|
+
/** Every line number that gets a persisted slot — all three agent lines. */
|
|
41
|
+
declare const SLOT_LINES: readonly [1, 2, 3];
|
|
42
|
+
type SlotLine = (typeof SLOT_LINES)[number];
|
|
43
|
+
export type LineSlot = {
|
|
44
|
+
readonly sessionId: string;
|
|
45
|
+
readonly label: string;
|
|
46
|
+
readonly runId: string | null;
|
|
47
|
+
};
|
|
48
|
+
/** Input to `writeLineSlot` — `runId` is OPTIONAL here (unlike the stored
|
|
49
|
+
* `LineSlot`) and defaults to `null` when omitted: every existing adoption
|
|
50
|
+
* call site (`persistSlotBinding`) writes a session/label pair without ever
|
|
51
|
+
* having an opinion on `runId`, and a fresh binding correctly has no run of
|
|
52
|
+
* its own yet (any run tracked against the PREVIOUS session at this slot is
|
|
53
|
+
* moot once the binding itself changes identity). `persistSlotRun` is the
|
|
54
|
+
* only writer that ever sets `runId` to a non-null value, via the narrower
|
|
55
|
+
* `writeLineSlotRun` below. */
|
|
56
|
+
export type LineSlotInput = {
|
|
57
|
+
readonly sessionId: string;
|
|
58
|
+
readonly label: string;
|
|
59
|
+
readonly runId?: string | null;
|
|
60
|
+
};
|
|
61
|
+
/** The persisted binding for line 1/2/3, or `null` when never set (or `line`
|
|
62
|
+
* isn't a valid agent line at all). */
|
|
63
|
+
export declare const readLineSlot: (line: number) => LineSlot | null;
|
|
64
|
+
/** Persist a line's current `{ sessionId, label }` so the NEXT rehydration
|
|
65
|
+
* (`resetAgentLines()`, or a plain reload for line 1) rebinds onto the same
|
|
66
|
+
* session. No-op for a line number that isn't 1/2/3, and no-op when the slot
|
|
67
|
+
* already holds this exact `{ sessionId, label, runId }` — callers (e.g.
|
|
68
|
+
* chat.tsx's per-render bind effect) call this on every render, so an
|
|
69
|
+
* unchanged binding must not touch storage. `runId` defaults to `null` when
|
|
70
|
+
* omitted (see `LineSlotInput`'s doc) — a fresh binding via this function
|
|
71
|
+
* always represents a NEW session identity, so any run tracked against
|
|
72
|
+
* whatever this slot held before is stale by construction. */
|
|
73
|
+
export declare const writeLineSlot: (line: number, slot: LineSlotInput) => void;
|
|
74
|
+
/** Update ONLY the persisted `runId` for a line's slot, leaving `sessionId`/
|
|
75
|
+
* `label` untouched — the durable half of `bindLineRun` (called together as
|
|
76
|
+
* `persistSlotRun` in voice-call-lines.ts), so a background line's in-flight
|
|
77
|
+
* run survives a reload (F3/R4). No-op for a line number that isn't 1/2/3,
|
|
78
|
+
* when the slot doesn't exist yet (nothing to attach a run to — the session
|
|
79
|
+
* itself hasn't been adopted), or when the runId is already what's
|
|
80
|
+
* persisted (bindLineRun's own no-op-on-unchanged tolerance, mirrored here so
|
|
81
|
+
* the two halves stay in lockstep). */
|
|
82
|
+
export declare const writeLineSlotRun: (line: number, runId: string | null) => void;
|
|
83
|
+
/** Drop a line's persisted binding — the durable half of `closeAgentLine`
|
|
84
|
+
* (voice-call-lines.ts). Called when a slot is RELEASED rather than rebound: a
|
|
85
|
+
* spawn whose session mint failed, or a session the user deleted. Without this
|
|
86
|
+
* the slot would rehydrate on the next boot onto a session that no longer
|
|
87
|
+
* exists (a dangling agent the rail keeps offering). No-op for a line number
|
|
88
|
+
* that isn't 1/2/3, and no-op when the slot is already empty. */
|
|
89
|
+
export declare const clearLineSlot: (line: number) => void;
|
|
90
|
+
/** Every persisted line slot, in ascending line order (1, then 2, then 3),
|
|
91
|
+
* skipping lines that were never bound. What `resetAgentLines()` reads to
|
|
92
|
+
* rebuild the switchboard. */
|
|
93
|
+
export declare const readAllLineSlots: () => readonly {
|
|
94
|
+
readonly line: SlotLine;
|
|
95
|
+
readonly slot: LineSlot;
|
|
96
|
+
}[];
|
|
97
|
+
/** Test-only: drop every persisted slot for the current workspace scope. */
|
|
98
|
+
export declare const __clearLineSlotsForTest: () => void;
|
|
99
|
+
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
|