@noodleseed/assistant 1.13.0 → 1.15.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/README.md +5 -0
- package/dist/{chunk-KRB2SXFD.js → chunk-RRJIK473.js} +211 -51
- package/dist/chunk-RRJIK473.js.map +1 -0
- package/dist/{chunk-ZPELSHUP.js → chunk-SUHNNWKP.js} +37 -20
- package/dist/chunk-SUHNNWKP.js.map +1 -0
- package/dist/{client-BKIeuSVS.d.cts → client-B_l59rWg.d.cts} +29 -2
- package/dist/{client-BccAX_om.d.ts → client-MnLfiyo2.d.ts} +29 -2
- package/dist/client.cjs +206 -50
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.js +1 -1
- package/dist/embed.global.js +540 -0
- package/dist/index.cjs +242 -67
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -2
- package/dist/index.d.ts +6 -2
- package/dist/index.js +2 -2
- package/dist/react/client.cjs +217 -54
- package/dist/react/client.cjs.map +1 -1
- package/dist/react/client.d.cts +3 -3
- package/dist/react/client.d.ts +3 -3
- package/dist/react/client.js +12 -5
- package/dist/react/client.js.map +1 -1
- package/dist/react.cjs +251 -70
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +7 -2
- package/dist/react.d.ts +7 -2
- package/dist/react.js +11 -5
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-KRB2SXFD.js.map +0 -1
- package/dist/chunk-ZPELSHUP.js.map +0 -1
|
@@ -22,6 +22,14 @@ interface AssistantErrorDetail {
|
|
|
22
22
|
readonly code: string;
|
|
23
23
|
readonly status?: number;
|
|
24
24
|
readonly retryable: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* The service's own refusal code, when it sent one — e.g. `daily_turn_budget_exhausted`.
|
|
27
|
+
*
|
|
28
|
+
* Additive beside `code` rather than replacing it: `code` is a published closed union that shipped
|
|
29
|
+
* consumers already switch on, so remapping it would break them. This is how a renderer tells a
|
|
30
|
+
* capacity decision apart from a fault.
|
|
31
|
+
*/
|
|
32
|
+
readonly serviceCode?: string;
|
|
25
33
|
}
|
|
26
34
|
|
|
27
35
|
interface NamedEvent<Name extends string, Data> {
|
|
@@ -165,6 +173,20 @@ interface AssistantChatState {
|
|
|
165
173
|
readonly error?: AssistantChatError;
|
|
166
174
|
}
|
|
167
175
|
|
|
176
|
+
/** The exclusive choice, expressed so the wrong pair does not typecheck in the first place. */
|
|
177
|
+
type AssistantSessionSourceOptions = {
|
|
178
|
+
/** The customer backend route that exchanges an embed secret for a session. */
|
|
179
|
+
readonly sessionEndpoint: string;
|
|
180
|
+
readonly embedId?: undefined;
|
|
181
|
+
readonly serviceUrl?: undefined;
|
|
182
|
+
} | {
|
|
183
|
+
/** The non-secret public embed id `noodle deploy` printed. Safe in page source. */
|
|
184
|
+
readonly embedId: string;
|
|
185
|
+
/** Defaults to the hosted service; set it for a dev or self-hosted deployment. */
|
|
186
|
+
readonly serviceUrl?: string | undefined;
|
|
187
|
+
readonly sessionEndpoint?: undefined;
|
|
188
|
+
};
|
|
189
|
+
|
|
168
190
|
type AssistantContextValue = string | number | boolean | null;
|
|
169
191
|
type AssistantContext = Readonly<Record<string, AssistantContextValue>>;
|
|
170
192
|
interface AssistantClientContext {
|
|
@@ -192,8 +214,7 @@ interface AssistantSessionResponse {
|
|
|
192
214
|
readonly configuration?: AssistantConfiguration;
|
|
193
215
|
}
|
|
194
216
|
|
|
195
|
-
interface
|
|
196
|
-
readonly sessionEndpoint: string;
|
|
217
|
+
interface AssistantClientBehaviorOptions<TPageContext extends AssistantPageContext = AssistantContext> {
|
|
197
218
|
readonly fetch?: typeof fetch;
|
|
198
219
|
/** Untrusted page context sent only when exchanging a session. */
|
|
199
220
|
readonly context?: AssistantContext;
|
|
@@ -204,6 +225,12 @@ interface CreateAssistantClientOptions<TPageContext extends AssistantPageContext
|
|
|
204
225
|
/** Latest renderer-selected summary included as untrusted data on every message turn. */
|
|
205
226
|
readonly modelContext?: AssistantModelContextUpdate;
|
|
206
227
|
}
|
|
228
|
+
/**
|
|
229
|
+
* How the client is mounted: through the customer's backend (`sessionEndpoint`) or, on a public page
|
|
230
|
+
* with no backend at all, straight to the service with a non-secret `embedId`. The two are exclusive —
|
|
231
|
+
* see `session-source.ts` for why they are not merged.
|
|
232
|
+
*/
|
|
233
|
+
type CreateAssistantClientOptions<TPageContext extends AssistantPageContext = AssistantContext> = AssistantClientBehaviorOptions<TPageContext> & AssistantSessionSourceOptions;
|
|
207
234
|
interface AssistantClient<TPageContext extends AssistantPageContext = AssistantContext> {
|
|
208
235
|
subscribe(listener: (event: AssistantClientEvent) => void): () => void;
|
|
209
236
|
/** Subscribe to detached AI SDK UIMessage state; the listener receives the current state immediately. */
|
|
@@ -22,6 +22,14 @@ interface AssistantErrorDetail {
|
|
|
22
22
|
readonly code: string;
|
|
23
23
|
readonly status?: number;
|
|
24
24
|
readonly retryable: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* The service's own refusal code, when it sent one — e.g. `daily_turn_budget_exhausted`.
|
|
27
|
+
*
|
|
28
|
+
* Additive beside `code` rather than replacing it: `code` is a published closed union that shipped
|
|
29
|
+
* consumers already switch on, so remapping it would break them. This is how a renderer tells a
|
|
30
|
+
* capacity decision apart from a fault.
|
|
31
|
+
*/
|
|
32
|
+
readonly serviceCode?: string;
|
|
25
33
|
}
|
|
26
34
|
|
|
27
35
|
interface NamedEvent<Name extends string, Data> {
|
|
@@ -165,6 +173,20 @@ interface AssistantChatState {
|
|
|
165
173
|
readonly error?: AssistantChatError;
|
|
166
174
|
}
|
|
167
175
|
|
|
176
|
+
/** The exclusive choice, expressed so the wrong pair does not typecheck in the first place. */
|
|
177
|
+
type AssistantSessionSourceOptions = {
|
|
178
|
+
/** The customer backend route that exchanges an embed secret for a session. */
|
|
179
|
+
readonly sessionEndpoint: string;
|
|
180
|
+
readonly embedId?: undefined;
|
|
181
|
+
readonly serviceUrl?: undefined;
|
|
182
|
+
} | {
|
|
183
|
+
/** The non-secret public embed id `noodle deploy` printed. Safe in page source. */
|
|
184
|
+
readonly embedId: string;
|
|
185
|
+
/** Defaults to the hosted service; set it for a dev or self-hosted deployment. */
|
|
186
|
+
readonly serviceUrl?: string | undefined;
|
|
187
|
+
readonly sessionEndpoint?: undefined;
|
|
188
|
+
};
|
|
189
|
+
|
|
168
190
|
type AssistantContextValue = string | number | boolean | null;
|
|
169
191
|
type AssistantContext = Readonly<Record<string, AssistantContextValue>>;
|
|
170
192
|
interface AssistantClientContext {
|
|
@@ -192,8 +214,7 @@ interface AssistantSessionResponse {
|
|
|
192
214
|
readonly configuration?: AssistantConfiguration;
|
|
193
215
|
}
|
|
194
216
|
|
|
195
|
-
interface
|
|
196
|
-
readonly sessionEndpoint: string;
|
|
217
|
+
interface AssistantClientBehaviorOptions<TPageContext extends AssistantPageContext = AssistantContext> {
|
|
197
218
|
readonly fetch?: typeof fetch;
|
|
198
219
|
/** Untrusted page context sent only when exchanging a session. */
|
|
199
220
|
readonly context?: AssistantContext;
|
|
@@ -204,6 +225,12 @@ interface CreateAssistantClientOptions<TPageContext extends AssistantPageContext
|
|
|
204
225
|
/** Latest renderer-selected summary included as untrusted data on every message turn. */
|
|
205
226
|
readonly modelContext?: AssistantModelContextUpdate;
|
|
206
227
|
}
|
|
228
|
+
/**
|
|
229
|
+
* How the client is mounted: through the customer's backend (`sessionEndpoint`) or, on a public page
|
|
230
|
+
* with no backend at all, straight to the service with a non-secret `embedId`. The two are exclusive —
|
|
231
|
+
* see `session-source.ts` for why they are not merged.
|
|
232
|
+
*/
|
|
233
|
+
type CreateAssistantClientOptions<TPageContext extends AssistantPageContext = AssistantContext> = AssistantClientBehaviorOptions<TPageContext> & AssistantSessionSourceOptions;
|
|
207
234
|
interface AssistantClient<TPageContext extends AssistantPageContext = AssistantContext> {
|
|
208
235
|
subscribe(listener: (event: AssistantClientEvent) => void): () => void;
|
|
209
236
|
/** Subscribe to detached AI SDK UIMessage state; the listener receives the current state immediately. */
|
package/dist/client.cjs
CHANGED
|
@@ -22643,7 +22643,7 @@ var AssistantChatStateStore = class {
|
|
|
22643
22643
|
this.#writeText(event.data.delta);
|
|
22644
22644
|
return;
|
|
22645
22645
|
case "tool_proposed":
|
|
22646
|
-
this.#writeConfirmation(event.data);
|
|
22646
|
+
this.#writeStandaloneData(() => this.#writeConfirmation(event.data));
|
|
22647
22647
|
return;
|
|
22648
22648
|
case "interaction_proposed":
|
|
22649
22649
|
this.#writeData("confirmation", event.data.id, {
|
|
@@ -22652,10 +22652,12 @@ var AssistantChatStateStore = class {
|
|
|
22652
22652
|
});
|
|
22653
22653
|
return;
|
|
22654
22654
|
case "input_requested":
|
|
22655
|
-
this.#
|
|
22656
|
-
|
|
22657
|
-
|
|
22658
|
-
|
|
22655
|
+
this.#writeStandaloneData(
|
|
22656
|
+
() => this.#writeData("input-request", event.data.id, {
|
|
22657
|
+
...event.data,
|
|
22658
|
+
status: "pending"
|
|
22659
|
+
})
|
|
22660
|
+
);
|
|
22659
22661
|
return;
|
|
22660
22662
|
case "tool_completed":
|
|
22661
22663
|
this.#writeData("tool-result", event.data.id, event.data);
|
|
@@ -22762,6 +22764,12 @@ var AssistantChatStateStore = class {
|
|
|
22762
22764
|
#writeConfirmation(data) {
|
|
22763
22765
|
this.#writeData("confirmation", data.id, { ...data, status: "pending" });
|
|
22764
22766
|
}
|
|
22767
|
+
#writeStandaloneData(write) {
|
|
22768
|
+
const standalone = this.#operation === void 0;
|
|
22769
|
+
if (standalone) this.#startOperation();
|
|
22770
|
+
write();
|
|
22771
|
+
if (standalone) this.#closeOperation("ready");
|
|
22772
|
+
}
|
|
22765
22773
|
#writeData(name21, id, data) {
|
|
22766
22774
|
const operation = this.#operation;
|
|
22767
22775
|
if (!operation || operation.closed) return;
|
|
@@ -23094,6 +23102,21 @@ function hasToJsonProperty(value) {
|
|
|
23094
23102
|
return false;
|
|
23095
23103
|
}
|
|
23096
23104
|
|
|
23105
|
+
// src/session-source.ts
|
|
23106
|
+
var NOODLE_CLOUD_URL = "https://cloud.noodleseed.dev";
|
|
23107
|
+
var PUBLIC_SESSION_PATH = "/v1/assistant/public-sessions";
|
|
23108
|
+
function resolveSessionSource(options) {
|
|
23109
|
+
const { sessionEndpoint, embedId, serviceUrl } = options;
|
|
23110
|
+
if (Boolean(embedId) === Boolean(sessionEndpoint)) {
|
|
23111
|
+
throw new Error("pass either embedId or sessionEndpoint, not both and not neither");
|
|
23112
|
+
}
|
|
23113
|
+
if (embedId) {
|
|
23114
|
+
const base = (serviceUrl ?? NOODLE_CLOUD_URL).replace(/\/+$/, "");
|
|
23115
|
+
return { kind: "public", url: `${base}${PUBLIC_SESSION_PATH}`, embedId };
|
|
23116
|
+
}
|
|
23117
|
+
return { kind: "exchange", url: sessionEndpoint };
|
|
23118
|
+
}
|
|
23119
|
+
|
|
23097
23120
|
// src/transport.ts
|
|
23098
23121
|
var AssistantTransportError = class extends Error {
|
|
23099
23122
|
code = "invalid_response";
|
|
@@ -23221,6 +23244,19 @@ function isAbortError2(error51) {
|
|
|
23221
23244
|
}
|
|
23222
23245
|
|
|
23223
23246
|
// src/client.ts
|
|
23247
|
+
async function refusalCode(response) {
|
|
23248
|
+
try {
|
|
23249
|
+
const body = await response.clone().json();
|
|
23250
|
+
const code = body.code;
|
|
23251
|
+
return typeof code === "string" ? code : void 0;
|
|
23252
|
+
} catch {
|
|
23253
|
+
return void 0;
|
|
23254
|
+
}
|
|
23255
|
+
}
|
|
23256
|
+
var UNRETRYABLE_SERVICE_CODES = /* @__PURE__ */ new Set([
|
|
23257
|
+
"daily_turn_budget_exhausted",
|
|
23258
|
+
"daily_session_budget_exhausted"
|
|
23259
|
+
]);
|
|
23224
23260
|
var AssistantClientError = class extends Error {
|
|
23225
23261
|
detail;
|
|
23226
23262
|
constructor(detail, message, options) {
|
|
@@ -23230,7 +23266,7 @@ var AssistantClientError = class extends Error {
|
|
|
23230
23266
|
}
|
|
23231
23267
|
};
|
|
23232
23268
|
var DefaultAssistantClient = class {
|
|
23233
|
-
#
|
|
23269
|
+
#source;
|
|
23234
23270
|
#fetch;
|
|
23235
23271
|
#listeners = /* @__PURE__ */ new Set();
|
|
23236
23272
|
#chat = new AssistantChatStateStore();
|
|
@@ -23240,9 +23276,9 @@ var DefaultAssistantClient = class {
|
|
|
23240
23276
|
#context;
|
|
23241
23277
|
#modelContext;
|
|
23242
23278
|
#active;
|
|
23279
|
+
#pendingAppInteractions = /* @__PURE__ */ new Map();
|
|
23243
23280
|
constructor(options) {
|
|
23244
|
-
|
|
23245
|
-
this.#sessionEndpoint = options.sessionEndpoint;
|
|
23281
|
+
this.#source = resolveSessionSource(options);
|
|
23246
23282
|
this.#fetch = options.fetch ?? ((input, init) => globalThis.fetch(input, init));
|
|
23247
23283
|
this.#context = options.context ? { ...options.context } : void 0;
|
|
23248
23284
|
this.#modelContext = options.modelContext ? copyAssistantModelContext(options.modelContext) : void 0;
|
|
@@ -23281,6 +23317,7 @@ var DefaultAssistantClient = class {
|
|
|
23281
23317
|
}
|
|
23282
23318
|
await this.#singleFlight(async (signal) => {
|
|
23283
23319
|
await this.#runChatOperation(signal, async () => {
|
|
23320
|
+
const pendingApp = this.#pendingAppInteractions.get(id);
|
|
23284
23321
|
const session = this.#session;
|
|
23285
23322
|
if (!session) {
|
|
23286
23323
|
throw clientError("confirmation_expired", "assistant session is not active", false);
|
|
@@ -23300,32 +23337,67 @@ var DefaultAssistantClient = class {
|
|
|
23300
23337
|
...resolution.action === "accept" && resolution.content !== void 0 ? { content: resolution.content } : {}
|
|
23301
23338
|
} : { id };
|
|
23302
23339
|
this.#emit({ event: "interaction_started", data: { id, action: resolution.action } });
|
|
23303
|
-
|
|
23304
|
-
|
|
23305
|
-
|
|
23306
|
-
|
|
23307
|
-
|
|
23308
|
-
|
|
23309
|
-
|
|
23310
|
-
|
|
23311
|
-
|
|
23312
|
-
|
|
23313
|
-
if (response.status === 401) {
|
|
23314
|
-
this.#session = void 0;
|
|
23315
|
-
this.#emit({ event: "session_expired", data: {} });
|
|
23316
|
-
}
|
|
23317
|
-
if (!response.ok) {
|
|
23318
|
-
const serverCode = await readStableErrorCode(response);
|
|
23319
|
-
const expired = response.status === 401 || response.status === 409;
|
|
23320
|
-
throw clientError(
|
|
23321
|
-
serverCode ?? (expired ? "confirmation_expired" : "confirmation_failed"),
|
|
23322
|
-
`Assistant interaction failed (${response.status})`,
|
|
23323
|
-
false,
|
|
23324
|
-
response.status
|
|
23340
|
+
try {
|
|
23341
|
+
const response = await this.#request(
|
|
23342
|
+
endpoint,
|
|
23343
|
+
{
|
|
23344
|
+
method: "POST",
|
|
23345
|
+
headers: authorizedHeaders(session.token, "text/event-stream"),
|
|
23346
|
+
body: JSON.stringify(body),
|
|
23347
|
+
signal
|
|
23348
|
+
},
|
|
23349
|
+
"confirmation_failed"
|
|
23325
23350
|
);
|
|
23351
|
+
if (response.status === 401) {
|
|
23352
|
+
this.#session = void 0;
|
|
23353
|
+
this.#emit({ event: "session_expired", data: {} });
|
|
23354
|
+
}
|
|
23355
|
+
if (!response.ok) {
|
|
23356
|
+
const serverCode = await readStableErrorCode(response);
|
|
23357
|
+
const expired = response.status === 401 || response.status === 409;
|
|
23358
|
+
throw clientError(
|
|
23359
|
+
serverCode ?? (expired ? "confirmation_expired" : "confirmation_failed"),
|
|
23360
|
+
`Assistant interaction failed (${response.status})`,
|
|
23361
|
+
false,
|
|
23362
|
+
response.status
|
|
23363
|
+
);
|
|
23364
|
+
}
|
|
23365
|
+
let completedResult;
|
|
23366
|
+
let nextInteractionId;
|
|
23367
|
+
await this.#consume(response, (event) => {
|
|
23368
|
+
if (event.event === "tool_completed" && event.data.id === id) {
|
|
23369
|
+
completedResult = event.data.result;
|
|
23370
|
+
}
|
|
23371
|
+
if ((event.event === "tool_proposed" || event.event === "input_requested") && event.data.id !== id) {
|
|
23372
|
+
nextInteractionId = event.data.id;
|
|
23373
|
+
}
|
|
23374
|
+
});
|
|
23375
|
+
this.#emit({ event: "interaction_completed", data: { id, action: resolution.action } });
|
|
23376
|
+
if (pendingApp) {
|
|
23377
|
+
this.#pendingAppInteractions.delete(id);
|
|
23378
|
+
if (nextInteractionId) {
|
|
23379
|
+
this.#pendingAppInteractions.set(nextInteractionId, pendingApp);
|
|
23380
|
+
} else if (resolution.action !== "accept") {
|
|
23381
|
+
pendingApp.resolve(appInteractionStopped(resolution.action));
|
|
23382
|
+
} else if (completedResult !== void 0) {
|
|
23383
|
+
pendingApp.resolve(appToolResult(completedResult));
|
|
23384
|
+
} else {
|
|
23385
|
+
pendingApp.reject(
|
|
23386
|
+
clientError(
|
|
23387
|
+
"invalid_response",
|
|
23388
|
+
"Assistant app interaction completed without a tool result",
|
|
23389
|
+
false
|
|
23390
|
+
)
|
|
23391
|
+
);
|
|
23392
|
+
}
|
|
23393
|
+
}
|
|
23394
|
+
} catch (error51) {
|
|
23395
|
+
if (pendingApp && this.#pendingAppInteractions.get(id) === pendingApp) {
|
|
23396
|
+
this.#pendingAppInteractions.delete(id);
|
|
23397
|
+
pendingApp.reject(error51);
|
|
23398
|
+
}
|
|
23399
|
+
throw error51;
|
|
23326
23400
|
}
|
|
23327
|
-
await this.#consume(response);
|
|
23328
|
-
this.#emit({ event: "interaction_completed", data: { id, action: resolution.action } });
|
|
23329
23401
|
});
|
|
23330
23402
|
});
|
|
23331
23403
|
}
|
|
@@ -23366,12 +23438,29 @@ var DefaultAssistantClient = class {
|
|
|
23366
23438
|
response.status
|
|
23367
23439
|
);
|
|
23368
23440
|
}
|
|
23369
|
-
|
|
23441
|
+
const value = await response.json();
|
|
23442
|
+
const interaction = parseAppInteraction(value);
|
|
23443
|
+
if (!interaction) return value;
|
|
23444
|
+
return new Promise((resolve2, reject) => {
|
|
23445
|
+
const id = interaction.data.id;
|
|
23446
|
+
const replaced = this.#pendingAppInteractions.get(id);
|
|
23447
|
+
if (replaced) {
|
|
23448
|
+
replaced.reject(
|
|
23449
|
+
clientError("invalid_response", "Assistant returned a duplicate app interaction", false)
|
|
23450
|
+
);
|
|
23451
|
+
}
|
|
23452
|
+
this.#pendingAppInteractions.set(id, { resolve: resolve2, reject });
|
|
23453
|
+
this.#emit(interaction);
|
|
23454
|
+
void this.#chat.flush();
|
|
23455
|
+
});
|
|
23370
23456
|
}
|
|
23371
23457
|
appSandboxUrl() {
|
|
23372
23458
|
return this.#session?.endpoints.sandbox;
|
|
23373
23459
|
}
|
|
23374
23460
|
resetSession() {
|
|
23461
|
+
this.#rejectPendingAppInteractions(
|
|
23462
|
+
clientError("confirmation_expired", "assistant session is not active", false)
|
|
23463
|
+
);
|
|
23375
23464
|
this.#session = void 0;
|
|
23376
23465
|
this.#emit({ event: "session_reset", data: {} });
|
|
23377
23466
|
}
|
|
@@ -23405,11 +23494,14 @@ var DefaultAssistantClient = class {
|
|
|
23405
23494
|
return;
|
|
23406
23495
|
}
|
|
23407
23496
|
if (!response.ok) {
|
|
23497
|
+
const serviceCode = await refusalCode(response);
|
|
23408
23498
|
throw clientError(
|
|
23409
23499
|
"turn_failed",
|
|
23410
23500
|
`Assistant turn failed (${response.status})`,
|
|
23411
23501
|
false,
|
|
23412
|
-
response.status
|
|
23502
|
+
response.status,
|
|
23503
|
+
void 0,
|
|
23504
|
+
serviceCode
|
|
23413
23505
|
);
|
|
23414
23506
|
}
|
|
23415
23507
|
await this.#consume(response);
|
|
@@ -23448,23 +23540,25 @@ var DefaultAssistantClient = class {
|
|
|
23448
23540
|
}
|
|
23449
23541
|
}
|
|
23450
23542
|
async #createSession(signal) {
|
|
23451
|
-
const
|
|
23452
|
-
|
|
23453
|
-
|
|
23454
|
-
|
|
23455
|
-
|
|
23456
|
-
|
|
23457
|
-
|
|
23458
|
-
|
|
23459
|
-
|
|
23460
|
-
|
|
23461
|
-
);
|
|
23543
|
+
const source = this.#source;
|
|
23544
|
+
const response = await this.#requestSession(source, {
|
|
23545
|
+
method: "POST",
|
|
23546
|
+
headers: { Accept: "application/json", "Content-Type": "application/json" },
|
|
23547
|
+
body: JSON.stringify(
|
|
23548
|
+
source.kind === "public" ? { embedId: source.embedId } : this.#context ? { context: this.#context } : {}
|
|
23549
|
+
),
|
|
23550
|
+
credentials: source.kind === "public" ? "omit" : "same-origin",
|
|
23551
|
+
signal
|
|
23552
|
+
});
|
|
23462
23553
|
if (!response.ok) {
|
|
23554
|
+
const serviceCode = await refusalCode(response);
|
|
23463
23555
|
throw clientError(
|
|
23464
23556
|
"session_failed",
|
|
23465
23557
|
`Assistant session failed (${response.status})`,
|
|
23466
|
-
|
|
23467
|
-
response.status
|
|
23558
|
+
serviceCode === void 0 || !UNRETRYABLE_SERVICE_CODES.has(serviceCode),
|
|
23559
|
+
response.status,
|
|
23560
|
+
void 0,
|
|
23561
|
+
serviceCode
|
|
23468
23562
|
);
|
|
23469
23563
|
}
|
|
23470
23564
|
let value;
|
|
@@ -23492,12 +23586,13 @@ var DefaultAssistantClient = class {
|
|
|
23492
23586
|
});
|
|
23493
23587
|
return session;
|
|
23494
23588
|
}
|
|
23495
|
-
async #consume(response) {
|
|
23589
|
+
async #consume(response, observe) {
|
|
23496
23590
|
let streamError;
|
|
23497
23591
|
try {
|
|
23498
23592
|
await consumeAssistantEvents(response, (event) => {
|
|
23499
23593
|
const clientEvent = toAssistantClientEvent(event);
|
|
23500
23594
|
this.#emit(clientEvent);
|
|
23595
|
+
observe?.(clientEvent);
|
|
23501
23596
|
if (clientEvent.event !== "error" || typeof clientEvent.data.code !== "string") return;
|
|
23502
23597
|
streamError = {
|
|
23503
23598
|
code: clientEvent.data.code,
|
|
@@ -23520,6 +23615,34 @@ var DefaultAssistantClient = class {
|
|
|
23520
23615
|
);
|
|
23521
23616
|
}
|
|
23522
23617
|
}
|
|
23618
|
+
/**
|
|
23619
|
+
* The mint, with the one failure a public page hits that an in-app embed cannot.
|
|
23620
|
+
*
|
|
23621
|
+
* A page that loads the embed script and then blocks `connect-src` fails here as a bare network
|
|
23622
|
+
* rejection — no status, no body, nothing to read. "Assistant request failed" sends a developer
|
|
23623
|
+
* hunting through their own code; naming the directive and the origin ends the search. The message
|
|
23624
|
+
* covers a plain outage too, because from inside the browser the two are indistinguishable.
|
|
23625
|
+
*/
|
|
23626
|
+
async #requestSession(source, init) {
|
|
23627
|
+
try {
|
|
23628
|
+
return await this.#fetch(source.url, init);
|
|
23629
|
+
} catch (error51) {
|
|
23630
|
+
if (init.signal?.aborted) throw error51;
|
|
23631
|
+
if (source.kind !== "public") {
|
|
23632
|
+
throw clientError("session_failed", "Assistant request failed", true, void 0, {
|
|
23633
|
+
cause: error51
|
|
23634
|
+
});
|
|
23635
|
+
}
|
|
23636
|
+
throw clientError(
|
|
23637
|
+
"session_failed",
|
|
23638
|
+
`Assistant could not reach ${new URL(source.url).origin}. If the page sets a Content-Security-Policy, allow that origin in connect-src (and in script-src and frame-src).`,
|
|
23639
|
+
true,
|
|
23640
|
+
void 0,
|
|
23641
|
+
{ cause: error51 },
|
|
23642
|
+
"blocked_by_page"
|
|
23643
|
+
);
|
|
23644
|
+
}
|
|
23645
|
+
}
|
|
23523
23646
|
async #request(input, init, failureCode) {
|
|
23524
23647
|
try {
|
|
23525
23648
|
return await this.#fetch(input, init);
|
|
@@ -23566,6 +23689,10 @@ var DefaultAssistantClient = class {
|
|
|
23566
23689
|
}
|
|
23567
23690
|
}
|
|
23568
23691
|
}
|
|
23692
|
+
#rejectPendingAppInteractions(error51) {
|
|
23693
|
+
for (const pending of this.#pendingAppInteractions.values()) pending.reject(error51);
|
|
23694
|
+
this.#pendingAppInteractions.clear();
|
|
23695
|
+
}
|
|
23569
23696
|
};
|
|
23570
23697
|
function createAssistantClient(options) {
|
|
23571
23698
|
return new DefaultAssistantClient(options);
|
|
@@ -23577,6 +23704,30 @@ function authorizedHeaders(token, accept) {
|
|
|
23577
23704
|
Accept: accept
|
|
23578
23705
|
};
|
|
23579
23706
|
}
|
|
23707
|
+
function parseAppInteraction(value) {
|
|
23708
|
+
if (!isRecord4(value) || !isRecord4(value.interaction)) return void 0;
|
|
23709
|
+
const event = value.interaction.event;
|
|
23710
|
+
const data = value.interaction.data;
|
|
23711
|
+
if (event !== "tool_proposed" && event !== "input_requested" || !isRecord4(data)) {
|
|
23712
|
+
return void 0;
|
|
23713
|
+
}
|
|
23714
|
+
const parsed = toAssistantClientEvent({ event, data });
|
|
23715
|
+
return parsed.event === "tool_proposed" || parsed.event === "input_requested" ? parsed : void 0;
|
|
23716
|
+
}
|
|
23717
|
+
function appToolResult(result) {
|
|
23718
|
+
const text2 = typeof result === "string" ? result : JSON.stringify(result);
|
|
23719
|
+
return result !== null && typeof result === "object" && !Array.isArray(result) ? {
|
|
23720
|
+
content: [{ type: "text", text: text2 }],
|
|
23721
|
+
structuredContent: result,
|
|
23722
|
+
isError: false
|
|
23723
|
+
} : { content: [{ type: "text", text: text2 }], isError: false };
|
|
23724
|
+
}
|
|
23725
|
+
function appInteractionStopped(action) {
|
|
23726
|
+
return {
|
|
23727
|
+
content: [{ type: "text", text: `interaction_${action}` }],
|
|
23728
|
+
isError: true
|
|
23729
|
+
};
|
|
23730
|
+
}
|
|
23580
23731
|
function parseSession(value) {
|
|
23581
23732
|
if (!isRecord4(value) || !isRecord4(value.endpoints)) {
|
|
23582
23733
|
throw clientError("session_failed", "Assistant session response is invalid", true);
|
|
@@ -23613,9 +23764,14 @@ async function readStableErrorCode(response) {
|
|
|
23613
23764
|
if (!isRecord4(value) || typeof value.code !== "string") return void 0;
|
|
23614
23765
|
return /^[A-Za-z0-9_.-]{1,64}$/.test(value.code) ? value.code : void 0;
|
|
23615
23766
|
}
|
|
23616
|
-
function clientError(code, message, retryable, status, options) {
|
|
23767
|
+
function clientError(code, message, retryable, status, options, serviceCode) {
|
|
23617
23768
|
return new AssistantClientError(
|
|
23618
|
-
{
|
|
23769
|
+
{
|
|
23770
|
+
code,
|
|
23771
|
+
...status === void 0 ? {} : { status },
|
|
23772
|
+
retryable,
|
|
23773
|
+
...serviceCode === void 0 ? {} : { serviceCode }
|
|
23774
|
+
},
|
|
23619
23775
|
message,
|
|
23620
23776
|
options
|
|
23621
23777
|
);
|