@noodleseed/assistant 1.19.0 → 1.21.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 +90 -0
- package/dist/{chunk-RFETV5KQ.js → chunk-LEKEIHJV.js} +68 -40
- package/dist/{chunk-RFETV5KQ.js.map → chunk-LEKEIHJV.js.map} +1 -1
- package/dist/{chunk-S373FCAI.js → chunk-ZPZHPXIQ.js} +137 -85
- package/dist/chunk-ZPZHPXIQ.js.map +1 -0
- package/dist/{client-BQ30Fq-c.d.cts → client-BZ7xPwfW.d.cts} +20 -9
- package/dist/{client-B6pnBmF8.d.ts → client-BkJlpN5N.d.ts} +20 -9
- package/dist/client.cjs +135 -83
- 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 +65 -65
- package/dist/index.cjs +201 -121
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/react/client.cjs +135 -83
- package/dist/react/client.cjs.map +1 -1
- package/dist/react/client.d.cts +1 -1
- package/dist/react/client.d.ts +1 -1
- package/dist/react/client.js +1 -1
- package/dist/react.cjs +202 -121
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +8 -1
- package/dist/react.d.ts +8 -1
- package/dist/react.js +3 -2
- package/dist/react.js.map +1 -1
- package/dist/server.cjs +48 -1
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +75 -7
- package/dist/server.d.ts +75 -7
- package/dist/server.js +46 -1
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-S373FCAI.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -27030,6 +27030,12 @@ var AssistantChatStateStore = class {
|
|
|
27030
27030
|
case "interaction_started":
|
|
27031
27031
|
this.#beginInteraction(event.data.id);
|
|
27032
27032
|
return;
|
|
27033
|
+
case "resume_started":
|
|
27034
|
+
this.#status = "submitted";
|
|
27035
|
+
this.#error = void 0;
|
|
27036
|
+
this.#startOperation();
|
|
27037
|
+
this.#notify();
|
|
27038
|
+
return;
|
|
27033
27039
|
case "content":
|
|
27034
27040
|
this.#writeText(event.data.delta);
|
|
27035
27041
|
return;
|
|
@@ -27285,6 +27291,78 @@ function isRecord(value) {
|
|
|
27285
27291
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27286
27292
|
}
|
|
27287
27293
|
|
|
27294
|
+
// src/client-errors.ts
|
|
27295
|
+
async function refusalCode(response) {
|
|
27296
|
+
try {
|
|
27297
|
+
const body = await response.clone().json();
|
|
27298
|
+
const code = body.code;
|
|
27299
|
+
return typeof code === "string" ? code : void 0;
|
|
27300
|
+
} catch {
|
|
27301
|
+
return void 0;
|
|
27302
|
+
}
|
|
27303
|
+
}
|
|
27304
|
+
var UNRETRYABLE_SERVICE_CODES = /* @__PURE__ */ new Set([
|
|
27305
|
+
"daily_turn_budget_exhausted",
|
|
27306
|
+
"daily_session_budget_exhausted"
|
|
27307
|
+
]);
|
|
27308
|
+
var AssistantClientError = class extends Error {
|
|
27309
|
+
detail;
|
|
27310
|
+
constructor(detail, message, options) {
|
|
27311
|
+
super(message, options);
|
|
27312
|
+
this.name = "AssistantClientError";
|
|
27313
|
+
this.detail = detail;
|
|
27314
|
+
}
|
|
27315
|
+
};
|
|
27316
|
+
function parseSession(value) {
|
|
27317
|
+
if (!isRecord2(value) || !isRecord2(value.endpoints)) {
|
|
27318
|
+
throw clientError("session_failed", "Assistant session response is invalid", true);
|
|
27319
|
+
}
|
|
27320
|
+
const interactions = value.endpoints.interactions;
|
|
27321
|
+
const apps = value.endpoints.apps;
|
|
27322
|
+
const sandbox = value.endpoints.sandbox;
|
|
27323
|
+
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") {
|
|
27324
|
+
throw clientError("session_failed", "Assistant session response is invalid", true);
|
|
27325
|
+
}
|
|
27326
|
+
return {
|
|
27327
|
+
token: value.token,
|
|
27328
|
+
expiresAt: value.expiresAt,
|
|
27329
|
+
endpoints: {
|
|
27330
|
+
turns: value.endpoints.turns,
|
|
27331
|
+
toolConfirmations: value.endpoints.toolConfirmations,
|
|
27332
|
+
...typeof interactions === "string" ? { interactions } : {},
|
|
27333
|
+
...typeof apps === "string" ? { apps } : {},
|
|
27334
|
+
...typeof sandbox === "string" ? { sandbox } : {}
|
|
27335
|
+
},
|
|
27336
|
+
...isRecord2(value.configuration) ? { configuration: value.configuration } : {},
|
|
27337
|
+
...isRecord2(value.resume) && typeof value.resume.tool === "string" ? { resume: { tool: value.resume.tool } } : {}
|
|
27338
|
+
};
|
|
27339
|
+
}
|
|
27340
|
+
function isRecord2(value) {
|
|
27341
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27342
|
+
}
|
|
27343
|
+
async function readStableErrorCode(response) {
|
|
27344
|
+
let value;
|
|
27345
|
+
try {
|
|
27346
|
+
value = await response.json();
|
|
27347
|
+
} catch {
|
|
27348
|
+
return void 0;
|
|
27349
|
+
}
|
|
27350
|
+
if (!isRecord2(value) || typeof value.code !== "string") return void 0;
|
|
27351
|
+
return /^[A-Za-z0-9_.-]{1,64}$/.test(value.code) ? value.code : void 0;
|
|
27352
|
+
}
|
|
27353
|
+
function clientError(code, message, retryable, status, options, serviceCode) {
|
|
27354
|
+
return new AssistantClientError(
|
|
27355
|
+
{
|
|
27356
|
+
code,
|
|
27357
|
+
...status === void 0 ? {} : { status },
|
|
27358
|
+
retryable,
|
|
27359
|
+
...serviceCode === void 0 ? {} : { serviceCode }
|
|
27360
|
+
},
|
|
27361
|
+
message,
|
|
27362
|
+
options
|
|
27363
|
+
);
|
|
27364
|
+
}
|
|
27365
|
+
|
|
27288
27366
|
// src/events.ts
|
|
27289
27367
|
function toAssistantClientEvent(event) {
|
|
27290
27368
|
const value = event.data;
|
|
@@ -27300,20 +27378,25 @@ function toAssistantClientEvent(event) {
|
|
|
27300
27378
|
}
|
|
27301
27379
|
break;
|
|
27302
27380
|
case "tool_proposed":
|
|
27303
|
-
if (hasString(value, "id") && hasString(value, "tool") && hasOptionalString(value.title) && hasOptionalString(value.description) && hasOptionalJson(value.arguments) && (value.reviewSchema === void 0 ||
|
|
27381
|
+
if (hasString(value, "id") && hasString(value, "tool") && hasOptionalString(value.title) && hasOptionalString(value.description) && hasOptionalJson(value.arguments) && (value.reviewSchema === void 0 || isRecord3(value.reviewSchema)) && hasOptionalString(value.expiresAt) && (value.requiresConfirmation === void 0 || value.requiresConfirmation === true) && hasOptionalTurnId(value)) {
|
|
27304
27382
|
return event;
|
|
27305
27383
|
}
|
|
27306
27384
|
break;
|
|
27307
27385
|
case "input_requested":
|
|
27308
|
-
if (hasString(value, "id") && hasString(value, "message") &&
|
|
27386
|
+
if (hasString(value, "id") && hasString(value, "message") && isRecord3(value.requestedSchema) && hasString(value, "expiresAt") && hasOptionalTurnId(value)) {
|
|
27309
27387
|
return event;
|
|
27310
27388
|
}
|
|
27311
27389
|
break;
|
|
27312
|
-
case "auth_requested":
|
|
27313
|
-
|
|
27314
|
-
|
|
27390
|
+
case "auth_requested": {
|
|
27391
|
+
const signInTicket = typeof value.signInTicket === "string" ? value.signInTicket : typeof value.continuation === "string" ? value.continuation : void 0;
|
|
27392
|
+
if (hasString(value, "id") && hasString(value, "tool") && signInTicket !== void 0 && hasString(value, "expiresAt") && hasOptionalTurnId(value)) {
|
|
27393
|
+
return {
|
|
27394
|
+
event: "auth_requested",
|
|
27395
|
+
data: { ...value, signInTicket }
|
|
27396
|
+
};
|
|
27315
27397
|
}
|
|
27316
27398
|
break;
|
|
27399
|
+
}
|
|
27317
27400
|
case "interaction_resolved":
|
|
27318
27401
|
if (hasString(value, "id") && (value.action === void 0 || isInteractionAction(value.action)) && hasOptionalTurnId(value)) {
|
|
27319
27402
|
return event;
|
|
@@ -27344,7 +27427,7 @@ function toAssistantClientEvent(event) {
|
|
|
27344
27427
|
return { event: "unrecognized", data: { name: event.event, payload: value } };
|
|
27345
27428
|
}
|
|
27346
27429
|
function isViewAvailableDetail(value) {
|
|
27347
|
-
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 ||
|
|
27430
|
+
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 || isRecord3(value.resourceMeta)) && (value.allowedOpenDomains === void 0 || Array.isArray(value.allowedOpenDomains) && value.allowedOpenDomains.every(isHttpsUrl)) && hasOptionalTurnId(value);
|
|
27348
27431
|
}
|
|
27349
27432
|
function isHttpsUrl(value) {
|
|
27350
27433
|
if (typeof value !== "string") return false;
|
|
@@ -27377,11 +27460,11 @@ function isJsonValue(value, depth) {
|
|
|
27377
27460
|
if (Array.isArray(value)) {
|
|
27378
27461
|
return value.length <= 256 && value.every((entry) => isJsonValue(entry, depth + 1));
|
|
27379
27462
|
}
|
|
27380
|
-
if (!
|
|
27463
|
+
if (!isRecord3(value)) return false;
|
|
27381
27464
|
const entries2 = Object.entries(value);
|
|
27382
27465
|
return entries2.length <= 256 && entries2.every(([, entry]) => isJsonValue(entry, depth + 1));
|
|
27383
27466
|
}
|
|
27384
|
-
function
|
|
27467
|
+
function isRecord3(value) {
|
|
27385
27468
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27386
27469
|
}
|
|
27387
27470
|
|
|
@@ -27511,15 +27594,15 @@ function parseFrame(frame) {
|
|
|
27511
27594
|
if (event === "done" && !isValidDonePayload(parsed)) {
|
|
27512
27595
|
throw invalidStream("assistant event stream contained an invalid done event");
|
|
27513
27596
|
}
|
|
27514
|
-
return { event, data:
|
|
27597
|
+
return { event, data: isRecord4(parsed) ? parsed : { value: parsed } };
|
|
27515
27598
|
}
|
|
27516
27599
|
function normalizeLineEndings(input) {
|
|
27517
27600
|
return input.replaceAll("\r\n", "\n").replaceAll("\r", "\n");
|
|
27518
27601
|
}
|
|
27519
27602
|
function isValidDonePayload(value) {
|
|
27520
|
-
return
|
|
27603
|
+
return isRecord4(value) && (value.turnId === void 0 || typeof value.turnId === "string" && value.turnId.length > 0);
|
|
27521
27604
|
}
|
|
27522
|
-
function
|
|
27605
|
+
function isRecord4(value) {
|
|
27523
27606
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27524
27607
|
}
|
|
27525
27608
|
function invalidStream(message, cause) {
|
|
@@ -27530,27 +27613,6 @@ function isAbortError2(error51) {
|
|
|
27530
27613
|
}
|
|
27531
27614
|
|
|
27532
27615
|
// src/client.ts
|
|
27533
|
-
async function refusalCode(response) {
|
|
27534
|
-
try {
|
|
27535
|
-
const body = await response.clone().json();
|
|
27536
|
-
const code = body.code;
|
|
27537
|
-
return typeof code === "string" ? code : void 0;
|
|
27538
|
-
} catch {
|
|
27539
|
-
return void 0;
|
|
27540
|
-
}
|
|
27541
|
-
}
|
|
27542
|
-
var UNRETRYABLE_SERVICE_CODES = /* @__PURE__ */ new Set([
|
|
27543
|
-
"daily_turn_budget_exhausted",
|
|
27544
|
-
"daily_session_budget_exhausted"
|
|
27545
|
-
]);
|
|
27546
|
-
var AssistantClientError = class extends Error {
|
|
27547
|
-
detail;
|
|
27548
|
-
constructor(detail, message, options) {
|
|
27549
|
-
super(message, options);
|
|
27550
|
-
this.name = "AssistantClientError";
|
|
27551
|
-
this.detail = detail;
|
|
27552
|
-
}
|
|
27553
|
-
};
|
|
27554
27616
|
var DefaultAssistantClient = class {
|
|
27555
27617
|
#source;
|
|
27556
27618
|
#fetch;
|
|
@@ -27585,12 +27647,50 @@ var DefaultAssistantClient = class {
|
|
|
27585
27647
|
hasSession() {
|
|
27586
27648
|
return this.#session !== void 0;
|
|
27587
27649
|
}
|
|
27650
|
+
/** Whether a request holds the single-flight slot, so callers can refuse before mutating UI. */
|
|
27651
|
+
isBusy() {
|
|
27652
|
+
return this.#active !== void 0;
|
|
27653
|
+
}
|
|
27588
27654
|
async connect() {
|
|
27589
27655
|
if (this.#session) return;
|
|
27590
27656
|
await this.#singleFlight(async (signal) => {
|
|
27591
|
-
if (
|
|
27657
|
+
if (this.#session) return;
|
|
27658
|
+
const session = await this.#createSession(signal);
|
|
27659
|
+
if (session.resume) {
|
|
27660
|
+
try {
|
|
27661
|
+
await this.#runChatOperation(signal, () => this.#resumeTurn(session, signal));
|
|
27662
|
+
} catch {
|
|
27663
|
+
}
|
|
27664
|
+
}
|
|
27592
27665
|
});
|
|
27593
27666
|
}
|
|
27667
|
+
/** POST the one-shot resume trigger; a 409 means nothing was pending, which renders as silence. */
|
|
27668
|
+
async #resumeTurn(session, signal) {
|
|
27669
|
+
const response = await this.#request(
|
|
27670
|
+
session.endpoints.turns,
|
|
27671
|
+
{
|
|
27672
|
+
method: "POST",
|
|
27673
|
+
headers: authorizedHeaders(session.token, "text/event-stream"),
|
|
27674
|
+
body: JSON.stringify({ resume: true }),
|
|
27675
|
+
signal
|
|
27676
|
+
},
|
|
27677
|
+
"turn_failed"
|
|
27678
|
+
);
|
|
27679
|
+
if (response.status === 409) return;
|
|
27680
|
+
if (!response.ok) {
|
|
27681
|
+
throw clientError(
|
|
27682
|
+
"turn_failed",
|
|
27683
|
+
`Assistant turn failed (${response.status})`,
|
|
27684
|
+
false,
|
|
27685
|
+
response.status,
|
|
27686
|
+
void 0,
|
|
27687
|
+
await refusalCode(response)
|
|
27688
|
+
);
|
|
27689
|
+
}
|
|
27690
|
+
this.#emit({ event: "resume_started", data: { tool: session.resume?.tool ?? "" } });
|
|
27691
|
+
await this.#consume(response);
|
|
27692
|
+
this.#emit({ event: "message_completed", data: {} });
|
|
27693
|
+
}
|
|
27594
27694
|
async sendMessage(text3) {
|
|
27595
27695
|
const message = text3.trim();
|
|
27596
27696
|
if (!message) return;
|
|
@@ -27995,10 +28095,10 @@ function authorizedHeaders(token, accept) {
|
|
|
27995
28095
|
};
|
|
27996
28096
|
}
|
|
27997
28097
|
function parseAppInteraction(value) {
|
|
27998
|
-
if (!
|
|
28098
|
+
if (!isRecord2(value) || !isRecord2(value.interaction)) return void 0;
|
|
27999
28099
|
const event = value.interaction.event;
|
|
28000
28100
|
const data = value.interaction.data;
|
|
28001
|
-
if (event !== "tool_proposed" && event !== "input_requested" || !
|
|
28101
|
+
if (event !== "tool_proposed" && event !== "input_requested" || !isRecord2(data)) {
|
|
28002
28102
|
return void 0;
|
|
28003
28103
|
}
|
|
28004
28104
|
const parsed = toAssistantClientEvent({ event, data });
|
|
@@ -28018,54 +28118,6 @@ function appInteractionStopped(action) {
|
|
|
28018
28118
|
isError: true
|
|
28019
28119
|
};
|
|
28020
28120
|
}
|
|
28021
|
-
function parseSession(value) {
|
|
28022
|
-
if (!isRecord4(value) || !isRecord4(value.endpoints)) {
|
|
28023
|
-
throw clientError("session_failed", "Assistant session response is invalid", true);
|
|
28024
|
-
}
|
|
28025
|
-
const interactions = value.endpoints.interactions;
|
|
28026
|
-
const apps = value.endpoints.apps;
|
|
28027
|
-
const sandbox = value.endpoints.sandbox;
|
|
28028
|
-
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") {
|
|
28029
|
-
throw clientError("session_failed", "Assistant session response is invalid", true);
|
|
28030
|
-
}
|
|
28031
|
-
return {
|
|
28032
|
-
token: value.token,
|
|
28033
|
-
expiresAt: value.expiresAt,
|
|
28034
|
-
endpoints: {
|
|
28035
|
-
turns: value.endpoints.turns,
|
|
28036
|
-
toolConfirmations: value.endpoints.toolConfirmations,
|
|
28037
|
-
...typeof interactions === "string" ? { interactions } : {},
|
|
28038
|
-
...typeof apps === "string" ? { apps } : {},
|
|
28039
|
-
...typeof sandbox === "string" ? { sandbox } : {}
|
|
28040
|
-
},
|
|
28041
|
-
...isRecord4(value.configuration) ? { configuration: value.configuration } : {}
|
|
28042
|
-
};
|
|
28043
|
-
}
|
|
28044
|
-
function isRecord4(value) {
|
|
28045
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
28046
|
-
}
|
|
28047
|
-
async function readStableErrorCode(response) {
|
|
28048
|
-
let value;
|
|
28049
|
-
try {
|
|
28050
|
-
value = await response.json();
|
|
28051
|
-
} catch {
|
|
28052
|
-
return void 0;
|
|
28053
|
-
}
|
|
28054
|
-
if (!isRecord4(value) || typeof value.code !== "string") return void 0;
|
|
28055
|
-
return /^[A-Za-z0-9_.-]{1,64}$/.test(value.code) ? value.code : void 0;
|
|
28056
|
-
}
|
|
28057
|
-
function clientError(code, message, retryable, status, options, serviceCode) {
|
|
28058
|
-
return new AssistantClientError(
|
|
28059
|
-
{
|
|
28060
|
-
code,
|
|
28061
|
-
...status === void 0 ? {} : { status },
|
|
28062
|
-
retryable,
|
|
28063
|
-
...serviceCode === void 0 ? {} : { serviceCode }
|
|
28064
|
-
},
|
|
28065
|
-
message,
|
|
28066
|
-
options
|
|
28067
|
-
);
|
|
28068
|
-
}
|
|
28069
28121
|
|
|
28070
28122
|
// src/input-request-card.ts
|
|
28071
28123
|
function createInputRequestCard(options) {
|
|
@@ -31250,6 +31302,11 @@ var AssistantElementEventController = class {
|
|
|
31250
31302
|
this.#completedTool = void 0;
|
|
31251
31303
|
return;
|
|
31252
31304
|
}
|
|
31305
|
+
if (name21 === "resume_started") {
|
|
31306
|
+
this.#startStream("message");
|
|
31307
|
+
this.#host.element.dispatchEvent(new CustomEvent("assistant-message-started"));
|
|
31308
|
+
return;
|
|
31309
|
+
}
|
|
31253
31310
|
if (name21 === "interaction_completed") {
|
|
31254
31311
|
if (this.#streamKind !== "interaction") return;
|
|
31255
31312
|
this.#finishInteraction(String(data.id ?? ""), String(data.action ?? "accept"));
|
|
@@ -31270,11 +31327,11 @@ var AssistantElementEventController = class {
|
|
|
31270
31327
|
);
|
|
31271
31328
|
return;
|
|
31272
31329
|
}
|
|
31273
|
-
if (name21 === "auth_requested" && typeof data.
|
|
31330
|
+
if (name21 === "auth_requested" && typeof data.signInTicket === "string") {
|
|
31274
31331
|
this.#appendSignInRequest(
|
|
31275
31332
|
String(data.id ?? ""),
|
|
31276
31333
|
String(data.tool ?? "this"),
|
|
31277
|
-
data.
|
|
31334
|
+
data.signInTicket,
|
|
31278
31335
|
String(data.expiresAt ?? "")
|
|
31279
31336
|
);
|
|
31280
31337
|
return;
|
|
@@ -31367,15 +31424,15 @@ var AssistantElementEventController = class {
|
|
|
31367
31424
|
/**
|
|
31368
31425
|
* The host application owns the login. This renders the prompt and raises
|
|
31369
31426
|
* `assistant-sign-in-requested`; the page signs the visitor in however it already does, then its
|
|
31370
|
-
* backend spends the
|
|
31427
|
+
* backend spends the sign-in ticket. Nothing here talks to an identity provider.
|
|
31371
31428
|
*/
|
|
31372
|
-
#appendSignInRequest(id, tool,
|
|
31429
|
+
#appendSignInRequest(id, tool, signInTicket, expiresAt) {
|
|
31373
31430
|
const messages = this.#host.messages();
|
|
31374
31431
|
if (!messages) return;
|
|
31375
31432
|
this.#proposalCards.get(id)?.remove();
|
|
31376
31433
|
const card = createSignInCard({
|
|
31377
31434
|
tool,
|
|
31378
|
-
|
|
31435
|
+
signInTicket,
|
|
31379
31436
|
expiresAt,
|
|
31380
31437
|
labels: {
|
|
31381
31438
|
heading: "Sign in to continue",
|
|
@@ -31383,7 +31440,7 @@ var AssistantElementEventController = class {
|
|
|
31383
31440
|
},
|
|
31384
31441
|
onSignIn: () => this.#host.element.dispatchEvent(
|
|
31385
31442
|
new CustomEvent("assistant-sign-in-requested", {
|
|
31386
|
-
detail: { id, tool,
|
|
31443
|
+
detail: { id, tool, signInTicket, expiresAt },
|
|
31387
31444
|
bubbles: true,
|
|
31388
31445
|
composed: true
|
|
31389
31446
|
})
|
|
@@ -31394,7 +31451,7 @@ var AssistantElementEventController = class {
|
|
|
31394
31451
|
this.#host.revealLatest();
|
|
31395
31452
|
this.#host.element.dispatchEvent(
|
|
31396
31453
|
new CustomEvent("assistant-sign-in-required", {
|
|
31397
|
-
detail: { id, tool,
|
|
31454
|
+
detail: { id, tool, signInTicket, expiresAt }
|
|
31398
31455
|
})
|
|
31399
31456
|
);
|
|
31400
31457
|
}
|
|
@@ -31468,6 +31525,36 @@ function queryRequired(root, selector) {
|
|
|
31468
31525
|
if (!element) throw new Error(`assistant renderer is missing ${selector}`);
|
|
31469
31526
|
return element;
|
|
31470
31527
|
}
|
|
31528
|
+
function assistantElementMarkup(appearance, open, styles) {
|
|
31529
|
+
return `${styles}
|
|
31530
|
+
<button class="launcher" type="button" aria-label="${escapeAttribute(appearance.labels.open)}" aria-controls="assistant-panel" aria-expanded="${String(open)}"><slot name="launcher-icon"></slot><span class="visually-hidden" data-session-status aria-live="polite" hidden></span></button>
|
|
31531
|
+
<section class="panel" id="assistant-panel" role="dialog" aria-label="${escapeAttribute(appearance.brand.name)}">
|
|
31532
|
+
<header><slot name="header-leading"></slot><img class="brand-logo" alt=""><strong></strong><slot name="header-actions"></slot><button class="close" type="button" aria-label="${escapeAttribute(appearance.labels.close)}"></button></header>
|
|
31533
|
+
<div class="welcome"><slot name="empty-state"></slot></div>
|
|
31534
|
+
<div class="suggested-prompts"></div>
|
|
31535
|
+
<div class="messages-region">
|
|
31536
|
+
<div class="messages" aria-live="polite"></div>
|
|
31537
|
+
<button class="new-messages" type="button" aria-label="${escapeAttribute(appearance.labels.newMessages)}" hidden></button>
|
|
31538
|
+
</div>
|
|
31539
|
+
<form><slot name="composer-leading"></slot><textarea rows="1"></textarea><button class="send" type="submit"></button><slot name="composer-trailing"></slot></form>
|
|
31540
|
+
<nav class="legal" aria-label="Legal"></nav>
|
|
31541
|
+
<slot name="conversation-footer"></slot>
|
|
31542
|
+
</section>`;
|
|
31543
|
+
}
|
|
31544
|
+
function appendLegalLinks(legal, appearance) {
|
|
31545
|
+
for (const [label, href] of [
|
|
31546
|
+
["Privacy", appearance.privacyUrl],
|
|
31547
|
+
["Terms", appearance.termsUrl]
|
|
31548
|
+
]) {
|
|
31549
|
+
if (!href) continue;
|
|
31550
|
+
const link = document.createElement("a");
|
|
31551
|
+
link.href = href;
|
|
31552
|
+
link.target = "_blank";
|
|
31553
|
+
link.rel = "noopener noreferrer";
|
|
31554
|
+
link.textContent = label;
|
|
31555
|
+
legal.append(link);
|
|
31556
|
+
}
|
|
31557
|
+
}
|
|
31471
31558
|
|
|
31472
31559
|
// src/element-page-context-controller.ts
|
|
31473
31560
|
var AssistantElementPageContextController = class {
|
|
@@ -32255,6 +32342,8 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32255
32342
|
#pendingUserEcho;
|
|
32256
32343
|
#sessionState = "idle";
|
|
32257
32344
|
#startOpenApplied = false;
|
|
32345
|
+
#readyDispatched = false;
|
|
32346
|
+
#turnInFlight = false;
|
|
32258
32347
|
#hostAppearance;
|
|
32259
32348
|
#appearanceWarningKeys = /* @__PURE__ */ new Set();
|
|
32260
32349
|
#appearanceStyleSnapshot = /* @__PURE__ */ new Map();
|
|
@@ -32326,7 +32415,10 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32326
32415
|
document.addEventListener("pointerdown", this.#handleDocumentPointerDown);
|
|
32327
32416
|
if (this.#appearance.behavior.startOpen) this.#applyStartOpenPolicy();
|
|
32328
32417
|
this.#render();
|
|
32329
|
-
|
|
32418
|
+
if (!this.#readyDispatched) {
|
|
32419
|
+
this.#readyDispatched = true;
|
|
32420
|
+
this.dispatchEvent(new CustomEvent("assistant-ready"));
|
|
32421
|
+
}
|
|
32330
32422
|
if (this.hasAttribute("start-open")) {
|
|
32331
32423
|
this.setAttribute("open", "");
|
|
32332
32424
|
this.#startOpenApplied = true;
|
|
@@ -32440,7 +32532,14 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32440
32532
|
async sendMessage(text3) {
|
|
32441
32533
|
const message = text3.trim();
|
|
32442
32534
|
if (!message) return;
|
|
32535
|
+
if (this.#turnInFlight) {
|
|
32536
|
+
throw new AssistantClientError(
|
|
32537
|
+
{ code: "request_in_progress", retryable: true },
|
|
32538
|
+
"an assistant request is already in progress"
|
|
32539
|
+
);
|
|
32540
|
+
}
|
|
32443
32541
|
const generation = this.#conversationGeneration;
|
|
32542
|
+
this.#turnInFlight = true;
|
|
32444
32543
|
this.#pendingUserEcho = message;
|
|
32445
32544
|
this.#appendMessage("user", message);
|
|
32446
32545
|
this.#setBusy(true);
|
|
@@ -32457,6 +32556,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32457
32556
|
this.#dispatchClientError(error51, "turn_failed");
|
|
32458
32557
|
throw error51;
|
|
32459
32558
|
} finally {
|
|
32559
|
+
this.#turnInFlight = false;
|
|
32460
32560
|
if (this.#pendingUserEcho === message) this.#pendingUserEcho = void 0;
|
|
32461
32561
|
if (generation === this.#conversationGeneration) this.#setBusy(false);
|
|
32462
32562
|
}
|
|
@@ -32525,6 +32625,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32525
32625
|
#primeSession() {
|
|
32526
32626
|
if (!this.sessionEndpoint && !this.embedId) return;
|
|
32527
32627
|
if (this.#sessionBootstrap || this.#client?.hasSession()) return;
|
|
32628
|
+
if (this.#client?.isBusy?.() === true) return;
|
|
32528
32629
|
if (this.embedId && !this.#pageContext) void this.#automaticPageContext.refresh();
|
|
32529
32630
|
const client = this.#ensureClient();
|
|
32530
32631
|
const generation = this.#conversationGeneration;
|
|
@@ -32554,6 +32655,8 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32554
32655
|
if (event.event === "content" || event.event === "message_completed" || event.event === "interaction_completed" || event.event === "error") {
|
|
32555
32656
|
this.#removeThinking();
|
|
32556
32657
|
}
|
|
32658
|
+
if (event.event === "resume_started") this.#setBusy(true);
|
|
32659
|
+
if (event.event === "message_completed" || event.event === "error") this.#setBusy(false);
|
|
32557
32660
|
}
|
|
32558
32661
|
#setBusy(busy) {
|
|
32559
32662
|
this.toggleAttribute("busy", busy);
|
|
@@ -32762,7 +32865,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32762
32865
|
queryRequired(this.shadowRoot, "header").hidden = !appearance.behavior.showHeader;
|
|
32763
32866
|
const legal = queryRequired(this.shadowRoot, ".legal");
|
|
32764
32867
|
legal.replaceChildren();
|
|
32765
|
-
|
|
32868
|
+
appendLegalLinks(legal, this.#appearance);
|
|
32766
32869
|
this.#applyTheme();
|
|
32767
32870
|
}
|
|
32768
32871
|
#render() {
|
|
@@ -32778,20 +32881,11 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32778
32881
|
this.dataset.position = appearance.layout.position;
|
|
32779
32882
|
this.dataset.density = appearance.layout.density;
|
|
32780
32883
|
this.toggleAttribute("mobile-fullscreen", appearance.layout.mobileFullscreen);
|
|
32781
|
-
this.shadowRoot.innerHTML =
|
|
32782
|
-
|
|
32783
|
-
|
|
32784
|
-
|
|
32785
|
-
|
|
32786
|
-
<div class="suggested-prompts"></div>
|
|
32787
|
-
<div class="messages-region">
|
|
32788
|
-
<div class="messages" aria-live="polite"></div>
|
|
32789
|
-
<button class="new-messages" type="button" aria-label="${escapeAttribute(appearance.labels.newMessages)}" hidden></button>
|
|
32790
|
-
</div>
|
|
32791
|
-
<form><slot name="composer-leading"></slot><textarea rows="1"></textarea><button class="send" type="submit"></button><slot name="composer-trailing"></slot></form>
|
|
32792
|
-
<nav class="legal" aria-label="Legal"></nav>
|
|
32793
|
-
<slot name="conversation-footer"></slot>
|
|
32794
|
-
</section>`;
|
|
32884
|
+
this.shadowRoot.innerHTML = assistantElementMarkup(
|
|
32885
|
+
appearance,
|
|
32886
|
+
this.hasAttribute("open"),
|
|
32887
|
+
`${ASSISTANT_ELEMENT_STYLES}${presentationStyles}`
|
|
32888
|
+
);
|
|
32795
32889
|
queryRequired(this.shadowRoot, "strong").textContent = appearance.brand.name;
|
|
32796
32890
|
const logo = queryRequired(this.shadowRoot, ".brand-logo");
|
|
32797
32891
|
const logoUrl = appearance.brand.logo[this.#resolvedMode()];
|
|
@@ -32818,7 +32912,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32818
32912
|
if (!appearance.behavior.showHeader)
|
|
32819
32913
|
queryRequired(this.shadowRoot, "header").hidden = true;
|
|
32820
32914
|
const legal = queryRequired(this.shadowRoot, ".legal");
|
|
32821
|
-
|
|
32915
|
+
appendLegalLinks(legal, this.#appearance);
|
|
32822
32916
|
this.#messages = this.shadowRoot.querySelector(".messages") ?? void 0;
|
|
32823
32917
|
this.#messages?.append(...conversation);
|
|
32824
32918
|
this.#thinking = this.#messages?.querySelector(".thinking") ?? void 0;
|
|
@@ -32857,20 +32951,6 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32857
32951
|
});
|
|
32858
32952
|
this.#applyTheme();
|
|
32859
32953
|
}
|
|
32860
|
-
#appendLegalLinks(legal) {
|
|
32861
|
-
for (const [label, href] of [
|
|
32862
|
-
["Privacy", this.#appearance.privacyUrl],
|
|
32863
|
-
["Terms", this.#appearance.termsUrl]
|
|
32864
|
-
]) {
|
|
32865
|
-
if (!href) continue;
|
|
32866
|
-
const link = document.createElement("a");
|
|
32867
|
-
link.href = href;
|
|
32868
|
-
link.target = "_blank";
|
|
32869
|
-
link.rel = "noopener noreferrer";
|
|
32870
|
-
link.textContent = label;
|
|
32871
|
-
legal.append(link);
|
|
32872
|
-
}
|
|
32873
|
-
}
|
|
32874
32954
|
};
|
|
32875
32955
|
function registerNoodleAssistant() {
|
|
32876
32956
|
if (globalThis.customElements && !customElements.get(ASSISTANT_TAG_NAME)) {
|