@noodleseed/assistant 1.7.0 → 1.9.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.
Files changed (50) hide show
  1. package/README.md +101 -22
  2. package/dist/{appearance-DowzFJjh.d.cts → appearance-Cc-eqSbp.d.cts} +1 -1
  3. package/dist/{appearance-DowzFJjh.d.ts → appearance-Cc-eqSbp.d.ts} +1 -1
  4. package/dist/{chunk-UXPKSCID.js → chunk-3YYTUJPJ.js} +2 -2
  5. package/dist/{chunk-35A7REQX.js → chunk-4B3XXGRP.js} +256 -91
  6. package/dist/chunk-4B3XXGRP.js.map +1 -0
  7. package/dist/{chunk-NSBPE2FW.js → chunk-5FUTL2UF.js} +6 -1
  8. package/dist/chunk-BLMJHF7U.js +544 -0
  9. package/dist/chunk-BLMJHF7U.js.map +1 -0
  10. package/dist/chunk-RYQBXTLR.js +9089 -0
  11. package/dist/chunk-RYQBXTLR.js.map +1 -0
  12. package/dist/{client-D2Y9UFh3.d.cts → client-B803xZVn.d.ts} +44 -2
  13. package/dist/{client-DBuETUVD.d.ts → client-CsmtpD1z.d.cts} +44 -2
  14. package/dist/client.cjs +22976 -92
  15. package/dist/client.cjs.map +1 -1
  16. package/dist/client.d.cts +3 -2
  17. package/dist/client.d.ts +3 -2
  18. package/dist/client.js +3 -2
  19. package/dist/index.cjs +10750 -2212
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.cts +4 -3
  22. package/dist/index.d.ts +4 -3
  23. package/dist/index.js +4 -4
  24. package/dist/react/client.cjs +23688 -0
  25. package/dist/react/client.cjs.map +1 -0
  26. package/dist/react/client.d.cts +24 -0
  27. package/dist/react/client.d.ts +24 -0
  28. package/dist/react/client.js +76 -0
  29. package/dist/react/client.js.map +1 -0
  30. package/dist/react.cjs +10803 -2215
  31. package/dist/react.cjs.map +1 -1
  32. package/dist/react.d.cts +23 -4
  33. package/dist/react.d.ts +23 -4
  34. package/dist/react.js +64 -14
  35. package/dist/react.js.map +1 -1
  36. package/dist/server.d.cts +1 -1
  37. package/dist/server.d.ts +1 -1
  38. package/dist/server.js +1 -1
  39. package/dist/token-Y6KCR3JT.js +70 -0
  40. package/dist/token-Y6KCR3JT.js.map +1 -0
  41. package/dist/token-util-XFYMRPAB.js +6 -0
  42. package/dist/{v4-2UXPDMWJ.js → v4-KBRL3YLO.js} +3 -3
  43. package/dist/v4-KBRL3YLO.js.map +1 -0
  44. package/package.json +14 -3
  45. package/dist/chunk-35A7REQX.js.map +0 -1
  46. package/dist/chunk-7E5HINN4.js +0 -713
  47. package/dist/chunk-7E5HINN4.js.map +0 -1
  48. /package/dist/{chunk-UXPKSCID.js.map → chunk-3YYTUJPJ.js.map} +0 -0
  49. /package/dist/{chunk-NSBPE2FW.js.map → chunk-5FUTL2UF.js.map} +0 -0
  50. /package/dist/{v4-2UXPDMWJ.js.map → token-util-XFYMRPAB.js.map} +0 -0
@@ -1,713 +0,0 @@
1
- // src/events.ts
2
- function toAssistantClientEvent(event) {
3
- const value = event.data;
4
- switch (event.event) {
5
- case "content":
6
- if (typeof value.delta === "string" && hasOptionalTurnId(value)) {
7
- return event;
8
- }
9
- break;
10
- case "tool_proposed":
11
- if (hasString(value, "id") && hasString(value, "tool") && hasOptionalString(value.title) && hasOptionalString(value.description) && hasOptionalJson(value.arguments) && (value.reviewSchema === void 0 || isRecord(value.reviewSchema)) && hasOptionalString(value.expiresAt) && (value.requiresConfirmation === void 0 || value.requiresConfirmation === true) && hasOptionalTurnId(value)) {
12
- return event;
13
- }
14
- break;
15
- case "input_requested":
16
- if (hasString(value, "id") && hasString(value, "message") && isRecord(value.requestedSchema) && hasString(value, "expiresAt") && hasOptionalTurnId(value)) {
17
- return event;
18
- }
19
- break;
20
- case "interaction_resolved":
21
- if (hasString(value, "id") && (value.action === void 0 || isInteractionAction(value.action)) && hasOptionalTurnId(value)) {
22
- return event;
23
- }
24
- break;
25
- case "tool_completed":
26
- if (hasString(value, "id") && hasString(value, "tool") && isJsonValue(value.result, 0) && (value.replayed === void 0 || value.replayed === true) && hasOptionalTurnId(value)) {
27
- return event;
28
- }
29
- break;
30
- case "view_available":
31
- if (isViewAvailableDetail(value)) return event;
32
- break;
33
- case "error":
34
- if (hasString(value, "code") && (value.status === void 0 || typeof value.status === "number") && (value.retryable === void 0 || typeof value.retryable === "boolean") && hasOptionalTurnId(value)) {
35
- return event;
36
- }
37
- break;
38
- case "done":
39
- if (hasOptionalTurnId(value)) return event;
40
- break;
41
- case "interaction_proposed":
42
- if (hasString(value, "id") && (hasString(value, "tool") || hasString(value, "title")) && hasOptionalJson(value.arguments)) {
43
- return event;
44
- }
45
- break;
46
- }
47
- return { event: "unrecognized", data: { name: event.event, payload: value } };
48
- }
49
- function isViewAvailableDetail(value) {
50
- return hasString(value, "id") && hasString(value, "tool") && typeof value.resourceUri === "string" && value.resourceUri.startsWith("ui://") && hasOptionalString(value.title) && (value.replayed === void 0 || value.replayed === true) && isJsonValue(value.result, 0) && hasOptionalJson(value.arguments) && hasOptionalString(value.html) && (value.resourceMeta === void 0 || isRecord(value.resourceMeta)) && (value.allowedOpenDomains === void 0 || Array.isArray(value.allowedOpenDomains) && value.allowedOpenDomains.every(isHttpsUrl)) && hasOptionalTurnId(value);
51
- }
52
- function isHttpsUrl(value) {
53
- if (typeof value !== "string") return false;
54
- try {
55
- return new URL(value).protocol === "https:";
56
- } catch {
57
- return false;
58
- }
59
- }
60
- function hasOptionalTurnId(value) {
61
- return hasOptionalString(value.turnId);
62
- }
63
- function hasString(value, key) {
64
- const entry = value[key];
65
- return typeof entry === "string" && entry.length > 0;
66
- }
67
- function hasOptionalString(value) {
68
- return value === void 0 || typeof value === "string";
69
- }
70
- function hasOptionalJson(value) {
71
- return value === void 0 || isJsonValue(value, 0);
72
- }
73
- function isInteractionAction(value) {
74
- return value === "accept" || value === "decline" || value === "cancel";
75
- }
76
- function isJsonValue(value, depth) {
77
- if (depth > 16) return false;
78
- if (value === null || typeof value === "string" || typeof value === "boolean") return true;
79
- if (typeof value === "number") return Number.isFinite(value);
80
- if (Array.isArray(value)) {
81
- return value.length <= 256 && value.every((entry) => isJsonValue(entry, depth + 1));
82
- }
83
- if (!isRecord(value)) return false;
84
- const entries = Object.entries(value);
85
- return entries.length <= 256 && entries.every(([, entry]) => isJsonValue(entry, depth + 1));
86
- }
87
- function isRecord(value) {
88
- return typeof value === "object" && value !== null && !Array.isArray(value);
89
- }
90
-
91
- // src/model-context.ts
92
- var MAX_BYTES = 16 * 1024;
93
- var MAX_DEPTH = 8;
94
- var MAX_ENTRIES = 128;
95
- var SENSITIVE_KEY = /(?:secret|token|api[-_]?key|password|credential|authorization|cookie)/i;
96
- var CREDENTIAL_SHAPED_TEXT = /(?:-----BEGIN [A-Z ]*PRIVATE KEY-----|\bsk-[A-Za-z0-9_-]{20,}\b|\b(?:bearer|basic)\s+[A-Za-z0-9._~+/=-]{20,}\b|\b[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}\b)/i;
97
- function copyAssistantModelContext(update) {
98
- const copied = copyJsonValue(update, "$", 0, /* @__PURE__ */ new Set());
99
- assertModelContextShape(copied);
100
- const encoded = JSON.stringify(copied);
101
- if (new TextEncoder().encode(encoded).byteLength > MAX_BYTES) {
102
- throw new Error("Model context must not exceed 16 KiB");
103
- }
104
- return copied;
105
- }
106
- function copyAssistantPageContext(context) {
107
- const copied = copyJsonValue(context, "$", 0, /* @__PURE__ */ new Set());
108
- if (typeof copied !== "object" || copied === null || Array.isArray(copied)) {
109
- throw new Error("Page context must be a JSON object");
110
- }
111
- const encoded = JSON.stringify(copied);
112
- if (new TextEncoder().encode(encoded).byteLength > MAX_BYTES) {
113
- throw new Error("Page context must not exceed 16 KiB");
114
- }
115
- return copied;
116
- }
117
- function assertModelContextShape(value) {
118
- if (!isPlainRecord(value)) throw new Error("Model context must be a JSON object");
119
- for (const key of Object.keys(value)) {
120
- if (key !== "content" && key !== "structuredContent") {
121
- throw new Error(`Model context contains unknown field ${key}`);
122
- }
123
- }
124
- if (value.content !== void 0) {
125
- if (!Array.isArray(value.content)) throw new Error("Model context content must be an array");
126
- for (const part of value.content) {
127
- if (!isPlainRecord(part) || Object.keys(part).some((key) => key !== "type" && key !== "text") || part.type !== "text" || typeof part.text !== "string") {
128
- throw new Error("Model context content supports text parts only");
129
- }
130
- }
131
- }
132
- if (value.structuredContent !== void 0 && !isPlainRecord(value.structuredContent)) {
133
- throw new Error("Model context structuredContent must be an object");
134
- }
135
- }
136
- function copyJsonValue(value, path, depth, ancestors) {
137
- if (depth > MAX_DEPTH) throw new Error(`Model context exceeds maximum depth at ${path}`);
138
- if (typeof value === "string") {
139
- if (CREDENTIAL_SHAPED_TEXT.test(value)) {
140
- throw new Error(`Model context contains credential-shaped text at ${path}`);
141
- }
142
- return value;
143
- }
144
- if (value === null || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value)) {
145
- return value;
146
- }
147
- if (typeof value !== "object") throw new Error(`Model context contains non-JSON data at ${path}`);
148
- if (hasToJsonProperty(value)) {
149
- throw new Error(`Model context must not define or inherit toJSON at ${path}`);
150
- }
151
- const prototype = Object.getPrototypeOf(value);
152
- if (Array.isArray(value)) {
153
- if (prototype !== Array.prototype) {
154
- throw new Error(`Model context contains a non-JSON object at ${path}`);
155
- }
156
- } else if (prototype !== Object.prototype && prototype !== null) {
157
- throw new Error(`Model context contains a non-JSON object at ${path}`);
158
- }
159
- if (ancestors.has(value)) throw new Error(`Model context contains a cycle at ${path}`);
160
- if (Array.isArray(value)) {
161
- if (value.length > MAX_ENTRIES) {
162
- throw new Error(`Model context has more than 128 entries at ${path}`);
163
- }
164
- const copy2 = [];
165
- ancestors.add(value);
166
- for (let index = 0; index < value.length; index += 1) {
167
- const entry = Object.hasOwn(value, index) ? value[index] : null;
168
- copy2.push(copyJsonValue(entry, `${path}.${index}`, depth + 1, ancestors));
169
- }
170
- ancestors.delete(value);
171
- return copy2;
172
- }
173
- const entries = Object.entries(value);
174
- if (entries.length > MAX_ENTRIES) {
175
- throw new Error(`Model context has more than 128 entries at ${path}`);
176
- }
177
- const copy = /* @__PURE__ */ Object.create(null);
178
- ancestors.add(value);
179
- for (const [key, entry] of entries) {
180
- if (SENSITIVE_KEY.test(key)) {
181
- throw new Error(`Model context contains sensitive key ${path}.${key}`);
182
- }
183
- copy[key] = copyJsonValue(entry, `${path}.${key}`, depth + 1, ancestors);
184
- }
185
- ancestors.delete(value);
186
- return copy;
187
- }
188
- function isPlainRecord(value) {
189
- if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
190
- const prototype = Object.getPrototypeOf(value);
191
- return prototype === Object.prototype || prototype === null;
192
- }
193
- function hasToJsonProperty(value) {
194
- let current = value;
195
- const visited = /* @__PURE__ */ new Set();
196
- while (current !== null && !visited.has(current)) {
197
- visited.add(current);
198
- if (Object.getOwnPropertyDescriptor(current, "toJSON") !== void 0) return true;
199
- current = Object.getPrototypeOf(current);
200
- }
201
- return false;
202
- }
203
-
204
- // src/transport.ts
205
- var AssistantTransportError = class extends Error {
206
- code = "invalid_response";
207
- constructor(message, options) {
208
- super(message, options);
209
- this.name = "AssistantTransportError";
210
- }
211
- };
212
- async function consumeAssistantEvents(response, onEvent) {
213
- const stream = new AssistantEventStream(onEvent);
214
- if (!response.body) {
215
- let text;
216
- try {
217
- text = await response.text();
218
- } catch (error) {
219
- if (isAbortError(error)) throw error;
220
- throw invalidStream("assistant event stream could not be read", error);
221
- }
222
- stream.push(text);
223
- stream.finish(response.headers.get("content-type") ?? "");
224
- return;
225
- }
226
- const reader = response.body.getReader();
227
- const decoder = new TextDecoder("utf-8", { fatal: true });
228
- while (true) {
229
- let result;
230
- try {
231
- result = await reader.read();
232
- } catch (error) {
233
- if (isAbortError(error)) throw error;
234
- throw invalidStream("assistant event stream ended unexpectedly", error);
235
- }
236
- let chunk;
237
- try {
238
- chunk = decoder.decode(result.value, { stream: !result.done });
239
- } catch (error) {
240
- throw invalidStream("assistant event stream contained invalid UTF-8", error);
241
- }
242
- stream.push(chunk);
243
- if (result.done) break;
244
- }
245
- stream.finish(response.headers.get("content-type") ?? "");
246
- }
247
- var AssistantEventStream = class {
248
- #onEvent;
249
- #pending = "";
250
- #terminal;
251
- constructor(onEvent) {
252
- this.#onEvent = onEvent;
253
- }
254
- push(chunk) {
255
- this.#pending += chunk;
256
- const protectedCarriageReturn = this.#pending.endsWith("\r");
257
- const normalizable = protectedCarriageReturn ? this.#pending.slice(0, -1) : this.#pending;
258
- const frames = normalizeLineEndings(normalizable).split("\n\n");
259
- this.#pending = `${frames.pop() ?? ""}${protectedCarriageReturn ? "\r" : ""}`;
260
- for (const frame of frames) this.#acceptFrame(frame);
261
- }
262
- finish(contentType) {
263
- if (this.#pending.trim().length > 0) {
264
- throw invalidStream("assistant event stream ended with an unterminated frame");
265
- }
266
- if (!this.#terminal) {
267
- throw invalidStream(
268
- `assistant response did not contain a terminal done event (content-type: ${contentType || "unknown"})`
269
- );
270
- }
271
- this.#onEvent(this.#terminal);
272
- }
273
- #acceptFrame(frame) {
274
- const event = parseFrame(frame);
275
- if (!event) return;
276
- if (this.#terminal) {
277
- throw invalidStream("assistant event stream contained an event after done");
278
- }
279
- if (event.event === "done") {
280
- this.#terminal = event;
281
- return;
282
- }
283
- this.#onEvent(event);
284
- }
285
- };
286
- function parseFrame(frame) {
287
- let event;
288
- const data = [];
289
- let hasFields = false;
290
- for (const line of frame.split("\n")) {
291
- if (!line || line.startsWith(":")) continue;
292
- hasFields = true;
293
- const separator = line.indexOf(":");
294
- const field = separator < 0 ? line : line.slice(0, separator);
295
- const value = separator < 0 ? "" : line.slice(separator + 1).replace(/^ /, "");
296
- if (field === "event") event = value;
297
- if (field === "data") data.push(value);
298
- }
299
- if (!hasFields) return void 0;
300
- if (!event || data.length === 0) {
301
- throw invalidStream("assistant event stream contained a malformed frame");
302
- }
303
- let parsed;
304
- try {
305
- parsed = JSON.parse(data.join("\n"));
306
- } catch (error) {
307
- throw invalidStream("assistant event stream contained malformed JSON", error);
308
- }
309
- if (event === "done" && !isValidDonePayload(parsed)) {
310
- throw invalidStream("assistant event stream contained an invalid done event");
311
- }
312
- return { event, data: isRecord2(parsed) ? parsed : { value: parsed } };
313
- }
314
- function normalizeLineEndings(input) {
315
- return input.replaceAll("\r\n", "\n").replaceAll("\r", "\n");
316
- }
317
- function isValidDonePayload(value) {
318
- return isRecord2(value) && (value.turnId === void 0 || typeof value.turnId === "string" && value.turnId.length > 0);
319
- }
320
- function isRecord2(value) {
321
- return typeof value === "object" && value !== null && !Array.isArray(value);
322
- }
323
- function invalidStream(message, cause) {
324
- return new AssistantTransportError(message, cause === void 0 ? void 0 : { cause });
325
- }
326
- function isAbortError(error) {
327
- return error instanceof DOMException && error.name === "AbortError";
328
- }
329
-
330
- // src/client.ts
331
- var AssistantClientError = class extends Error {
332
- detail;
333
- constructor(detail, message, options) {
334
- super(message, options);
335
- this.name = "AssistantClientError";
336
- this.detail = detail;
337
- }
338
- };
339
- var DefaultAssistantClient = class {
340
- #sessionEndpoint;
341
- #fetch;
342
- #listeners = /* @__PURE__ */ new Set();
343
- #clientContext;
344
- #pageContext;
345
- #session;
346
- #context;
347
- #modelContext;
348
- #active;
349
- constructor(options) {
350
- if (!options.sessionEndpoint) throw new Error("sessionEndpoint is required");
351
- this.#sessionEndpoint = options.sessionEndpoint;
352
- this.#fetch = options.fetch ?? ((input, init) => globalThis.fetch(input, init));
353
- this.#context = options.context ? { ...options.context } : void 0;
354
- this.#modelContext = options.modelContext ? copyAssistantModelContext(options.modelContext) : void 0;
355
- this.#clientContext = options.clientContext;
356
- this.#pageContext = options.pageContext;
357
- }
358
- subscribe(listener) {
359
- this.#listeners.add(listener);
360
- return () => this.#listeners.delete(listener);
361
- }
362
- async connect() {
363
- if (this.#session) return;
364
- await this.#singleFlight(async (signal) => {
365
- if (!this.#session) await this.#createSession(signal);
366
- });
367
- }
368
- async sendMessage(text) {
369
- const message = text.trim();
370
- if (!message) return;
371
- await this.#singleFlight(async (signal) => {
372
- await this.#sendTurn(message, true, signal, this.#modelContext);
373
- });
374
- }
375
- async respond(id, resolution) {
376
- if (!id) {
377
- throw clientError("invalid_request", "interaction id is required", false);
378
- }
379
- await this.#singleFlight(async (signal) => {
380
- const session = this.#session;
381
- if (!session) {
382
- throw clientError("confirmation_expired", "assistant session is not active", false);
383
- }
384
- const modernEndpoint = session.endpoints.interactions;
385
- if (!modernEndpoint && resolution.action !== "accept") {
386
- throw clientError(
387
- "unsupported_service",
388
- "the assistant service does not support declining or cancelling interactions",
389
- false
390
- );
391
- }
392
- const endpoint = modernEndpoint ?? session.endpoints.toolConfirmations;
393
- const body = modernEndpoint ? {
394
- id,
395
- action: resolution.action,
396
- ...resolution.action === "accept" && resolution.content !== void 0 ? { content: resolution.content } : {}
397
- } : { id };
398
- this.#emit({ event: "interaction_started", data: { id, action: resolution.action } });
399
- const response = await this.#request(
400
- endpoint,
401
- {
402
- method: "POST",
403
- headers: authorizedHeaders(session.token, "text/event-stream"),
404
- body: JSON.stringify(body),
405
- signal
406
- },
407
- "confirmation_failed"
408
- );
409
- if (response.status === 401) {
410
- this.#session = void 0;
411
- this.#emit({ event: "session_expired", data: {} });
412
- }
413
- if (!response.ok) {
414
- const serverCode = await readStableErrorCode(response);
415
- const expired = response.status === 401 || response.status === 409;
416
- throw clientError(
417
- serverCode ?? (expired ? "confirmation_expired" : "confirmation_failed"),
418
- `Assistant interaction failed (${response.status})`,
419
- false,
420
- response.status
421
- );
422
- }
423
- await this.#consume(response);
424
- this.#emit({ event: "interaction_completed", data: { id, action: resolution.action } });
425
- });
426
- }
427
- updateContext(context) {
428
- this.#context = { ...context };
429
- this.#emit({ event: "context_changed", data: { context: this.#context } });
430
- }
431
- updatePageContext(context) {
432
- this.#pageContext = copyAssistantPageContext(context);
433
- }
434
- updateModelContext(update) {
435
- this.#modelContext = copyAssistantModelContext(update);
436
- this.#emit({ event: "model_context_changed", data: { modelContext: this.#modelContext } });
437
- }
438
- async requestApp(method, params) {
439
- const session = this.#session;
440
- if (!session?.endpoints.apps) {
441
- throw clientError(
442
- "unsupported_service",
443
- "the assistant service does not support MCP Apps",
444
- false
445
- );
446
- }
447
- const response = await this.#request(
448
- session.endpoints.apps,
449
- {
450
- method: "POST",
451
- headers: authorizedHeaders(session.token, "application/json"),
452
- body: JSON.stringify({ method, params })
453
- },
454
- "app_request_failed"
455
- );
456
- if (!response.ok) {
457
- throw clientError(
458
- "app_request_failed",
459
- `Assistant app request failed (${response.status})`,
460
- false,
461
- response.status
462
- );
463
- }
464
- return response.json();
465
- }
466
- appSandboxUrl() {
467
- return this.#session?.endpoints.sandbox;
468
- }
469
- resetSession() {
470
- this.#session = void 0;
471
- this.#emit({ event: "session_reset", data: {} });
472
- }
473
- abort() {
474
- this.#active?.abort();
475
- }
476
- async #sendTurn(message, mayRetry, signal, modelContext) {
477
- const session = this.#session ?? await this.#createSession(signal);
478
- if (mayRetry) this.#emit({ event: "message_started", data: { message } });
479
- const clientContext = this.#resolveClientContext();
480
- const pageContext = this.#resolvePageContext();
481
- const response = await this.#request(
482
- session.endpoints.turns,
483
- {
484
- method: "POST",
485
- headers: authorizedHeaders(session.token, "text/event-stream"),
486
- body: JSON.stringify({
487
- message,
488
- ...clientContext ? { clientContext } : {},
489
- ...pageContext === void 0 ? {} : { pageContext },
490
- ...modelContext ? { modelContext } : {}
491
- }),
492
- signal
493
- },
494
- "turn_failed"
495
- );
496
- if (response.status === 401 && mayRetry) {
497
- this.#session = void 0;
498
- this.#emit({ event: "session_expired", data: {} });
499
- await this.#sendTurn(message, false, signal, modelContext);
500
- return;
501
- }
502
- if (!response.ok) {
503
- throw clientError(
504
- "turn_failed",
505
- `Assistant turn failed (${response.status})`,
506
- false,
507
- response.status
508
- );
509
- }
510
- await this.#consume(response);
511
- this.#emit({ event: "message_completed", data: {} });
512
- }
513
- #resolveClientContext() {
514
- let value;
515
- try {
516
- value = typeof this.#clientContext === "function" ? this.#clientContext() : this.#clientContext;
517
- } catch (error) {
518
- throw clientError(
519
- "turn_failed",
520
- "Assistant client context provider failed",
521
- false,
522
- void 0,
523
- {
524
- cause: error
525
- }
526
- );
527
- }
528
- if (!value) return void 0;
529
- const context = {
530
- ...typeof value.locale === "string" && value.locale ? { locale: value.locale } : {},
531
- ...typeof value.timeZone === "string" && value.timeZone ? { timeZone: value.timeZone } : {}
532
- };
533
- return Object.keys(context).length > 0 ? context : void 0;
534
- }
535
- #resolvePageContext() {
536
- try {
537
- const value = typeof this.#pageContext === "function" ? this.#pageContext() : this.#pageContext;
538
- return value === void 0 ? void 0 : copyAssistantPageContext(value);
539
- } catch (error) {
540
- throw clientError("turn_failed", "Assistant page context provider failed", false, void 0, {
541
- cause: error
542
- });
543
- }
544
- }
545
- async #createSession(signal) {
546
- const response = await this.#request(
547
- this.#sessionEndpoint,
548
- {
549
- method: "POST",
550
- headers: { Accept: "application/json", "Content-Type": "application/json" },
551
- body: JSON.stringify(this.#context ? { context: this.#context } : {}),
552
- credentials: "same-origin",
553
- signal
554
- },
555
- "session_failed"
556
- );
557
- if (!response.ok) {
558
- throw clientError(
559
- "session_failed",
560
- `Assistant session failed (${response.status})`,
561
- true,
562
- response.status
563
- );
564
- }
565
- let value;
566
- try {
567
- value = await response.json();
568
- } catch (error) {
569
- throw clientError(
570
- "session_failed",
571
- "Assistant session returned invalid JSON",
572
- true,
573
- void 0,
574
- {
575
- cause: error
576
- }
577
- );
578
- }
579
- const session = parseSession(value);
580
- this.#session = session;
581
- this.#emit({
582
- event: "session_started",
583
- data: {
584
- expiresAt: session.expiresAt,
585
- ...session.configuration ? { configuration: session.configuration } : {}
586
- }
587
- });
588
- return session;
589
- }
590
- async #consume(response) {
591
- let streamError;
592
- try {
593
- await consumeAssistantEvents(response, (event) => {
594
- const clientEvent = toAssistantClientEvent(event);
595
- this.#emit(clientEvent);
596
- if (clientEvent.event !== "error" || typeof clientEvent.data.code !== "string") return;
597
- streamError = {
598
- code: clientEvent.data.code,
599
- ...typeof clientEvent.data.status === "number" ? { status: clientEvent.data.status } : {},
600
- retryable: clientEvent.data.retryable === true
601
- };
602
- });
603
- } catch (error) {
604
- if (error instanceof AssistantTransportError) {
605
- throw clientError(error.code, error.message, false, void 0, { cause: error });
606
- }
607
- throw error;
608
- }
609
- if (streamError) {
610
- throw clientError(
611
- streamError.code,
612
- `Assistant stream failed (${streamError.code})`,
613
- streamError.retryable,
614
- streamError.status
615
- );
616
- }
617
- }
618
- async #request(input, init, failureCode) {
619
- try {
620
- return await this.#fetch(input, init);
621
- } catch (error) {
622
- if (init.signal?.aborted) throw error;
623
- throw clientError(failureCode, "Assistant request failed", true, void 0, { cause: error });
624
- }
625
- }
626
- async #singleFlight(operation) {
627
- if (this.#active) {
628
- throw clientError("request_in_progress", "an assistant request is already in progress", true);
629
- }
630
- const controller = new AbortController();
631
- this.#active = controller;
632
- try {
633
- await operation(controller.signal);
634
- } catch (error) {
635
- if (controller.signal.aborted) {
636
- throw clientError("request_aborted", "assistant request was aborted", true, void 0, {
637
- cause: error
638
- });
639
- }
640
- throw error;
641
- } finally {
642
- this.#active = void 0;
643
- }
644
- }
645
- #emit(event) {
646
- for (const listener of this.#listeners) {
647
- try {
648
- listener(event);
649
- } catch {
650
- }
651
- }
652
- }
653
- };
654
- function createAssistantClient(options) {
655
- return new DefaultAssistantClient(options);
656
- }
657
- function authorizedHeaders(token, accept) {
658
- return {
659
- Authorization: `Bearer ${token}`,
660
- "Content-Type": "application/json",
661
- Accept: accept
662
- };
663
- }
664
- function parseSession(value) {
665
- if (!isRecord3(value) || !isRecord3(value.endpoints)) {
666
- throw clientError("session_failed", "Assistant session response is invalid", true);
667
- }
668
- const interactions = value.endpoints.interactions;
669
- const apps = value.endpoints.apps;
670
- const sandbox = value.endpoints.sandbox;
671
- if (typeof value.token !== "string" || typeof value.expiresAt !== "string" || typeof value.endpoints.turns !== "string" || typeof value.endpoints.toolConfirmations !== "string" || interactions !== void 0 && typeof interactions !== "string" || apps !== void 0 && typeof apps !== "string" || sandbox !== void 0 && typeof sandbox !== "string") {
672
- throw clientError("session_failed", "Assistant session response is invalid", true);
673
- }
674
- return {
675
- token: value.token,
676
- expiresAt: value.expiresAt,
677
- endpoints: {
678
- turns: value.endpoints.turns,
679
- toolConfirmations: value.endpoints.toolConfirmations,
680
- ...typeof interactions === "string" ? { interactions } : {},
681
- ...typeof apps === "string" ? { apps } : {},
682
- ...typeof sandbox === "string" ? { sandbox } : {}
683
- },
684
- ...isRecord3(value.configuration) ? { configuration: value.configuration } : {}
685
- };
686
- }
687
- function isRecord3(value) {
688
- return typeof value === "object" && value !== null && !Array.isArray(value);
689
- }
690
- async function readStableErrorCode(response) {
691
- let value;
692
- try {
693
- value = await response.json();
694
- } catch {
695
- return void 0;
696
- }
697
- if (!isRecord3(value) || typeof value.code !== "string") return void 0;
698
- return /^[A-Za-z0-9_.-]{1,64}$/.test(value.code) ? value.code : void 0;
699
- }
700
- function clientError(code, message, retryable, status, options) {
701
- return new AssistantClientError(
702
- { code, ...status === void 0 ? {} : { status }, retryable },
703
- message,
704
- options
705
- );
706
- }
707
-
708
- export {
709
- copyAssistantModelContext,
710
- AssistantClientError,
711
- createAssistantClient
712
- };
713
- //# sourceMappingURL=chunk-7E5HINN4.js.map