bunnyquery 1.10.12 → 1.11.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/README.md +23 -11
- package/bunnyquery.js +139 -62
- package/dist/engine.cjs +78 -23
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.d.mts +137 -35
- package/dist/engine.d.ts +137 -35
- package/dist/engine.mjs +78 -23
- package/dist/engine.mjs.map +1 -1
- package/package.json +1 -1
- package/src/engine/budget.ts +13 -3
- package/src/engine/config.ts +249 -39
- package/src/engine/history.ts +1 -1
- package/src/engine/requests.ts +25 -17
- package/src/engine/session.ts +8 -9
- package/src/engine/sse.ts +1 -1
package/dist/engine.d.mts
CHANGED
|
@@ -54,13 +54,22 @@ declare function parseAttachmentContent(file: File, name: string, mime?: string)
|
|
|
54
54
|
* The engine is framework- and transport-agnostic: it never imports a skapi
|
|
55
55
|
* instance or `import.meta.env`. Each consumer calls `configureChatEngine()`
|
|
56
56
|
* once at startup to inject the skapi transport functions, the MCP base URL,
|
|
57
|
-
* and (optionally) the `poll` value to attach to
|
|
57
|
+
* and (optionally) the `poll` value to attach to every forwarded request.
|
|
58
58
|
*
|
|
59
59
|
* Why `poll` is configurable: agent.vue uses the npm-bundled skapi-js and OMITS
|
|
60
|
-
* `poll` (its
|
|
60
|
+
* `poll` (its request auto-resolves with the final body), whereas
|
|
61
61
|
* the BunnyQuery widget uses the deployed skapi-js@latest and must pass
|
|
62
62
|
* `poll: 0` to get the early ack + a manual `.poll()` handle (needed for queued-
|
|
63
63
|
* send cancel). So the request builders include `poll` only when it is set.
|
|
64
|
+
*
|
|
65
|
+
* THE TRANSPORT HAS TWO SPELLINGS, and a host may inject either. skapi-js renamed
|
|
66
|
+
* clientSecretRequest and its companions to the forwardRequest family, and kept
|
|
67
|
+
* every old name working. So this config accepts both families of keys, prefers
|
|
68
|
+
* the new one, and every call goes through the resolveForwardRequest* functions
|
|
69
|
+
* below, which are the only code in the engine that knows there are two. The old
|
|
70
|
+
* keys are not a courtesy: this package is pinned with a caret range, so a host
|
|
71
|
+
* written against an earlier release takes this one on its next install with
|
|
72
|
+
* nothing but the old keys injected, and it has to keep working unchanged.
|
|
64
73
|
*/
|
|
65
74
|
|
|
66
75
|
/**
|
|
@@ -111,15 +120,74 @@ interface LiveStreamUpdate {
|
|
|
111
120
|
poll: number;
|
|
112
121
|
};
|
|
113
122
|
}
|
|
123
|
+
/** The finalize call, identical under its new and its deprecated key. */
|
|
124
|
+
type ForwardRequestFinalizeFn = (requestId: string, data: any, options: {
|
|
125
|
+
url: string;
|
|
126
|
+
method: string;
|
|
127
|
+
service?: string;
|
|
128
|
+
owner?: string;
|
|
129
|
+
}) => Promise<any>;
|
|
130
|
+
/** The chunk read-back call, identical under its new and its deprecated key. */
|
|
131
|
+
type ForwardRequestStreamFn = (requestId: string, options: {
|
|
132
|
+
url: string;
|
|
133
|
+
method: string;
|
|
134
|
+
onStream?: (chunk: string, seq: number) => void;
|
|
135
|
+
since?: number;
|
|
136
|
+
poll?: number;
|
|
137
|
+
service?: string;
|
|
138
|
+
owner?: string;
|
|
139
|
+
}) => Promise<any>;
|
|
114
140
|
interface ChatEngineConfig {
|
|
115
|
-
/**
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
141
|
+
/**
|
|
142
|
+
* skapi.forwardRequest, bound to the consumer's skapi instance.
|
|
143
|
+
*
|
|
144
|
+
* The engine always calls it as `forwardRequest(null, opts)`. Null because it
|
|
145
|
+
* never has a form: every request it builds carries its whole body in
|
|
146
|
+
* `opts.data`, the `_skapi_*` directives included, and the stored secret is
|
|
147
|
+
* named with `secretName`.
|
|
148
|
+
*
|
|
149
|
+
* INJECT IT ONLY FROM AN SKAPI-JS THAT HAS THE WHOLE FORWARDREQUEST FAMILY. An
|
|
150
|
+
* older skapi-js also has a method called forwardRequest, taking the same two
|
|
151
|
+
* arguments, and it is a different thing entirely: the retired streaming
|
|
152
|
+
* forwarder, which posts to another endpoint and never queues, so a chat turn
|
|
153
|
+
* handed to it goes somewhere else and comes back as nothing the engine can
|
|
154
|
+
* read. A host that cannot be sure which skapi-js it holds (the widget, which
|
|
155
|
+
* is given the embedder's) decides by a companion only the new SDK has,
|
|
156
|
+
* `forwardRequestHistory`, and never by this method's presence.
|
|
157
|
+
*
|
|
158
|
+
* This or the deprecated `clientSecretRequest` is required; with both, this
|
|
159
|
+
* one is used. See resolveForwardRequest.
|
|
160
|
+
*/
|
|
161
|
+
forwardRequest?: (form: any, opts: any) => Promise<any>;
|
|
162
|
+
/**
|
|
163
|
+
* skapi.forwardRequestHistory, bound to the consumer's skapi instance. This or
|
|
164
|
+
* the deprecated `clientSecretRequestHistory` is required; with both, this one
|
|
165
|
+
* is used. Same arguments either way.
|
|
166
|
+
*/
|
|
167
|
+
forwardRequestHistory?: (params: any, fetchOptions: any) => Promise<any>;
|
|
168
|
+
/**
|
|
169
|
+
* @deprecated Inject `forwardRequest` instead.
|
|
170
|
+
*
|
|
171
|
+
* skapi.clientSecretRequest, bound to the consumer's skapi instance. Still
|
|
172
|
+
* accepted as a COMPATIBILITY CONTRACT, not a leftover: a host that injects
|
|
173
|
+
* only the old keys must keep working on this release. Used only when
|
|
174
|
+
* `forwardRequest` is absent, and handed the engine's request with `secretName`
|
|
175
|
+
* moved back to `clientSecretName`, which is exactly the request it was handed
|
|
176
|
+
* before the rename (see resolveForwardRequest).
|
|
177
|
+
*/
|
|
178
|
+
clientSecretRequest?: (opts: any) => Promise<any>;
|
|
179
|
+
/**
|
|
180
|
+
* @deprecated Inject `forwardRequestHistory` instead.
|
|
181
|
+
*
|
|
182
|
+
* skapi.clientSecretRequestHistory, bound to the consumer's skapi instance.
|
|
183
|
+
* Kept for the same compatibility contract as `clientSecretRequest`, and used
|
|
184
|
+
* only when `forwardRequestHistory` is absent.
|
|
185
|
+
*/
|
|
186
|
+
clientSecretRequestHistory?: (params: any, fetchOptions: any) => Promise<any>;
|
|
119
187
|
/** MCP server base URL (prod vs dev resolved by the consumer). */
|
|
120
188
|
mcpBaseUrl: string;
|
|
121
189
|
/**
|
|
122
|
-
* Value to attach as `poll` on every
|
|
190
|
+
* Value to attach as `poll` on every forwarded request. When `undefined`
|
|
123
191
|
* the `poll` key is omitted entirely (agent.vue). BunnyQuery sets `0`.
|
|
124
192
|
*/
|
|
125
193
|
poll?: number;
|
|
@@ -198,9 +266,10 @@ interface ChatEngineConfig {
|
|
|
198
266
|
* answer. So it stays off until the worker is deployed, then flips per
|
|
199
267
|
* environment.
|
|
200
268
|
*
|
|
201
|
-
* It also needs `
|
|
202
|
-
*
|
|
203
|
-
*
|
|
269
|
+
* It also needs `forwardRequestFinalize` below (or its deprecated name,
|
|
270
|
+
* `clientSecretRequestFinalize`): without it a streamed turn is never
|
|
271
|
+
* finalized, so its row keeps a status and no body forever and a later
|
|
272
|
+
* history load shows the question with an empty answer.
|
|
204
273
|
*/
|
|
205
274
|
liveStreaming?: boolean;
|
|
206
275
|
/**
|
|
@@ -218,25 +287,30 @@ interface ChatEngineConfig {
|
|
|
218
287
|
*/
|
|
219
288
|
liveStreamingRealtime?: boolean;
|
|
220
289
|
/**
|
|
221
|
-
* skapi.
|
|
290
|
+
* skapi.forwardRequestFinalize, bound to the consumer's skapi instance.
|
|
222
291
|
* Stores the version of a streamed turn that history should keep (the engine
|
|
223
292
|
* sends the ASSEMBLED provider body, so history reads it exactly as it reads
|
|
224
293
|
* a buffered turn) and releases that request's chunks. Optional: a host
|
|
225
294
|
* without it can still stream, it just leaves the chunks and an empty row.
|
|
295
|
+
* Takes precedence over the deprecated `clientSecretRequestFinalize`.
|
|
226
296
|
*/
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
297
|
+
forwardRequestFinalize?: ForwardRequestFinalizeFn;
|
|
298
|
+
/**
|
|
299
|
+
* @deprecated Inject `forwardRequestFinalize` instead.
|
|
300
|
+
*
|
|
301
|
+
* skapi.clientSecretRequestFinalize, the same call under its old name. Kept
|
|
302
|
+
* for the compatibility contract `clientSecretRequest` describes, and used
|
|
303
|
+
* only when `forwardRequestFinalize` is absent.
|
|
304
|
+
*/
|
|
305
|
+
clientSecretRequestFinalize?: ForwardRequestFinalizeFn;
|
|
233
306
|
/**
|
|
234
|
-
* skapi.
|
|
307
|
+
* skapi.forwardRequestStream, bound to the consumer's skapi instance. Takes
|
|
308
|
+
* precedence over the deprecated `clientSecretRequestStream`.
|
|
235
309
|
*
|
|
236
310
|
* THE SECOND HALF OF THE DURABILITY GUARANTEE, and without it a streamed turn
|
|
237
311
|
* is only as durable as the tab that started it. A streamed row settles with a
|
|
238
312
|
* status and NO body; the answer is stored as chunks until
|
|
239
|
-
*
|
|
313
|
+
* forwardRequestFinalize says what to keep. A row that settles while no
|
|
240
314
|
* poll is attached (the user closed the tab, a mobile browser discarded it,
|
|
241
315
|
* the device slept and the interval stopped) is therefore never finalized, and
|
|
242
316
|
* a later history load sees a terminal row with no body and used to emit no
|
|
@@ -258,15 +332,16 @@ interface ChatEngineConfig {
|
|
|
258
332
|
* NOTE THAT THIS HOOK, NOT `liveStreaming`, IS WHAT ARMS RECOVERY. See
|
|
259
333
|
* streamRecoveryEnabled() below for why the two decisions are separate.
|
|
260
334
|
*/
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
335
|
+
forwardRequestStream?: ForwardRequestStreamFn;
|
|
336
|
+
/**
|
|
337
|
+
* @deprecated Inject `forwardRequestStream` instead.
|
|
338
|
+
*
|
|
339
|
+
* skapi.clientSecretRequestStream, the same call under its old name. Kept for
|
|
340
|
+
* the compatibility contract `clientSecretRequest` describes, and used only
|
|
341
|
+
* when `forwardRequestStream` is absent. It arms recovery exactly as the new
|
|
342
|
+
* key does.
|
|
343
|
+
*/
|
|
344
|
+
clientSecretRequestStream?: ForwardRequestStreamFn;
|
|
270
345
|
/**
|
|
271
346
|
* Observation hook for a live-streaming turn, called at most once per paint
|
|
272
347
|
* (about once a second) plus once when the turn settles.
|
|
@@ -286,7 +361,8 @@ interface ChatEngineConfig {
|
|
|
286
361
|
* reader is injected.
|
|
287
362
|
*
|
|
288
363
|
* There is no need to set it to turn recovery ON: injecting
|
|
289
|
-
* `
|
|
364
|
+
* `forwardRequestStream` (or its deprecated name, `clientSecretRequestStream`)
|
|
365
|
+
* is what arms it (see streamRecoveryEnabled).
|
|
290
366
|
* This exists only as the way back out for a host that wants byte-for-byte the
|
|
291
367
|
* pre-recovery rendering of a terminal-but-empty row - no bubble, no marker, no
|
|
292
368
|
* chunk read - while keeping the reader available for its own use. Omit it and
|
|
@@ -333,6 +409,12 @@ declare function chatEngineConfig(): ChatEngineConfig;
|
|
|
333
409
|
* whose body the worker never managed to spill). That read finds no chunks, the
|
|
334
410
|
* bubble is dropped, and the list looks exactly as it did before. Set
|
|
335
411
|
* `streamRecovery: false` to opt out of even that.
|
|
412
|
+
*
|
|
413
|
+
* The reader is asked for through resolveForwardRequestStream, so either spelling of
|
|
414
|
+
* it arms recovery: `forwardRequestStream`, or the deprecated
|
|
415
|
+
* `clientSecretRequestStream` a host written before the rename still injects. Asked
|
|
416
|
+
* for the new key alone, this would quietly disarm recovery for every such host on
|
|
417
|
+
* its next install, which is the stranding described above arriving by a rename.
|
|
336
418
|
*/
|
|
337
419
|
declare function streamRecoveryEnabled(): boolean;
|
|
338
420
|
/**
|
|
@@ -344,9 +426,10 @@ declare function streamRecoveryEnabled(): boolean;
|
|
|
344
426
|
* streamed turn carries TWO `stream` flags: skapi's (relay the destination's bytes
|
|
345
427
|
* into the chunk table) and the DESTINATION's own field inside `data`, which
|
|
346
428
|
* BunnyQuery is the party that sets, because skapi relays bytes and knows no
|
|
347
|
-
* vendor.
|
|
348
|
-
* THE KEYS IN THAT SCHEMA, so an skapi-js predating the feature
|
|
349
|
-
* `stream` - it silently DROPS it. What
|
|
429
|
+
* vendor. skapi validates the request's params against a schema and KEEPS ONLY
|
|
430
|
+
* THE KEYS IN THAT SCHEMA, so an skapi-js predating the feature (whose only door
|
|
431
|
+
* was clientSecretRequest) does not reject `stream` - it silently DROPS it. What
|
|
432
|
+
* ships is then the exact split
|
|
350
433
|
* chatStreamWiring exists to make impossible: the destination is asked to answer in
|
|
351
434
|
* SSE frames, skapi waits and stores the whole transcript on the row, and
|
|
352
435
|
* extractClaudeText / extractOpenAIText read a wall of `data: {...}` lines where a
|
|
@@ -372,6 +455,25 @@ declare function streamRecoveryEnabled(): boolean;
|
|
|
372
455
|
* able to fetch it. There is no cheap DIRECT probe of the schema: the only way to
|
|
373
456
|
* learn that `stream` was dropped is to send a real request and read an empty
|
|
374
457
|
* answer, which is the bug itself.
|
|
458
|
+
*
|
|
459
|
+
* EITHER SPELLING OF THE PAIR ANSWERS YES, and it has to be a whole pair. skapi-js
|
|
460
|
+
* renamed the two to forwardRequestStream and forwardRequestFinalize and kept the old
|
|
461
|
+
* names as aliases, so three SDKs are out there: the renamed one carries both pairs,
|
|
462
|
+
* one from the streaming release up to the rename carries only the old pair, and one
|
|
463
|
+
* that predates streaming carries neither. Accepting the old pair is what keeps an
|
|
464
|
+
* embed page pinned between the two releases streaming; accepting the new pair is
|
|
465
|
+
* what keeps this answering yes once the old aliases are finally removed. The
|
|
466
|
+
* reasoning above holds for both: each pair shipped in the same change as, or after,
|
|
467
|
+
* the `stream` key, and each IS the capability rather than a proxy for it. A mixed
|
|
468
|
+
* half of each is not a pair and is refused, because no real SDK has that shape and
|
|
469
|
+
* the engine would still be missing one half of the protocol under the name it asks
|
|
470
|
+
* for.
|
|
471
|
+
*
|
|
472
|
+
* A presence probe is safe for these two names in a way it is NOT for forwardRequest
|
|
473
|
+
* itself: no skapi-js ever shipped a forwardRequestStream or forwardRequestFinalize
|
|
474
|
+
* that meant something else, while an older forwardRequest exists and is the retired
|
|
475
|
+
* streaming forwarder. That is why the widget's family probe asks for
|
|
476
|
+
* forwardRequestHistory instead.
|
|
375
477
|
*/
|
|
376
478
|
declare function skapiSupportsStreaming(sk: any): boolean;
|
|
377
479
|
|
|
@@ -1598,7 +1700,7 @@ declare function buildAiAgentValue(platform: string | null | undefined, model?:
|
|
|
1598
1700
|
* buffered call would have returned out.
|
|
1599
1701
|
*
|
|
1600
1702
|
* WHY THIS FILE EXISTS, AND WHY IT IS HERE AND NOT IN SKAPI.
|
|
1601
|
-
* skapi's
|
|
1703
|
+
* skapi's forwardRequest is a byte relay. On a streamed turn the worker reads
|
|
1602
1704
|
* the destination's response incrementally and appends the raw bytes to a chunk
|
|
1603
1705
|
* table; it settles the polling row with STATUS ONLY, no body, because the content
|
|
1604
1706
|
* lives in the chunks. skapi therefore does not know that Anthropic or OpenAI
|
|
@@ -1850,7 +1952,7 @@ declare const DEFAULT_OPENAI_MODEL = "gpt-5.6-luna";
|
|
|
1850
1952
|
* that drifts when someone edits one arm.
|
|
1851
1953
|
*/
|
|
1852
1954
|
type ChatStreamWiring = {
|
|
1853
|
-
/** Spread into the
|
|
1955
|
+
/** Spread into the forwardRequest OPTIONS (skapi's relay switch). `realtime`
|
|
1854
1956
|
* belongs here and never in `body`: it is skapi's, not the destination's. */
|
|
1855
1957
|
transport: {
|
|
1856
1958
|
stream?: true;
|
|
@@ -3416,7 +3518,7 @@ declare function typewriterResumeIndex(painted: string, fullText: string, region
|
|
|
3416
3518
|
* because the row's status describes the destination's request and not our read
|
|
3417
3519
|
* of it. Anything short of a finished answer leaves the chunks exactly where they
|
|
3418
3520
|
* are, which is what they are for: the turn stays re-readable through
|
|
3419
|
-
*
|
|
3521
|
+
* forwardRequestStream and a later load recovers it in full.
|
|
3420
3522
|
*
|
|
3421
3523
|
* `unframed` is the one exception to needing a terminal event, and it is not a
|
|
3422
3524
|
* loophole: bytes that were never SSE carry no events at all and none is ever
|
package/dist/engine.d.ts
CHANGED
|
@@ -54,13 +54,22 @@ declare function parseAttachmentContent(file: File, name: string, mime?: string)
|
|
|
54
54
|
* The engine is framework- and transport-agnostic: it never imports a skapi
|
|
55
55
|
* instance or `import.meta.env`. Each consumer calls `configureChatEngine()`
|
|
56
56
|
* once at startup to inject the skapi transport functions, the MCP base URL,
|
|
57
|
-
* and (optionally) the `poll` value to attach to
|
|
57
|
+
* and (optionally) the `poll` value to attach to every forwarded request.
|
|
58
58
|
*
|
|
59
59
|
* Why `poll` is configurable: agent.vue uses the npm-bundled skapi-js and OMITS
|
|
60
|
-
* `poll` (its
|
|
60
|
+
* `poll` (its request auto-resolves with the final body), whereas
|
|
61
61
|
* the BunnyQuery widget uses the deployed skapi-js@latest and must pass
|
|
62
62
|
* `poll: 0` to get the early ack + a manual `.poll()` handle (needed for queued-
|
|
63
63
|
* send cancel). So the request builders include `poll` only when it is set.
|
|
64
|
+
*
|
|
65
|
+
* THE TRANSPORT HAS TWO SPELLINGS, and a host may inject either. skapi-js renamed
|
|
66
|
+
* clientSecretRequest and its companions to the forwardRequest family, and kept
|
|
67
|
+
* every old name working. So this config accepts both families of keys, prefers
|
|
68
|
+
* the new one, and every call goes through the resolveForwardRequest* functions
|
|
69
|
+
* below, which are the only code in the engine that knows there are two. The old
|
|
70
|
+
* keys are not a courtesy: this package is pinned with a caret range, so a host
|
|
71
|
+
* written against an earlier release takes this one on its next install with
|
|
72
|
+
* nothing but the old keys injected, and it has to keep working unchanged.
|
|
64
73
|
*/
|
|
65
74
|
|
|
66
75
|
/**
|
|
@@ -111,15 +120,74 @@ interface LiveStreamUpdate {
|
|
|
111
120
|
poll: number;
|
|
112
121
|
};
|
|
113
122
|
}
|
|
123
|
+
/** The finalize call, identical under its new and its deprecated key. */
|
|
124
|
+
type ForwardRequestFinalizeFn = (requestId: string, data: any, options: {
|
|
125
|
+
url: string;
|
|
126
|
+
method: string;
|
|
127
|
+
service?: string;
|
|
128
|
+
owner?: string;
|
|
129
|
+
}) => Promise<any>;
|
|
130
|
+
/** The chunk read-back call, identical under its new and its deprecated key. */
|
|
131
|
+
type ForwardRequestStreamFn = (requestId: string, options: {
|
|
132
|
+
url: string;
|
|
133
|
+
method: string;
|
|
134
|
+
onStream?: (chunk: string, seq: number) => void;
|
|
135
|
+
since?: number;
|
|
136
|
+
poll?: number;
|
|
137
|
+
service?: string;
|
|
138
|
+
owner?: string;
|
|
139
|
+
}) => Promise<any>;
|
|
114
140
|
interface ChatEngineConfig {
|
|
115
|
-
/**
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
141
|
+
/**
|
|
142
|
+
* skapi.forwardRequest, bound to the consumer's skapi instance.
|
|
143
|
+
*
|
|
144
|
+
* The engine always calls it as `forwardRequest(null, opts)`. Null because it
|
|
145
|
+
* never has a form: every request it builds carries its whole body in
|
|
146
|
+
* `opts.data`, the `_skapi_*` directives included, and the stored secret is
|
|
147
|
+
* named with `secretName`.
|
|
148
|
+
*
|
|
149
|
+
* INJECT IT ONLY FROM AN SKAPI-JS THAT HAS THE WHOLE FORWARDREQUEST FAMILY. An
|
|
150
|
+
* older skapi-js also has a method called forwardRequest, taking the same two
|
|
151
|
+
* arguments, and it is a different thing entirely: the retired streaming
|
|
152
|
+
* forwarder, which posts to another endpoint and never queues, so a chat turn
|
|
153
|
+
* handed to it goes somewhere else and comes back as nothing the engine can
|
|
154
|
+
* read. A host that cannot be sure which skapi-js it holds (the widget, which
|
|
155
|
+
* is given the embedder's) decides by a companion only the new SDK has,
|
|
156
|
+
* `forwardRequestHistory`, and never by this method's presence.
|
|
157
|
+
*
|
|
158
|
+
* This or the deprecated `clientSecretRequest` is required; with both, this
|
|
159
|
+
* one is used. See resolveForwardRequest.
|
|
160
|
+
*/
|
|
161
|
+
forwardRequest?: (form: any, opts: any) => Promise<any>;
|
|
162
|
+
/**
|
|
163
|
+
* skapi.forwardRequestHistory, bound to the consumer's skapi instance. This or
|
|
164
|
+
* the deprecated `clientSecretRequestHistory` is required; with both, this one
|
|
165
|
+
* is used. Same arguments either way.
|
|
166
|
+
*/
|
|
167
|
+
forwardRequestHistory?: (params: any, fetchOptions: any) => Promise<any>;
|
|
168
|
+
/**
|
|
169
|
+
* @deprecated Inject `forwardRequest` instead.
|
|
170
|
+
*
|
|
171
|
+
* skapi.clientSecretRequest, bound to the consumer's skapi instance. Still
|
|
172
|
+
* accepted as a COMPATIBILITY CONTRACT, not a leftover: a host that injects
|
|
173
|
+
* only the old keys must keep working on this release. Used only when
|
|
174
|
+
* `forwardRequest` is absent, and handed the engine's request with `secretName`
|
|
175
|
+
* moved back to `clientSecretName`, which is exactly the request it was handed
|
|
176
|
+
* before the rename (see resolveForwardRequest).
|
|
177
|
+
*/
|
|
178
|
+
clientSecretRequest?: (opts: any) => Promise<any>;
|
|
179
|
+
/**
|
|
180
|
+
* @deprecated Inject `forwardRequestHistory` instead.
|
|
181
|
+
*
|
|
182
|
+
* skapi.clientSecretRequestHistory, bound to the consumer's skapi instance.
|
|
183
|
+
* Kept for the same compatibility contract as `clientSecretRequest`, and used
|
|
184
|
+
* only when `forwardRequestHistory` is absent.
|
|
185
|
+
*/
|
|
186
|
+
clientSecretRequestHistory?: (params: any, fetchOptions: any) => Promise<any>;
|
|
119
187
|
/** MCP server base URL (prod vs dev resolved by the consumer). */
|
|
120
188
|
mcpBaseUrl: string;
|
|
121
189
|
/**
|
|
122
|
-
* Value to attach as `poll` on every
|
|
190
|
+
* Value to attach as `poll` on every forwarded request. When `undefined`
|
|
123
191
|
* the `poll` key is omitted entirely (agent.vue). BunnyQuery sets `0`.
|
|
124
192
|
*/
|
|
125
193
|
poll?: number;
|
|
@@ -198,9 +266,10 @@ interface ChatEngineConfig {
|
|
|
198
266
|
* answer. So it stays off until the worker is deployed, then flips per
|
|
199
267
|
* environment.
|
|
200
268
|
*
|
|
201
|
-
* It also needs `
|
|
202
|
-
*
|
|
203
|
-
*
|
|
269
|
+
* It also needs `forwardRequestFinalize` below (or its deprecated name,
|
|
270
|
+
* `clientSecretRequestFinalize`): without it a streamed turn is never
|
|
271
|
+
* finalized, so its row keeps a status and no body forever and a later
|
|
272
|
+
* history load shows the question with an empty answer.
|
|
204
273
|
*/
|
|
205
274
|
liveStreaming?: boolean;
|
|
206
275
|
/**
|
|
@@ -218,25 +287,30 @@ interface ChatEngineConfig {
|
|
|
218
287
|
*/
|
|
219
288
|
liveStreamingRealtime?: boolean;
|
|
220
289
|
/**
|
|
221
|
-
* skapi.
|
|
290
|
+
* skapi.forwardRequestFinalize, bound to the consumer's skapi instance.
|
|
222
291
|
* Stores the version of a streamed turn that history should keep (the engine
|
|
223
292
|
* sends the ASSEMBLED provider body, so history reads it exactly as it reads
|
|
224
293
|
* a buffered turn) and releases that request's chunks. Optional: a host
|
|
225
294
|
* without it can still stream, it just leaves the chunks and an empty row.
|
|
295
|
+
* Takes precedence over the deprecated `clientSecretRequestFinalize`.
|
|
226
296
|
*/
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
297
|
+
forwardRequestFinalize?: ForwardRequestFinalizeFn;
|
|
298
|
+
/**
|
|
299
|
+
* @deprecated Inject `forwardRequestFinalize` instead.
|
|
300
|
+
*
|
|
301
|
+
* skapi.clientSecretRequestFinalize, the same call under its old name. Kept
|
|
302
|
+
* for the compatibility contract `clientSecretRequest` describes, and used
|
|
303
|
+
* only when `forwardRequestFinalize` is absent.
|
|
304
|
+
*/
|
|
305
|
+
clientSecretRequestFinalize?: ForwardRequestFinalizeFn;
|
|
233
306
|
/**
|
|
234
|
-
* skapi.
|
|
307
|
+
* skapi.forwardRequestStream, bound to the consumer's skapi instance. Takes
|
|
308
|
+
* precedence over the deprecated `clientSecretRequestStream`.
|
|
235
309
|
*
|
|
236
310
|
* THE SECOND HALF OF THE DURABILITY GUARANTEE, and without it a streamed turn
|
|
237
311
|
* is only as durable as the tab that started it. A streamed row settles with a
|
|
238
312
|
* status and NO body; the answer is stored as chunks until
|
|
239
|
-
*
|
|
313
|
+
* forwardRequestFinalize says what to keep. A row that settles while no
|
|
240
314
|
* poll is attached (the user closed the tab, a mobile browser discarded it,
|
|
241
315
|
* the device slept and the interval stopped) is therefore never finalized, and
|
|
242
316
|
* a later history load sees a terminal row with no body and used to emit no
|
|
@@ -258,15 +332,16 @@ interface ChatEngineConfig {
|
|
|
258
332
|
* NOTE THAT THIS HOOK, NOT `liveStreaming`, IS WHAT ARMS RECOVERY. See
|
|
259
333
|
* streamRecoveryEnabled() below for why the two decisions are separate.
|
|
260
334
|
*/
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
335
|
+
forwardRequestStream?: ForwardRequestStreamFn;
|
|
336
|
+
/**
|
|
337
|
+
* @deprecated Inject `forwardRequestStream` instead.
|
|
338
|
+
*
|
|
339
|
+
* skapi.clientSecretRequestStream, the same call under its old name. Kept for
|
|
340
|
+
* the compatibility contract `clientSecretRequest` describes, and used only
|
|
341
|
+
* when `forwardRequestStream` is absent. It arms recovery exactly as the new
|
|
342
|
+
* key does.
|
|
343
|
+
*/
|
|
344
|
+
clientSecretRequestStream?: ForwardRequestStreamFn;
|
|
270
345
|
/**
|
|
271
346
|
* Observation hook for a live-streaming turn, called at most once per paint
|
|
272
347
|
* (about once a second) plus once when the turn settles.
|
|
@@ -286,7 +361,8 @@ interface ChatEngineConfig {
|
|
|
286
361
|
* reader is injected.
|
|
287
362
|
*
|
|
288
363
|
* There is no need to set it to turn recovery ON: injecting
|
|
289
|
-
* `
|
|
364
|
+
* `forwardRequestStream` (or its deprecated name, `clientSecretRequestStream`)
|
|
365
|
+
* is what arms it (see streamRecoveryEnabled).
|
|
290
366
|
* This exists only as the way back out for a host that wants byte-for-byte the
|
|
291
367
|
* pre-recovery rendering of a terminal-but-empty row - no bubble, no marker, no
|
|
292
368
|
* chunk read - while keeping the reader available for its own use. Omit it and
|
|
@@ -333,6 +409,12 @@ declare function chatEngineConfig(): ChatEngineConfig;
|
|
|
333
409
|
* whose body the worker never managed to spill). That read finds no chunks, the
|
|
334
410
|
* bubble is dropped, and the list looks exactly as it did before. Set
|
|
335
411
|
* `streamRecovery: false` to opt out of even that.
|
|
412
|
+
*
|
|
413
|
+
* The reader is asked for through resolveForwardRequestStream, so either spelling of
|
|
414
|
+
* it arms recovery: `forwardRequestStream`, or the deprecated
|
|
415
|
+
* `clientSecretRequestStream` a host written before the rename still injects. Asked
|
|
416
|
+
* for the new key alone, this would quietly disarm recovery for every such host on
|
|
417
|
+
* its next install, which is the stranding described above arriving by a rename.
|
|
336
418
|
*/
|
|
337
419
|
declare function streamRecoveryEnabled(): boolean;
|
|
338
420
|
/**
|
|
@@ -344,9 +426,10 @@ declare function streamRecoveryEnabled(): boolean;
|
|
|
344
426
|
* streamed turn carries TWO `stream` flags: skapi's (relay the destination's bytes
|
|
345
427
|
* into the chunk table) and the DESTINATION's own field inside `data`, which
|
|
346
428
|
* BunnyQuery is the party that sets, because skapi relays bytes and knows no
|
|
347
|
-
* vendor.
|
|
348
|
-
* THE KEYS IN THAT SCHEMA, so an skapi-js predating the feature
|
|
349
|
-
* `stream` - it silently DROPS it. What
|
|
429
|
+
* vendor. skapi validates the request's params against a schema and KEEPS ONLY
|
|
430
|
+
* THE KEYS IN THAT SCHEMA, so an skapi-js predating the feature (whose only door
|
|
431
|
+
* was clientSecretRequest) does not reject `stream` - it silently DROPS it. What
|
|
432
|
+
* ships is then the exact split
|
|
350
433
|
* chatStreamWiring exists to make impossible: the destination is asked to answer in
|
|
351
434
|
* SSE frames, skapi waits and stores the whole transcript on the row, and
|
|
352
435
|
* extractClaudeText / extractOpenAIText read a wall of `data: {...}` lines where a
|
|
@@ -372,6 +455,25 @@ declare function streamRecoveryEnabled(): boolean;
|
|
|
372
455
|
* able to fetch it. There is no cheap DIRECT probe of the schema: the only way to
|
|
373
456
|
* learn that `stream` was dropped is to send a real request and read an empty
|
|
374
457
|
* answer, which is the bug itself.
|
|
458
|
+
*
|
|
459
|
+
* EITHER SPELLING OF THE PAIR ANSWERS YES, and it has to be a whole pair. skapi-js
|
|
460
|
+
* renamed the two to forwardRequestStream and forwardRequestFinalize and kept the old
|
|
461
|
+
* names as aliases, so three SDKs are out there: the renamed one carries both pairs,
|
|
462
|
+
* one from the streaming release up to the rename carries only the old pair, and one
|
|
463
|
+
* that predates streaming carries neither. Accepting the old pair is what keeps an
|
|
464
|
+
* embed page pinned between the two releases streaming; accepting the new pair is
|
|
465
|
+
* what keeps this answering yes once the old aliases are finally removed. The
|
|
466
|
+
* reasoning above holds for both: each pair shipped in the same change as, or after,
|
|
467
|
+
* the `stream` key, and each IS the capability rather than a proxy for it. A mixed
|
|
468
|
+
* half of each is not a pair and is refused, because no real SDK has that shape and
|
|
469
|
+
* the engine would still be missing one half of the protocol under the name it asks
|
|
470
|
+
* for.
|
|
471
|
+
*
|
|
472
|
+
* A presence probe is safe for these two names in a way it is NOT for forwardRequest
|
|
473
|
+
* itself: no skapi-js ever shipped a forwardRequestStream or forwardRequestFinalize
|
|
474
|
+
* that meant something else, while an older forwardRequest exists and is the retired
|
|
475
|
+
* streaming forwarder. That is why the widget's family probe asks for
|
|
476
|
+
* forwardRequestHistory instead.
|
|
375
477
|
*/
|
|
376
478
|
declare function skapiSupportsStreaming(sk: any): boolean;
|
|
377
479
|
|
|
@@ -1598,7 +1700,7 @@ declare function buildAiAgentValue(platform: string | null | undefined, model?:
|
|
|
1598
1700
|
* buffered call would have returned out.
|
|
1599
1701
|
*
|
|
1600
1702
|
* WHY THIS FILE EXISTS, AND WHY IT IS HERE AND NOT IN SKAPI.
|
|
1601
|
-
* skapi's
|
|
1703
|
+
* skapi's forwardRequest is a byte relay. On a streamed turn the worker reads
|
|
1602
1704
|
* the destination's response incrementally and appends the raw bytes to a chunk
|
|
1603
1705
|
* table; it settles the polling row with STATUS ONLY, no body, because the content
|
|
1604
1706
|
* lives in the chunks. skapi therefore does not know that Anthropic or OpenAI
|
|
@@ -1850,7 +1952,7 @@ declare const DEFAULT_OPENAI_MODEL = "gpt-5.6-luna";
|
|
|
1850
1952
|
* that drifts when someone edits one arm.
|
|
1851
1953
|
*/
|
|
1852
1954
|
type ChatStreamWiring = {
|
|
1853
|
-
/** Spread into the
|
|
1955
|
+
/** Spread into the forwardRequest OPTIONS (skapi's relay switch). `realtime`
|
|
1854
1956
|
* belongs here and never in `body`: it is skapi's, not the destination's. */
|
|
1855
1957
|
transport: {
|
|
1856
1958
|
stream?: true;
|
|
@@ -3416,7 +3518,7 @@ declare function typewriterResumeIndex(painted: string, fullText: string, region
|
|
|
3416
3518
|
* because the row's status describes the destination's request and not our read
|
|
3417
3519
|
* of it. Anything short of a finished answer leaves the chunks exactly where they
|
|
3418
3520
|
* are, which is what they are for: the turn stays re-readable through
|
|
3419
|
-
*
|
|
3521
|
+
* forwardRequestStream and a later load recovers it in full.
|
|
3420
3522
|
*
|
|
3421
3523
|
* `unframed` is the one exception to needing a terminal event, and it is not a
|
|
3422
3524
|
* loophole: bytes that were never SSE carry no events at all and none is ever
|