@mihe-dev/js 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +114 -2
- package/dist/audio.d.ts +121 -0
- package/dist/audio.d.ts.map +1 -0
- package/dist/audio.js +377 -0
- package/dist/audio.js.map +1 -0
- package/dist/chart.d.ts +15 -0
- package/dist/chart.d.ts.map +1 -0
- package/dist/chart.js +58 -0
- package/dist/chart.js.map +1 -0
- package/dist/client.d.ts +226 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +358 -0
- package/dist/client.js.map +1 -0
- package/dist/commands.d.ts +70 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +295 -0
- package/dist/commands.js.map +1 -0
- package/dist/debug.d.ts +17 -0
- package/dist/debug.d.ts.map +1 -0
- package/dist/debug.js +29 -0
- package/dist/debug.js.map +1 -0
- package/dist/declarations.d.ts +160 -0
- package/dist/declarations.d.ts.map +1 -0
- package/dist/declarations.js +171 -0
- package/dist/declarations.js.map +1 -0
- package/dist/highlight.d.ts +77 -0
- package/dist/highlight.d.ts.map +1 -0
- package/dist/highlight.js +233 -0
- package/dist/highlight.js.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/mihe.d.ts +343 -0
- package/dist/mihe.d.ts.map +1 -0
- package/dist/mihe.iife.min.js +206 -0
- package/dist/mihe.iife.min.js.map +7 -0
- package/dist/mihe.js +720 -0
- package/dist/mihe.js.map +1 -0
- package/dist/mihe.min.js +206 -0
- package/dist/mihe.min.js.map +7 -0
- package/dist/store.d.ts +175 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +208 -0
- package/dist/store.js.map +1 -0
- package/dist/voice.d.ts +192 -0
- package/dist/voice.d.ts.map +1 -0
- package/dist/voice.js +443 -0
- package/dist/voice.js.map +1 -0
- package/dist/widget/card.d.ts +15 -0
- package/dist/widget/card.d.ts.map +1 -0
- package/dist/widget/card.js +28 -0
- package/dist/widget/card.js.map +1 -0
- package/dist/widget/dom.d.ts +24 -0
- package/dist/widget/dom.d.ts.map +1 -0
- package/dist/widget/dom.js +49 -0
- package/dist/widget/dom.js.map +1 -0
- package/dist/widget/element.d.ts +88 -0
- package/dist/widget/element.d.ts.map +1 -0
- package/dist/widget/element.js +285 -0
- package/dist/widget/element.js.map +1 -0
- package/dist/widget/format.d.ts +24 -0
- package/dist/widget/format.d.ts.map +1 -0
- package/dist/widget/format.js +64 -0
- package/dist/widget/format.js.map +1 -0
- package/dist/widget/icons.d.ts +5 -0
- package/dist/widget/icons.d.ts.map +1 -0
- package/dist/widget/icons.js +19 -0
- package/dist/widget/icons.js.map +1 -0
- package/dist/widget/launcher.d.ts +13 -0
- package/dist/widget/launcher.d.ts.map +1 -0
- package/dist/widget/launcher.js +27 -0
- package/dist/widget/launcher.js.map +1 -0
- package/dist/widget/mark.d.ts +10 -0
- package/dist/widget/mark.d.ts.map +1 -0
- package/dist/widget/mark.js +20 -0
- package/dist/widget/mark.js.map +1 -0
- package/dist/widget/orb.d.ts +91 -0
- package/dist/widget/orb.d.ts.map +1 -0
- package/dist/widget/orb.js +497 -0
- package/dist/widget/orb.js.map +1 -0
- package/dist/widget/panel.d.ts +40 -0
- package/dist/widget/panel.d.ts.map +1 -0
- package/dist/widget/panel.js +239 -0
- package/dist/widget/panel.js.map +1 -0
- package/dist/widget/styles.d.ts +22 -0
- package/dist/widget/styles.d.ts.map +1 -0
- package/dist/widget/styles.js +181 -0
- package/dist/widget/styles.js.map +1 -0
- package/package.json +43 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chart.d.ts","sourceRoot":"","sources":["../../../js/src/chart.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAa,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAE/E,wBAAgB,SAAS,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,OAAO,EAAE,OAAO,GAAG,aAAa,GAAG,SAAS,CAoC3F;AAED;;;GAGG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,EAAE,CAKvD"}
|
package/dist/chart.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chart summaries, worked out where the numbers are (amendment 67, step 4).
|
|
3
|
+
*
|
|
4
|
+
* The model explains a trend from these figures, so it is handed the start,
|
|
5
|
+
* end, high, low, total and largest steps rather than a list to do arithmetic
|
|
6
|
+
* over, which models get wrong.
|
|
7
|
+
*/
|
|
8
|
+
export function summarise(points, ordered) {
|
|
9
|
+
const [first] = points;
|
|
10
|
+
if (!first)
|
|
11
|
+
return undefined;
|
|
12
|
+
const last = points[points.length - 1];
|
|
13
|
+
let min = first;
|
|
14
|
+
let max = first;
|
|
15
|
+
let total = 0;
|
|
16
|
+
let rise;
|
|
17
|
+
let fall;
|
|
18
|
+
points.forEach((point, i) => {
|
|
19
|
+
total += point.y;
|
|
20
|
+
if (point.y < min.y)
|
|
21
|
+
min = point;
|
|
22
|
+
if (point.y > max.y)
|
|
23
|
+
max = point;
|
|
24
|
+
if (!ordered || i === 0)
|
|
25
|
+
return;
|
|
26
|
+
const previous = points[i - 1];
|
|
27
|
+
const change = point.y - previous.y;
|
|
28
|
+
if (change > 0 && (!rise || change > rise.change)) {
|
|
29
|
+
rise = { from: previous.x, to: point.x, change };
|
|
30
|
+
}
|
|
31
|
+
if (change < 0 && (!fall || change < fall.change)) {
|
|
32
|
+
fall = { from: previous.x, to: point.x, change };
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
return {
|
|
36
|
+
points: points.length,
|
|
37
|
+
first,
|
|
38
|
+
last,
|
|
39
|
+
min,
|
|
40
|
+
max,
|
|
41
|
+
total: Math.round(total * 100) / 100,
|
|
42
|
+
...(rise ? { largestRise: rise } : {}),
|
|
43
|
+
...(fall ? { largestFall: fall } : {}),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* At most `limit` points, evenly spaced, keeping both ends. The summary
|
|
48
|
+
* already carries the high and low, which thinning could skip.
|
|
49
|
+
*/
|
|
50
|
+
export function thin(points, limit) {
|
|
51
|
+
if (points.length <= limit)
|
|
52
|
+
return points;
|
|
53
|
+
if (limit <= 1)
|
|
54
|
+
return points.slice(0, 1);
|
|
55
|
+
const step = (points.length - 1) / (limit - 1);
|
|
56
|
+
return Array.from({ length: limit }, (_, i) => points[Math.round(i * step)]);
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=chart.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chart.js","sourceRoot":"","sources":["../../../js/src/chart.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,UAAU,SAAS,CAAC,MAAoB,EAAE,OAAgB;IAC9D,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC;IACvB,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC;IAExC,IAAI,GAAG,GAAG,KAAK,CAAC;IAChB,IAAI,GAAG,GAAG,KAAK,CAAC;IAChB,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,IAA2B,CAAC;IAChC,IAAI,IAA2B,CAAC;IAEhC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QAC1B,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC;QACjB,IAAI,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;YAAE,GAAG,GAAG,KAAK,CAAC;QACjC,IAAI,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;YAAE,GAAG,GAAG,KAAK,CAAC;QACjC,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC;YAAE,OAAO;QAChC,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC;QAChC,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;QACpC,IAAI,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAClD,IAAI,GAAG,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;QACnD,CAAC;QACD,IAAI,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAClD,IAAI,GAAG,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;QACnD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,KAAK;QACL,IAAI;QACJ,GAAG;QACH,GAAG;QACH,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG;QACpC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACvC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,IAAI,CAAI,MAAW,EAAE,KAAa;IAChD,IAAI,MAAM,CAAC,MAAM,IAAI,KAAK;QAAE,OAAO,MAAM,CAAC;IAC1C,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IAC/C,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,CAAE,CAAC,CAAC;AAChF,CAAC"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The WebSocket client (doc 02).
|
|
3
|
+
*
|
|
4
|
+
* One persistent socket per session carries chat, commands, and
|
|
5
|
+
* confirmations. Two properties drive the design:
|
|
6
|
+
*
|
|
7
|
+
* - A frontend action is a tool call that round-trips through the browser, so
|
|
8
|
+
* the runtime pushes a command and blocks until this client acks it. Every
|
|
9
|
+
* command MUST be answered, including on failure — an unanswered command
|
|
10
|
+
* stalls the assistant's turn until the runtime's timeout fires.
|
|
11
|
+
* - Confirming an action needs server-to-client push, which is why this is a
|
|
12
|
+
* socket rather than a request per message.
|
|
13
|
+
*
|
|
14
|
+
* The client owns transport only. It never decides what a command means; the
|
|
15
|
+
* provider does that and hands back a result.
|
|
16
|
+
*/
|
|
17
|
+
import type { ContextReport } from "./debug.js";
|
|
18
|
+
import { type AssistantCommand, type KnowledgeSourceRef, type ProposalStatus, type ScreenContext, type WidgetSettings } from "@mihe-dev/protocol";
|
|
19
|
+
export type ConnectionState = "idle" | "connecting" | "open" | "reconnecting" | "closed";
|
|
20
|
+
/** What the provider needs to react to. */
|
|
21
|
+
export type ClientEvent = {
|
|
22
|
+
type: "state";
|
|
23
|
+
state: ConnectionState;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Answered on every handshake, so it cannot drift out of step with the
|
|
27
|
+
* connection the way a one-shot probe could.
|
|
28
|
+
*/
|
|
29
|
+
| {
|
|
30
|
+
type: "voice_available";
|
|
31
|
+
available: boolean;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* What the assistant calls itself, from the app's settings.
|
|
35
|
+
*
|
|
36
|
+
* Re-sent on every handshake for the same reason `voice_available` is: a
|
|
37
|
+
* rename takes effect on the next session rather than on the next deploy of
|
|
38
|
+
* the host app.
|
|
39
|
+
*/
|
|
40
|
+
| {
|
|
41
|
+
type: "assistant_name";
|
|
42
|
+
name: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The customer's launcher icon from the app's settings, or `null` for the
|
|
46
|
+
* Mihe mark. Emitted on every handshake, absent or not: unlike the name,
|
|
47
|
+
* removing an icon has to take effect, and an absent field is how the
|
|
48
|
+
* runtime says "the default".
|
|
49
|
+
*/
|
|
50
|
+
| {
|
|
51
|
+
type: "launcher_icon";
|
|
52
|
+
url: string | null;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* How the widget presents itself, from the app's settings (amendment 61).
|
|
56
|
+
* `null` from a runtime too old to send any, which leaves the SDK's own
|
|
57
|
+
* defaults and the host's props in charge.
|
|
58
|
+
*/
|
|
59
|
+
| {
|
|
60
|
+
type: "widget_settings";
|
|
61
|
+
settings: WidgetSettings | null;
|
|
62
|
+
} | {
|
|
63
|
+
type: "turn_start";
|
|
64
|
+
turnId: string;
|
|
65
|
+
} | {
|
|
66
|
+
type: "delta";
|
|
67
|
+
turnId: string;
|
|
68
|
+
text: string;
|
|
69
|
+
} | {
|
|
70
|
+
type: "complete";
|
|
71
|
+
turnId: string;
|
|
72
|
+
message: string;
|
|
73
|
+
/** Documentation the answer drew on. Empty when none was used. */
|
|
74
|
+
sources: KnowledgeSourceRef[];
|
|
75
|
+
} | {
|
|
76
|
+
type: "command";
|
|
77
|
+
commandId: string;
|
|
78
|
+
command: AssistantCommand;
|
|
79
|
+
} | {
|
|
80
|
+
type: "proposal";
|
|
81
|
+
proposal: ProposalPayload;
|
|
82
|
+
} | {
|
|
83
|
+
type: "action_status";
|
|
84
|
+
proposalId: string;
|
|
85
|
+
status: ProposalStatus;
|
|
86
|
+
result?: unknown;
|
|
87
|
+
error?: string;
|
|
88
|
+
} | {
|
|
89
|
+
type: "error";
|
|
90
|
+
code: string;
|
|
91
|
+
message: string;
|
|
92
|
+
recoverable: boolean;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* A single-use permit for the voice socket, in reply to
|
|
96
|
+
* `requestVoiceToken`. Short-lived by design — see doc 03.
|
|
97
|
+
*/
|
|
98
|
+
| {
|
|
99
|
+
type: "voice_token";
|
|
100
|
+
token: string;
|
|
101
|
+
expiresAt: string;
|
|
102
|
+
}
|
|
103
|
+
/** What one answer on this screen re-sends, when `debug` is on. */
|
|
104
|
+
| {
|
|
105
|
+
type: "context_report";
|
|
106
|
+
report: ContextReport;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* A confirmation card's contents.
|
|
110
|
+
*
|
|
111
|
+
* Every human-readable field here comes from the runtime's registry, never
|
|
112
|
+
* from model output — that is the prompt-injection firebreak, and it is why
|
|
113
|
+
* the widget renders exclusively from this payload and never from the
|
|
114
|
+
* assistant's prose.
|
|
115
|
+
*/
|
|
116
|
+
export interface ProposalPayload {
|
|
117
|
+
proposalId: string;
|
|
118
|
+
actionName: string;
|
|
119
|
+
label: string;
|
|
120
|
+
description: string;
|
|
121
|
+
risk: "low" | "medium" | "high";
|
|
122
|
+
input: Record<string, unknown>;
|
|
123
|
+
inputSchema: unknown;
|
|
124
|
+
expiresAt: string;
|
|
125
|
+
uiConfirmationRequired: boolean;
|
|
126
|
+
}
|
|
127
|
+
export interface ClientOptions {
|
|
128
|
+
/** Runtime WebSocket URL, e.g. `wss://runtime.example.com/v1/ws`. */
|
|
129
|
+
url: string;
|
|
130
|
+
publicKey: string;
|
|
131
|
+
/**
|
|
132
|
+
* Fetches a user token from the host app's own backend, which mints it
|
|
133
|
+
* signed with the app secret.
|
|
134
|
+
*
|
|
135
|
+
* Called on every connect and reconnect rather than once, so a token that
|
|
136
|
+
* expired while the tab was backgrounded is replaced rather than replayed.
|
|
137
|
+
*/
|
|
138
|
+
getUserToken: () => Promise<string>;
|
|
139
|
+
sdkVersion: string;
|
|
140
|
+
onEvent: (event: ClientEvent) => void;
|
|
141
|
+
/**
|
|
142
|
+
* Ask the runtime what each screen costs, reported after every screen
|
|
143
|
+
* update (amendment 67). For building the integration, not for production.
|
|
144
|
+
*/
|
|
145
|
+
debug?: boolean;
|
|
146
|
+
/** Injectable for tests. */
|
|
147
|
+
socketFactory?: (url: string) => WebSocketLike;
|
|
148
|
+
/** Injectable for tests; defaults to exponential backoff with jitter. */
|
|
149
|
+
reconnectDelay?: (attempt: number) => number;
|
|
150
|
+
}
|
|
151
|
+
/** The slice of `WebSocket` this client uses, so tests can supply a fake. */
|
|
152
|
+
export interface WebSocketLike {
|
|
153
|
+
send(data: string): void;
|
|
154
|
+
close(): void;
|
|
155
|
+
onopen: ((event: unknown) => void) | null;
|
|
156
|
+
onclose: ((event: unknown) => void) | null;
|
|
157
|
+
onerror: ((event: unknown) => void) | null;
|
|
158
|
+
onmessage: ((event: {
|
|
159
|
+
data: unknown;
|
|
160
|
+
}) => void) | null;
|
|
161
|
+
}
|
|
162
|
+
export declare class AssistantClient {
|
|
163
|
+
private readonly options;
|
|
164
|
+
private socket;
|
|
165
|
+
private state;
|
|
166
|
+
private attempt;
|
|
167
|
+
private reconnectTimer;
|
|
168
|
+
private heartbeatTimer;
|
|
169
|
+
/** Set when the caller closed deliberately, so we do not reconnect. */
|
|
170
|
+
private stopped;
|
|
171
|
+
private conversationId;
|
|
172
|
+
/** Re-sent after every reconnect, so the runtime is never blind to context. */
|
|
173
|
+
private lastScreen;
|
|
174
|
+
constructor(options: ClientOptions);
|
|
175
|
+
get connectionState(): ConnectionState;
|
|
176
|
+
connect(): Promise<void>;
|
|
177
|
+
close(): void;
|
|
178
|
+
/** Send a user message. Silently dropped when offline — the widget shows the state. */
|
|
179
|
+
sendMessage(text: string, clientMsgId: string): void;
|
|
180
|
+
/**
|
|
181
|
+
* Publish the current screen. Idempotent: a full snapshot that replaces
|
|
182
|
+
* whatever the runtime held.
|
|
183
|
+
*/
|
|
184
|
+
/**
|
|
185
|
+
* Tell the runtime where the user is, or that they are somewhere it does not
|
|
186
|
+
* know about.
|
|
187
|
+
*
|
|
188
|
+
* `null` matters as much as a screen. The host app registers the screens it
|
|
189
|
+
* chooses to; every other page is one the runtime must be told it cannot
|
|
190
|
+
* see. Left unsaid, the runtime keeps the last screen it heard about, and
|
|
191
|
+
* the assistant names a page the user left — which is worse than admitting
|
|
192
|
+
* it does not know, and quietly keeps that screen's scoped actions callable.
|
|
193
|
+
*/
|
|
194
|
+
updateScreen(screen: ScreenContext | null): void;
|
|
195
|
+
/**
|
|
196
|
+
* Answer a command. Must be called for every command received, including
|
|
197
|
+
* failures — the runtime is blocking a turn on this.
|
|
198
|
+
*/
|
|
199
|
+
ackCommand(commandId: string, ok: boolean, result?: unknown, error?: string): void;
|
|
200
|
+
confirmAction(proposalId: string, confirmed: boolean, editedInput?: Record<string, unknown>): void;
|
|
201
|
+
cancelTurn(turnId: string): void;
|
|
202
|
+
/**
|
|
203
|
+
* Ask for a permit to open the voice socket.
|
|
204
|
+
*
|
|
205
|
+
* Requested on the chat socket rather than fetched over HTTP because this
|
|
206
|
+
* session is what the permit is scoped to: the runtime hands back a token
|
|
207
|
+
* bound to the very session actor holding this connection, so the voice
|
|
208
|
+
* socket joins the conversation already in progress instead of starting a
|
|
209
|
+
* second one beside it.
|
|
210
|
+
*
|
|
211
|
+
* Answered by a `voice_token` event, or by an `error` when voice is not
|
|
212
|
+
* available for this app — which is the signal to hide the microphone
|
|
213
|
+
* rather than offer one that fails on the first press.
|
|
214
|
+
*/
|
|
215
|
+
requestVoiceToken(): void;
|
|
216
|
+
private open;
|
|
217
|
+
private handle;
|
|
218
|
+
private send;
|
|
219
|
+
private scheduleReconnect;
|
|
220
|
+
private startHeartbeat;
|
|
221
|
+
private clearHeartbeat;
|
|
222
|
+
private clearTimers;
|
|
223
|
+
private setState;
|
|
224
|
+
private emit;
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../js/src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The WebSocket client (doc 02).
|
|
3
|
+
*
|
|
4
|
+
* One persistent socket per session carries chat, commands, and
|
|
5
|
+
* confirmations. Two properties drive the design:
|
|
6
|
+
*
|
|
7
|
+
* - A frontend action is a tool call that round-trips through the browser, so
|
|
8
|
+
* the runtime pushes a command and blocks until this client acks it. Every
|
|
9
|
+
* command MUST be answered, including on failure — an unanswered command
|
|
10
|
+
* stalls the assistant's turn until the runtime's timeout fires.
|
|
11
|
+
* - Confirming an action needs server-to-client push, which is why this is a
|
|
12
|
+
* socket rather than a request per message.
|
|
13
|
+
*
|
|
14
|
+
* The client owns transport only. It never decides what a command means; the
|
|
15
|
+
* provider does that and hands back a result.
|
|
16
|
+
*/
|
|
17
|
+
import { PROTOCOL_VERSION, } from "@mihe-dev/protocol";
|
|
18
|
+
const MAX_RECONNECT_DELAY_MS = 30_000;
|
|
19
|
+
export class AssistantClient {
|
|
20
|
+
options;
|
|
21
|
+
socket = null;
|
|
22
|
+
state = "idle";
|
|
23
|
+
attempt = 0;
|
|
24
|
+
reconnectTimer = null;
|
|
25
|
+
heartbeatTimer = null;
|
|
26
|
+
/** Set when the caller closed deliberately, so we do not reconnect. */
|
|
27
|
+
stopped = false;
|
|
28
|
+
conversationId = null;
|
|
29
|
+
/** Re-sent after every reconnect, so the runtime is never blind to context. */
|
|
30
|
+
lastScreen = null;
|
|
31
|
+
constructor(options) {
|
|
32
|
+
this.options = options;
|
|
33
|
+
}
|
|
34
|
+
get connectionState() {
|
|
35
|
+
return this.state;
|
|
36
|
+
}
|
|
37
|
+
async connect() {
|
|
38
|
+
if (this.state === "connecting" || this.state === "open")
|
|
39
|
+
return;
|
|
40
|
+
this.stopped = false;
|
|
41
|
+
await this.open();
|
|
42
|
+
}
|
|
43
|
+
close() {
|
|
44
|
+
this.stopped = true;
|
|
45
|
+
this.clearTimers();
|
|
46
|
+
this.socket?.close();
|
|
47
|
+
this.socket = null;
|
|
48
|
+
this.setState("closed");
|
|
49
|
+
}
|
|
50
|
+
/** Send a user message. Silently dropped when offline — the widget shows the state. */
|
|
51
|
+
sendMessage(text, clientMsgId) {
|
|
52
|
+
this.send({ type: "message", data: { text, clientMsgId } });
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Publish the current screen. Idempotent: a full snapshot that replaces
|
|
56
|
+
* whatever the runtime held.
|
|
57
|
+
*/
|
|
58
|
+
/**
|
|
59
|
+
* Tell the runtime where the user is, or that they are somewhere it does not
|
|
60
|
+
* know about.
|
|
61
|
+
*
|
|
62
|
+
* `null` matters as much as a screen. The host app registers the screens it
|
|
63
|
+
* chooses to; every other page is one the runtime must be told it cannot
|
|
64
|
+
* see. Left unsaid, the runtime keeps the last screen it heard about, and
|
|
65
|
+
* the assistant names a page the user left — which is worse than admitting
|
|
66
|
+
* it does not know, and quietly keeps that screen's scoped actions callable.
|
|
67
|
+
*/
|
|
68
|
+
updateScreen(screen) {
|
|
69
|
+
this.lastScreen = screen;
|
|
70
|
+
this.send({ type: "screen_update", data: { screen } });
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Answer a command. Must be called for every command received, including
|
|
74
|
+
* failures — the runtime is blocking a turn on this.
|
|
75
|
+
*/
|
|
76
|
+
ackCommand(commandId, ok, result, error) {
|
|
77
|
+
this.send({
|
|
78
|
+
type: "command_result",
|
|
79
|
+
data: {
|
|
80
|
+
commandId,
|
|
81
|
+
ok,
|
|
82
|
+
result: (result ?? null),
|
|
83
|
+
error: error ?? null,
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
confirmAction(proposalId, confirmed, editedInput) {
|
|
88
|
+
this.send({
|
|
89
|
+
type: "action_confirm",
|
|
90
|
+
data: {
|
|
91
|
+
proposalId,
|
|
92
|
+
confirmed,
|
|
93
|
+
editedInput: (editedInput ?? null),
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
cancelTurn(turnId) {
|
|
98
|
+
this.send({ type: "cancel", data: { turnId } });
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Ask for a permit to open the voice socket.
|
|
102
|
+
*
|
|
103
|
+
* Requested on the chat socket rather than fetched over HTTP because this
|
|
104
|
+
* session is what the permit is scoped to: the runtime hands back a token
|
|
105
|
+
* bound to the very session actor holding this connection, so the voice
|
|
106
|
+
* socket joins the conversation already in progress instead of starting a
|
|
107
|
+
* second one beside it.
|
|
108
|
+
*
|
|
109
|
+
* Answered by a `voice_token` event, or by an `error` when voice is not
|
|
110
|
+
* available for this app — which is the signal to hide the microphone
|
|
111
|
+
* rather than offer one that fails on the first press.
|
|
112
|
+
*/
|
|
113
|
+
requestVoiceToken() {
|
|
114
|
+
this.send({ type: "voice_token_request" });
|
|
115
|
+
}
|
|
116
|
+
// ------------------------------------------------------------- internals
|
|
117
|
+
async open() {
|
|
118
|
+
this.setState(this.attempt === 0 ? "connecting" : "reconnecting");
|
|
119
|
+
let token;
|
|
120
|
+
try {
|
|
121
|
+
token = await this.options.getUserToken();
|
|
122
|
+
}
|
|
123
|
+
catch (cause) {
|
|
124
|
+
if (this.stopped)
|
|
125
|
+
return;
|
|
126
|
+
// The host app's token endpoint is down. Retrying is right — this is
|
|
127
|
+
// usually transient — but the user should be told why it is quiet.
|
|
128
|
+
this.emit({
|
|
129
|
+
type: "error",
|
|
130
|
+
code: "user_token_unavailable",
|
|
131
|
+
message: "Could not get a session token from the app.",
|
|
132
|
+
recoverable: true,
|
|
133
|
+
});
|
|
134
|
+
this.scheduleReconnect();
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
// Closed while the token was on its way. Opening anyway left a socket
|
|
138
|
+
// nothing would ever close: a second live session, which React's
|
|
139
|
+
// StrictMode made on every development mount by connecting, closing and
|
|
140
|
+
// connecting again.
|
|
141
|
+
if (this.stopped)
|
|
142
|
+
return;
|
|
143
|
+
const factory = this.options.socketFactory ??
|
|
144
|
+
((url) => new WebSocket(url));
|
|
145
|
+
const socket = factory(this.options.url);
|
|
146
|
+
this.socket = socket;
|
|
147
|
+
socket.onopen = () => {
|
|
148
|
+
const auth = {
|
|
149
|
+
type: "auth",
|
|
150
|
+
data: {
|
|
151
|
+
publicKey: this.options.publicKey,
|
|
152
|
+
userToken: token,
|
|
153
|
+
sdkVersion: this.options.sdkVersion,
|
|
154
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
155
|
+
conversationId: this.conversationId,
|
|
156
|
+
...(this.options.debug ? { debug: true } : {}),
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
socket.send(JSON.stringify(auth));
|
|
160
|
+
};
|
|
161
|
+
socket.onmessage = (event) => {
|
|
162
|
+
if (typeof event.data !== "string")
|
|
163
|
+
return;
|
|
164
|
+
let message;
|
|
165
|
+
try {
|
|
166
|
+
message = JSON.parse(event.data);
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
this.handle(message);
|
|
172
|
+
};
|
|
173
|
+
socket.onclose = () => {
|
|
174
|
+
this.clearTimers();
|
|
175
|
+
if (this.stopped) {
|
|
176
|
+
this.setState("closed");
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
this.scheduleReconnect();
|
|
180
|
+
};
|
|
181
|
+
socket.onerror = () => {
|
|
182
|
+
// `onclose` always follows, and that is where reconnect is handled.
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
handle(message) {
|
|
186
|
+
switch (message.type) {
|
|
187
|
+
case "auth_ok": {
|
|
188
|
+
this.attempt = 0;
|
|
189
|
+
this.conversationId = message.data.conversationId;
|
|
190
|
+
this.emit({
|
|
191
|
+
type: "voice_available",
|
|
192
|
+
available: message.data.voiceAvailable ?? false,
|
|
193
|
+
});
|
|
194
|
+
// Only when the runtime actually sent one. An older runtime omits the
|
|
195
|
+
// field, and overwriting a good name with "" would rename the panel to
|
|
196
|
+
// nothing — worse than leaving the SDK's own default in place.
|
|
197
|
+
if (message.data.assistantName) {
|
|
198
|
+
this.emit({ type: "assistant_name", name: message.data.assistantName });
|
|
199
|
+
}
|
|
200
|
+
this.emit({
|
|
201
|
+
type: "launcher_icon",
|
|
202
|
+
url: message.data.launcherIconUrl ?? null,
|
|
203
|
+
});
|
|
204
|
+
this.emit({ type: "widget_settings", settings: message.data.widget ?? null });
|
|
205
|
+
this.setState("open");
|
|
206
|
+
this.startHeartbeat(message.data.heartbeatIntervalMs);
|
|
207
|
+
// The runtime replays nothing, so re-publish context immediately.
|
|
208
|
+
if (this.lastScreen)
|
|
209
|
+
this.updateScreen(this.lastScreen);
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
case "auth_error": {
|
|
213
|
+
this.emit({
|
|
214
|
+
type: "error",
|
|
215
|
+
code: message.data.code,
|
|
216
|
+
message: message.data.message,
|
|
217
|
+
// A bad key or an unsupported protocol version will not fix itself.
|
|
218
|
+
recoverable: false,
|
|
219
|
+
});
|
|
220
|
+
this.stopped = true;
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
case "auth_expired": {
|
|
224
|
+
// Re-authenticate in place rather than tearing down the socket.
|
|
225
|
+
void this.options
|
|
226
|
+
.getUserToken()
|
|
227
|
+
.then((token) => this.send({
|
|
228
|
+
type: "auth",
|
|
229
|
+
data: {
|
|
230
|
+
publicKey: this.options.publicKey,
|
|
231
|
+
userToken: token,
|
|
232
|
+
sdkVersion: this.options.sdkVersion,
|
|
233
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
234
|
+
conversationId: this.conversationId,
|
|
235
|
+
...(this.options.debug ? { debug: true } : {}),
|
|
236
|
+
},
|
|
237
|
+
}))
|
|
238
|
+
.catch(() => this.socket?.close());
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
case "turn_start":
|
|
242
|
+
this.emit({ type: "turn_start", turnId: message.data.turnId });
|
|
243
|
+
break;
|
|
244
|
+
case "delta":
|
|
245
|
+
this.emit({
|
|
246
|
+
type: "delta",
|
|
247
|
+
turnId: message.data.turnId,
|
|
248
|
+
text: message.data.text,
|
|
249
|
+
});
|
|
250
|
+
break;
|
|
251
|
+
case "complete":
|
|
252
|
+
this.emit({
|
|
253
|
+
type: "complete",
|
|
254
|
+
turnId: message.data.turnId,
|
|
255
|
+
message: message.data.message,
|
|
256
|
+
sources: message.data.sources ?? [],
|
|
257
|
+
});
|
|
258
|
+
break;
|
|
259
|
+
case "command":
|
|
260
|
+
this.emit({
|
|
261
|
+
type: "command",
|
|
262
|
+
commandId: message.data.commandId,
|
|
263
|
+
command: message.data.command,
|
|
264
|
+
});
|
|
265
|
+
break;
|
|
266
|
+
case "action_proposal":
|
|
267
|
+
this.emit({
|
|
268
|
+
type: "proposal",
|
|
269
|
+
proposal: message.data,
|
|
270
|
+
});
|
|
271
|
+
break;
|
|
272
|
+
case "action_status":
|
|
273
|
+
this.emit({
|
|
274
|
+
type: "action_status",
|
|
275
|
+
proposalId: message.data.proposalId,
|
|
276
|
+
status: message.data.status,
|
|
277
|
+
result: message.data.result ?? undefined,
|
|
278
|
+
error: message.data.error ?? undefined,
|
|
279
|
+
});
|
|
280
|
+
break;
|
|
281
|
+
case "error":
|
|
282
|
+
this.emit({
|
|
283
|
+
type: "error",
|
|
284
|
+
code: message.data.code,
|
|
285
|
+
message: message.data.message,
|
|
286
|
+
recoverable: message.data.recoverable,
|
|
287
|
+
});
|
|
288
|
+
break;
|
|
289
|
+
case "voice_token":
|
|
290
|
+
this.emit({
|
|
291
|
+
type: "voice_token",
|
|
292
|
+
token: message.data.token,
|
|
293
|
+
expiresAt: message.data.expiresAt,
|
|
294
|
+
});
|
|
295
|
+
break;
|
|
296
|
+
case "context_report":
|
|
297
|
+
this.emit({ type: "context_report", report: message.data });
|
|
298
|
+
break;
|
|
299
|
+
case "pong":
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
send(message) {
|
|
304
|
+
if (this.state !== "open" && message.type !== "auth")
|
|
305
|
+
return;
|
|
306
|
+
try {
|
|
307
|
+
this.socket?.send(JSON.stringify(message));
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
// A send on a closing socket throws; `onclose` handles recovery.
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
scheduleReconnect() {
|
|
314
|
+
this.setState("reconnecting");
|
|
315
|
+
const delay = this.options.reconnectDelay?.(this.attempt) ?? backoff(this.attempt);
|
|
316
|
+
this.attempt += 1;
|
|
317
|
+
this.reconnectTimer = setTimeout(() => void this.open(), delay);
|
|
318
|
+
}
|
|
319
|
+
startHeartbeat(intervalMs) {
|
|
320
|
+
this.clearHeartbeat();
|
|
321
|
+
this.heartbeatTimer = setInterval(() => {
|
|
322
|
+
this.send({ type: "ping" });
|
|
323
|
+
}, intervalMs);
|
|
324
|
+
}
|
|
325
|
+
clearHeartbeat() {
|
|
326
|
+
if (this.heartbeatTimer !== null) {
|
|
327
|
+
clearInterval(this.heartbeatTimer);
|
|
328
|
+
this.heartbeatTimer = null;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
clearTimers() {
|
|
332
|
+
this.clearHeartbeat();
|
|
333
|
+
if (this.reconnectTimer !== null) {
|
|
334
|
+
clearTimeout(this.reconnectTimer);
|
|
335
|
+
this.reconnectTimer = null;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
setState(state) {
|
|
339
|
+
if (this.state === state)
|
|
340
|
+
return;
|
|
341
|
+
this.state = state;
|
|
342
|
+
this.emit({ type: "state", state });
|
|
343
|
+
}
|
|
344
|
+
emit(event) {
|
|
345
|
+
this.options.onEvent(event);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Exponential backoff with jitter, capped.
|
|
350
|
+
*
|
|
351
|
+
* Jitter matters more than it looks: without it, every tab of every customer
|
|
352
|
+
* reconnects in lockstep after a runtime restart and stampedes it.
|
|
353
|
+
*/
|
|
354
|
+
function backoff(attempt) {
|
|
355
|
+
const base = Math.min(1000 * 2 ** attempt, MAX_RECONNECT_DELAY_MS);
|
|
356
|
+
return base / 2 + Math.random() * (base / 2);
|
|
357
|
+
}
|
|
358
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../js/src/client.ts"],"names":[],"mappings":"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"}
|