@webskill/chatbot 0.24.3 → 0.25.1
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/chatbot.css +8 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.js +132 -23
- package/package.json +2 -2
package/dist/chatbot.css
CHANGED
|
@@ -1204,6 +1204,9 @@
|
|
|
1204
1204
|
.pb-1 {
|
|
1205
1205
|
padding-bottom: var(--spacing);
|
|
1206
1206
|
}
|
|
1207
|
+
.pb-2 {
|
|
1208
|
+
padding-bottom: calc(var(--spacing) * 2);
|
|
1209
|
+
}
|
|
1207
1210
|
.pb-3 {
|
|
1208
1211
|
padding-bottom: calc(var(--spacing) * 3);
|
|
1209
1212
|
}
|
|
@@ -1867,6 +1870,11 @@
|
|
|
1867
1870
|
color: var(--sidebar-accent-foreground);
|
|
1868
1871
|
}
|
|
1869
1872
|
}
|
|
1873
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1874
|
+
.motion-reduce\:animate-none {
|
|
1875
|
+
animation: none;
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1870
1878
|
@media (width < 40rem) {
|
|
1871
1879
|
.max-sm\:top-0 {
|
|
1872
1880
|
top: 0px;
|
package/dist/index.d.ts
CHANGED
|
@@ -340,7 +340,7 @@ interface ChatbotHostAdapter {
|
|
|
340
340
|
/** xlsx → 行流(`createXlsxBlockReader`);不注入即 `read_document` 读不了 Excel @experimental */
|
|
341
341
|
xlsxDocumentReader?: XlsxDocumentReader;
|
|
342
342
|
/**
|
|
343
|
-
* xlsx →
|
|
343
|
+
* xlsx → 单元格网格或可重复扫描的行流(`createXlsxTableReader`)。注入后,估算超过阈值的 xlsx 附件只以画像进消息,
|
|
344
344
|
* 统计交给 `query_table` 在本机对全表计算(整张表不进上下文);不注入则两者都不发生。
|
|
345
345
|
* @experimental
|
|
346
346
|
*/
|
|
@@ -1632,6 +1632,7 @@ declare const chatbotDictionary: {
|
|
|
1632
1632
|
'composer.inputLabel': string;
|
|
1633
1633
|
'composer.send': string;
|
|
1634
1634
|
'composer.stop': string;
|
|
1635
|
+
'composer.processingAttachments': string;
|
|
1635
1636
|
'composer.attachments': string;
|
|
1636
1637
|
'composer.addAttachment': string;
|
|
1637
1638
|
'composer.removeAttachment': string;
|
|
@@ -2092,6 +2093,7 @@ declare const chatbotDictionary: {
|
|
|
2092
2093
|
'composer.inputLabel': string;
|
|
2093
2094
|
'composer.send': string;
|
|
2094
2095
|
'composer.stop': string;
|
|
2096
|
+
'composer.processingAttachments': string;
|
|
2095
2097
|
'composer.attachments': string;
|
|
2096
2098
|
'composer.addAttachment': string;
|
|
2097
2099
|
'composer.removeAttachment': string;
|
|
@@ -2555,6 +2557,7 @@ declare const useT: () => TranslateFn<{
|
|
|
2555
2557
|
'composer.inputLabel': string;
|
|
2556
2558
|
'composer.send': string;
|
|
2557
2559
|
'composer.stop': string;
|
|
2560
|
+
'composer.processingAttachments': string;
|
|
2558
2561
|
'composer.attachments': string;
|
|
2559
2562
|
'composer.addAttachment': string;
|
|
2560
2563
|
'composer.removeAttachment': string;
|
|
@@ -3015,6 +3018,7 @@ declare const useT: () => TranslateFn<{
|
|
|
3015
3018
|
'composer.inputLabel': string;
|
|
3016
3019
|
'composer.send': string;
|
|
3017
3020
|
'composer.stop': string;
|
|
3021
|
+
'composer.processingAttachments': string;
|
|
3018
3022
|
'composer.attachments': string;
|
|
3019
3023
|
'composer.addAttachment': string;
|
|
3020
3024
|
'composer.removeAttachment': string;
|
|
@@ -3494,6 +3498,6 @@ declare function ErrorCard({ code, message, loopLimits, onOpenSettings, onDismis
|
|
|
3494
3498
|
* Version of the published `@webskill/chatbot` package, injected at build time.
|
|
3495
3499
|
* @stable
|
|
3496
3500
|
*/
|
|
3497
|
-
declare const CHATBOT_VERSION = "0.
|
|
3501
|
+
declare const CHATBOT_VERSION = "0.25.1";
|
|
3498
3502
|
//#endregion
|
|
3499
3503
|
export { A2uiSurfaceHost, type A2uiSurfaceHostProps, A2uiSurfaceSnapshotHost, type A2uiSurfaceSnapshotHostProps, type AppearanceChange, CHATBOT_VERSION, type ChatAttachmentInput, type ChatAttachmentMeta, type ChatComponent, type ChatComponentCallRecord, type ChatComponentConfirmation, type ChatComponentCredentialField, type ChatComponentInvokeContext, type ChatComponentOutcome, type ChatComponentStore, type ChatComponentText, type ChatContentPart, ChatEngine, type ChatEngineOptions, type ChatEvent, type ChatInteractionRecord, type ChatLayout, type ChatMessage, type ChatRunPhase, type ChatSessionListResult, type ChatSessionMeta, type ChatTheme, type ChatThinking, type ChatTokenUsage, type ChatToolCall, Chatbot, type ChatbotConfig, type ChatbotGovernancePorts, type ChatbotHostAdapter, type ChatbotProps, ChatbotVisionDelegate, type ChatbotVisionDelegateOptions, CompositeUiBridge, type CompositeUiBridgeDeps, DEFAULT_RENDERER_CAPABILITIES, DEFAULT_RUNTIME_CONFIG_STORAGE_KEY, type DownloadableFile, type DwgHost, ErrorCard, type ErrorCardProps, type HttpMessageComponentOptions, InteractionCard, type InteractionCardProps, InterruptedBanner, type InterruptedBannerProps, type Locale, type LocalizedText, OpenUiSurfaceHost, type OpenUiSurfaceHostProps, OpenUiSurfaceSnapshotHost, type OpenUiSurfaceSnapshotHostProps, type QuickPrompt, type QuickPromptIconName, type RendererCapability, type RendererKind, type ResolvedChatLayout, ResultBlockList, type ResultBlockListProps, ResultBlocksPro, type ResultBlocksProProps, type RunSnapshot, type RuntimeAppearanceConfig, type RuntimeConfig, type RuntimeConfigStore, type RuntimeQuickPrompt, type RuntimeRendererId, type SandboxExecutorDeps, type SettingsSectionId, SkillBadges, SpecInteraction, type SpecInteractionProps, VercelPayloadPreview, type VercelPayloadPreviewProps, VercelSurfaceHost, type VercelSurfaceHostProps, VercelSurfaceSnapshotHost, type VercelSurfaceSnapshotHostProps, type VisionDelegationConsent, type VisionDelegationEndpoint, WEB_OFFICE_TEMPLATE_PREFIX, chatbotDictionary, configureA2uiMarkdown, createHttpMessageComponent, createLocalStorageRuntimeConfigStore, createMemoryRuntimeConfigStore, isLlmEntryUsable, pickUsableLlmEntry, probeA2uiAvailability, probeOpenUiAvailability, sandboxExecutorDeps, useT };
|
package/dist/index.js
CHANGED
|
@@ -23,7 +23,7 @@ import { ActionBarPrimitive, AttachmentPrimitive, AuiProvider, ComposerPrimitive
|
|
|
23
23
|
import { BrowserWorkerScriptExecutor, WebOfficePolicy, capturePhoto, checkCameraAvailability, checkDictationAvailability, compressImageToBudget, createEncryptedMemoryStore, createLlmClient, createWebOfficeToolSource, deleteMemoryEncryptionKey, openCamera, openMemoryEncryptionKey, probeChromeBuiltinAvailability, startDictation, toDocumentImage } from "@webskill/sdk/browser";
|
|
24
24
|
import { JsonRenderSpecSurface, NativeSpecSurface, OpenUiSpecSurface, ReactBridgeState, SpecInteractionChannel, SurfaceFormTextsProvider, UiSurfaceSnapshotList, probeJsonRenderAvailability } from "@webskill/sdk/ui-react";
|
|
25
25
|
import { A2UI_SPEC_FORM_PATH, collectFormScopes, createUiCatalogToolSource, fromA2uiSpecAction, fromA2uiSurfaceAction, interactionToFormModel, interactionToUiSpec, loadOpenUiPeers, loadWebSkillLitCatalog, renderMiniChart, shapeInteractionValue, toA2uiSpecMessages, toA2uiSurfaceAction, toVercelToolInvocation, uiCatalog } from "@webskill/sdk/ui";
|
|
26
|
-
import { DownloadedFilePolicy, PAGE_ACTION_KINDS, SCROLL_DIRECTIONS, TodoStore, createDelegationToolSource, createDocumentToolSource, createDownloadedFileToolSource, createDwgToolSource, createPageActionToolSource, createPageImageToolSource, createPagePerceptionToolSource, createRemoteImageToolSource, createSkillGenerationToolSource, createSpreadsheetToolSource, createTabWorksetToolSource, createTableQueryToolSource, createTemplateToolSource, createTodoToolSource, profileTable, sniffDocumentFormat, withDelegationOrigin } from "@webskill/sdk/agent";
|
|
26
|
+
import { DownloadedFilePolicy, PAGE_ACTION_KINDS, SCROLL_DIRECTIONS, TodoStore, createDelegationToolSource, createDocumentToolSource, createDownloadedFileToolSource, createDwgToolSource, createPageActionToolSource, createPageImageToolSource, createPagePerceptionToolSource, createRemoteImageToolSource, createSkillGenerationToolSource, createSpreadsheetToolSource, createTabWorksetToolSource, createTableQueryToolSource, createTemplateToolSource, createTodoToolSource, isStreamingTableWorkbook, profileStreamingTable, profileTable, sniffDocumentFormat, summarizeStreamingWorkbook, withDelegationOrigin } from "@webskill/sdk/agent";
|
|
27
27
|
import { DataRenderers, Tools } from "@assistant-ui/core/react";
|
|
28
28
|
import { ModelContext, Suggestions } from "@assistant-ui/core/store";
|
|
29
29
|
import { Derived, attachTransformScopes, useClientLookup, useClientResource } from "@assistant-ui/store";
|
|
@@ -25916,6 +25916,7 @@ const chatbotDictionary = defineDictionary({
|
|
|
25916
25916
|
"composer.inputLabel": "Message input",
|
|
25917
25917
|
"composer.send": "Send",
|
|
25918
25918
|
"composer.stop": "Stop",
|
|
25919
|
+
"composer.processingAttachments": "Processing attachments on this device. Large files may take a while; please keep this chat open…",
|
|
25919
25920
|
"composer.attachments": "Attachments",
|
|
25920
25921
|
"composer.addAttachment": "Attach a file",
|
|
25921
25922
|
"composer.removeAttachment": "Remove attachment: {name}",
|
|
@@ -26376,6 +26377,7 @@ const chatbotDictionary = defineDictionary({
|
|
|
26376
26377
|
"composer.inputLabel": "消息输入框",
|
|
26377
26378
|
"composer.send": "发送",
|
|
26378
26379
|
"composer.stop": "停止",
|
|
26380
|
+
"composer.processingAttachments": "正在本机处理附件,大文件可能需要一些时间,请保持对话打开…",
|
|
26379
26381
|
"composer.attachments": "附件",
|
|
26380
26382
|
"composer.addAttachment": "添加附件",
|
|
26381
26383
|
"composer.removeAttachment": "移除附件:{name}",
|
|
@@ -27918,7 +27920,7 @@ function smallTableHint(id) {
|
|
|
27918
27920
|
* 已解析的表按「会话 + 来源」缓存(FR-10.17)。
|
|
27919
27921
|
*
|
|
27920
27922
|
* 缓存的是进行中的 promise:分流时解析一次,紧接着的查询复用同一份;失败不留。
|
|
27921
|
-
* 容量 2
|
|
27923
|
+
* 容量 2、最近使用淘汰——网格工作簿会占堆内存,流式工作簿只缓存元数据与取件出口,
|
|
27922
27924
|
* 留两格是为「同一会话里先后传两份表做对比」。
|
|
27923
27925
|
*/
|
|
27924
27926
|
var TableCache = class {
|
|
@@ -29474,33 +29476,56 @@ var ChatEngine = class {
|
|
|
29474
29476
|
if (extract === void 0) return void 0;
|
|
29475
29477
|
return await extract(bytes);
|
|
29476
29478
|
}
|
|
29479
|
+
async #readTable(reader, path) {
|
|
29480
|
+
if (reader.readStreaming !== void 0) {
|
|
29481
|
+
const storage = this.#adapter.storage;
|
|
29482
|
+
if (storage.createReadStream !== void 0) return await reader.readStreaming(() => storage.createReadStream(path));
|
|
29483
|
+
return await reader.readStreaming(await storage.readBinary(path));
|
|
29484
|
+
}
|
|
29485
|
+
return await reader.read(await this.#adapter.storage.readBinary(path));
|
|
29486
|
+
}
|
|
29477
29487
|
/**
|
|
29478
29488
|
* xlsx 附件的发送形态分流(0.26.0 分册 10 · FR-10.1 / FR-10.5)。
|
|
29479
29489
|
*
|
|
29480
29490
|
* 返回 `undefined` = 不适用(没接端口、不是 xlsx、解析失败),调用方走 0.25.0 的原路径——
|
|
29481
29491
|
* 解析失败时同一份坏文件会在原路径里以既有的形态报错,这里不新增失败形态。
|
|
29482
|
-
*
|
|
29492
|
+
* 解析在这里先做一次、工作簿进缓存,随后的 `query_table` 复用同一份。
|
|
29483
29493
|
*/
|
|
29484
29494
|
async #tableRouting(attachment, path, sessionId) {
|
|
29485
29495
|
const reader = this.#adapter.xlsxTableReader;
|
|
29486
29496
|
if (reader === void 0 || attachment.kind !== "document-text") return void 0;
|
|
29487
29497
|
if (extractedDocumentFormat(attachment.contentType, attachment.name) !== "xlsx") return void 0;
|
|
29488
|
-
const workbook = await this.#tables.get(sessionId, `att:${attachment.path}`, async () =>
|
|
29498
|
+
const workbook = await this.#tables.get(sessionId, `att:${attachment.path}`, async () => this.#readTable(reader, path)).catch(() => void 0);
|
|
29489
29499
|
if (workbook === void 0) return void 0;
|
|
29490
|
-
|
|
29500
|
+
let tokens;
|
|
29501
|
+
let rows;
|
|
29502
|
+
let profile;
|
|
29503
|
+
if (isStreamingTableWorkbook(workbook)) {
|
|
29504
|
+
const summary = await summarizeStreamingWorkbook(workbook);
|
|
29505
|
+
tokens = summary.tokens;
|
|
29506
|
+
rows = summary.dataRows;
|
|
29507
|
+
profile = () => profileStreamingTable({
|
|
29508
|
+
name: attachment.name,
|
|
29509
|
+
id: attachment.id,
|
|
29510
|
+
workbook
|
|
29511
|
+
});
|
|
29512
|
+
} else {
|
|
29513
|
+
tokens = estimateTableTokens(workbook);
|
|
29514
|
+
rows = countDataRows(workbook);
|
|
29515
|
+
profile = () => Promise.resolve(profileTable({
|
|
29516
|
+
name: attachment.name,
|
|
29517
|
+
id: attachment.id,
|
|
29518
|
+
workbook
|
|
29519
|
+
}));
|
|
29520
|
+
}
|
|
29491
29521
|
if (tokens <= 24e3) return {
|
|
29492
29522
|
kind: "inline",
|
|
29493
29523
|
hint: smallTableHint(attachment.id)
|
|
29494
29524
|
};
|
|
29495
|
-
const rows = countDataRows(workbook);
|
|
29496
29525
|
const locale = this.#liveConfig?.appearance.locale ?? "en";
|
|
29497
29526
|
return {
|
|
29498
29527
|
kind: "profile",
|
|
29499
|
-
profile:
|
|
29500
|
-
name: attachment.name,
|
|
29501
|
-
id: attachment.id,
|
|
29502
|
-
workbook
|
|
29503
|
-
}),
|
|
29528
|
+
profile: await profile(),
|
|
29504
29529
|
steering: tableQuerySteering({
|
|
29505
29530
|
id: attachment.id,
|
|
29506
29531
|
tokens,
|
|
@@ -29523,8 +29548,22 @@ var ChatEngine = class {
|
|
|
29523
29548
|
async #downloadSheetRouting(input) {
|
|
29524
29549
|
const reader = this.#adapter.xlsxTableReader;
|
|
29525
29550
|
if (reader === void 0) return void 0;
|
|
29526
|
-
const workbook = await this.#tables.get(this.#currentSessionId ?? "", `dl:${input.entry.id}`, () => reader.read(input.bytes)).catch(() => void 0);
|
|
29551
|
+
const workbook = await this.#tables.get(this.#currentSessionId ?? "", `dl:${input.entry.id}`, () => reader.readStreaming !== void 0 ? reader.readStreaming(input.bytes) : reader.read(input.bytes)).catch(() => void 0);
|
|
29527
29552
|
if (workbook === void 0) return void 0;
|
|
29553
|
+
if (isStreamingTableWorkbook(workbook)) {
|
|
29554
|
+
const summary = await summarizeStreamingWorkbook(workbook);
|
|
29555
|
+
if (summary.tokens <= 24e3 && summary.textChars <= ATTACHMENT_TEXT_LIMIT) return void 0;
|
|
29556
|
+
return `${await profileStreamingTable({
|
|
29557
|
+
name: input.entry.name,
|
|
29558
|
+
id: input.entry.id,
|
|
29559
|
+
workbook
|
|
29560
|
+
})}\n\n` + tableQuerySteering({
|
|
29561
|
+
id: input.entry.id,
|
|
29562
|
+
tokens: summary.tokens,
|
|
29563
|
+
rows: summary.dataRows,
|
|
29564
|
+
download: true
|
|
29565
|
+
});
|
|
29566
|
+
}
|
|
29528
29567
|
const tokens = estimateTableTokens(workbook);
|
|
29529
29568
|
if (tokens <= 24e3 && tableTextChars(workbook) <= ATTACHMENT_TEXT_LIMIT) return void 0;
|
|
29530
29569
|
return `${profileTable({
|
|
@@ -29554,7 +29593,7 @@ var ChatEngine = class {
|
|
|
29554
29593
|
const notXlsx = (name) => new WebSkillError("TOOL_UNSUPPORTED", `"${name}" is not an Excel (.xlsx) workbook; query_table reads .xlsx only.`);
|
|
29555
29594
|
const fromAttachment = async (a) => {
|
|
29556
29595
|
if (a.kind !== "document-text" || extractedDocumentFormat(a.contentType, a.name) !== "xlsx") throw notXlsx(a.name);
|
|
29557
|
-
const workbook = await this.#tables.get(sessionId, `att:${a.path}`, async () =>
|
|
29596
|
+
const workbook = await this.#tables.get(sessionId, `att:${a.path}`, async () => this.#readTable(reader, `${this.attachmentsRoot}/${a.path}`));
|
|
29558
29597
|
return {
|
|
29559
29598
|
name: a.name,
|
|
29560
29599
|
workbook
|
|
@@ -29575,7 +29614,7 @@ var ChatEngine = class {
|
|
|
29575
29614
|
if (sniffDocumentFormat(bytes, name) !== "xlsx") throw notXlsx(name);
|
|
29576
29615
|
return {
|
|
29577
29616
|
name,
|
|
29578
|
-
workbook: await this.#tables.get(sessionId, source, () => reader.read(bytes))
|
|
29617
|
+
workbook: await this.#tables.get(sessionId, source, () => reader.readStreaming !== void 0 ? reader.readStreaming(bytes) : reader.read(bytes))
|
|
29579
29618
|
};
|
|
29580
29619
|
};
|
|
29581
29620
|
const stored = context?.binaries?.get(id);
|
|
@@ -30266,7 +30305,16 @@ var ChatEngine = class {
|
|
|
30266
30305
|
}),
|
|
30267
30306
|
...this.#adapter.xlsxTableReader ? [createTableQueryToolSource({
|
|
30268
30307
|
tables: { load: (id, context) => this.#loadTable(id, context, downloadPolicy) },
|
|
30269
|
-
downloadedFiles: () => downloadPolicy?.enabled === true
|
|
30308
|
+
downloadedFiles: () => downloadPolicy?.enabled === true,
|
|
30309
|
+
writeArtifact: (path, content, mimeType, context) => {
|
|
30310
|
+
if (!context?.runId) throw new WebSkillError("TOOL_EXECUTION_FAILED", "Writing a query result requires an active run.");
|
|
30311
|
+
return artifactStore.createBinaryArtifact({
|
|
30312
|
+
runId: context.runId,
|
|
30313
|
+
path,
|
|
30314
|
+
content,
|
|
30315
|
+
mimeType
|
|
30316
|
+
});
|
|
30317
|
+
}
|
|
30270
30318
|
})] : [],
|
|
30271
30319
|
...this.#adapter.xlsxTemplateEngine || this.#adapter.docxTemplateEngine ? [createTemplateToolSource({
|
|
30272
30320
|
files: { read: readTemplateBytes },
|
|
@@ -32442,7 +32490,7 @@ function ModelMenuButton({ models }) {
|
|
|
32442
32490
|
}, option.id))
|
|
32443
32491
|
})] });
|
|
32444
32492
|
}
|
|
32445
|
-
function AssistantUiComposer({ running, disabled = false, waitTarget, placeholder, attachments = false, attachmentInfo, attachmentImages, centered = false, models, noModel, dictationLang, onDictationPermissionDenied, onCameraPermissionDenied, capabilities }) {
|
|
32493
|
+
function AssistantUiComposer({ running, disabled = false, processingAttachments = false, waitTarget, placeholder, attachments = false, attachmentInfo, attachmentImages, centered = false, models, noModel, dictationLang, onDictationPermissionDenied, onCameraPermissionDenied, capabilities }) {
|
|
32446
32494
|
const t = useT();
|
|
32447
32495
|
const locale = useLocale();
|
|
32448
32496
|
const dictation = useComposerDictation(dictationLang ?? DEFAULT_DICTATION_LANG[locale], onDictationPermissionDenied);
|
|
@@ -32459,11 +32507,20 @@ function AssistantUiComposer({ running, disabled = false, waitTarget, placeholde
|
|
|
32459
32507
|
const cameraReason = !attachments ? t("composer.camera.noStorage") : attachmentReason ?? (camera.availability.available ? void 0 : t(`composer.camera.${camera.availability.reason}`));
|
|
32460
32508
|
const cameraFailure = camera.failure === void 0 ? void 0 : camera.failure === "denied" && onCameraPermissionDenied !== void 0 ? t("composer.camera.denied.handoff") : t(`composer.camera.${camera.failure}`);
|
|
32461
32509
|
const plainChatHintId = useId();
|
|
32462
|
-
return /* @__PURE__ */
|
|
32510
|
+
return /* @__PURE__ */ jsxs(ComposerPrimitive.Root, {
|
|
32463
32511
|
"data-testid": "assistant-ui-composer",
|
|
32464
32512
|
"data-centered": centered,
|
|
32465
32513
|
className: "webskill-aui-composer shrink-0 px-4 py-4",
|
|
32466
|
-
children: /* @__PURE__ */ jsxs(
|
|
32514
|
+
children: [processingAttachments ? /* @__PURE__ */ jsxs("div", {
|
|
32515
|
+
"data-testid": "attachment-processing",
|
|
32516
|
+
role: "status",
|
|
32517
|
+
"aria-live": "polite",
|
|
32518
|
+
className: "webskill-chat-prose mx-auto flex w-full items-center gap-2 px-3 pb-2 text-xs text-muted",
|
|
32519
|
+
children: [/* @__PURE__ */ jsx(LoaderCircle, {
|
|
32520
|
+
className: "size-3.5 shrink-0 animate-spin motion-reduce:animate-none",
|
|
32521
|
+
"aria-hidden": true
|
|
32522
|
+
}), /* @__PURE__ */ jsx("span", { children: t("composer.processingAttachments") })]
|
|
32523
|
+
}) : null, /* @__PURE__ */ jsxs(ComposerPrimitive.AttachmentDropzone, {
|
|
32467
32524
|
disabled: !attachments,
|
|
32468
32525
|
className: "webskill-aui-composer-shell webskill-chat-prose mx-auto flex w-full flex-col gap-2 px-3 py-2 transition-colors data-[dragging=true]:border-ring",
|
|
32469
32526
|
children: [
|
|
@@ -32689,7 +32746,7 @@ function AssistantUiComposer({ running, disabled = false, waitTarget, placeholde
|
|
|
32689
32746
|
onCancel: camera.cancel
|
|
32690
32747
|
})
|
|
32691
32748
|
]
|
|
32692
|
-
})
|
|
32749
|
+
})]
|
|
32693
32750
|
});
|
|
32694
32751
|
}
|
|
32695
32752
|
|
|
@@ -42980,6 +43037,22 @@ function fallbackReason(error) {
|
|
|
42980
43037
|
const code = error?.code;
|
|
42981
43038
|
return typeof code === "string" && code !== "" ? code : "a2ui-render-failed";
|
|
42982
43039
|
}
|
|
43040
|
+
function formControlValues(root) {
|
|
43041
|
+
const values = {};
|
|
43042
|
+
const visit = (node) => {
|
|
43043
|
+
for (const child of node.children) {
|
|
43044
|
+
if (child instanceof HTMLInputElement) {
|
|
43045
|
+
if (child.id) values[child.id] = child.type === "checkbox" ? child.checked : child.type === "number" ? Number(child.value) : child.value;
|
|
43046
|
+
} else if (child instanceof HTMLTextAreaElement || child instanceof HTMLSelectElement) {
|
|
43047
|
+
if (child.id) values[child.id] = child instanceof HTMLSelectElement && child.multiple ? [...child.selectedOptions].map((option) => option.value) : child.value;
|
|
43048
|
+
}
|
|
43049
|
+
if (child.shadowRoot) visit(child.shadowRoot);
|
|
43050
|
+
else visit(child);
|
|
43051
|
+
}
|
|
43052
|
+
};
|
|
43053
|
+
if (root) visit(root.shadowRoot ?? root);
|
|
43054
|
+
return values;
|
|
43055
|
+
}
|
|
42983
43056
|
/**
|
|
42984
43057
|
* `a2ui` 档:catalog 声明树经 BYOC catalog 的 Lit 元素渲染。
|
|
42985
43058
|
* 元素与协议里公布的 `catalog_definition` 派生自同一份 shape,因此这里
|
|
@@ -42990,6 +43063,7 @@ function fallbackReason(error) {
|
|
|
42990
43063
|
*/
|
|
42991
43064
|
function A2uiSpecSurface({ spec, surfaceId, actions, onAction, registry, runId, draft, onDraftChange }) {
|
|
42992
43065
|
const mountRef = useRef(null);
|
|
43066
|
+
const formValuesRef = useRef({});
|
|
42993
43067
|
const [fallback, setFallback] = useState();
|
|
42994
43068
|
const emit = useEffectEvent((actionId, value) => {
|
|
42995
43069
|
const declared = (actions ?? []).find((action) => action.id === actionId);
|
|
@@ -43019,8 +43093,11 @@ function A2uiSpecSurface({ spec, surfaceId, actions, onAction, registry, runId,
|
|
|
43019
43093
|
const processor = new MessageProcessor([catalog, lit.basicCatalog], (action) => {
|
|
43020
43094
|
const decoded = fromA2uiSpecAction(action);
|
|
43021
43095
|
if (!decoded) return;
|
|
43022
|
-
const values =
|
|
43023
|
-
|
|
43096
|
+
const values = {
|
|
43097
|
+
...processor.getClientDataModel("v0.9.1")?.surfaces?.[a2uiSurfaceId]?.[A2UI_SPEC_FORM_PATH.slice(1)],
|
|
43098
|
+
...formControlValues(surfaceElement)
|
|
43099
|
+
};
|
|
43100
|
+
emit(decoded.actionId, values);
|
|
43024
43101
|
}, { version: "v0.9.1" });
|
|
43025
43102
|
processor.onSurfaceCreated((surface) => {
|
|
43026
43103
|
if (disposed) return;
|
|
@@ -43029,6 +43106,21 @@ function A2uiSpecSurface({ spec, surfaceId, actions, onAction, registry, runId,
|
|
|
43029
43106
|
mount.replaceChildren(surfaceElement);
|
|
43030
43107
|
});
|
|
43031
43108
|
processor.processMessages(toA2uiSpecMessages(uiCatalog, spec, { surfaceId: a2uiSurfaceId }));
|
|
43109
|
+
const previousValues = formValuesRef.current;
|
|
43110
|
+
if (Object.keys(previousValues).length > 0) {
|
|
43111
|
+
const defaults = processor.getClientDataModel("v0.9.1")?.surfaces?.[a2uiSurfaceId]?.[A2UI_SPEC_FORM_PATH.slice(1)];
|
|
43112
|
+
processor.processMessages([{
|
|
43113
|
+
version: "v0.9.1",
|
|
43114
|
+
updateDataModel: {
|
|
43115
|
+
surfaceId: a2uiSurfaceId,
|
|
43116
|
+
path: A2UI_SPEC_FORM_PATH,
|
|
43117
|
+
value: {
|
|
43118
|
+
...defaults,
|
|
43119
|
+
...previousValues
|
|
43120
|
+
}
|
|
43121
|
+
}
|
|
43122
|
+
}]);
|
|
43123
|
+
}
|
|
43032
43124
|
} catch (error) {
|
|
43033
43125
|
reportA2uiFallback(surfaceId, "spec", error);
|
|
43034
43126
|
if (!disposed) setFallback(fallbackReason(error));
|
|
@@ -43036,6 +43128,8 @@ function A2uiSpecSurface({ spec, surfaceId, actions, onAction, registry, runId,
|
|
|
43036
43128
|
})();
|
|
43037
43129
|
return () => {
|
|
43038
43130
|
disposed = true;
|
|
43131
|
+
const values = surfaceElement?.surface?.dataModel.get(A2UI_SPEC_FORM_PATH);
|
|
43132
|
+
if (typeof values === "object" && values !== null && !Array.isArray(values)) formValuesRef.current = values;
|
|
43039
43133
|
surfaceElement?.remove();
|
|
43040
43134
|
};
|
|
43041
43135
|
}, [spec, surfaceId]);
|
|
@@ -46053,6 +46147,7 @@ function Chatbot({ adapter, config, locale: localeProp, theme: themeProp, render
|
|
|
46053
46147
|
const [loadingEarlierMessages, setLoadingEarlierMessages] = useState(false);
|
|
46054
46148
|
const [currentSessionId, setCurrentSessionId] = useState();
|
|
46055
46149
|
const [sending, setSending] = useState(false);
|
|
46150
|
+
const [processingAttachments, setProcessingAttachments] = useState(false);
|
|
46056
46151
|
/** 这一条排在同会话的上一条后面(FR-20.3):排队本身保护历史顺序,要改的是它不可见 */
|
|
46057
46152
|
const [queuedSend, setQueuedSend] = useState(false);
|
|
46058
46153
|
/**
|
|
@@ -46323,6 +46418,7 @@ function Chatbot({ adapter, config, locale: localeProp, theme: themeProp, render
|
|
|
46323
46418
|
setError(void 0);
|
|
46324
46419
|
break;
|
|
46325
46420
|
case "message-complete":
|
|
46421
|
+
if (event.message.role === "user") setProcessingAttachments(false);
|
|
46326
46422
|
setMessages((prev) => prev.some((message) => message.id === event.message.id) ? prev : [...prev, event.message]);
|
|
46327
46423
|
break;
|
|
46328
46424
|
case "interaction-requested":
|
|
@@ -46396,7 +46492,13 @@ function Chatbot({ adapter, config, locale: localeProp, theme: themeProp, render
|
|
|
46396
46492
|
setNoModelGuideOpen(true);
|
|
46397
46493
|
return;
|
|
46398
46494
|
}
|
|
46495
|
+
const hasAttachments = attachments.length > 0;
|
|
46496
|
+
if (hasAttachments) {
|
|
46497
|
+
setProcessingAttachments(true);
|
|
46498
|
+
setSending(true);
|
|
46499
|
+
}
|
|
46399
46500
|
(async () => {
|
|
46501
|
+
if (hasAttachments) await new Promise((resolve) => setTimeout(resolve, 0));
|
|
46400
46502
|
await flushPendingDeletes();
|
|
46401
46503
|
let sessionId = currentSessionId;
|
|
46402
46504
|
if (!sessionId) {
|
|
@@ -46408,7 +46510,13 @@ function Chatbot({ adapter, config, locale: localeProp, theme: themeProp, render
|
|
|
46408
46510
|
const needsTitle = sessionsRef.current.find((session) => session.id === sessionId)?.title === void 0;
|
|
46409
46511
|
await engine.send(text, attachments);
|
|
46410
46512
|
if (needsTitle) await refreshSessions();
|
|
46411
|
-
})().catch((e) =>
|
|
46513
|
+
})().catch((e) => {
|
|
46514
|
+
if (hasAttachments) {
|
|
46515
|
+
setProcessingAttachments(false);
|
|
46516
|
+
setSending(false);
|
|
46517
|
+
}
|
|
46518
|
+
setError({ message: toErrorMessage(e) });
|
|
46519
|
+
});
|
|
46412
46520
|
}, [
|
|
46413
46521
|
engine,
|
|
46414
46522
|
currentSessionId,
|
|
@@ -46764,6 +46872,7 @@ function Chatbot({ adapter, config, locale: localeProp, theme: themeProp, render
|
|
|
46764
46872
|
} } : {},
|
|
46765
46873
|
running: busy,
|
|
46766
46874
|
disabled: interactionPending,
|
|
46875
|
+
processingAttachments,
|
|
46767
46876
|
...interactionTarget !== void 0 ? { waitTarget: interactionTarget } : {},
|
|
46768
46877
|
centered: composerCentered,
|
|
46769
46878
|
attachments: attachmentsReady,
|
|
@@ -46852,7 +46961,7 @@ function VercelPayloadPreview({ bridge }) {
|
|
|
46852
46961
|
* Version of the published `@webskill/chatbot` package, injected at build time.
|
|
46853
46962
|
* @stable
|
|
46854
46963
|
*/
|
|
46855
|
-
const CHATBOT_VERSION = "0.
|
|
46964
|
+
const CHATBOT_VERSION = "0.25.1";
|
|
46856
46965
|
|
|
46857
46966
|
//#endregion
|
|
46858
46967
|
export { A2uiSurfaceHost, A2uiSurfaceSnapshotHost, CHATBOT_VERSION, ChatEngine, Chatbot, ChatbotVisionDelegate, CompositeUiBridge, DEFAULT_RENDERER_CAPABILITIES, DEFAULT_RUNTIME_CONFIG_STORAGE_KEY, ErrorCard, InteractionCard, InterruptedBanner, OpenUiSurfaceHost, OpenUiSurfaceSnapshotHost, ResultBlockList, ResultBlocksPro, SkillBadges, SpecInteraction, VercelPayloadPreview, VercelSurfaceHost, VercelSurfaceSnapshotHost, WEB_OFFICE_TEMPLATE_PREFIX, chatbotDictionary, configureA2uiMarkdown, createHttpMessageComponent, createLocalStorageRuntimeConfigStore, createMemoryRuntimeConfigStore, isLlmEntryUsable, pickUsableLlmEntry, probeA2uiAvailability, probeOpenUiAvailability, sandboxExecutorDeps, useT };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webskill/chatbot",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"@a2ui/web_core": "^0.10.5",
|
|
39
39
|
"@lit/context": "^1.1.0",
|
|
40
40
|
"@openuidev/react-lang": "0.2.8",
|
|
41
|
-
"@webskill/sdk": "^0.
|
|
41
|
+
"@webskill/sdk": "^0.28.1",
|
|
42
42
|
"mermaid": "^12.0.0",
|
|
43
43
|
"react": ">=19.0.0",
|
|
44
44
|
"react-dom": ">=19.0.0",
|