@syntrologie/adapt-chatbot 2.8.0-canary.292 → 2.8.0-canary.293
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/dist/AdaptiveChatBar.js +2 -2
- package/dist/AdaptiveChatTrail.js +2 -2
- package/dist/ChatAssistantLit.js +2 -2
- package/dist/{chunk-UC4XU6GH.js → chunk-C6K7W3LO.js} +264 -12
- package/dist/chunk-C6K7W3LO.js.map +7 -0
- package/dist/{chunk-IQKCST6R.js → chunk-FLSMUFFX.js} +392 -199
- package/dist/chunk-FLSMUFFX.js.map +7 -0
- package/dist/{chunk-4P74RX6V.js → chunk-YQU3O7VK.js} +2 -2
- package/dist/runtime.js +3 -3
- package/package.json +3 -2
- package/dist/chunk-IQKCST6R.js.map +0 -7
- package/dist/chunk-UC4XU6GH.js.map +0 -7
- /package/dist/{chunk-4P74RX6V.js.map → chunk-YQU3O7VK.js.map} +0 -0
package/dist/AdaptiveChatBar.js
CHANGED
package/dist/ChatAssistantLit.js
CHANGED
|
@@ -223,8 +223,8 @@ var _createTrustedTypesPolicy = function _createTrustedTypesPolicy2(trustedTypes
|
|
|
223
223
|
const policyName = "dompurify" + (suffix ? "#" + suffix : "");
|
|
224
224
|
try {
|
|
225
225
|
return trustedTypes.createPolicy(policyName, {
|
|
226
|
-
createHTML(
|
|
227
|
-
return
|
|
226
|
+
createHTML(html9) {
|
|
227
|
+
return html9;
|
|
228
228
|
},
|
|
229
229
|
createScriptURL(scriptUrl) {
|
|
230
230
|
return scriptUrl;
|
|
@@ -2238,6 +2238,7 @@ var en = x.lex;
|
|
|
2238
2238
|
import { html as html22 } from "lit";
|
|
2239
2239
|
import { html as html3, nothing as nothing2 } from "lit";
|
|
2240
2240
|
import { html as html5 } from "lit";
|
|
2241
|
+
import { html as html8, LitElement as LitElement2 } from "lit";
|
|
2241
2242
|
var sendIcon = html2`<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M8 14V2M8 2L3 7M8 2L13 7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
|
|
2242
2243
|
var stopIcon = html2`<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><rect x="1" y="1" width="12" height="12" rx="2" fill="currentColor"/></svg>`;
|
|
2243
2244
|
function autoResize(e) {
|
|
@@ -2369,18 +2370,20 @@ function renderBubbleContent(message) {
|
|
|
2369
2370
|
return html4`<div data-sc-msg-assistant>${unsafeHTML(renderMarkdown(message.content))}</div>`;
|
|
2370
2371
|
}
|
|
2371
2372
|
function renderMessageBubble(props) {
|
|
2372
|
-
const { message, toolLabels, toolRenderers, defaultToolRenderer } = props;
|
|
2373
|
+
const { message, toolLabels, toolRenderers, toolContext, defaultToolRenderer } = props;
|
|
2373
2374
|
const isUser = message.role === "user";
|
|
2374
2375
|
const toolCards = message.toolCalls?.map((tc) => {
|
|
2375
|
-
const approve = () => props.onToolApprove(tc.id);
|
|
2376
|
+
const approve = (payload) => props.onToolApprove(tc.id, payload);
|
|
2376
2377
|
const deny = () => props.onToolDeny(tc.id);
|
|
2378
|
+
const context = toolContext?.[tc.name];
|
|
2377
2379
|
const customRenderer = toolRenderers?.[tc.name];
|
|
2378
2380
|
if (customRenderer) {
|
|
2379
2381
|
return customRenderer.render({
|
|
2380
2382
|
toolCall: tc,
|
|
2381
2383
|
phase: tc.status,
|
|
2382
2384
|
approve,
|
|
2383
|
-
deny
|
|
2385
|
+
deny,
|
|
2386
|
+
context
|
|
2384
2387
|
});
|
|
2385
2388
|
}
|
|
2386
2389
|
if (defaultToolRenderer) {
|
|
@@ -2388,13 +2391,14 @@ function renderMessageBubble(props) {
|
|
|
2388
2391
|
toolCall: tc,
|
|
2389
2392
|
phase: tc.status,
|
|
2390
2393
|
approve,
|
|
2391
|
-
deny
|
|
2394
|
+
deny,
|
|
2395
|
+
context
|
|
2392
2396
|
});
|
|
2393
2397
|
}
|
|
2394
2398
|
return renderToolCallCard({
|
|
2395
2399
|
toolCall: tc,
|
|
2396
2400
|
toolLabel: toolLabels?.[tc.name],
|
|
2397
|
-
approve,
|
|
2401
|
+
approve: () => approve(),
|
|
2398
2402
|
deny
|
|
2399
2403
|
});
|
|
2400
2404
|
});
|
|
@@ -2435,11 +2439,12 @@ function renderMessageList(props) {
|
|
|
2435
2439
|
props.messages,
|
|
2436
2440
|
(msg) => msg.id,
|
|
2437
2441
|
(msg) => guard(
|
|
2438
|
-
[fingerprint(msg)],
|
|
2442
|
+
[fingerprint(msg), props.toolContext],
|
|
2439
2443
|
() => renderMessageBubble({
|
|
2440
2444
|
message: msg,
|
|
2441
2445
|
toolLabels: props.toolLabels,
|
|
2442
2446
|
toolRenderers: props.toolRenderers,
|
|
2447
|
+
toolContext: props.toolContext,
|
|
2443
2448
|
defaultToolRenderer: props.defaultToolRenderer,
|
|
2444
2449
|
onCopy: props.onCopy,
|
|
2445
2450
|
onRegenerate: props.onRegenerate,
|
|
@@ -2990,6 +2995,19 @@ var SyntroChat = class extends LitElement {
|
|
|
2990
2995
|
if (event.isTyping) this._scrollToBottom();
|
|
2991
2996
|
break;
|
|
2992
2997
|
case "tool-call": {
|
|
2998
|
+
const hasParent = this._messages.some((m2) => m2.id === event.messageId);
|
|
2999
|
+
if (!hasParent) {
|
|
3000
|
+
this._messages = [
|
|
3001
|
+
...this._messages,
|
|
3002
|
+
{
|
|
3003
|
+
id: event.messageId,
|
|
3004
|
+
role: "assistant",
|
|
3005
|
+
content: "",
|
|
3006
|
+
timestamp: Date.now(),
|
|
3007
|
+
status: "streaming"
|
|
3008
|
+
}
|
|
3009
|
+
];
|
|
3010
|
+
}
|
|
2993
3011
|
this._messages = this._messages.map((m2) => {
|
|
2994
3012
|
if (m2.id !== event.messageId) return m2;
|
|
2995
3013
|
const existing = (m2.toolCalls ?? []).findIndex((tc) => tc.id === event.toolCall.id);
|
|
@@ -3038,6 +3056,50 @@ var SyntroChat = class extends LitElement {
|
|
|
3038
3056
|
});
|
|
3039
3057
|
break;
|
|
3040
3058
|
}
|
|
3059
|
+
case "tool-call-deferred": {
|
|
3060
|
+
this._messages = this._messages.map((m2) => {
|
|
3061
|
+
if (!m2.toolCalls) return m2;
|
|
3062
|
+
const toolCalls = m2.toolCalls.map(
|
|
3063
|
+
(tc) => tc.id === event.toolCallId ? { ...tc, interruptId: event.interruptId, status: "pending" } : tc
|
|
3064
|
+
);
|
|
3065
|
+
return { ...m2, toolCalls };
|
|
3066
|
+
});
|
|
3067
|
+
break;
|
|
3068
|
+
}
|
|
3069
|
+
case "tool-call-cancelled": {
|
|
3070
|
+
this._messages = this._messages.map((m2) => {
|
|
3071
|
+
if (!m2.toolCalls) return m2;
|
|
3072
|
+
const toolCalls = m2.toolCalls.map(
|
|
3073
|
+
(tc) => tc.id === event.toolCallId ? { ...tc, status: "cancelled" } : tc
|
|
3074
|
+
);
|
|
3075
|
+
return { ...m2, toolCalls };
|
|
3076
|
+
});
|
|
3077
|
+
break;
|
|
3078
|
+
}
|
|
3079
|
+
case "tool-call-result": {
|
|
3080
|
+
let foundToolName;
|
|
3081
|
+
this._messages = this._messages.map((m2) => {
|
|
3082
|
+
if (!m2.toolCalls) return m2;
|
|
3083
|
+
const toolCalls = m2.toolCalls.map((tc) => {
|
|
3084
|
+
if (tc.id !== event.toolCallId) return tc;
|
|
3085
|
+
foundToolName = tc.name;
|
|
3086
|
+
return { ...tc, result: event.result, status: "done" };
|
|
3087
|
+
});
|
|
3088
|
+
return { ...m2, toolCalls };
|
|
3089
|
+
});
|
|
3090
|
+
this.dispatchEvent(
|
|
3091
|
+
new CustomEvent("tool-result-received", {
|
|
3092
|
+
detail: {
|
|
3093
|
+
toolCallId: event.toolCallId,
|
|
3094
|
+
toolName: foundToolName,
|
|
3095
|
+
result: event.result
|
|
3096
|
+
},
|
|
3097
|
+
bubbles: true,
|
|
3098
|
+
composed: true
|
|
3099
|
+
})
|
|
3100
|
+
);
|
|
3101
|
+
break;
|
|
3102
|
+
}
|
|
3041
3103
|
case "error":
|
|
3042
3104
|
this._errorMessage = event.message;
|
|
3043
3105
|
break;
|
|
@@ -3074,16 +3136,45 @@ var SyntroChat = class extends LitElement {
|
|
|
3074
3136
|
this._onRegenerate = (messageId) => {
|
|
3075
3137
|
this.transport.send({ type: "regenerate", messageId });
|
|
3076
3138
|
};
|
|
3077
|
-
this._onToolApprove = (toolCallId) => {
|
|
3139
|
+
this._onToolApprove = (toolCallId, payload, _retryCount = 0) => {
|
|
3140
|
+
const interruptId = this._findInterruptId(toolCallId);
|
|
3141
|
+
if (interruptId) {
|
|
3142
|
+
this._markToolDone(toolCallId);
|
|
3143
|
+
this.transport.send({
|
|
3144
|
+
type: "deferred-tool-resume",
|
|
3145
|
+
interruptId,
|
|
3146
|
+
decision: "approve",
|
|
3147
|
+
...payload?.editedArgs ? { editedArgs: payload.editedArgs } : {}
|
|
3148
|
+
});
|
|
3149
|
+
return;
|
|
3150
|
+
}
|
|
3151
|
+
if (_retryCount < 10) {
|
|
3152
|
+
setTimeout(() => this._onToolApprove(toolCallId, payload, _retryCount + 1), 200);
|
|
3153
|
+
return;
|
|
3154
|
+
}
|
|
3078
3155
|
this._markToolDone(toolCallId);
|
|
3079
3156
|
this.transport.send({
|
|
3080
3157
|
type: "tool-result",
|
|
3081
3158
|
toolCallId,
|
|
3082
|
-
result: null,
|
|
3159
|
+
result: payload?.editedArgs ?? null,
|
|
3083
3160
|
approved: true
|
|
3084
3161
|
});
|
|
3085
3162
|
};
|
|
3086
|
-
this._onToolDeny = (toolCallId) => {
|
|
3163
|
+
this._onToolDeny = (toolCallId, _retryCount = 0) => {
|
|
3164
|
+
const interruptId = this._findInterruptId(toolCallId);
|
|
3165
|
+
if (interruptId) {
|
|
3166
|
+
this._markToolDone(toolCallId);
|
|
3167
|
+
this.transport.send({
|
|
3168
|
+
type: "deferred-tool-resume",
|
|
3169
|
+
interruptId,
|
|
3170
|
+
decision: "deny"
|
|
3171
|
+
});
|
|
3172
|
+
return;
|
|
3173
|
+
}
|
|
3174
|
+
if (_retryCount < 10) {
|
|
3175
|
+
setTimeout(() => this._onToolDeny(toolCallId, _retryCount + 1), 200);
|
|
3176
|
+
return;
|
|
3177
|
+
}
|
|
3087
3178
|
this._markToolDone(toolCallId);
|
|
3088
3179
|
this.transport.send({
|
|
3089
3180
|
type: "tool-result",
|
|
@@ -3102,6 +3193,47 @@ var SyntroChat = class extends LitElement {
|
|
|
3102
3193
|
this.sendUserMessage(text2);
|
|
3103
3194
|
};
|
|
3104
3195
|
}
|
|
3196
|
+
// ── Public API: thread navigation ──────────────────────────────────
|
|
3197
|
+
//
|
|
3198
|
+
// Composing elements (the per-surface wrappers like
|
|
3199
|
+
// <ap-action-plan-chat>) call these to load past threads and start
|
|
3200
|
+
// new ones. The chat element doesn't own the thread index — that's
|
|
3201
|
+
// the consumer's job (typically a sibling <syntro-chat-thread-list>
|
|
3202
|
+
// + the consumer's REST endpoint). This element just owns the
|
|
3203
|
+
// visible message state.
|
|
3204
|
+
/**
|
|
3205
|
+
* Replace the chat's message history wholesale. Used by the host
|
|
3206
|
+
* shell when switching threads (after fetching the new thread's
|
|
3207
|
+
* messages from persistence) or when restoring a session.
|
|
3208
|
+
*
|
|
3209
|
+
* Emits `chat-messages-replaced` so dependent UI (overlay cards,
|
|
3210
|
+
* action plan sidebar) can react.
|
|
3211
|
+
*/
|
|
3212
|
+
replaceMessages(messages) {
|
|
3213
|
+
this._messages = [...messages];
|
|
3214
|
+
this._isStreaming = messages.some((m2) => m2.status === "streaming");
|
|
3215
|
+
this._userScrolledUp = false;
|
|
3216
|
+
requestAnimationFrame(() => this._scrollToBottom());
|
|
3217
|
+
this.dispatchEvent(
|
|
3218
|
+
new CustomEvent("chat-messages-replaced", {
|
|
3219
|
+
detail: { messageCount: messages.length },
|
|
3220
|
+
bubbles: true,
|
|
3221
|
+
composed: true
|
|
3222
|
+
})
|
|
3223
|
+
);
|
|
3224
|
+
}
|
|
3225
|
+
/**
|
|
3226
|
+
* Clear the chat for a fresh conversation. Equivalent to
|
|
3227
|
+
* `replaceMessages([])` plus a state reset.
|
|
3228
|
+
*/
|
|
3229
|
+
reset() {
|
|
3230
|
+
this._messages = [];
|
|
3231
|
+
this._isStreaming = false;
|
|
3232
|
+
this._isTyping = false;
|
|
3233
|
+
this._inputValue = "";
|
|
3234
|
+
this._userScrolledUp = false;
|
|
3235
|
+
this._errorMessage = null;
|
|
3236
|
+
}
|
|
3105
3237
|
createRenderRoot() {
|
|
3106
3238
|
return this;
|
|
3107
3239
|
}
|
|
@@ -3198,6 +3330,13 @@ var SyntroChat = class extends LitElement {
|
|
|
3198
3330
|
this._messages = [...this._messages, msg];
|
|
3199
3331
|
this._scrollToBottom();
|
|
3200
3332
|
}
|
|
3333
|
+
_findInterruptId(toolCallId) {
|
|
3334
|
+
for (const m2 of this._messages) {
|
|
3335
|
+
const tc = m2.toolCalls?.find((t) => t.id === toolCallId);
|
|
3336
|
+
if (tc?.interruptId) return tc.interruptId;
|
|
3337
|
+
}
|
|
3338
|
+
return void 0;
|
|
3339
|
+
}
|
|
3201
3340
|
_markToolDone(toolCallId) {
|
|
3202
3341
|
this._messages = this._messages.map((m2) => {
|
|
3203
3342
|
if (!m2.toolCalls) return m2;
|
|
@@ -3237,6 +3376,7 @@ var SyntroChat = class extends LitElement {
|
|
|
3237
3376
|
isTyping: this._isTyping,
|
|
3238
3377
|
toolLabels: this.toolLabels,
|
|
3239
3378
|
toolRenderers: this.toolRenderers,
|
|
3379
|
+
toolContext: this.toolContext,
|
|
3240
3380
|
defaultToolRenderer: this.defaultToolRenderer,
|
|
3241
3381
|
onCopy: this._onCopy,
|
|
3242
3382
|
onRegenerate: this._onRegenerate,
|
|
@@ -3277,6 +3417,7 @@ SyntroChat.properties = {
|
|
|
3277
3417
|
suggestions: { attribute: false },
|
|
3278
3418
|
toolLabels: { attribute: false },
|
|
3279
3419
|
toolRenderers: { attribute: false },
|
|
3420
|
+
toolContext: { attribute: false },
|
|
3280
3421
|
defaultToolRenderer: { attribute: false },
|
|
3281
3422
|
autoExecTools: { attribute: false },
|
|
3282
3423
|
placeholder: { type: String },
|
|
@@ -3291,6 +3432,117 @@ SyntroChat.properties = {
|
|
|
3291
3432
|
_userScrolledUp: { state: true },
|
|
3292
3433
|
_errorMessage: { state: true }
|
|
3293
3434
|
};
|
|
3435
|
+
var SyntroChatThreadList = class extends LitElement2 {
|
|
3436
|
+
constructor() {
|
|
3437
|
+
super(...arguments);
|
|
3438
|
+
this.threadsEndpoint = "";
|
|
3439
|
+
this.activeThreadId = null;
|
|
3440
|
+
this.newThreadLabel = "New thread";
|
|
3441
|
+
this.emptyStateLabel = "No threads yet";
|
|
3442
|
+
this._threads = [];
|
|
3443
|
+
this._loading = false;
|
|
3444
|
+
this._error = null;
|
|
3445
|
+
this._onThreadClick = (threadId) => {
|
|
3446
|
+
if (threadId === this.activeThreadId) return;
|
|
3447
|
+
this.dispatchEvent(
|
|
3448
|
+
new CustomEvent("thread-selected", {
|
|
3449
|
+
detail: { threadId },
|
|
3450
|
+
bubbles: true,
|
|
3451
|
+
composed: true
|
|
3452
|
+
})
|
|
3453
|
+
);
|
|
3454
|
+
};
|
|
3455
|
+
}
|
|
3456
|
+
createRenderRoot() {
|
|
3457
|
+
return this;
|
|
3458
|
+
}
|
|
3459
|
+
connectedCallback() {
|
|
3460
|
+
super.connectedCallback();
|
|
3461
|
+
if (this.threadsEndpoint) void this.refresh();
|
|
3462
|
+
}
|
|
3463
|
+
updated(changed) {
|
|
3464
|
+
if (changed.has("threadsEndpoint") && this.threadsEndpoint) {
|
|
3465
|
+
void this.refresh();
|
|
3466
|
+
}
|
|
3467
|
+
}
|
|
3468
|
+
/** Re-fetch the thread index. Call after creating/archiving a thread. */
|
|
3469
|
+
async refresh() {
|
|
3470
|
+
if (!this.threadsEndpoint) return;
|
|
3471
|
+
this._loading = true;
|
|
3472
|
+
this._error = null;
|
|
3473
|
+
try {
|
|
3474
|
+
const res = await fetch(this.threadsEndpoint, {
|
|
3475
|
+
method: "GET",
|
|
3476
|
+
headers: { ...this.authHeaders ?? {}, Accept: "application/json" }
|
|
3477
|
+
});
|
|
3478
|
+
if (!res.ok) {
|
|
3479
|
+
this._error = `Failed to load threads (${res.status})`;
|
|
3480
|
+
this._threads = [];
|
|
3481
|
+
return;
|
|
3482
|
+
}
|
|
3483
|
+
const data = await res.json();
|
|
3484
|
+
this._threads = (data.threads ?? []).filter((t) => t.status !== "archived");
|
|
3485
|
+
} catch (e) {
|
|
3486
|
+
this._error = e instanceof Error ? e.message : "Failed to load threads";
|
|
3487
|
+
this._threads = [];
|
|
3488
|
+
} finally {
|
|
3489
|
+
this._loading = false;
|
|
3490
|
+
}
|
|
3491
|
+
}
|
|
3492
|
+
/** Imperative: request the host to start a new thread.
|
|
3493
|
+
* Fires `new-thread-requested`. The host clears the chat element and
|
|
3494
|
+
* drops `activeThreadId` so the next user message goes to a fresh
|
|
3495
|
+
* backend thread.
|
|
3496
|
+
*/
|
|
3497
|
+
createNewThread() {
|
|
3498
|
+
this.dispatchEvent(new CustomEvent("new-thread-requested", { bubbles: true, composed: true }));
|
|
3499
|
+
}
|
|
3500
|
+
render() {
|
|
3501
|
+
return html8`
|
|
3502
|
+
<div data-sc-thread-list>
|
|
3503
|
+
<button
|
|
3504
|
+
type="button"
|
|
3505
|
+
data-sc-new-thread-btn
|
|
3506
|
+
@click=${() => this.createNewThread()}
|
|
3507
|
+
aria-label=${this.newThreadLabel}
|
|
3508
|
+
>
|
|
3509
|
+
${this.newThreadLabel}
|
|
3510
|
+
</button>
|
|
3511
|
+
${this._loading ? html8`<div data-sc-thread-list-loading>Loading…</div>` : this._error ? html8`<div data-sc-thread-list-error>${this._error}</div>` : this._threads.length === 0 ? html8`<div data-sc-thread-list-empty>${this.emptyStateLabel}</div>` : html8`<ul data-sc-thread-list-items role="list">
|
|
3512
|
+
${this._threads.map(
|
|
3513
|
+
(t) => html8`
|
|
3514
|
+
<li
|
|
3515
|
+
data-sc-thread-list-item
|
|
3516
|
+
?data-sc-active=${t.remoteId === this.activeThreadId}
|
|
3517
|
+
>
|
|
3518
|
+
<button
|
|
3519
|
+
type="button"
|
|
3520
|
+
@click=${() => this._onThreadClick(t.remoteId)}
|
|
3521
|
+
title=${t.title ?? t.remoteId}
|
|
3522
|
+
>
|
|
3523
|
+
${t.title || "Untitled thread"}
|
|
3524
|
+
</button>
|
|
3525
|
+
</li>
|
|
3526
|
+
`
|
|
3527
|
+
)}
|
|
3528
|
+
</ul>`}
|
|
3529
|
+
</div>
|
|
3530
|
+
`;
|
|
3531
|
+
}
|
|
3532
|
+
};
|
|
3533
|
+
SyntroChatThreadList.properties = {
|
|
3534
|
+
threadsEndpoint: { type: String, attribute: "threads-endpoint" },
|
|
3535
|
+
authHeaders: { attribute: false },
|
|
3536
|
+
activeThreadId: { type: String, attribute: "active-thread-id" },
|
|
3537
|
+
newThreadLabel: { type: String, attribute: "new-thread-label" },
|
|
3538
|
+
emptyStateLabel: { type: String, attribute: "empty-state-label" },
|
|
3539
|
+
_threads: { state: true },
|
|
3540
|
+
_loading: { state: true },
|
|
3541
|
+
_error: { state: true }
|
|
3542
|
+
};
|
|
3543
|
+
if (!customElements.get("syntro-chat-thread-list")) {
|
|
3544
|
+
customElements.define("syntro-chat-thread-list", SyntroChatThreadList);
|
|
3545
|
+
}
|
|
3294
3546
|
if (!customElements.get("syntro-chat")) {
|
|
3295
3547
|
customElements.define("syntro-chat", SyntroChat);
|
|
3296
3548
|
}
|
|
@@ -3303,4 +3555,4 @@ export {
|
|
|
3303
3555
|
dompurify/dist/purify.es.mjs:
|
|
3304
3556
|
(*! @license DOMPurify 3.3.1 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.3.1/LICENSE *)
|
|
3305
3557
|
*/
|
|
3306
|
-
//# sourceMappingURL=chunk-
|
|
3558
|
+
//# sourceMappingURL=chunk-C6K7W3LO.js.map
|