@mihe-dev/js 0.0.0-stage → 0.2.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/card-view.d.ts +79 -0
- package/dist/card-view.d.ts.map +1 -0
- package/dist/card-view.js +99 -0
- package/dist/card-view.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 +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/mihe.d.ts +364 -0
- package/dist/mihe.d.ts.map +1 -0
- package/dist/mihe.iife.min.js +217 -0
- package/dist/mihe.iife.min.js.map +7 -0
- package/dist/mihe.js +758 -0
- package/dist/mihe.js.map +1 -0
- package/dist/mihe.min.js +217 -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 +17 -0
- package/dist/widget/card.d.ts.map +1 -0
- package/dist/widget/card.js +31 -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 +92 -0
- package/dist/widget/orb.d.ts.map +1 -0
- package/dist/widget/orb.js +500 -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 +240 -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 +192 -0
- package/dist/widget/styles.js.map +1 -0
- package/package.json +43 -4
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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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Executing the commands the runtime sends.
|
|
3
|
+
*
|
|
4
|
+
* Every command names a registered target — a route the runtime resolved from
|
|
5
|
+
* its screen catalogue, or a component key the app declared. Nothing here
|
|
6
|
+
* takes a CSS selector or a coordinate, so there is no path by which the model
|
|
7
|
+
* drives the UI directly (spec §5.2).
|
|
8
|
+
*
|
|
9
|
+
* Every branch returns a result, including failures, because the runtime is
|
|
10
|
+
* blocking a turn on the ack and the model needs to learn the truth. Reporting
|
|
11
|
+
* "the element was not on screen" is far better than reporting nothing.
|
|
12
|
+
*/
|
|
13
|
+
import type { AssistantCommand } from "@mihe-dev/protocol";
|
|
14
|
+
import type { HighlightEngine } from "./highlight.js";
|
|
15
|
+
import type { AssistantStore, QueryParamDeclaration } from "./store.js";
|
|
16
|
+
/** When a frontend action is warned about as slow. */
|
|
17
|
+
export declare const ACTION_SLOW_MS = 5000;
|
|
18
|
+
/**
|
|
19
|
+
* How long the runtime waits for a command's answer (`COMMAND_ACK_TIMEOUT`
|
|
20
|
+
* in the runtime's session.rs). Past it, the assistant is told the command
|
|
21
|
+
* failed.
|
|
22
|
+
*/
|
|
23
|
+
export declare const RUNTIME_ACK_WAIT_MS = 10000;
|
|
24
|
+
export interface CommandResult {
|
|
25
|
+
ok: boolean;
|
|
26
|
+
result?: unknown;
|
|
27
|
+
error?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface CommandContext {
|
|
30
|
+
store: AssistantStore;
|
|
31
|
+
highlighter: HighlightEngine;
|
|
32
|
+
/**
|
|
33
|
+
* How the host app changes route. Supplied by the customer, because only
|
|
34
|
+
* they know whether that is Next.js's router, React Router, or something
|
|
35
|
+
* else. Defaults to a full page load, which works everywhere and is
|
|
36
|
+
* noticeably worse — the docs should push people to wire this up.
|
|
37
|
+
*/
|
|
38
|
+
navigate: (route: string) => void;
|
|
39
|
+
/**
|
|
40
|
+
* Resolves once the screen at `route` has published its context to the
|
|
41
|
+
* runtime, or `false` if it has not done so within the timeout.
|
|
42
|
+
*
|
|
43
|
+
* Navigating is the one command whose effects are not finished when the
|
|
44
|
+
* function returns: the router swaps the tree, React mounts the destination,
|
|
45
|
+
* its hooks register, and only then does the new context travel. The runtime
|
|
46
|
+
* re-reads the screen after every tool call to decide what the next step may
|
|
47
|
+
* do, so acking before that lands would tell it the user is still on the
|
|
48
|
+
* screen they just left — and the action they navigated *for* would be
|
|
49
|
+
* filtered out as off-screen.
|
|
50
|
+
*
|
|
51
|
+
* Optional so a hand-built context still works; the provider always supplies
|
|
52
|
+
* it.
|
|
53
|
+
*/
|
|
54
|
+
screenPublished?: (route: string, options?: {
|
|
55
|
+
fresh?: boolean;
|
|
56
|
+
}) => Promise<boolean>;
|
|
57
|
+
/**
|
|
58
|
+
* Resolves once a published screen shows `controlKey` set to `value`, or
|
|
59
|
+
* `false` if none does within the timeout. A switch is acked only then, for
|
|
60
|
+
* `screenPublished`'s reason: the runtime's next step reads the screen.
|
|
61
|
+
*/
|
|
62
|
+
viewPublished?: (controlKey: string, value: string) => Promise<boolean>;
|
|
63
|
+
/** Opens a registered modal, when the host app has modals to open. */
|
|
64
|
+
/** Return `false` when the key is not one this app can open. */
|
|
65
|
+
openModal?: (modalKey: string) => void | boolean;
|
|
66
|
+
}
|
|
67
|
+
/** Why a set of search parameters is not what the table declared, or null. */
|
|
68
|
+
export declare function checkQueryParams(declared: QueryParamDeclaration[], params: Record<string, string>): string | null;
|
|
69
|
+
export declare function executeCommand(command: AssistantCommand, ctx: CommandContext): Promise<CommandResult>;
|
|
70
|
+
//# sourceMappingURL=commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../js/src/commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAY,MAAM,SAAS,CAAC;AAE/E,sDAAsD;AACtD,eAAO,MAAM,cAAc,OAAQ,CAAC;AAEpC;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,QAAS,CAAC;AAE1C,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,cAAc,CAAC;IACtB,WAAW,EAAE,eAAe,CAAC;IAC7B;;;;;OAKG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC;;;;;;;;;;;;;;OAcG;IACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACrF;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACxE,sEAAsE;IACtE,gEAAgE;IAChE,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC;CAClD;AAED,8EAA8E;AAC9E,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,qBAAqB,EAAE,EACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,MAAM,GAAG,IAAI,CAgBf;AAqBD,wBAAsB,cAAc,CAClC,OAAO,EAAE,gBAAgB,EACzB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,aAAa,CAAC,CAgPxB"}
|