@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/react/client.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as AssistantPageContext, a as AssistantContext, C as CreateAssistantClientOptions, b as AssistantChatState, c as AssistantClient } from '../client-
|
|
1
|
+
import { A as AssistantPageContext, a as AssistantContext, C as CreateAssistantClientOptions, b as AssistantChatState, c as AssistantClient } from '../client-BZ7xPwfW.cjs';
|
|
2
2
|
import '../appearance-Cc-eqSbp.cjs';
|
|
3
3
|
import 'ai';
|
|
4
4
|
|
package/dist/react/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as AssistantPageContext, a as AssistantContext, C as CreateAssistantClientOptions, b as AssistantChatState, c as AssistantClient } from '../client-
|
|
1
|
+
import { A as AssistantPageContext, a as AssistantContext, C as CreateAssistantClientOptions, b as AssistantChatState, c as AssistantClient } from '../client-BkJlpN5N.js';
|
|
2
2
|
import '../appearance-Cc-eqSbp.js';
|
|
3
3
|
import 'ai';
|
|
4
4
|
|
package/dist/react/client.js
CHANGED
package/dist/react.cjs
CHANGED
|
@@ -27033,6 +27033,12 @@ var AssistantChatStateStore = class {
|
|
|
27033
27033
|
case "interaction_started":
|
|
27034
27034
|
this.#beginInteraction(event.data.id);
|
|
27035
27035
|
return;
|
|
27036
|
+
case "resume_started":
|
|
27037
|
+
this.#status = "submitted";
|
|
27038
|
+
this.#error = void 0;
|
|
27039
|
+
this.#startOperation();
|
|
27040
|
+
this.#notify();
|
|
27041
|
+
return;
|
|
27036
27042
|
case "content":
|
|
27037
27043
|
this.#writeText(event.data.delta);
|
|
27038
27044
|
return;
|
|
@@ -27288,6 +27294,78 @@ function isRecord(value) {
|
|
|
27288
27294
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27289
27295
|
}
|
|
27290
27296
|
|
|
27297
|
+
// src/client-errors.ts
|
|
27298
|
+
async function refusalCode(response) {
|
|
27299
|
+
try {
|
|
27300
|
+
const body = await response.clone().json();
|
|
27301
|
+
const code = body.code;
|
|
27302
|
+
return typeof code === "string" ? code : void 0;
|
|
27303
|
+
} catch {
|
|
27304
|
+
return void 0;
|
|
27305
|
+
}
|
|
27306
|
+
}
|
|
27307
|
+
var UNRETRYABLE_SERVICE_CODES = /* @__PURE__ */ new Set([
|
|
27308
|
+
"daily_turn_budget_exhausted",
|
|
27309
|
+
"daily_session_budget_exhausted"
|
|
27310
|
+
]);
|
|
27311
|
+
var AssistantClientError = class extends Error {
|
|
27312
|
+
detail;
|
|
27313
|
+
constructor(detail, message, options) {
|
|
27314
|
+
super(message, options);
|
|
27315
|
+
this.name = "AssistantClientError";
|
|
27316
|
+
this.detail = detail;
|
|
27317
|
+
}
|
|
27318
|
+
};
|
|
27319
|
+
function parseSession(value) {
|
|
27320
|
+
if (!isRecord2(value) || !isRecord2(value.endpoints)) {
|
|
27321
|
+
throw clientError("session_failed", "Assistant session response is invalid", true);
|
|
27322
|
+
}
|
|
27323
|
+
const interactions = value.endpoints.interactions;
|
|
27324
|
+
const apps = value.endpoints.apps;
|
|
27325
|
+
const sandbox = value.endpoints.sandbox;
|
|
27326
|
+
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") {
|
|
27327
|
+
throw clientError("session_failed", "Assistant session response is invalid", true);
|
|
27328
|
+
}
|
|
27329
|
+
return {
|
|
27330
|
+
token: value.token,
|
|
27331
|
+
expiresAt: value.expiresAt,
|
|
27332
|
+
endpoints: {
|
|
27333
|
+
turns: value.endpoints.turns,
|
|
27334
|
+
toolConfirmations: value.endpoints.toolConfirmations,
|
|
27335
|
+
...typeof interactions === "string" ? { interactions } : {},
|
|
27336
|
+
...typeof apps === "string" ? { apps } : {},
|
|
27337
|
+
...typeof sandbox === "string" ? { sandbox } : {}
|
|
27338
|
+
},
|
|
27339
|
+
...isRecord2(value.configuration) ? { configuration: value.configuration } : {},
|
|
27340
|
+
...isRecord2(value.resume) && typeof value.resume.tool === "string" ? { resume: { tool: value.resume.tool } } : {}
|
|
27341
|
+
};
|
|
27342
|
+
}
|
|
27343
|
+
function isRecord2(value) {
|
|
27344
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27345
|
+
}
|
|
27346
|
+
async function readStableErrorCode(response) {
|
|
27347
|
+
let value;
|
|
27348
|
+
try {
|
|
27349
|
+
value = await response.json();
|
|
27350
|
+
} catch {
|
|
27351
|
+
return void 0;
|
|
27352
|
+
}
|
|
27353
|
+
if (!isRecord2(value) || typeof value.code !== "string") return void 0;
|
|
27354
|
+
return /^[A-Za-z0-9_.-]{1,64}$/.test(value.code) ? value.code : void 0;
|
|
27355
|
+
}
|
|
27356
|
+
function clientError(code, message, retryable, status, options, serviceCode) {
|
|
27357
|
+
return new AssistantClientError(
|
|
27358
|
+
{
|
|
27359
|
+
code,
|
|
27360
|
+
...status === void 0 ? {} : { status },
|
|
27361
|
+
retryable,
|
|
27362
|
+
...serviceCode === void 0 ? {} : { serviceCode }
|
|
27363
|
+
},
|
|
27364
|
+
message,
|
|
27365
|
+
options
|
|
27366
|
+
);
|
|
27367
|
+
}
|
|
27368
|
+
|
|
27291
27369
|
// src/events.ts
|
|
27292
27370
|
function toAssistantClientEvent(event) {
|
|
27293
27371
|
const value = event.data;
|
|
@@ -27303,20 +27381,25 @@ function toAssistantClientEvent(event) {
|
|
|
27303
27381
|
}
|
|
27304
27382
|
break;
|
|
27305
27383
|
case "tool_proposed":
|
|
27306
|
-
if (hasString(value, "id") && hasString(value, "tool") && hasOptionalString(value.title) && hasOptionalString(value.description) && hasOptionalJson(value.arguments) && (value.reviewSchema === void 0 ||
|
|
27384
|
+
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)) {
|
|
27307
27385
|
return event;
|
|
27308
27386
|
}
|
|
27309
27387
|
break;
|
|
27310
27388
|
case "input_requested":
|
|
27311
|
-
if (hasString(value, "id") && hasString(value, "message") &&
|
|
27389
|
+
if (hasString(value, "id") && hasString(value, "message") && isRecord3(value.requestedSchema) && hasString(value, "expiresAt") && hasOptionalTurnId(value)) {
|
|
27312
27390
|
return event;
|
|
27313
27391
|
}
|
|
27314
27392
|
break;
|
|
27315
|
-
case "auth_requested":
|
|
27316
|
-
|
|
27317
|
-
|
|
27393
|
+
case "auth_requested": {
|
|
27394
|
+
const signInTicket = typeof value.signInTicket === "string" ? value.signInTicket : typeof value.continuation === "string" ? value.continuation : void 0;
|
|
27395
|
+
if (hasString(value, "id") && hasString(value, "tool") && signInTicket !== void 0 && hasString(value, "expiresAt") && hasOptionalTurnId(value)) {
|
|
27396
|
+
return {
|
|
27397
|
+
event: "auth_requested",
|
|
27398
|
+
data: { ...value, signInTicket }
|
|
27399
|
+
};
|
|
27318
27400
|
}
|
|
27319
27401
|
break;
|
|
27402
|
+
}
|
|
27320
27403
|
case "interaction_resolved":
|
|
27321
27404
|
if (hasString(value, "id") && (value.action === void 0 || isInteractionAction(value.action)) && hasOptionalTurnId(value)) {
|
|
27322
27405
|
return event;
|
|
@@ -27347,7 +27430,7 @@ function toAssistantClientEvent(event) {
|
|
|
27347
27430
|
return { event: "unrecognized", data: { name: event.event, payload: value } };
|
|
27348
27431
|
}
|
|
27349
27432
|
function isViewAvailableDetail(value) {
|
|
27350
|
-
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 ||
|
|
27433
|
+
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);
|
|
27351
27434
|
}
|
|
27352
27435
|
function isHttpsUrl(value) {
|
|
27353
27436
|
if (typeof value !== "string") return false;
|
|
@@ -27380,11 +27463,11 @@ function isJsonValue(value, depth) {
|
|
|
27380
27463
|
if (Array.isArray(value)) {
|
|
27381
27464
|
return value.length <= 256 && value.every((entry) => isJsonValue(entry, depth + 1));
|
|
27382
27465
|
}
|
|
27383
|
-
if (!
|
|
27466
|
+
if (!isRecord3(value)) return false;
|
|
27384
27467
|
const entries2 = Object.entries(value);
|
|
27385
27468
|
return entries2.length <= 256 && entries2.every(([, entry]) => isJsonValue(entry, depth + 1));
|
|
27386
27469
|
}
|
|
27387
|
-
function
|
|
27470
|
+
function isRecord3(value) {
|
|
27388
27471
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27389
27472
|
}
|
|
27390
27473
|
|
|
@@ -27514,15 +27597,15 @@ function parseFrame(frame) {
|
|
|
27514
27597
|
if (event === "done" && !isValidDonePayload(parsed)) {
|
|
27515
27598
|
throw invalidStream("assistant event stream contained an invalid done event");
|
|
27516
27599
|
}
|
|
27517
|
-
return { event, data:
|
|
27600
|
+
return { event, data: isRecord4(parsed) ? parsed : { value: parsed } };
|
|
27518
27601
|
}
|
|
27519
27602
|
function normalizeLineEndings(input) {
|
|
27520
27603
|
return input.replaceAll("\r\n", "\n").replaceAll("\r", "\n");
|
|
27521
27604
|
}
|
|
27522
27605
|
function isValidDonePayload(value) {
|
|
27523
|
-
return
|
|
27606
|
+
return isRecord4(value) && (value.turnId === void 0 || typeof value.turnId === "string" && value.turnId.length > 0);
|
|
27524
27607
|
}
|
|
27525
|
-
function
|
|
27608
|
+
function isRecord4(value) {
|
|
27526
27609
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27527
27610
|
}
|
|
27528
27611
|
function invalidStream(message, cause) {
|
|
@@ -27533,27 +27616,6 @@ function isAbortError2(error51) {
|
|
|
27533
27616
|
}
|
|
27534
27617
|
|
|
27535
27618
|
// src/client.ts
|
|
27536
|
-
async function refusalCode(response) {
|
|
27537
|
-
try {
|
|
27538
|
-
const body = await response.clone().json();
|
|
27539
|
-
const code = body.code;
|
|
27540
|
-
return typeof code === "string" ? code : void 0;
|
|
27541
|
-
} catch {
|
|
27542
|
-
return void 0;
|
|
27543
|
-
}
|
|
27544
|
-
}
|
|
27545
|
-
var UNRETRYABLE_SERVICE_CODES = /* @__PURE__ */ new Set([
|
|
27546
|
-
"daily_turn_budget_exhausted",
|
|
27547
|
-
"daily_session_budget_exhausted"
|
|
27548
|
-
]);
|
|
27549
|
-
var AssistantClientError = class extends Error {
|
|
27550
|
-
detail;
|
|
27551
|
-
constructor(detail, message, options) {
|
|
27552
|
-
super(message, options);
|
|
27553
|
-
this.name = "AssistantClientError";
|
|
27554
|
-
this.detail = detail;
|
|
27555
|
-
}
|
|
27556
|
-
};
|
|
27557
27619
|
var DefaultAssistantClient = class {
|
|
27558
27620
|
#source;
|
|
27559
27621
|
#fetch;
|
|
@@ -27588,12 +27650,50 @@ var DefaultAssistantClient = class {
|
|
|
27588
27650
|
hasSession() {
|
|
27589
27651
|
return this.#session !== void 0;
|
|
27590
27652
|
}
|
|
27653
|
+
/** Whether a request holds the single-flight slot, so callers can refuse before mutating UI. */
|
|
27654
|
+
isBusy() {
|
|
27655
|
+
return this.#active !== void 0;
|
|
27656
|
+
}
|
|
27591
27657
|
async connect() {
|
|
27592
27658
|
if (this.#session) return;
|
|
27593
27659
|
await this.#singleFlight(async (signal) => {
|
|
27594
|
-
if (
|
|
27660
|
+
if (this.#session) return;
|
|
27661
|
+
const session = await this.#createSession(signal);
|
|
27662
|
+
if (session.resume) {
|
|
27663
|
+
try {
|
|
27664
|
+
await this.#runChatOperation(signal, () => this.#resumeTurn(session, signal));
|
|
27665
|
+
} catch {
|
|
27666
|
+
}
|
|
27667
|
+
}
|
|
27595
27668
|
});
|
|
27596
27669
|
}
|
|
27670
|
+
/** POST the one-shot resume trigger; a 409 means nothing was pending, which renders as silence. */
|
|
27671
|
+
async #resumeTurn(session, signal) {
|
|
27672
|
+
const response = await this.#request(
|
|
27673
|
+
session.endpoints.turns,
|
|
27674
|
+
{
|
|
27675
|
+
method: "POST",
|
|
27676
|
+
headers: authorizedHeaders(session.token, "text/event-stream"),
|
|
27677
|
+
body: JSON.stringify({ resume: true }),
|
|
27678
|
+
signal
|
|
27679
|
+
},
|
|
27680
|
+
"turn_failed"
|
|
27681
|
+
);
|
|
27682
|
+
if (response.status === 409) return;
|
|
27683
|
+
if (!response.ok) {
|
|
27684
|
+
throw clientError(
|
|
27685
|
+
"turn_failed",
|
|
27686
|
+
`Assistant turn failed (${response.status})`,
|
|
27687
|
+
false,
|
|
27688
|
+
response.status,
|
|
27689
|
+
void 0,
|
|
27690
|
+
await refusalCode(response)
|
|
27691
|
+
);
|
|
27692
|
+
}
|
|
27693
|
+
this.#emit({ event: "resume_started", data: { tool: session.resume?.tool ?? "" } });
|
|
27694
|
+
await this.#consume(response);
|
|
27695
|
+
this.#emit({ event: "message_completed", data: {} });
|
|
27696
|
+
}
|
|
27597
27697
|
async sendMessage(text3) {
|
|
27598
27698
|
const message = text3.trim();
|
|
27599
27699
|
if (!message) return;
|
|
@@ -27998,10 +28098,10 @@ function authorizedHeaders(token, accept) {
|
|
|
27998
28098
|
};
|
|
27999
28099
|
}
|
|
28000
28100
|
function parseAppInteraction(value) {
|
|
28001
|
-
if (!
|
|
28101
|
+
if (!isRecord2(value) || !isRecord2(value.interaction)) return void 0;
|
|
28002
28102
|
const event = value.interaction.event;
|
|
28003
28103
|
const data = value.interaction.data;
|
|
28004
|
-
if (event !== "tool_proposed" && event !== "input_requested" || !
|
|
28104
|
+
if (event !== "tool_proposed" && event !== "input_requested" || !isRecord2(data)) {
|
|
28005
28105
|
return void 0;
|
|
28006
28106
|
}
|
|
28007
28107
|
const parsed = toAssistantClientEvent({ event, data });
|
|
@@ -28021,54 +28121,6 @@ function appInteractionStopped(action) {
|
|
|
28021
28121
|
isError: true
|
|
28022
28122
|
};
|
|
28023
28123
|
}
|
|
28024
|
-
function parseSession(value) {
|
|
28025
|
-
if (!isRecord4(value) || !isRecord4(value.endpoints)) {
|
|
28026
|
-
throw clientError("session_failed", "Assistant session response is invalid", true);
|
|
28027
|
-
}
|
|
28028
|
-
const interactions = value.endpoints.interactions;
|
|
28029
|
-
const apps = value.endpoints.apps;
|
|
28030
|
-
const sandbox = value.endpoints.sandbox;
|
|
28031
|
-
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") {
|
|
28032
|
-
throw clientError("session_failed", "Assistant session response is invalid", true);
|
|
28033
|
-
}
|
|
28034
|
-
return {
|
|
28035
|
-
token: value.token,
|
|
28036
|
-
expiresAt: value.expiresAt,
|
|
28037
|
-
endpoints: {
|
|
28038
|
-
turns: value.endpoints.turns,
|
|
28039
|
-
toolConfirmations: value.endpoints.toolConfirmations,
|
|
28040
|
-
...typeof interactions === "string" ? { interactions } : {},
|
|
28041
|
-
...typeof apps === "string" ? { apps } : {},
|
|
28042
|
-
...typeof sandbox === "string" ? { sandbox } : {}
|
|
28043
|
-
},
|
|
28044
|
-
...isRecord4(value.configuration) ? { configuration: value.configuration } : {}
|
|
28045
|
-
};
|
|
28046
|
-
}
|
|
28047
|
-
function isRecord4(value) {
|
|
28048
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
28049
|
-
}
|
|
28050
|
-
async function readStableErrorCode(response) {
|
|
28051
|
-
let value;
|
|
28052
|
-
try {
|
|
28053
|
-
value = await response.json();
|
|
28054
|
-
} catch {
|
|
28055
|
-
return void 0;
|
|
28056
|
-
}
|
|
28057
|
-
if (!isRecord4(value) || typeof value.code !== "string") return void 0;
|
|
28058
|
-
return /^[A-Za-z0-9_.-]{1,64}$/.test(value.code) ? value.code : void 0;
|
|
28059
|
-
}
|
|
28060
|
-
function clientError(code, message, retryable, status, options, serviceCode) {
|
|
28061
|
-
return new AssistantClientError(
|
|
28062
|
-
{
|
|
28063
|
-
code,
|
|
28064
|
-
...status === void 0 ? {} : { status },
|
|
28065
|
-
retryable,
|
|
28066
|
-
...serviceCode === void 0 ? {} : { serviceCode }
|
|
28067
|
-
},
|
|
28068
|
-
message,
|
|
28069
|
-
options
|
|
28070
|
-
);
|
|
28071
|
-
}
|
|
28072
28124
|
|
|
28073
28125
|
// src/input-request-card.ts
|
|
28074
28126
|
function createInputRequestCard(options) {
|
|
@@ -31253,6 +31305,11 @@ var AssistantElementEventController = class {
|
|
|
31253
31305
|
this.#completedTool = void 0;
|
|
31254
31306
|
return;
|
|
31255
31307
|
}
|
|
31308
|
+
if (name21 === "resume_started") {
|
|
31309
|
+
this.#startStream("message");
|
|
31310
|
+
this.#host.element.dispatchEvent(new CustomEvent("assistant-message-started"));
|
|
31311
|
+
return;
|
|
31312
|
+
}
|
|
31256
31313
|
if (name21 === "interaction_completed") {
|
|
31257
31314
|
if (this.#streamKind !== "interaction") return;
|
|
31258
31315
|
this.#finishInteraction(String(data.id ?? ""), String(data.action ?? "accept"));
|
|
@@ -31273,11 +31330,11 @@ var AssistantElementEventController = class {
|
|
|
31273
31330
|
);
|
|
31274
31331
|
return;
|
|
31275
31332
|
}
|
|
31276
|
-
if (name21 === "auth_requested" && typeof data.
|
|
31333
|
+
if (name21 === "auth_requested" && typeof data.signInTicket === "string") {
|
|
31277
31334
|
this.#appendSignInRequest(
|
|
31278
31335
|
String(data.id ?? ""),
|
|
31279
31336
|
String(data.tool ?? "this"),
|
|
31280
|
-
data.
|
|
31337
|
+
data.signInTicket,
|
|
31281
31338
|
String(data.expiresAt ?? "")
|
|
31282
31339
|
);
|
|
31283
31340
|
return;
|
|
@@ -31370,15 +31427,15 @@ var AssistantElementEventController = class {
|
|
|
31370
31427
|
/**
|
|
31371
31428
|
* The host application owns the login. This renders the prompt and raises
|
|
31372
31429
|
* `assistant-sign-in-requested`; the page signs the visitor in however it already does, then its
|
|
31373
|
-
* backend spends the
|
|
31430
|
+
* backend spends the sign-in ticket. Nothing here talks to an identity provider.
|
|
31374
31431
|
*/
|
|
31375
|
-
#appendSignInRequest(id, tool,
|
|
31432
|
+
#appendSignInRequest(id, tool, signInTicket, expiresAt) {
|
|
31376
31433
|
const messages = this.#host.messages();
|
|
31377
31434
|
if (!messages) return;
|
|
31378
31435
|
this.#proposalCards.get(id)?.remove();
|
|
31379
31436
|
const card = createSignInCard({
|
|
31380
31437
|
tool,
|
|
31381
|
-
|
|
31438
|
+
signInTicket,
|
|
31382
31439
|
expiresAt,
|
|
31383
31440
|
labels: {
|
|
31384
31441
|
heading: "Sign in to continue",
|
|
@@ -31386,7 +31443,7 @@ var AssistantElementEventController = class {
|
|
|
31386
31443
|
},
|
|
31387
31444
|
onSignIn: () => this.#host.element.dispatchEvent(
|
|
31388
31445
|
new CustomEvent("assistant-sign-in-requested", {
|
|
31389
|
-
detail: { id, tool,
|
|
31446
|
+
detail: { id, tool, signInTicket, expiresAt },
|
|
31390
31447
|
bubbles: true,
|
|
31391
31448
|
composed: true
|
|
31392
31449
|
})
|
|
@@ -31397,7 +31454,7 @@ var AssistantElementEventController = class {
|
|
|
31397
31454
|
this.#host.revealLatest();
|
|
31398
31455
|
this.#host.element.dispatchEvent(
|
|
31399
31456
|
new CustomEvent("assistant-sign-in-required", {
|
|
31400
|
-
detail: { id, tool,
|
|
31457
|
+
detail: { id, tool, signInTicket, expiresAt }
|
|
31401
31458
|
})
|
|
31402
31459
|
);
|
|
31403
31460
|
}
|
|
@@ -31471,6 +31528,36 @@ function queryRequired(root, selector) {
|
|
|
31471
31528
|
if (!element) throw new Error(`assistant renderer is missing ${selector}`);
|
|
31472
31529
|
return element;
|
|
31473
31530
|
}
|
|
31531
|
+
function assistantElementMarkup(appearance, open, styles) {
|
|
31532
|
+
return `${styles}
|
|
31533
|
+
<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>
|
|
31534
|
+
<section class="panel" id="assistant-panel" role="dialog" aria-label="${escapeAttribute(appearance.brand.name)}">
|
|
31535
|
+
<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>
|
|
31536
|
+
<div class="welcome"><slot name="empty-state"></slot></div>
|
|
31537
|
+
<div class="suggested-prompts"></div>
|
|
31538
|
+
<div class="messages-region">
|
|
31539
|
+
<div class="messages" aria-live="polite"></div>
|
|
31540
|
+
<button class="new-messages" type="button" aria-label="${escapeAttribute(appearance.labels.newMessages)}" hidden></button>
|
|
31541
|
+
</div>
|
|
31542
|
+
<form><slot name="composer-leading"></slot><textarea rows="1"></textarea><button class="send" type="submit"></button><slot name="composer-trailing"></slot></form>
|
|
31543
|
+
<nav class="legal" aria-label="Legal"></nav>
|
|
31544
|
+
<slot name="conversation-footer"></slot>
|
|
31545
|
+
</section>`;
|
|
31546
|
+
}
|
|
31547
|
+
function appendLegalLinks(legal, appearance) {
|
|
31548
|
+
for (const [label, href] of [
|
|
31549
|
+
["Privacy", appearance.privacyUrl],
|
|
31550
|
+
["Terms", appearance.termsUrl]
|
|
31551
|
+
]) {
|
|
31552
|
+
if (!href) continue;
|
|
31553
|
+
const link = document.createElement("a");
|
|
31554
|
+
link.href = href;
|
|
31555
|
+
link.target = "_blank";
|
|
31556
|
+
link.rel = "noopener noreferrer";
|
|
31557
|
+
link.textContent = label;
|
|
31558
|
+
legal.append(link);
|
|
31559
|
+
}
|
|
31560
|
+
}
|
|
31474
31561
|
|
|
31475
31562
|
// src/element-page-context-controller.ts
|
|
31476
31563
|
var AssistantElementPageContextController = class {
|
|
@@ -32258,6 +32345,8 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32258
32345
|
#pendingUserEcho;
|
|
32259
32346
|
#sessionState = "idle";
|
|
32260
32347
|
#startOpenApplied = false;
|
|
32348
|
+
#readyDispatched = false;
|
|
32349
|
+
#turnInFlight = false;
|
|
32261
32350
|
#hostAppearance;
|
|
32262
32351
|
#appearanceWarningKeys = /* @__PURE__ */ new Set();
|
|
32263
32352
|
#appearanceStyleSnapshot = /* @__PURE__ */ new Map();
|
|
@@ -32329,7 +32418,10 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32329
32418
|
document.addEventListener("pointerdown", this.#handleDocumentPointerDown);
|
|
32330
32419
|
if (this.#appearance.behavior.startOpen) this.#applyStartOpenPolicy();
|
|
32331
32420
|
this.#render();
|
|
32332
|
-
|
|
32421
|
+
if (!this.#readyDispatched) {
|
|
32422
|
+
this.#readyDispatched = true;
|
|
32423
|
+
this.dispatchEvent(new CustomEvent("assistant-ready"));
|
|
32424
|
+
}
|
|
32333
32425
|
if (this.hasAttribute("start-open")) {
|
|
32334
32426
|
this.setAttribute("open", "");
|
|
32335
32427
|
this.#startOpenApplied = true;
|
|
@@ -32443,7 +32535,14 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32443
32535
|
async sendMessage(text3) {
|
|
32444
32536
|
const message = text3.trim();
|
|
32445
32537
|
if (!message) return;
|
|
32538
|
+
if (this.#turnInFlight) {
|
|
32539
|
+
throw new AssistantClientError(
|
|
32540
|
+
{ code: "request_in_progress", retryable: true },
|
|
32541
|
+
"an assistant request is already in progress"
|
|
32542
|
+
);
|
|
32543
|
+
}
|
|
32446
32544
|
const generation = this.#conversationGeneration;
|
|
32545
|
+
this.#turnInFlight = true;
|
|
32447
32546
|
this.#pendingUserEcho = message;
|
|
32448
32547
|
this.#appendMessage("user", message);
|
|
32449
32548
|
this.#setBusy(true);
|
|
@@ -32460,6 +32559,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32460
32559
|
this.#dispatchClientError(error51, "turn_failed");
|
|
32461
32560
|
throw error51;
|
|
32462
32561
|
} finally {
|
|
32562
|
+
this.#turnInFlight = false;
|
|
32463
32563
|
if (this.#pendingUserEcho === message) this.#pendingUserEcho = void 0;
|
|
32464
32564
|
if (generation === this.#conversationGeneration) this.#setBusy(false);
|
|
32465
32565
|
}
|
|
@@ -32528,6 +32628,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32528
32628
|
#primeSession() {
|
|
32529
32629
|
if (!this.sessionEndpoint && !this.embedId) return;
|
|
32530
32630
|
if (this.#sessionBootstrap || this.#client?.hasSession()) return;
|
|
32631
|
+
if (this.#client?.isBusy?.() === true) return;
|
|
32531
32632
|
if (this.embedId && !this.#pageContext) void this.#automaticPageContext.refresh();
|
|
32532
32633
|
const client = this.#ensureClient();
|
|
32533
32634
|
const generation = this.#conversationGeneration;
|
|
@@ -32557,6 +32658,8 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32557
32658
|
if (event.event === "content" || event.event === "message_completed" || event.event === "interaction_completed" || event.event === "error") {
|
|
32558
32659
|
this.#removeThinking();
|
|
32559
32660
|
}
|
|
32661
|
+
if (event.event === "resume_started") this.#setBusy(true);
|
|
32662
|
+
if (event.event === "message_completed" || event.event === "error") this.#setBusy(false);
|
|
32560
32663
|
}
|
|
32561
32664
|
#setBusy(busy) {
|
|
32562
32665
|
this.toggleAttribute("busy", busy);
|
|
@@ -32765,7 +32868,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32765
32868
|
queryRequired(this.shadowRoot, "header").hidden = !appearance.behavior.showHeader;
|
|
32766
32869
|
const legal = queryRequired(this.shadowRoot, ".legal");
|
|
32767
32870
|
legal.replaceChildren();
|
|
32768
|
-
|
|
32871
|
+
appendLegalLinks(legal, this.#appearance);
|
|
32769
32872
|
this.#applyTheme();
|
|
32770
32873
|
}
|
|
32771
32874
|
#render() {
|
|
@@ -32781,20 +32884,11 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32781
32884
|
this.dataset.position = appearance.layout.position;
|
|
32782
32885
|
this.dataset.density = appearance.layout.density;
|
|
32783
32886
|
this.toggleAttribute("mobile-fullscreen", appearance.layout.mobileFullscreen);
|
|
32784
|
-
this.shadowRoot.innerHTML =
|
|
32785
|
-
|
|
32786
|
-
|
|
32787
|
-
|
|
32788
|
-
|
|
32789
|
-
<div class="suggested-prompts"></div>
|
|
32790
|
-
<div class="messages-region">
|
|
32791
|
-
<div class="messages" aria-live="polite"></div>
|
|
32792
|
-
<button class="new-messages" type="button" aria-label="${escapeAttribute(appearance.labels.newMessages)}" hidden></button>
|
|
32793
|
-
</div>
|
|
32794
|
-
<form><slot name="composer-leading"></slot><textarea rows="1"></textarea><button class="send" type="submit"></button><slot name="composer-trailing"></slot></form>
|
|
32795
|
-
<nav class="legal" aria-label="Legal"></nav>
|
|
32796
|
-
<slot name="conversation-footer"></slot>
|
|
32797
|
-
</section>`;
|
|
32887
|
+
this.shadowRoot.innerHTML = assistantElementMarkup(
|
|
32888
|
+
appearance,
|
|
32889
|
+
this.hasAttribute("open"),
|
|
32890
|
+
`${ASSISTANT_ELEMENT_STYLES}${presentationStyles}`
|
|
32891
|
+
);
|
|
32798
32892
|
queryRequired(this.shadowRoot, "strong").textContent = appearance.brand.name;
|
|
32799
32893
|
const logo = queryRequired(this.shadowRoot, ".brand-logo");
|
|
32800
32894
|
const logoUrl = appearance.brand.logo[this.#resolvedMode()];
|
|
@@ -32821,7 +32915,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32821
32915
|
if (!appearance.behavior.showHeader)
|
|
32822
32916
|
queryRequired(this.shadowRoot, "header").hidden = true;
|
|
32823
32917
|
const legal = queryRequired(this.shadowRoot, ".legal");
|
|
32824
|
-
|
|
32918
|
+
appendLegalLinks(legal, this.#appearance);
|
|
32825
32919
|
this.#messages = this.shadowRoot.querySelector(".messages") ?? void 0;
|
|
32826
32920
|
this.#messages?.append(...conversation);
|
|
32827
32921
|
this.#thinking = this.#messages?.querySelector(".thinking") ?? void 0;
|
|
@@ -32860,20 +32954,6 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32860
32954
|
});
|
|
32861
32955
|
this.#applyTheme();
|
|
32862
32956
|
}
|
|
32863
|
-
#appendLegalLinks(legal) {
|
|
32864
|
-
for (const [label, href] of [
|
|
32865
|
-
["Privacy", this.#appearance.privacyUrl],
|
|
32866
|
-
["Terms", this.#appearance.termsUrl]
|
|
32867
|
-
]) {
|
|
32868
|
-
if (!href) continue;
|
|
32869
|
-
const link = document.createElement("a");
|
|
32870
|
-
link.href = href;
|
|
32871
|
-
link.target = "_blank";
|
|
32872
|
-
link.rel = "noopener noreferrer";
|
|
32873
|
-
link.textContent = label;
|
|
32874
|
-
legal.append(link);
|
|
32875
|
-
}
|
|
32876
|
-
}
|
|
32877
32957
|
};
|
|
32878
32958
|
function registerNoodleAssistant() {
|
|
32879
32959
|
if (globalThis.customElements && !customElements.get(ASSISTANT_TAG_NAME)) {
|
|
@@ -32943,6 +33023,7 @@ var NoodleAssistantWithRef = (0, import_react2.forwardRef)(
|
|
|
32943
33023
|
const ready = () => {
|
|
32944
33024
|
if (readyNotified.current) return;
|
|
32945
33025
|
readyNotified.current = true;
|
|
33026
|
+
console.debug("[noodle-assistant] ready");
|
|
32946
33027
|
props.onReady?.();
|
|
32947
33028
|
};
|
|
32948
33029
|
const error51 = (event) => props.onError?.(event.detail);
|