@webskill/chatbot 0.0.1 → 0.0.2
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/LICENSE +21 -0
- package/README.md +1 -1
- package/dist/index.d.ts +2 -19
- package/dist/index.js +64 -180
- package/package.json +3 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Chunhui Mo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -133,7 +133,7 @@ implementation (OPFS storage, skills, demo/model providers, console embedding).
|
|
|
133
133
|
`CompositeUiBridge`, the i18n dictionary. Covered by semver from 0.1.0.
|
|
134
134
|
- **`@experimental`** — A2UI/OpenUI/Vercel surface hosts and snapshot hosts,
|
|
135
135
|
`VercelPayloadPreview`, `configureA2uiMarkdown`, the `probe*` availability
|
|
136
|
-
helpers, `RendererKind` (renamed in 0.
|
|
136
|
+
helpers, `RendererKind` (renamed in 0.4.0), and the `RunSnapshot` format.
|
|
137
137
|
These may change between 0.0.x releases.
|
|
138
138
|
|
|
139
139
|
## License
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AgentLoopConfig, ApprovalScope, BridgeCapabilities, ExternalSkillProvider, ExternalToolSource, FileSystemProvider, InteractionRequest, InteractionResponse, LlmClient, NetworkPolicy, RenderBlock, RenderResultRequest, RunSnapshot, RunSnapshot as RunSnapshot$1, RuntimePhase,
|
|
1
|
+
import { AgentLoopConfig, ApprovalScope, BridgeCapabilities, ExternalSkillProvider, ExternalToolSource, FileSystemProvider, InteractionRequest, InteractionResponse, LlmClient, NetworkPolicy, RenderBlock, RenderResultRequest, RunSnapshot, RunSnapshot as RunSnapshot$1, RuntimePhase, ScriptExecutor, UiBridge, UiSurfaceActionRequest, UiSurfaceActionResponse, UiSurfaceDrafts, UiSurfaceEvent, UiSurfaceSnapshot } from "@webskill/sdk";
|
|
2
2
|
import { SandboxMode } from "@webskill/sdk/browser";
|
|
3
3
|
import { ReactBridgeState, SurfaceRegistry, UiSurfaceActionEvent } from "@webskill/sdk/ui-react";
|
|
4
4
|
import "@webskill/sdk/ui";
|
|
@@ -452,23 +452,6 @@ declare class ChatEngine {
|
|
|
452
452
|
resume(runId: string): Promise<void>;
|
|
453
453
|
}
|
|
454
454
|
//#endregion
|
|
455
|
-
//#region src/core/traceSink.d.ts
|
|
456
|
-
/**
|
|
457
|
-
* run trace 落盘格式:与 console 包的共享约定(两包零依赖,console 的
|
|
458
|
-
* createFsTraceSource(fs, chatRoot) 读同一位置),字段名不得擅自变更。
|
|
459
|
-
*/
|
|
460
|
-
interface RunTraceFile {
|
|
461
|
-
runId: string;
|
|
462
|
-
sessionId: string;
|
|
463
|
-
startedAt: string;
|
|
464
|
-
endedAt?: string;
|
|
465
|
-
status: 'completed' | 'failed' | 'cancelled';
|
|
466
|
-
activeSkills: string[];
|
|
467
|
-
events: TraceEvent[];
|
|
468
|
-
}
|
|
469
|
-
/** 写 `<chatRoot>/traces/<runId>.json`;写失败降级 console.warn,不阻断对话 */
|
|
470
|
-
declare function writeRunTrace(fs: FileSystemProvider, chatRoot: string, run: RuntimeRun): Promise<void>;
|
|
471
|
-
//#endregion
|
|
472
455
|
//#region src/i18n.d.ts
|
|
473
456
|
/**
|
|
474
457
|
* chatbot 双语字典:全部 UI 文案的单一来源(英文为主,zh 条目齐全)。
|
|
@@ -1229,4 +1212,4 @@ interface ErrorCardProps {
|
|
|
1229
1212
|
/** 结构化错误卡:错误码徽章 + 描述 + 建议(engine error 事件 / 失败 run) */
|
|
1230
1213
|
declare function ErrorCard({ code, message, onDismiss }: ErrorCardProps): import("react").JSX.Element;
|
|
1231
1214
|
//#endregion
|
|
1232
|
-
export { A2uiSurfaceHost, type A2uiSurfaceHostProps, A2uiSurfaceSnapshotHost, type A2uiSurfaceSnapshotHostProps, type AppearanceChange, type ChatAttachmentInput, type ChatAttachmentMeta, ChatEngine, type ChatEngineOptions, type ChatEvent, type ChatLayout, type ChatMessage, type ChatSessionMeta, type ChatTheme, type ChatToolCall, Chatbot, type ChatbotConfig, type ChatbotHostAdapter, type ChatbotProps, CompositeUiBridge, type CompositeUiBridgeDeps, type DownloadableFile, ErrorCard, type ErrorCardProps, InteractionCard, type InteractionCardProps, InterruptedBanner, type InterruptedBannerProps, type LlmConfig, type Locale, OpenUiChannel, OpenUiInteraction, type OpenUiInteractionProps, type OpenUiSession, OpenUiSurfaceHost, type OpenUiSurfaceHostProps, OpenUiSurfaceSnapshotHost, type OpenUiSurfaceSnapshotHostProps, type RendererKind, type ResolvedChatLayout, ResultBlockList, type ResultBlockListProps, ResultBlocksPro, type ResultBlocksProProps, type RunSnapshot, type
|
|
1215
|
+
export { A2uiSurfaceHost, type A2uiSurfaceHostProps, A2uiSurfaceSnapshotHost, type A2uiSurfaceSnapshotHostProps, type AppearanceChange, type ChatAttachmentInput, type ChatAttachmentMeta, ChatEngine, type ChatEngineOptions, type ChatEvent, type ChatLayout, type ChatMessage, type ChatSessionMeta, type ChatTheme, type ChatToolCall, Chatbot, type ChatbotConfig, type ChatbotHostAdapter, type ChatbotProps, CompositeUiBridge, type CompositeUiBridgeDeps, type DownloadableFile, ErrorCard, type ErrorCardProps, InteractionCard, type InteractionCardProps, InterruptedBanner, type InterruptedBannerProps, type LlmConfig, type Locale, OpenUiChannel, OpenUiInteraction, type OpenUiInteractionProps, type OpenUiSession, OpenUiSurfaceHost, type OpenUiSurfaceHostProps, OpenUiSurfaceSnapshotHost, type OpenUiSurfaceSnapshotHostProps, type RendererKind, type ResolvedChatLayout, ResultBlockList, type ResultBlockListProps, ResultBlocksPro, type ResultBlocksProProps, type RunSnapshot, type SandboxExecutorDeps, SettingsDrawer, type SettingsDrawerProps, SkillBadges, VercelPayloadPreview, type VercelPayloadPreviewProps, VercelSurfaceHost, type VercelSurfaceHostProps, VercelSurfaceSnapshotHost, type VercelSurfaceSnapshotHostProps, chatbotDictionary, configureA2uiMarkdown, probeA2uiAvailability, probeOpenUiAvailability, useT };
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { t as yaml } from "./yaml-C888tCbJ.js";
|
|
|
6
6
|
import { t as json } from "./json-BOcU6nei.js";
|
|
7
7
|
import { t as typescript } from "./typescript-DAau_Qyl.js";
|
|
8
8
|
import { t as jsx$1 } from "./jsx-D2Jv0wvt.js";
|
|
9
|
-
import { AnthropicClient, FsArtifactStore, FsMemoryStore, FsRunSnapshotStore, FullDisclosureRouter, GoogleGenAiClient, OpenAiCompatibleClient, SkillDiscovery, WebSkillError, WebSkillRuntime, messageOf } from "@webskill/sdk";
|
|
9
|
+
import { AnthropicClient, FsArtifactStore, FsMemoryStore, FsRunSnapshotStore, FsRunTraceStore, FsSessionStore, FullDisclosureRouter, GoogleGenAiClient, OpenAiCompatibleClient, SkillDiscovery, WebSkillError, WebSkillRuntime, messageOf, summarizeToolCalls } from "@webskill/sdk";
|
|
10
10
|
import { BrowserWorkerScriptExecutor } from "@webskill/sdk/browser";
|
|
11
11
|
import { JsonRenderSpecSurface, NativeSpecSurface, OpenUiSpecSurface, ReactBridgeState, UiSurfaceList, UiSurfaceSnapshotList } from "@webskill/sdk/ui-react";
|
|
12
12
|
import { A2UI_SPEC_FORM_PATH, LitRendererBridge, OPENUI_SURFACE_ACTION, VERCEL_SURFACE_ACTION_DATA_PART_TYPE, collectValues, createUiCatalogToolSource, fromA2uiSpecAction, fromA2uiSurfaceAction, fromOpenUiAction, fromOpenUiSurfaceAction, fromVercelSurfaceAction, interactionToFormModel, isUiSpecSurface, loadOpenUiPeers, loadWebSkillLitCatalog, renderMiniChart, shapeInteractionValue, toA2uiSpecMessages, toA2uiSurfaceAction, toA2uiSurfaceMessages, toOpenUiLang, toOpenUiSurfaceLang, toVercelSurfaceDataPart, toVercelToolInvocation, uiCatalog } from "@webskill/sdk/ui";
|
|
@@ -41024,31 +41024,11 @@ var CompositeUiBridge = class {
|
|
|
41024
41024
|
}
|
|
41025
41025
|
};
|
|
41026
41026
|
|
|
41027
|
-
//#endregion
|
|
41028
|
-
//#region src/core/traceSink.ts
|
|
41029
|
-
/** 写 `<chatRoot>/traces/<runId>.json`;写失败降级 console.warn,不阻断对话 */
|
|
41030
|
-
async function writeRunTrace(fs, chatRoot, run) {
|
|
41031
|
-
const trace = {
|
|
41032
|
-
runId: run.id,
|
|
41033
|
-
sessionId: run.sessionId,
|
|
41034
|
-
startedAt: run.startedAt,
|
|
41035
|
-
...run.endedAt ? { endedAt: run.endedAt } : {},
|
|
41036
|
-
status: run.status === "completed" || run.status === "cancelled" ? run.status : "failed",
|
|
41037
|
-
activeSkills: run.activeSkillNames,
|
|
41038
|
-
events: run.trace
|
|
41039
|
-
};
|
|
41040
|
-
try {
|
|
41041
|
-
await fs.writeText(`${chatRoot}/traces/${run.id}.json`, JSON.stringify(trace, null, 2));
|
|
41042
|
-
} catch (e) {
|
|
41043
|
-
console.warn(`Failed to persist run trace "${run.id}": ${messageOf(e)}`);
|
|
41044
|
-
}
|
|
41045
|
-
}
|
|
41046
|
-
|
|
41047
41027
|
//#endregion
|
|
41048
41028
|
//#region src/core/chatEngine.ts
|
|
41049
41029
|
/** 注入模型的单个附件正文上限(超出截断并标注) */
|
|
41050
41030
|
const ATTACHMENT_TEXT_LIMIT = 32 * 1024;
|
|
41051
|
-
/**
|
|
41031
|
+
/** sdk 的 `SessionMeta` → chatbot 的列表视图类型(跨层适配,非复刻) */
|
|
41052
41032
|
const toSessionMeta = (session) => ({
|
|
41053
41033
|
id: session.id,
|
|
41054
41034
|
createdAt: session.createdAt,
|
|
@@ -41137,8 +41117,6 @@ var ChatEngine = class {
|
|
|
41137
41117
|
#listeners = /* @__PURE__ */ new Set();
|
|
41138
41118
|
/** runId → 已激活技能累积(skill-activated 事件用;终态清理) */
|
|
41139
41119
|
#runSkills = /* @__PURE__ */ new Map();
|
|
41140
|
-
/** runId → callId → 已发出的工具事件种类(live 与 trace 重放去重;同 callId 同事件不重复发) */
|
|
41141
|
-
#emittedToolEvents = /* @__PURE__ */ new Map();
|
|
41142
41120
|
/** 当前渲染框架档(复合 uiBridge 分发;setRenderer 热切换) */
|
|
41143
41121
|
#renderer;
|
|
41144
41122
|
/** a2ui 档交互容器(Chatbot ref 回调注入) */
|
|
@@ -41151,10 +41129,22 @@ var ChatEngine = class {
|
|
|
41151
41129
|
#maxHistoryMessages;
|
|
41152
41130
|
/** Serializes OPFS draft writes so a slower prior keystroke cannot overwrite a newer value. */
|
|
41153
41131
|
#surfaceDraftWrites = /* @__PURE__ */ new Map();
|
|
41132
|
+
/** run trace 落盘(写失败降级 warn,不阻断对话) */
|
|
41133
|
+
#traceStore;
|
|
41134
|
+
/** 会话落盘:本包内引用 `FsSessionStore` 的唯一处 */
|
|
41135
|
+
#sessions;
|
|
41154
41136
|
constructor(adapter, options = {}) {
|
|
41155
41137
|
this.#adapter = adapter;
|
|
41156
41138
|
this.#options = options;
|
|
41157
41139
|
this.#chatRoot = (options.chatRoot ?? "/chat").replace(/\/+$/, "");
|
|
41140
|
+
this.#traceStore = new FsRunTraceStore({
|
|
41141
|
+
root: `${this.#chatRoot}/traces`,
|
|
41142
|
+
fs: adapter.storage
|
|
41143
|
+
});
|
|
41144
|
+
this.#sessions = new FsSessionStore({
|
|
41145
|
+
root: `${this.#chatRoot}/sessions`,
|
|
41146
|
+
fs: adapter.storage
|
|
41147
|
+
});
|
|
41158
41148
|
this.#renderer = options.renderer ?? "native";
|
|
41159
41149
|
this.bridge = new ReactBridgeState({ onSurfaceDraftChange: (runId, surfaceId, value) => this.#persistSurfaceDraft(runId, surfaceId, value) });
|
|
41160
41150
|
const accumulate = this.bridge.onTextDelta.bind(this.bridge);
|
|
@@ -41218,28 +41208,10 @@ var ChatEngine = class {
|
|
|
41218
41208
|
this.reloadConfig();
|
|
41219
41209
|
}
|
|
41220
41210
|
async listSessions() {
|
|
41221
|
-
|
|
41222
|
-
if (!await this.#adapter.storage.exists(dir)) return [];
|
|
41223
|
-
const entries = await this.#adapter.storage.list(dir);
|
|
41224
|
-
const metas = [];
|
|
41225
|
-
for (const entry of entries) {
|
|
41226
|
-
if (entry.type !== "file" || !entry.path.endsWith(".json")) continue;
|
|
41227
|
-
try {
|
|
41228
|
-
const session = JSON.parse(await this.#adapter.storage.readText(entry.path));
|
|
41229
|
-
metas.push(toSessionMeta(session));
|
|
41230
|
-
} catch (e) {
|
|
41231
|
-
console.warn(`Skipping corrupt session file "${entry.path}": ${messageOf(e)}`);
|
|
41232
|
-
}
|
|
41233
|
-
}
|
|
41234
|
-
return metas.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
41211
|
+
return (await this.#sessions.list({ includeArchived: true })).map(toSessionMeta);
|
|
41235
41212
|
}
|
|
41236
41213
|
async createSession() {
|
|
41237
|
-
const session = {
|
|
41238
|
-
id: newId("session"),
|
|
41239
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
41240
|
-
messages: []
|
|
41241
|
-
};
|
|
41242
|
-
await this.#writeSession(session);
|
|
41214
|
+
const session = await this.#sessions.create({ id: newId("session") });
|
|
41243
41215
|
this.#currentSessionId = session.id;
|
|
41244
41216
|
return {
|
|
41245
41217
|
id: session.id,
|
|
@@ -41247,13 +41219,12 @@ var ChatEngine = class {
|
|
|
41247
41219
|
};
|
|
41248
41220
|
}
|
|
41249
41221
|
async selectSession(id) {
|
|
41250
|
-
const session = await this.#
|
|
41222
|
+
const session = await this.#requireSession(id);
|
|
41251
41223
|
this.#currentSessionId = id;
|
|
41252
41224
|
return session.messages;
|
|
41253
41225
|
}
|
|
41254
41226
|
async deleteSession(id) {
|
|
41255
|
-
|
|
41256
|
-
if (await this.#adapter.storage.exists(path)) await this.#adapter.storage.remove(path);
|
|
41227
|
+
await this.#sessions.delete(id);
|
|
41257
41228
|
const attachments = `${this.attachmentsRoot}/${id}`;
|
|
41258
41229
|
if (await this.#adapter.storage.exists(attachments)) await this.#adapter.storage.remove(attachments, { recursive: true });
|
|
41259
41230
|
this.#handles.delete(id);
|
|
@@ -41261,36 +41232,32 @@ var ChatEngine = class {
|
|
|
41261
41232
|
}
|
|
41262
41233
|
/** 重命名会话:写入 title 并锁定(后续 send 不再用首条消息覆盖) */
|
|
41263
41234
|
async renameSession(id, title) {
|
|
41264
|
-
|
|
41265
|
-
session.title = title;
|
|
41266
|
-
session.titleLocked = true;
|
|
41267
|
-
await this.#writeSession(session);
|
|
41235
|
+
await this.#sessions.setTitle(id, title, { lock: true });
|
|
41268
41236
|
this.#emit({
|
|
41269
41237
|
type: "session-updated",
|
|
41270
|
-
session: toSessionMeta(
|
|
41238
|
+
session: toSessionMeta(await this.#requireSession(id))
|
|
41271
41239
|
});
|
|
41272
41240
|
}
|
|
41273
41241
|
/** 归档会话(仅标记,消息与 trace 不动) */
|
|
41274
41242
|
async archiveSession(id) {
|
|
41275
|
-
await this.#setArchived(id, true);
|
|
41243
|
+
await this.#sessions.setArchived(id, true);
|
|
41244
|
+
this.#emit({
|
|
41245
|
+
type: "session-updated",
|
|
41246
|
+
session: toSessionMeta(await this.#requireSession(id))
|
|
41247
|
+
});
|
|
41276
41248
|
}
|
|
41277
41249
|
/** 取消归档 */
|
|
41278
41250
|
async unarchiveSession(id) {
|
|
41279
|
-
await this.#setArchived(id, false);
|
|
41280
|
-
}
|
|
41281
|
-
async #setArchived(id, archived) {
|
|
41282
|
-
const session = await this.#readSession(id);
|
|
41283
|
-
session.archived = archived;
|
|
41284
|
-
await this.#writeSession(session);
|
|
41251
|
+
await this.#sessions.setArchived(id, false);
|
|
41285
41252
|
this.#emit({
|
|
41286
41253
|
type: "session-updated",
|
|
41287
|
-
session: toSessionMeta(
|
|
41254
|
+
session: toSessionMeta(await this.#requireSession(id))
|
|
41288
41255
|
});
|
|
41289
41256
|
}
|
|
41290
41257
|
/** 重发语义:取该 user 消息文本重新 send(assistant 应答新起一轮;不重写历史) */
|
|
41291
41258
|
async retry(messageId) {
|
|
41292
41259
|
const sessionId = this.#currentSessionId;
|
|
41293
|
-
const message = (sessionId ? await this.#
|
|
41260
|
+
const message = (sessionId ? await this.#sessions.get(sessionId) : void 0)?.messages.find((m) => m.id === messageId);
|
|
41294
41261
|
if (!sessionId || !message || message.role !== "user") throw new WebSkillError("VALIDATION_FAILED", `Cannot retry message "${messageId}": no matching user message in the active session`);
|
|
41295
41262
|
await this.send(message.text);
|
|
41296
41263
|
}
|
|
@@ -41300,23 +41267,21 @@ var ChatEngine = class {
|
|
|
41300
41267
|
*/
|
|
41301
41268
|
async editAndResend(messageId, text) {
|
|
41302
41269
|
const sessionId = this.#currentSessionId;
|
|
41303
|
-
const session = sessionId ? await this.#
|
|
41270
|
+
const session = sessionId ? await this.#sessions.get(sessionId) : void 0;
|
|
41304
41271
|
const index = session?.messages.findIndex((m) => m.id === messageId) ?? -1;
|
|
41305
41272
|
const target = session && index >= 0 ? session.messages[index] : void 0;
|
|
41306
|
-
if (!session || !target || target.role !== "user") throw new WebSkillError("VALIDATION_FAILED", `Cannot edit message "${messageId}": no matching user message in the active session`);
|
|
41307
|
-
|
|
41308
|
-
await this.#writeSession(session);
|
|
41273
|
+
if (!sessionId || !session || !target || target.role !== "user") throw new WebSkillError("VALIDATION_FAILED", `Cannot edit message "${messageId}": no matching user message in the active session`);
|
|
41274
|
+
await this.#sessions.replaceMessages(sessionId, session.messages.slice(0, index));
|
|
41309
41275
|
await this.send(text);
|
|
41310
41276
|
}
|
|
41311
41277
|
/** 从当前会话消息列表删除指定消息并持久化(消息不存在/无当前会话时静默跳过) */
|
|
41312
41278
|
async deleteMessage(messageId) {
|
|
41313
41279
|
const sessionId = this.#currentSessionId;
|
|
41314
41280
|
if (!sessionId) return;
|
|
41315
|
-
const session = await this.#
|
|
41281
|
+
const session = await this.#requireSession(sessionId);
|
|
41316
41282
|
const next = session.messages.filter((m) => m.id !== messageId);
|
|
41317
41283
|
if (next.length === session.messages.length) return;
|
|
41318
|
-
|
|
41319
|
-
await this.#writeSession(session);
|
|
41284
|
+
await this.#sessions.replaceMessages(sessionId, next);
|
|
41320
41285
|
}
|
|
41321
41286
|
/**
|
|
41322
41287
|
* 驱动当前 session 的一轮 run。同 session 并发由 runtime session handle 内部
|
|
@@ -41327,7 +41292,7 @@ var ChatEngine = class {
|
|
|
41327
41292
|
if (text.trim() === "" && attachments.length === 0) return;
|
|
41328
41293
|
const runtime = await this.#ensureReady();
|
|
41329
41294
|
const sessionId = this.#currentSessionId ?? (await this.createSession()).id;
|
|
41330
|
-
const session = await this.#
|
|
41295
|
+
const session = await this.#requireSession(sessionId);
|
|
41331
41296
|
const prompt = await this.#withAttachments(text, attachments);
|
|
41332
41297
|
const userMessage = {
|
|
41333
41298
|
id: newId("msg"),
|
|
@@ -41339,9 +41304,8 @@ var ChatEngine = class {
|
|
|
41339
41304
|
kind: "text"
|
|
41340
41305
|
})) } : {}
|
|
41341
41306
|
};
|
|
41342
|
-
|
|
41343
|
-
if (!session.title && !session.titleLocked)
|
|
41344
|
-
await this.#writeSession(session);
|
|
41307
|
+
await this.#sessions.appendMessages(sessionId, [userMessage]);
|
|
41308
|
+
if (!session.title && !session.titleLocked) await this.#sessions.setTitle(sessionId, text.slice(0, 30));
|
|
41345
41309
|
this.#emit({
|
|
41346
41310
|
type: "message-complete",
|
|
41347
41311
|
message: userMessage
|
|
@@ -41349,7 +41313,7 @@ var ChatEngine = class {
|
|
|
41349
41313
|
const handle = this.#sessionHandle(runtime, sessionId);
|
|
41350
41314
|
try {
|
|
41351
41315
|
const result = await handle.run(prompt);
|
|
41352
|
-
await this.#finishRun(
|
|
41316
|
+
await this.#finishRun(sessionId, result);
|
|
41353
41317
|
} catch (e) {
|
|
41354
41318
|
this.#emitError(e);
|
|
41355
41319
|
}
|
|
@@ -41393,8 +41357,9 @@ var ChatEngine = class {
|
|
|
41393
41357
|
runId
|
|
41394
41358
|
});
|
|
41395
41359
|
const result = await runtime.resumeRun(runId);
|
|
41396
|
-
const
|
|
41397
|
-
await this.#
|
|
41360
|
+
const sessionId = result.run.sessionId;
|
|
41361
|
+
if (!await this.#sessions.get(sessionId)) await this.#sessions.create({ id: sessionId });
|
|
41362
|
+
await this.#finishRun(sessionId, result);
|
|
41398
41363
|
} catch (e) {
|
|
41399
41364
|
this.#emitError(e);
|
|
41400
41365
|
}
|
|
@@ -41557,33 +41522,30 @@ var ChatEngine = class {
|
|
|
41557
41522
|
const callId = data["callId"];
|
|
41558
41523
|
if (typeof name !== "string" || typeof callId !== "string") return;
|
|
41559
41524
|
const args = typeof data["args"] === "string" ? { args: data["args"] } : {};
|
|
41560
|
-
if (status === "started") {
|
|
41561
|
-
|
|
41562
|
-
|
|
41563
|
-
|
|
41564
|
-
|
|
41565
|
-
|
|
41566
|
-
|
|
41567
|
-
|
|
41568
|
-
|
|
41569
|
-
|
|
41570
|
-
|
|
41571
|
-
|
|
41572
|
-
|
|
41573
|
-
|
|
41574
|
-
...args
|
|
41575
|
-
});
|
|
41576
|
-
}
|
|
41525
|
+
if (status === "started") this.#emit({
|
|
41526
|
+
type: "tool-started",
|
|
41527
|
+
runId: event.runId,
|
|
41528
|
+
callId,
|
|
41529
|
+
name,
|
|
41530
|
+
...args
|
|
41531
|
+
});
|
|
41532
|
+
else if (status === "completed" || status === "failed") this.#emit({
|
|
41533
|
+
type: status === "completed" ? "tool-completed" : "tool-failed",
|
|
41534
|
+
runId: event.runId,
|
|
41535
|
+
callId,
|
|
41536
|
+
name,
|
|
41537
|
+
...args
|
|
41538
|
+
});
|
|
41577
41539
|
} else if (event.phase === "complete" || event.phase === "fail") this.#runSkills.delete(event.runId);
|
|
41578
41540
|
});
|
|
41579
41541
|
this.#runtime = runtime;
|
|
41580
41542
|
return runtime;
|
|
41581
41543
|
}
|
|
41582
|
-
/** run 终态公共路径(send / resume
|
|
41583
|
-
async #finishRun(
|
|
41544
|
+
/** run 终态公共路径(send / resume 共用):消息持久化 → trace 落盘 → 事件 */
|
|
41545
|
+
async #finishRun(sessionId, result) {
|
|
41584
41546
|
const run = result.run;
|
|
41585
41547
|
const status = run.status === "completed" || run.status === "cancelled" ? run.status : "failed";
|
|
41586
|
-
const toolCalls =
|
|
41548
|
+
const toolCalls = summarizeToolCalls(run);
|
|
41587
41549
|
const latest = this.bridge.latestResult;
|
|
41588
41550
|
const blocks = latest && latest.runId === run.id ? latest.blocks.filter((block) => block.type !== "markdown" || block.text.trim() !== result.output.trim()) : void 0;
|
|
41589
41551
|
const surfaces = this.bridge.surfaceSnapshots.filter((snapshot) => snapshot.runId === run.id);
|
|
@@ -41598,9 +41560,8 @@ var ChatEngine = class {
|
|
|
41598
41560
|
...surfaces.length > 0 ? { surfaces } : {},
|
|
41599
41561
|
...toolCalls.length > 0 ? { toolCalls } : {}
|
|
41600
41562
|
};
|
|
41601
|
-
|
|
41602
|
-
await this.#
|
|
41603
|
-
await writeRunTrace(this.#adapter.storage, this.#chatRoot, run);
|
|
41563
|
+
await this.#sessions.appendMessages(sessionId, [assistantMessage]);
|
|
41564
|
+
await this.#traceStore.put(run);
|
|
41604
41565
|
this.#emit({
|
|
41605
41566
|
type: "run-completed",
|
|
41606
41567
|
runId: run.id,
|
|
@@ -41613,67 +41574,6 @@ var ChatEngine = class {
|
|
|
41613
41574
|
message: assistantMessage
|
|
41614
41575
|
});
|
|
41615
41576
|
this.#runSkills.delete(run.id);
|
|
41616
|
-
this.#emittedToolEvents.delete(run.id);
|
|
41617
|
-
}
|
|
41618
|
-
/**
|
|
41619
|
-
* 工具事件去重标记:live(runtime.events)与 trace 重放共用。
|
|
41620
|
-
* 返回 true 表示该 (runId, callId, kind) 首次标记(应发出事件),false 表示已发过。
|
|
41621
|
-
*/
|
|
41622
|
-
#markToolEvent(runId, callId, kind) {
|
|
41623
|
-
let byCallId = this.#emittedToolEvents.get(runId);
|
|
41624
|
-
if (!byCallId) {
|
|
41625
|
-
byCallId = /* @__PURE__ */ new Map();
|
|
41626
|
-
this.#emittedToolEvents.set(runId, byCallId);
|
|
41627
|
-
}
|
|
41628
|
-
let kinds = byCallId.get(callId);
|
|
41629
|
-
if (!kinds) {
|
|
41630
|
-
kinds = /* @__PURE__ */ new Set();
|
|
41631
|
-
byCallId.set(callId, kinds);
|
|
41632
|
-
}
|
|
41633
|
-
if (kinds.has(kind)) return false;
|
|
41634
|
-
kinds.add(kind);
|
|
41635
|
-
return true;
|
|
41636
|
-
}
|
|
41637
|
-
/**
|
|
41638
|
-
* 工具事件 trace 重放(去重兜底):live 已发出的 (callId, kind) 不重复发;
|
|
41639
|
-
* 返回该 run 的工具调用终态序列(写入 assistant 消息,trace 为权威来源)。
|
|
41640
|
-
*/
|
|
41641
|
-
#replayToolEvents(run) {
|
|
41642
|
-
const toolCalls = [];
|
|
41643
|
-
for (const event of run.trace) {
|
|
41644
|
-
if (event.type !== "tool.started" && event.type !== "tool.completed" && event.type !== "tool.failed") continue;
|
|
41645
|
-
const name = event.data?.["name"];
|
|
41646
|
-
const callId = event.data?.["callId"];
|
|
41647
|
-
if (typeof name !== "string" || typeof callId !== "string") continue;
|
|
41648
|
-
const args = typeof event.data?.["args"] === "string" ? { args: event.data["args"] } : {};
|
|
41649
|
-
if (event.type === "tool.started") {
|
|
41650
|
-
if (this.#markToolEvent(run.id, callId, "started")) this.#emit({
|
|
41651
|
-
type: "tool-started",
|
|
41652
|
-
runId: run.id,
|
|
41653
|
-
callId,
|
|
41654
|
-
name,
|
|
41655
|
-
...args
|
|
41656
|
-
});
|
|
41657
|
-
} else {
|
|
41658
|
-
const status = event.type === "tool.completed" ? "completed" : "failed";
|
|
41659
|
-
const durationMs = typeof event.data?.["durationMs"] === "number" ? { durationMs: event.data["durationMs"] } : {};
|
|
41660
|
-
if (this.#markToolEvent(run.id, callId, status)) this.#emit({
|
|
41661
|
-
type: status === "completed" ? "tool-completed" : "tool-failed",
|
|
41662
|
-
runId: run.id,
|
|
41663
|
-
callId,
|
|
41664
|
-
name,
|
|
41665
|
-
...args
|
|
41666
|
-
});
|
|
41667
|
-
toolCalls.push({
|
|
41668
|
-
callId,
|
|
41669
|
-
name,
|
|
41670
|
-
status,
|
|
41671
|
-
...args,
|
|
41672
|
-
...durationMs
|
|
41673
|
-
});
|
|
41674
|
-
}
|
|
41675
|
-
}
|
|
41676
|
-
return toolCalls;
|
|
41677
41577
|
}
|
|
41678
41578
|
#snapshotStore() {
|
|
41679
41579
|
return new FsRunSnapshotStore({
|
|
@@ -41693,26 +41593,10 @@ var ChatEngine = class {
|
|
|
41693
41593
|
}
|
|
41694
41594
|
return handle;
|
|
41695
41595
|
}
|
|
41696
|
-
#
|
|
41697
|
-
|
|
41698
|
-
|
|
41699
|
-
|
|
41700
|
-
const path = this.#sessionPath(id);
|
|
41701
|
-
if (!await this.#adapter.storage.exists(path)) throw new WebSkillError("FS_NOT_FOUND", `Chat session "${id}" not found at ${path}`);
|
|
41702
|
-
return JSON.parse(await this.#adapter.storage.readText(path));
|
|
41703
|
-
}
|
|
41704
|
-
/** resume 用:会话文件被删除时用空会话兜底(恢复不因此失败) */
|
|
41705
|
-
async #readSessionOrNew(id) {
|
|
41706
|
-
const path = this.#sessionPath(id);
|
|
41707
|
-
if (await this.#adapter.storage.exists(path)) return JSON.parse(await this.#adapter.storage.readText(path));
|
|
41708
|
-
return {
|
|
41709
|
-
id,
|
|
41710
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
41711
|
-
messages: []
|
|
41712
|
-
};
|
|
41713
|
-
}
|
|
41714
|
-
async #writeSession(session) {
|
|
41715
|
-
await this.#adapter.storage.writeText(this.#sessionPath(session.id), JSON.stringify(session, null, 2));
|
|
41596
|
+
async #requireSession(id) {
|
|
41597
|
+
const session = await this.#sessions.get(id);
|
|
41598
|
+
if (!session) throw new WebSkillError("FS_NOT_FOUND", `Chat session "${id}" not found under ${this.#chatRoot}/sessions`);
|
|
41599
|
+
return session;
|
|
41716
41600
|
}
|
|
41717
41601
|
};
|
|
41718
41602
|
|
|
@@ -55160,4 +55044,4 @@ function Chatbot({ adapter, config, locale: localeProp, theme: themeProp, render
|
|
|
55160
55044
|
}
|
|
55161
55045
|
|
|
55162
55046
|
//#endregion
|
|
55163
|
-
export { A2uiSurfaceHost, A2uiSurfaceSnapshotHost, ChatEngine, Chatbot, CompositeUiBridge, ErrorCard, InteractionCard, InterruptedBanner, OpenUiChannel, OpenUiInteraction, OpenUiSurfaceHost, OpenUiSurfaceSnapshotHost, ResultBlockList, ResultBlocksPro, SettingsDrawer, SkillBadges, VercelPayloadPreview, VercelSurfaceHost, VercelSurfaceSnapshotHost, chatbotDictionary, configureA2uiMarkdown, probeA2uiAvailability, probeOpenUiAvailability, useT
|
|
55047
|
+
export { A2uiSurfaceHost, A2uiSurfaceSnapshotHost, ChatEngine, Chatbot, CompositeUiBridge, ErrorCard, InteractionCard, InterruptedBanner, OpenUiChannel, OpenUiInteraction, OpenUiSurfaceHost, OpenUiSurfaceSnapshotHost, ResultBlockList, ResultBlocksPro, SettingsDrawer, SkillBadges, VercelPayloadPreview, VercelSurfaceHost, VercelSurfaceSnapshotHost, chatbotDictionary, configureA2uiMarkdown, probeA2uiAvailability, probeOpenUiAvailability, useT };
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webskill/chatbot",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"license": "MIT",
|
|
4
5
|
"type": "module",
|
|
5
6
|
"exports": {
|
|
6
7
|
".": {
|
|
@@ -25,7 +26,7 @@
|
|
|
25
26
|
"@a2ui/web_core": "0.10.5",
|
|
26
27
|
"@lit/context": "^1.1.0",
|
|
27
28
|
"@openuidev/react-lang": "0.2.8",
|
|
28
|
-
"@webskill/sdk": "^0.
|
|
29
|
+
"@webskill/sdk": "^0.3.0",
|
|
29
30
|
"react": ">=19.0.0",
|
|
30
31
|
"react-dom": ">=19.0.0",
|
|
31
32
|
"zod": "^3.25.0 || ^4.0.0"
|