@noodleseed/assistant 1.20.0 → 1.22.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 +27 -2
- package/dist/{chunk-DLUINP4W.js → chunk-6TT3R555.js} +101 -42
- package/dist/chunk-6TT3R555.js.map +1 -0
- package/dist/{chunk-52XT7BLR.js → chunk-ZPZHPXIQ.js} +129 -82
- package/dist/chunk-ZPZHPXIQ.js.map +1 -0
- package/dist/{client-7o7n2nqw.d.cts → client-BZ7xPwfW.d.cts} +14 -5
- package/dist/{client-CysBQBdd.d.ts → client-BkJlpN5N.d.ts} +14 -5
- package/dist/client.cjs +127 -80
- 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 +68 -67
- package/dist/index.cjs +226 -120
- 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 +127 -80
- 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 +227 -120
- 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 +1 -0
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +15 -0
- package/dist/server.d.ts +15 -0
- package/dist/server.js +1 -0
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-52XT7BLR.js.map +0 -1
- package/dist/chunk-DLUINP4W.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,12 +27381,12 @@ 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;
|
|
@@ -27352,7 +27430,7 @@ function toAssistantClientEvent(event) {
|
|
|
27352
27430
|
return { event: "unrecognized", data: { name: event.event, payload: value } };
|
|
27353
27431
|
}
|
|
27354
27432
|
function isViewAvailableDetail(value) {
|
|
27355
|
-
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);
|
|
27356
27434
|
}
|
|
27357
27435
|
function isHttpsUrl(value) {
|
|
27358
27436
|
if (typeof value !== "string") return false;
|
|
@@ -27385,11 +27463,11 @@ function isJsonValue(value, depth) {
|
|
|
27385
27463
|
if (Array.isArray(value)) {
|
|
27386
27464
|
return value.length <= 256 && value.every((entry) => isJsonValue(entry, depth + 1));
|
|
27387
27465
|
}
|
|
27388
|
-
if (!
|
|
27466
|
+
if (!isRecord3(value)) return false;
|
|
27389
27467
|
const entries2 = Object.entries(value);
|
|
27390
27468
|
return entries2.length <= 256 && entries2.every(([, entry]) => isJsonValue(entry, depth + 1));
|
|
27391
27469
|
}
|
|
27392
|
-
function
|
|
27470
|
+
function isRecord3(value) {
|
|
27393
27471
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27394
27472
|
}
|
|
27395
27473
|
|
|
@@ -27519,15 +27597,15 @@ function parseFrame(frame) {
|
|
|
27519
27597
|
if (event === "done" && !isValidDonePayload(parsed)) {
|
|
27520
27598
|
throw invalidStream("assistant event stream contained an invalid done event");
|
|
27521
27599
|
}
|
|
27522
|
-
return { event, data:
|
|
27600
|
+
return { event, data: isRecord4(parsed) ? parsed : { value: parsed } };
|
|
27523
27601
|
}
|
|
27524
27602
|
function normalizeLineEndings(input) {
|
|
27525
27603
|
return input.replaceAll("\r\n", "\n").replaceAll("\r", "\n");
|
|
27526
27604
|
}
|
|
27527
27605
|
function isValidDonePayload(value) {
|
|
27528
|
-
return
|
|
27606
|
+
return isRecord4(value) && (value.turnId === void 0 || typeof value.turnId === "string" && value.turnId.length > 0);
|
|
27529
27607
|
}
|
|
27530
|
-
function
|
|
27608
|
+
function isRecord4(value) {
|
|
27531
27609
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27532
27610
|
}
|
|
27533
27611
|
function invalidStream(message, cause) {
|
|
@@ -27538,27 +27616,6 @@ function isAbortError2(error51) {
|
|
|
27538
27616
|
}
|
|
27539
27617
|
|
|
27540
27618
|
// src/client.ts
|
|
27541
|
-
async function refusalCode(response) {
|
|
27542
|
-
try {
|
|
27543
|
-
const body = await response.clone().json();
|
|
27544
|
-
const code = body.code;
|
|
27545
|
-
return typeof code === "string" ? code : void 0;
|
|
27546
|
-
} catch {
|
|
27547
|
-
return void 0;
|
|
27548
|
-
}
|
|
27549
|
-
}
|
|
27550
|
-
var UNRETRYABLE_SERVICE_CODES = /* @__PURE__ */ new Set([
|
|
27551
|
-
"daily_turn_budget_exhausted",
|
|
27552
|
-
"daily_session_budget_exhausted"
|
|
27553
|
-
]);
|
|
27554
|
-
var AssistantClientError = class extends Error {
|
|
27555
|
-
detail;
|
|
27556
|
-
constructor(detail, message, options) {
|
|
27557
|
-
super(message, options);
|
|
27558
|
-
this.name = "AssistantClientError";
|
|
27559
|
-
this.detail = detail;
|
|
27560
|
-
}
|
|
27561
|
-
};
|
|
27562
27619
|
var DefaultAssistantClient = class {
|
|
27563
27620
|
#source;
|
|
27564
27621
|
#fetch;
|
|
@@ -27593,12 +27650,50 @@ var DefaultAssistantClient = class {
|
|
|
27593
27650
|
hasSession() {
|
|
27594
27651
|
return this.#session !== void 0;
|
|
27595
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
|
+
}
|
|
27596
27657
|
async connect() {
|
|
27597
27658
|
if (this.#session) return;
|
|
27598
27659
|
await this.#singleFlight(async (signal) => {
|
|
27599
|
-
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
|
+
}
|
|
27600
27668
|
});
|
|
27601
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
|
+
}
|
|
27602
27697
|
async sendMessage(text3) {
|
|
27603
27698
|
const message = text3.trim();
|
|
27604
27699
|
if (!message) return;
|
|
@@ -28003,10 +28098,10 @@ function authorizedHeaders(token, accept) {
|
|
|
28003
28098
|
};
|
|
28004
28099
|
}
|
|
28005
28100
|
function parseAppInteraction(value) {
|
|
28006
|
-
if (!
|
|
28101
|
+
if (!isRecord2(value) || !isRecord2(value.interaction)) return void 0;
|
|
28007
28102
|
const event = value.interaction.event;
|
|
28008
28103
|
const data = value.interaction.data;
|
|
28009
|
-
if (event !== "tool_proposed" && event !== "input_requested" || !
|
|
28104
|
+
if (event !== "tool_proposed" && event !== "input_requested" || !isRecord2(data)) {
|
|
28010
28105
|
return void 0;
|
|
28011
28106
|
}
|
|
28012
28107
|
const parsed = toAssistantClientEvent({ event, data });
|
|
@@ -28026,54 +28121,6 @@ function appInteractionStopped(action) {
|
|
|
28026
28121
|
isError: true
|
|
28027
28122
|
};
|
|
28028
28123
|
}
|
|
28029
|
-
function parseSession(value) {
|
|
28030
|
-
if (!isRecord4(value) || !isRecord4(value.endpoints)) {
|
|
28031
|
-
throw clientError("session_failed", "Assistant session response is invalid", true);
|
|
28032
|
-
}
|
|
28033
|
-
const interactions = value.endpoints.interactions;
|
|
28034
|
-
const apps = value.endpoints.apps;
|
|
28035
|
-
const sandbox = value.endpoints.sandbox;
|
|
28036
|
-
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") {
|
|
28037
|
-
throw clientError("session_failed", "Assistant session response is invalid", true);
|
|
28038
|
-
}
|
|
28039
|
-
return {
|
|
28040
|
-
token: value.token,
|
|
28041
|
-
expiresAt: value.expiresAt,
|
|
28042
|
-
endpoints: {
|
|
28043
|
-
turns: value.endpoints.turns,
|
|
28044
|
-
toolConfirmations: value.endpoints.toolConfirmations,
|
|
28045
|
-
...typeof interactions === "string" ? { interactions } : {},
|
|
28046
|
-
...typeof apps === "string" ? { apps } : {},
|
|
28047
|
-
...typeof sandbox === "string" ? { sandbox } : {}
|
|
28048
|
-
},
|
|
28049
|
-
...isRecord4(value.configuration) ? { configuration: value.configuration } : {}
|
|
28050
|
-
};
|
|
28051
|
-
}
|
|
28052
|
-
function isRecord4(value) {
|
|
28053
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
28054
|
-
}
|
|
28055
|
-
async function readStableErrorCode(response) {
|
|
28056
|
-
let value;
|
|
28057
|
-
try {
|
|
28058
|
-
value = await response.json();
|
|
28059
|
-
} catch {
|
|
28060
|
-
return void 0;
|
|
28061
|
-
}
|
|
28062
|
-
if (!isRecord4(value) || typeof value.code !== "string") return void 0;
|
|
28063
|
-
return /^[A-Za-z0-9_.-]{1,64}$/.test(value.code) ? value.code : void 0;
|
|
28064
|
-
}
|
|
28065
|
-
function clientError(code, message, retryable, status, options, serviceCode) {
|
|
28066
|
-
return new AssistantClientError(
|
|
28067
|
-
{
|
|
28068
|
-
code,
|
|
28069
|
-
...status === void 0 ? {} : { status },
|
|
28070
|
-
retryable,
|
|
28071
|
-
...serviceCode === void 0 ? {} : { serviceCode }
|
|
28072
|
-
},
|
|
28073
|
-
message,
|
|
28074
|
-
options
|
|
28075
|
-
);
|
|
28076
|
-
}
|
|
28077
28124
|
|
|
28078
28125
|
// src/input-request-card.ts
|
|
28079
28126
|
function createInputRequestCard(options) {
|
|
@@ -31258,6 +31305,11 @@ var AssistantElementEventController = class {
|
|
|
31258
31305
|
this.#completedTool = void 0;
|
|
31259
31306
|
return;
|
|
31260
31307
|
}
|
|
31308
|
+
if (name21 === "resume_started") {
|
|
31309
|
+
this.#startStream("message");
|
|
31310
|
+
this.#host.element.dispatchEvent(new CustomEvent("assistant-message-started"));
|
|
31311
|
+
return;
|
|
31312
|
+
}
|
|
31261
31313
|
if (name21 === "interaction_completed") {
|
|
31262
31314
|
if (this.#streamKind !== "interaction") return;
|
|
31263
31315
|
this.#finishInteraction(String(data.id ?? ""), String(data.action ?? "accept"));
|
|
@@ -31476,6 +31528,36 @@ function queryRequired(root, selector) {
|
|
|
31476
31528
|
if (!element) throw new Error(`assistant renderer is missing ${selector}`);
|
|
31477
31529
|
return element;
|
|
31478
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
|
+
}
|
|
31479
31561
|
|
|
31480
31562
|
// src/element-page-context-controller.ts
|
|
31481
31563
|
var AssistantElementPageContextController = class {
|
|
@@ -31517,6 +31599,33 @@ var AssistantElementPageContextController = class {
|
|
|
31517
31599
|
}
|
|
31518
31600
|
};
|
|
31519
31601
|
|
|
31602
|
+
// src/element-presentation-gate.ts
|
|
31603
|
+
var AssistantElementPresentationGate = class {
|
|
31604
|
+
#host;
|
|
31605
|
+
#primeSession;
|
|
31606
|
+
#focusComposer;
|
|
31607
|
+
constructor(host, primeSession, focusComposer) {
|
|
31608
|
+
this.#host = host;
|
|
31609
|
+
this.#primeSession = primeSession;
|
|
31610
|
+
this.#focusComposer = focusComposer;
|
|
31611
|
+
}
|
|
31612
|
+
syncOpenState() {
|
|
31613
|
+
const open = this.#host.hasAttribute("open");
|
|
31614
|
+
const presentationReady = this.#host.hasAttribute("data-presentation-ready");
|
|
31615
|
+
const launcher = this.#host.shadowRoot?.querySelector(".launcher");
|
|
31616
|
+
launcher?.setAttribute("aria-expanded", String(open && presentationReady));
|
|
31617
|
+
launcher?.setAttribute("aria-busy", String(open && !presentationReady));
|
|
31618
|
+
if (launcher) launcher.disabled = open && !presentationReady;
|
|
31619
|
+
if (open && this.#host.isConnected) this.#primeSession();
|
|
31620
|
+
}
|
|
31621
|
+
reveal() {
|
|
31622
|
+
if (this.#host.hasAttribute("data-presentation-ready")) return;
|
|
31623
|
+
this.#host.setAttribute("data-presentation-ready", "");
|
|
31624
|
+
this.syncOpenState();
|
|
31625
|
+
if (this.#host.hasAttribute("open")) queueMicrotask(this.#focusComposer);
|
|
31626
|
+
}
|
|
31627
|
+
};
|
|
31628
|
+
|
|
31520
31629
|
// src/element-scroll-controller.ts
|
|
31521
31630
|
var AssistantElementScrollController = class {
|
|
31522
31631
|
#region;
|
|
@@ -31632,9 +31741,10 @@ var ASSISTANT_ELEMENT_STYLES = `<style>
|
|
|
31632
31741
|
.launcher:hover { transform: translateY(-2px) scale(1.03); box-shadow: 0 8px 26px rgba(0,0,0,.16); }
|
|
31633
31742
|
.launcher img { width: 28px; height: 28px; border-radius: 50%; object-fit: contain; }
|
|
31634
31743
|
.panel { display: none; flex-direction: column; width: min(var(--ns-assistant-panel-width, var(--ns-assistant-default-panel-width)), calc(100vw - 40px)); min-height: var(--ns-assistant-min-height, var(--ns-assistant-default-min-height)); max-height: min(var(--ns-assistant-max-height, var(--ns-assistant-default-max-height)), calc(100vh - 40px)); overflow: hidden; color: var(--ns-assistant-panel-text, var(--ns-assistant-text, var(--ns-assistant-default-text))); background: var(--ns-assistant-panel, var(--ns-assistant-default-panel)); border: 1px solid var(--ns-assistant-panel-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: var(--ns-assistant-panel-radius, var(--ns-assistant-default-panel-radius)); box-shadow: var(--ns-assistant-shadow, var(--ns-assistant-default-shadow)); transform-origin: bottom right; isolation: isolate; animation: halo-panel-in .28s cubic-bezier(.23,1,.32,1) both; }
|
|
31635
|
-
:host([open]) .panel { display: flex; }
|
|
31744
|
+
:host([open][data-presentation-ready]) .panel { display: flex; }
|
|
31636
31745
|
.panel { position: relative; }
|
|
31637
|
-
:host([open]) .launcher { display: none; }
|
|
31746
|
+
:host([open][data-presentation-ready]) .launcher { display: none; }
|
|
31747
|
+
:host([open]:not([data-presentation-ready])) .launcher { cursor: progress; opacity: .72; transform: none; }
|
|
31638
31748
|
header { display: flex; flex: 0 0 auto; gap: 10px; align-items: center; min-height: 64px; padding: 12px 18px; color: var(--ns-assistant-header-text, inherit); background: var(--ns-assistant-header, transparent); border-bottom: 1px solid color-mix(in srgb, var(--ns-assistant-header-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))) 78%, transparent); }
|
|
31639
31749
|
header strong { flex: 1; font-size: 16px; font-weight: 600; letter-spacing: 0; }
|
|
31640
31750
|
.brand-logo { display: block; max-width: 120px; max-height: 28px; object-fit: contain; }
|
|
@@ -32260,9 +32370,16 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32260
32370
|
#automaticPageContext = new AssistantElementPageContextController(
|
|
32261
32371
|
() => !this.#pageContext
|
|
32262
32372
|
);
|
|
32373
|
+
#presentationGate = new AssistantElementPresentationGate(
|
|
32374
|
+
this,
|
|
32375
|
+
() => this.#primeSession(),
|
|
32376
|
+
() => this.focusComposer()
|
|
32377
|
+
);
|
|
32263
32378
|
#pendingUserEcho;
|
|
32264
32379
|
#sessionState = "idle";
|
|
32265
32380
|
#startOpenApplied = false;
|
|
32381
|
+
#readyDispatched = false;
|
|
32382
|
+
#turnInFlight = false;
|
|
32266
32383
|
#hostAppearance;
|
|
32267
32384
|
#appearanceWarningKeys = /* @__PURE__ */ new Set();
|
|
32268
32385
|
#appearanceStyleSnapshot = /* @__PURE__ */ new Map();
|
|
@@ -32328,20 +32445,24 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32328
32445
|
if (!this.sessionEndpoint) this.sessionEndpoint = this.getAttribute("session-endpoint") ?? "";
|
|
32329
32446
|
if (!this.embedId) this.embedId = this.getAttribute("embed-id") ?? "";
|
|
32330
32447
|
if (!this.serviceUrl) this.serviceUrl = this.getAttribute("service-url") ?? "";
|
|
32448
|
+
if (!this.sessionEndpoint && !this.embedId) this.#presentationGate.reveal();
|
|
32331
32449
|
this.#media = globalThis.matchMedia?.("(prefers-color-scheme: dark)");
|
|
32332
32450
|
this.#media?.addEventListener("change", this.#handleSystemTheme);
|
|
32333
32451
|
document.addEventListener("keydown", this.#handleDocumentKeydown);
|
|
32334
32452
|
document.addEventListener("pointerdown", this.#handleDocumentPointerDown);
|
|
32335
32453
|
if (this.#appearance.behavior.startOpen) this.#applyStartOpenPolicy();
|
|
32336
32454
|
this.#render();
|
|
32337
|
-
|
|
32455
|
+
if (!this.#readyDispatched) {
|
|
32456
|
+
this.#readyDispatched = true;
|
|
32457
|
+
this.dispatchEvent(new CustomEvent("assistant-ready"));
|
|
32458
|
+
}
|
|
32338
32459
|
if (this.hasAttribute("start-open")) {
|
|
32339
32460
|
this.setAttribute("open", "");
|
|
32340
32461
|
this.#startOpenApplied = true;
|
|
32341
32462
|
} else if (!this.embedId) {
|
|
32342
32463
|
this.#primeSession();
|
|
32343
32464
|
}
|
|
32344
|
-
this.#syncOpenState();
|
|
32465
|
+
this.#presentationGate.syncOpenState();
|
|
32345
32466
|
}
|
|
32346
32467
|
disconnectedCallback() {
|
|
32347
32468
|
this.#conversationGeneration += 1;
|
|
@@ -32359,7 +32480,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32359
32480
|
}
|
|
32360
32481
|
attributeChangedCallback(name21) {
|
|
32361
32482
|
if (name21 === "theme") this.#applyTheme();
|
|
32362
|
-
if (name21 === "open") this.#syncOpenState();
|
|
32483
|
+
if (name21 === "open") this.#presentationGate.syncOpenState();
|
|
32363
32484
|
}
|
|
32364
32485
|
open() {
|
|
32365
32486
|
this.setAttribute("open", "");
|
|
@@ -32448,7 +32569,14 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32448
32569
|
async sendMessage(text3) {
|
|
32449
32570
|
const message = text3.trim();
|
|
32450
32571
|
if (!message) return;
|
|
32572
|
+
if (this.#turnInFlight) {
|
|
32573
|
+
throw new AssistantClientError(
|
|
32574
|
+
{ code: "request_in_progress", retryable: true },
|
|
32575
|
+
"an assistant request is already in progress"
|
|
32576
|
+
);
|
|
32577
|
+
}
|
|
32451
32578
|
const generation = this.#conversationGeneration;
|
|
32579
|
+
this.#turnInFlight = true;
|
|
32452
32580
|
this.#pendingUserEcho = message;
|
|
32453
32581
|
this.#appendMessage("user", message);
|
|
32454
32582
|
this.#setBusy(true);
|
|
@@ -32465,6 +32593,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32465
32593
|
this.#dispatchClientError(error51, "turn_failed");
|
|
32466
32594
|
throw error51;
|
|
32467
32595
|
} finally {
|
|
32596
|
+
this.#turnInFlight = false;
|
|
32468
32597
|
if (this.#pendingUserEcho === message) this.#pendingUserEcho = void 0;
|
|
32469
32598
|
if (generation === this.#conversationGeneration) this.#setBusy(false);
|
|
32470
32599
|
}
|
|
@@ -32533,6 +32662,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32533
32662
|
#primeSession() {
|
|
32534
32663
|
if (!this.sessionEndpoint && !this.embedId) return;
|
|
32535
32664
|
if (this.#sessionBootstrap || this.#client?.hasSession()) return;
|
|
32665
|
+
if (this.#client?.isBusy?.() === true) return;
|
|
32536
32666
|
if (this.embedId && !this.#pageContext) void this.#automaticPageContext.refresh();
|
|
32537
32667
|
const client = this.#ensureClient();
|
|
32538
32668
|
const generation = this.#conversationGeneration;
|
|
@@ -32540,6 +32670,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32540
32670
|
const bootstrap = client.connect().catch((error51) => {
|
|
32541
32671
|
if (generation !== this.#conversationGeneration || this.#client !== client) return;
|
|
32542
32672
|
this.#dispatchClientError(error51, "session_failed");
|
|
32673
|
+
this.#presentationGate.reveal();
|
|
32543
32674
|
}).finally(() => {
|
|
32544
32675
|
if (this.#sessionBootstrap === bootstrap) this.#sessionBootstrap = void 0;
|
|
32545
32676
|
});
|
|
@@ -32549,6 +32680,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32549
32680
|
this.dispatchEvent(new CustomEvent("assistant-event", { detail: event }));
|
|
32550
32681
|
this.#events.handle(event);
|
|
32551
32682
|
if (event.event === "session_started") {
|
|
32683
|
+
this.#presentationGate.reveal();
|
|
32552
32684
|
this.#setSessionState("ready");
|
|
32553
32685
|
this.#messages?.querySelector(".conversation-error")?.remove();
|
|
32554
32686
|
}
|
|
@@ -32562,6 +32694,8 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32562
32694
|
if (event.event === "content" || event.event === "message_completed" || event.event === "interaction_completed" || event.event === "error") {
|
|
32563
32695
|
this.#removeThinking();
|
|
32564
32696
|
}
|
|
32697
|
+
if (event.event === "resume_started") this.#setBusy(true);
|
|
32698
|
+
if (event.event === "message_completed" || event.event === "error") this.#setBusy(false);
|
|
32565
32699
|
}
|
|
32566
32700
|
#setBusy(busy) {
|
|
32567
32701
|
this.toggleAttribute("busy", busy);
|
|
@@ -32716,11 +32850,6 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32716
32850
|
this.#sessionState = state;
|
|
32717
32851
|
syncAssistantSessionVisualState(this, this.shadowRoot, state, this.#appearance);
|
|
32718
32852
|
}
|
|
32719
|
-
#syncOpenState() {
|
|
32720
|
-
const open = this.hasAttribute("open");
|
|
32721
|
-
this.shadowRoot?.querySelector(".launcher")?.setAttribute("aria-expanded", String(open));
|
|
32722
|
-
if (open && this.isConnected) this.#primeSession();
|
|
32723
|
-
}
|
|
32724
32853
|
#closeAndRestoreFocus() {
|
|
32725
32854
|
this.close();
|
|
32726
32855
|
this.shadowRoot?.querySelector(".launcher")?.focus();
|
|
@@ -32770,7 +32899,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32770
32899
|
queryRequired(this.shadowRoot, "header").hidden = !appearance.behavior.showHeader;
|
|
32771
32900
|
const legal = queryRequired(this.shadowRoot, ".legal");
|
|
32772
32901
|
legal.replaceChildren();
|
|
32773
|
-
|
|
32902
|
+
appendLegalLinks(legal, this.#appearance);
|
|
32774
32903
|
this.#applyTheme();
|
|
32775
32904
|
}
|
|
32776
32905
|
#render() {
|
|
@@ -32786,20 +32915,11 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32786
32915
|
this.dataset.position = appearance.layout.position;
|
|
32787
32916
|
this.dataset.density = appearance.layout.density;
|
|
32788
32917
|
this.toggleAttribute("mobile-fullscreen", appearance.layout.mobileFullscreen);
|
|
32789
|
-
this.shadowRoot.innerHTML =
|
|
32790
|
-
|
|
32791
|
-
|
|
32792
|
-
|
|
32793
|
-
|
|
32794
|
-
<div class="suggested-prompts"></div>
|
|
32795
|
-
<div class="messages-region">
|
|
32796
|
-
<div class="messages" aria-live="polite"></div>
|
|
32797
|
-
<button class="new-messages" type="button" aria-label="${escapeAttribute(appearance.labels.newMessages)}" hidden></button>
|
|
32798
|
-
</div>
|
|
32799
|
-
<form><slot name="composer-leading"></slot><textarea rows="1"></textarea><button class="send" type="submit"></button><slot name="composer-trailing"></slot></form>
|
|
32800
|
-
<nav class="legal" aria-label="Legal"></nav>
|
|
32801
|
-
<slot name="conversation-footer"></slot>
|
|
32802
|
-
</section>`;
|
|
32918
|
+
this.shadowRoot.innerHTML = assistantElementMarkup(
|
|
32919
|
+
appearance,
|
|
32920
|
+
this.hasAttribute("open"),
|
|
32921
|
+
`${ASSISTANT_ELEMENT_STYLES}${presentationStyles}`
|
|
32922
|
+
);
|
|
32803
32923
|
queryRequired(this.shadowRoot, "strong").textContent = appearance.brand.name;
|
|
32804
32924
|
const logo = queryRequired(this.shadowRoot, ".brand-logo");
|
|
32805
32925
|
const logoUrl = appearance.brand.logo[this.#resolvedMode()];
|
|
@@ -32826,7 +32946,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32826
32946
|
if (!appearance.behavior.showHeader)
|
|
32827
32947
|
queryRequired(this.shadowRoot, "header").hidden = true;
|
|
32828
32948
|
const legal = queryRequired(this.shadowRoot, ".legal");
|
|
32829
|
-
|
|
32949
|
+
appendLegalLinks(legal, this.#appearance);
|
|
32830
32950
|
this.#messages = this.shadowRoot.querySelector(".messages") ?? void 0;
|
|
32831
32951
|
this.#messages?.append(...conversation);
|
|
32832
32952
|
this.#thinking = this.#messages?.querySelector(".thinking") ?? void 0;
|
|
@@ -32865,20 +32985,6 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
32865
32985
|
});
|
|
32866
32986
|
this.#applyTheme();
|
|
32867
32987
|
}
|
|
32868
|
-
#appendLegalLinks(legal) {
|
|
32869
|
-
for (const [label, href] of [
|
|
32870
|
-
["Privacy", this.#appearance.privacyUrl],
|
|
32871
|
-
["Terms", this.#appearance.termsUrl]
|
|
32872
|
-
]) {
|
|
32873
|
-
if (!href) continue;
|
|
32874
|
-
const link = document.createElement("a");
|
|
32875
|
-
link.href = href;
|
|
32876
|
-
link.target = "_blank";
|
|
32877
|
-
link.rel = "noopener noreferrer";
|
|
32878
|
-
link.textContent = label;
|
|
32879
|
-
legal.append(link);
|
|
32880
|
-
}
|
|
32881
|
-
}
|
|
32882
32988
|
};
|
|
32883
32989
|
function registerNoodleAssistant() {
|
|
32884
32990
|
if (globalThis.customElements && !customElements.get(ASSISTANT_TAG_NAME)) {
|
|
@@ -32948,6 +33054,7 @@ var NoodleAssistantWithRef = (0, import_react2.forwardRef)(
|
|
|
32948
33054
|
const ready = () => {
|
|
32949
33055
|
if (readyNotified.current) return;
|
|
32950
33056
|
readyNotified.current = true;
|
|
33057
|
+
console.debug("[noodle-assistant] ready");
|
|
32951
33058
|
props.onReady?.();
|
|
32952
33059
|
};
|
|
32953
33060
|
const error51 = (event) => props.onError?.(event.detail);
|