@huyooo/ai-chat-bridge-elysia 0.1.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/dist/index.cjs ADDED
@@ -0,0 +1,401 @@
1
+ 'use strict';
2
+
3
+ var elysia = require('elysia');
4
+ var aiChatCore = require('@huyooo/ai-chat-core');
5
+ var aiChatStorage = require('@huyooo/ai-chat-storage');
6
+
7
+ // src/index.ts
8
+ var ChatRequestSchema = elysia.t.Object({
9
+ message: elysia.t.String(),
10
+ sessionId: elysia.t.Optional(elysia.t.String()),
11
+ images: elysia.t.Optional(elysia.t.Array(elysia.t.String())),
12
+ options: elysia.t.Optional(elysia.t.Object({
13
+ mode: elysia.t.Optional(elysia.t.Union([
14
+ elysia.t.Literal("agent"),
15
+ elysia.t.Literal("plan"),
16
+ elysia.t.Literal("ask")
17
+ ])),
18
+ model: elysia.t.Optional(elysia.t.String()),
19
+ provider: elysia.t.Optional(elysia.t.Union([
20
+ elysia.t.Literal("doubao"),
21
+ elysia.t.Literal("deepseek")
22
+ ])),
23
+ enableWebSearch: elysia.t.Optional(elysia.t.Boolean()),
24
+ enableDeepThinking: elysia.t.Optional(elysia.t.Boolean()),
25
+ thinkingBudget: elysia.t.Optional(elysia.t.Number())
26
+ }))
27
+ });
28
+ var SessionCreateSchema = elysia.t.Object({
29
+ title: elysia.t.Optional(elysia.t.String()),
30
+ model: elysia.t.Optional(elysia.t.String()),
31
+ mode: elysia.t.Optional(elysia.t.Union([
32
+ elysia.t.Literal("agent"),
33
+ elysia.t.Literal("plan"),
34
+ elysia.t.Literal("ask")
35
+ ]))
36
+ });
37
+ var SessionUpdateSchema = elysia.t.Object({
38
+ title: elysia.t.Optional(elysia.t.String()),
39
+ model: elysia.t.Optional(elysia.t.String()),
40
+ mode: elysia.t.Optional(elysia.t.Union([
41
+ elysia.t.Literal("agent"),
42
+ elysia.t.Literal("plan"),
43
+ elysia.t.Literal("ask")
44
+ ]))
45
+ });
46
+ var MessageSaveSchema = elysia.t.Object({
47
+ sessionId: elysia.t.String(),
48
+ role: elysia.t.Union([elysia.t.Literal("user"), elysia.t.Literal("assistant")]),
49
+ content: elysia.t.String(),
50
+ thinking: elysia.t.Optional(elysia.t.String()),
51
+ toolCalls: elysia.t.Optional(elysia.t.String()),
52
+ searchResults: elysia.t.Optional(elysia.t.String()),
53
+ operationIds: elysia.t.Optional(elysia.t.String())
54
+ });
55
+ function extractContext(headers) {
56
+ return {
57
+ appId: headers["x-app-id"] || void 0,
58
+ userId: headers["x-user-id"] || void 0
59
+ };
60
+ }
61
+ async function createElysiaBridge(options) {
62
+ const { prefix = "/api/chat", storage: storageConfig, ...agentConfig } = options;
63
+ const agent = new aiChatCore.HybridAgent(agentConfig);
64
+ const storage = await aiChatStorage.createStorage(storageConfig || {
65
+ type: "sqlite",
66
+ sqlitePath: "./data/db.sqlite"
67
+ });
68
+ return new elysia.Elysia({ prefix }).get("/models", () => ({
69
+ models: aiChatCore.AVAILABLE_MODELS
70
+ })).get("/stream", async function* ({ query, headers }) {
71
+ const message = query.message;
72
+ const images = query.images?.split(",").filter(Boolean);
73
+ const chatOptions = {};
74
+ if (query.mode) chatOptions.mode = query.mode;
75
+ if (query.model) chatOptions.model = query.model;
76
+ if (query.provider) chatOptions.provider = query.provider;
77
+ if (query.enableWebSearch !== void 0) {
78
+ chatOptions.enableWebSearch = query.enableWebSearch === "true";
79
+ }
80
+ if (query.thinkingMode) {
81
+ chatOptions.thinkingMode = query.thinkingMode;
82
+ }
83
+ if (query.thinkingBudget) {
84
+ chatOptions.thinkingBudget = parseInt(query.thinkingBudget);
85
+ }
86
+ for await (const progress of agent.chat(message, chatOptions, images)) {
87
+ yield `data: ${JSON.stringify(progress)}
88
+
89
+ `;
90
+ }
91
+ }, {
92
+ query: elysia.t.Object({
93
+ message: elysia.t.String(),
94
+ images: elysia.t.Optional(elysia.t.String()),
95
+ mode: elysia.t.Optional(elysia.t.String()),
96
+ model: elysia.t.Optional(elysia.t.String()),
97
+ provider: elysia.t.Optional(elysia.t.String()),
98
+ enableWebSearch: elysia.t.Optional(elysia.t.String()),
99
+ thinkingMode: elysia.t.Optional(elysia.t.String()),
100
+ thinkingBudget: elysia.t.Optional(elysia.t.String())
101
+ })
102
+ }).ws("/ws", {
103
+ body: elysia.t.Object({
104
+ type: elysia.t.Union([
105
+ elysia.t.Literal("chat"),
106
+ elysia.t.Literal("abort")
107
+ ]),
108
+ message: elysia.t.Optional(elysia.t.String()),
109
+ images: elysia.t.Optional(elysia.t.Array(elysia.t.String())),
110
+ options: elysia.t.Optional(elysia.t.Object({
111
+ mode: elysia.t.Optional(elysia.t.String()),
112
+ model: elysia.t.Optional(elysia.t.String()),
113
+ provider: elysia.t.Optional(elysia.t.String()),
114
+ enableWebSearch: elysia.t.Optional(elysia.t.Boolean()),
115
+ thinkingMode: elysia.t.Optional(elysia.t.String()),
116
+ thinkingBudget: elysia.t.Optional(elysia.t.Number())
117
+ }))
118
+ }),
119
+ async message(ws, data) {
120
+ if (data.type === "abort") {
121
+ agent.abort();
122
+ ws.send({ type: "aborted", data: "\u8BF7\u6C42\u5DF2\u53D6\u6D88" });
123
+ return;
124
+ }
125
+ if (data.type === "chat" && data.message) {
126
+ const chatOptions = {
127
+ mode: data.options?.mode,
128
+ model: data.options?.model,
129
+ provider: data.options?.provider,
130
+ enableWebSearch: data.options?.enableWebSearch,
131
+ thinkingMode: data.options?.thinkingMode,
132
+ thinkingBudget: data.options?.thinkingBudget
133
+ };
134
+ for await (const progress of agent.chat(
135
+ data.message,
136
+ chatOptions,
137
+ data.images
138
+ )) {
139
+ ws.send(progress);
140
+ }
141
+ }
142
+ }
143
+ }).post("/send", async ({ body }) => {
144
+ const results = [];
145
+ const chatOptions = body.options || {};
146
+ for await (const progress of agent.chat(
147
+ body.message,
148
+ chatOptions,
149
+ body.images
150
+ )) {
151
+ results.push(progress);
152
+ }
153
+ return {
154
+ success: true,
155
+ results
156
+ };
157
+ }, {
158
+ body: ChatRequestSchema
159
+ }).post("/abort", () => {
160
+ agent.abort();
161
+ return { success: true, message: "\u4E2D\u65AD\u4FE1\u53F7\u5DF2\u53D1\u9001" };
162
+ }).post("/clear-agent", () => {
163
+ agent.clearHistory();
164
+ return { success: true };
165
+ }).get("/agent-history", () => ({
166
+ history: agent.getHistory()
167
+ })).post("/working-dir", ({ body }) => {
168
+ agent.setWorkingDir(body.dir);
169
+ return { success: true };
170
+ }, {
171
+ body: elysia.t.Object({
172
+ dir: elysia.t.String()
173
+ })
174
+ }).get("/config", () => ({
175
+ config: agent.getConfig()
176
+ })).get("/sessions", async ({ headers }) => {
177
+ const ctx = extractContext(headers);
178
+ const sessions = await storage.getSessions(ctx);
179
+ return { sessions };
180
+ }).get("/sessions/:id", async ({ params, headers }) => {
181
+ const ctx = extractContext(headers);
182
+ const session = await storage.getSession(params.id, ctx);
183
+ if (!session) {
184
+ return { error: "\u4F1A\u8BDD\u4E0D\u5B58\u5728" };
185
+ }
186
+ return { session };
187
+ }).post("/sessions", async ({ body, headers }) => {
188
+ const ctx = extractContext(headers);
189
+ const input = {
190
+ id: crypto.randomUUID(),
191
+ title: body.title || "\u65B0\u5BF9\u8BDD",
192
+ model: body.model || "doubao-seed-1-6-251015",
193
+ mode: body.mode || "agent"
194
+ };
195
+ const session = await storage.createSession(input, ctx);
196
+ return { session };
197
+ }, {
198
+ body: SessionCreateSchema
199
+ }).patch("/sessions/:id", async ({ params, body, headers }) => {
200
+ const ctx = extractContext(headers);
201
+ await storage.updateSession(params.id, body, ctx);
202
+ const session = await storage.getSession(params.id, ctx);
203
+ return { session };
204
+ }, {
205
+ body: SessionUpdateSchema
206
+ }).delete("/sessions/:id", async ({ params, headers }) => {
207
+ const ctx = extractContext(headers);
208
+ await storage.deleteSession(params.id, ctx);
209
+ return { success: true };
210
+ }).get("/sessions/:id/messages", async ({ params, headers }) => {
211
+ const ctx = extractContext(headers);
212
+ const messages = await storage.getMessages(params.id, ctx);
213
+ return { messages };
214
+ }).post("/messages", async ({ body, headers }) => {
215
+ const ctx = extractContext(headers);
216
+ const input = {
217
+ id: crypto.randomUUID(),
218
+ sessionId: body.sessionId,
219
+ role: body.role,
220
+ content: body.content,
221
+ thinking: body.thinking || null,
222
+ toolCalls: body.toolCalls || null,
223
+ searchResults: body.searchResults || null,
224
+ operationIds: body.operationIds || null
225
+ };
226
+ const message = await storage.saveMessage(input, ctx);
227
+ return { message };
228
+ }, {
229
+ body: MessageSaveSchema
230
+ }).delete("/sessions/:id/messages", async ({ params, query, headers }) => {
231
+ const ctx = extractContext(headers);
232
+ const timestamp = query.afterTimestamp ? parseInt(query.afterTimestamp) : 0;
233
+ if (timestamp) {
234
+ await storage.deleteMessagesAfter(params.id, new Date(timestamp), ctx);
235
+ }
236
+ return { success: true };
237
+ }, {
238
+ query: elysia.t.Object({
239
+ afterTimestamp: elysia.t.Optional(elysia.t.String())
240
+ })
241
+ }).get("/sessions/:id/operations", async ({ params, headers }) => {
242
+ const ctx = extractContext(headers);
243
+ const operations = await storage.getOperations(params.id, ctx);
244
+ return { operations };
245
+ }).get("/trash", async ({ headers }) => {
246
+ const ctx = extractContext(headers);
247
+ const items = await storage.getTrashItems?.(ctx) || [];
248
+ return { items };
249
+ }).post("/trash/:id/restore", async ({ params, headers }) => {
250
+ const ctx = extractContext(headers);
251
+ const item = await storage.restoreFromTrash?.(params.id, ctx);
252
+ return { item };
253
+ }).get("/health", () => ({ status: "ok" }));
254
+ }
255
+ function createWebAdapter(baseUrl) {
256
+ let abortController = null;
257
+ function getHeaders(ctx) {
258
+ const headers = {
259
+ "Content-Type": "application/json"
260
+ };
261
+ if (ctx?.appId) headers["X-App-Id"] = ctx.appId;
262
+ if (ctx?.userId) headers["X-User-Id"] = ctx.userId;
263
+ return headers;
264
+ }
265
+ return {
266
+ /** 获取可用模型 */
267
+ async getModels() {
268
+ const response = await fetch(`${baseUrl}/models`);
269
+ return response.json();
270
+ },
271
+ /** 发送消息(流式) */
272
+ async *sendMessage(message, options, images) {
273
+ abortController = new AbortController();
274
+ const url = new URL(`${baseUrl}/stream`);
275
+ url.searchParams.set("message", message);
276
+ if (images?.length) url.searchParams.set("images", images.join(","));
277
+ if (options?.mode) url.searchParams.set("mode", options.mode);
278
+ if (options?.model) url.searchParams.set("model", options.model);
279
+ if (options?.provider) url.searchParams.set("provider", options.provider);
280
+ if (options?.enableWebSearch !== void 0) {
281
+ url.searchParams.set("enableWebSearch", String(options.enableWebSearch));
282
+ }
283
+ if (options?.thinkingMode !== void 0) {
284
+ url.searchParams.set("thinkingMode", options.thinkingMode);
285
+ }
286
+ if (options?.thinkingBudget !== void 0) {
287
+ url.searchParams.set("thinkingBudget", String(options.thinkingBudget));
288
+ }
289
+ const response = await fetch(url.toString(), {
290
+ signal: abortController.signal
291
+ });
292
+ if (!response.ok) {
293
+ throw new Error(`HTTP error: ${response.status}`);
294
+ }
295
+ const reader = response.body.getReader();
296
+ const decoder = new TextDecoder();
297
+ let buffer = "";
298
+ while (true) {
299
+ const { done, value } = await reader.read();
300
+ if (done) break;
301
+ buffer += decoder.decode(value, { stream: true });
302
+ const lines = buffer.split("\n\n");
303
+ buffer = lines.pop() || "";
304
+ for (const line of lines) {
305
+ if (line.startsWith("data: ")) {
306
+ const progress = JSON.parse(line.slice(6));
307
+ yield progress;
308
+ }
309
+ }
310
+ }
311
+ },
312
+ /** 中断当前请求 */
313
+ async cancel() {
314
+ abortController?.abort();
315
+ await fetch(`${baseUrl}/abort`, { method: "POST" });
316
+ },
317
+ /** 清空 Agent 对话历史 */
318
+ async clearAgentHistory() {
319
+ await fetch(`${baseUrl}/clear-agent`, { method: "POST" });
320
+ },
321
+ /** 获取 Agent 对话历史 */
322
+ async getAgentHistory() {
323
+ const response = await fetch(`${baseUrl}/agent-history`);
324
+ return response.json();
325
+ },
326
+ /** 设置工作目录 */
327
+ async setWorkingDir(dir) {
328
+ await fetch(`${baseUrl}/working-dir`, {
329
+ method: "POST",
330
+ headers: { "Content-Type": "application/json" },
331
+ body: JSON.stringify({ dir })
332
+ });
333
+ },
334
+ // ============ Sessions ============
335
+ /** 获取会话列表 */
336
+ async getSessions(ctx) {
337
+ const response = await fetch(`${baseUrl}/sessions`, {
338
+ headers: getHeaders(ctx)
339
+ });
340
+ return response.json();
341
+ },
342
+ /** 获取单个会话 */
343
+ async getSession(id, ctx) {
344
+ const response = await fetch(`${baseUrl}/sessions/${id}`, {
345
+ headers: getHeaders(ctx)
346
+ });
347
+ return response.json();
348
+ },
349
+ /** 创建会话 */
350
+ async createSession(data, ctx) {
351
+ const response = await fetch(`${baseUrl}/sessions`, {
352
+ method: "POST",
353
+ headers: getHeaders(ctx),
354
+ body: JSON.stringify(data)
355
+ });
356
+ return response.json();
357
+ },
358
+ /** 更新会话 */
359
+ async updateSession(id, data, ctx) {
360
+ const response = await fetch(`${baseUrl}/sessions/${id}`, {
361
+ method: "PATCH",
362
+ headers: getHeaders(ctx),
363
+ body: JSON.stringify(data)
364
+ });
365
+ return response.json();
366
+ },
367
+ /** 删除会话 */
368
+ async deleteSession(id, ctx) {
369
+ await fetch(`${baseUrl}/sessions/${id}`, {
370
+ method: "DELETE",
371
+ headers: getHeaders(ctx)
372
+ });
373
+ },
374
+ // ============ Messages ============
375
+ /** 获取会话消息 */
376
+ async getMessages(sessionId, ctx) {
377
+ const response = await fetch(`${baseUrl}/sessions/${sessionId}/messages`, {
378
+ headers: getHeaders(ctx)
379
+ });
380
+ return response.json();
381
+ },
382
+ /** 保存消息 */
383
+ async saveMessage(data, ctx) {
384
+ const response = await fetch(`${baseUrl}/messages`, {
385
+ method: "POST",
386
+ headers: getHeaders(ctx),
387
+ body: JSON.stringify(data)
388
+ });
389
+ return response.json();
390
+ }
391
+ };
392
+ }
393
+
394
+ Object.defineProperty(exports, "AVAILABLE_MODELS", {
395
+ enumerable: true,
396
+ get: function () { return aiChatCore.AVAILABLE_MODELS; }
397
+ });
398
+ exports.createElysiaBridge = createElysiaBridge;
399
+ exports.createWebAdapter = createWebAdapter;
400
+ //# sourceMappingURL=index.cjs.map
401
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":["t","HybridAgent","createStorage","Elysia","AVAILABLE_MODELS"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @huyooo/ai-chat-bridge-elysia\n * \n * Elysia.js 桥接 - HTTP/WebSocket/SSE API\n * 集成 PostgreSQL 存储(支持多租户)\n * \n * 支持功能:\n * - 多模型切换 (豆包/DeepSeek)\n * - 对话模式切换 (agent/plan/ask)\n * - 联网搜索\n * - 深度思考\n * - 请求中断\n * - 会话/消息持久化存储\n */\n\nimport { Elysia, t } from 'elysia';\nimport { \n HybridAgent, \n type AgentConfig, \n type ChatProgress, \n type ChatOptions,\n type ChatMode,\n type ModelProvider,\n type ThinkingMode,\n AVAILABLE_MODELS\n} from '@huyooo/ai-chat-core';\nimport {\n createStorage,\n type StorageAdapter,\n type StorageContext,\n type StorageConfig,\n type SessionRecord,\n type MessageRecord,\n type CreateSessionInput,\n type CreateMessageInput,\n} from '@huyooo/ai-chat-storage';\n\nexport interface ElysiaBridgeOptions extends AgentConfig {\n /** API 路由前缀 */\n prefix?: string;\n /** 存储配置 */\n storage?: StorageConfig;\n}\n\n/** 聊天请求参数 */\nconst ChatRequestSchema = t.Object({\n message: t.String(),\n sessionId: t.Optional(t.String()),\n images: t.Optional(t.Array(t.String())),\n options: t.Optional(t.Object({\n mode: t.Optional(t.Union([\n t.Literal('agent'),\n t.Literal('plan'),\n t.Literal('ask')\n ])),\n model: t.Optional(t.String()),\n provider: t.Optional(t.Union([\n t.Literal('doubao'),\n t.Literal('deepseek')\n ])),\n enableWebSearch: t.Optional(t.Boolean()),\n enableDeepThinking: t.Optional(t.Boolean()),\n thinkingBudget: t.Optional(t.Number())\n }))\n});\n\n/** 会话创建参数 */\nconst SessionCreateSchema = t.Object({\n title: t.Optional(t.String()),\n model: t.Optional(t.String()),\n mode: t.Optional(t.Union([\n t.Literal('agent'),\n t.Literal('plan'),\n t.Literal('ask')\n ])),\n});\n\n/** 会话更新参数 */\nconst SessionUpdateSchema = t.Object({\n title: t.Optional(t.String()),\n model: t.Optional(t.String()),\n mode: t.Optional(t.Union([\n t.Literal('agent'),\n t.Literal('plan'),\n t.Literal('ask')\n ])),\n});\n\n/** 消息保存参数 */\nconst MessageSaveSchema = t.Object({\n sessionId: t.String(),\n role: t.Union([t.Literal('user'), t.Literal('assistant')]),\n content: t.String(),\n thinking: t.Optional(t.String()),\n toolCalls: t.Optional(t.String()),\n searchResults: t.Optional(t.String()),\n operationIds: t.Optional(t.String()),\n});\n\n/**\n * 从请求头提取租户上下文\n */\nfunction extractContext(headers: Record<string, string | undefined>): StorageContext {\n return {\n appId: headers['x-app-id'] || undefined,\n userId: headers['x-user-id'] || undefined,\n };\n}\n\n/**\n * 创建 Elysia AI Chat 插件\n * \n * @example\n * ```ts\n * import { Elysia } from 'elysia';\n * import { createElysiaBridge } from '@huyooo/ai-chat-bridge-elysia';\n * \n * new Elysia()\n * .use(await createElysiaBridge({\n * arkApiKey: 'xxx',\n * geminiApiKey: 'xxx',\n * storage: {\n * type: 'postgres',\n * postgresUrl: 'postgres://...',\n * }\n * }))\n * .listen(3000);\n * ```\n */\nexport async function createElysiaBridge(options: ElysiaBridgeOptions) {\n const { prefix = '/api/chat', storage: storageConfig, ...agentConfig } = options;\n const agent = new HybridAgent(agentConfig);\n \n // 初始化存储(默认使用 SQLite)\n const storage = await createStorage(storageConfig || {\n type: 'sqlite',\n sqlitePath: './data/db.sqlite',\n });\n\n return new Elysia({ prefix })\n // ============ 模型 API ============\n \n // 获取可用模型列表\n .get('/models', () => ({\n models: AVAILABLE_MODELS\n }))\n\n // ============ Chat API ============\n\n // SSE 流式响应\n .get('/stream', async function* ({ query, headers }) {\n const message = query.message;\n const images = query.images?.split(',').filter(Boolean);\n const chatOptions: ChatOptions = {};\n \n if (query.mode) chatOptions.mode = query.mode as ChatMode;\n if (query.model) chatOptions.model = query.model;\n if (query.provider) chatOptions.provider = query.provider as ModelProvider;\n if (query.enableWebSearch !== undefined) {\n chatOptions.enableWebSearch = query.enableWebSearch === 'true';\n }\n if (query.thinkingMode) {\n chatOptions.thinkingMode = query.thinkingMode as ThinkingMode;\n }\n if (query.thinkingBudget) {\n chatOptions.thinkingBudget = parseInt(query.thinkingBudget);\n }\n\n for await (const progress of agent.chat(message, chatOptions, images)) {\n yield `data: ${JSON.stringify(progress)}\\n\\n`;\n }\n }, {\n query: t.Object({\n message: t.String(),\n images: t.Optional(t.String()),\n mode: t.Optional(t.String()),\n model: t.Optional(t.String()),\n provider: t.Optional(t.String()),\n enableWebSearch: t.Optional(t.String()),\n thinkingMode: t.Optional(t.String()),\n thinkingBudget: t.Optional(t.String()),\n }),\n })\n\n // WebSocket 流式响应\n .ws('/ws', {\n body: t.Object({\n type: t.Union([\n t.Literal('chat'),\n t.Literal('abort')\n ]),\n message: t.Optional(t.String()),\n images: t.Optional(t.Array(t.String())),\n options: t.Optional(t.Object({\n mode: t.Optional(t.String()),\n model: t.Optional(t.String()),\n provider: t.Optional(t.String()),\n enableWebSearch: t.Optional(t.Boolean()),\n thinkingMode: t.Optional(t.String()),\n thinkingBudget: t.Optional(t.Number())\n }))\n }),\n async message(ws, data) {\n if (data.type === 'abort') {\n agent.abort();\n ws.send({ type: 'aborted', data: '请求已取消' });\n return;\n }\n \n if (data.type === 'chat' && data.message) {\n const chatOptions: ChatOptions = {\n mode: data.options?.mode as ChatMode | undefined,\n model: data.options?.model,\n provider: data.options?.provider as ModelProvider | undefined,\n enableWebSearch: data.options?.enableWebSearch,\n thinkingMode: data.options?.thinkingMode as ThinkingMode | undefined,\n thinkingBudget: data.options?.thinkingBudget\n };\n \n for await (const progress of agent.chat(\n data.message, \n chatOptions,\n data.images\n )) {\n ws.send(progress);\n }\n }\n },\n })\n\n // REST API(非流式)\n .post('/send', async ({ body }) => {\n const results: ChatProgress[] = [];\n const chatOptions: ChatOptions = body.options || {};\n \n for await (const progress of agent.chat(\n body.message, \n chatOptions,\n body.images\n )) {\n results.push(progress);\n }\n\n return {\n success: true,\n results,\n };\n }, {\n body: ChatRequestSchema,\n })\n\n // 中断当前请求\n .post('/abort', () => {\n agent.abort();\n return { success: true, message: '中断信号已发送' };\n })\n\n // 清空 Agent 对话历史\n .post('/clear-agent', () => {\n agent.clearHistory();\n return { success: true };\n })\n\n // 获取 Agent 对话历史\n .get('/agent-history', () => ({\n history: agent.getHistory()\n }))\n\n // 设置工作目录\n .post('/working-dir', ({ body }) => {\n agent.setWorkingDir(body.dir);\n return { success: true };\n }, {\n body: t.Object({\n dir: t.String(),\n }),\n })\n\n // 获取当前配置\n .get('/config', () => ({\n config: agent.getConfig()\n }))\n\n // ============ Sessions API ============\n\n // 获取会话列表\n .get('/sessions', async ({ headers }) => {\n const ctx = extractContext(headers as Record<string, string | undefined>);\n const sessions = await storage.getSessions(ctx);\n return { sessions };\n })\n\n // 获取单个会话\n .get('/sessions/:id', async ({ params, headers }) => {\n const ctx = extractContext(headers as Record<string, string | undefined>);\n const session = await storage.getSession(params.id, ctx);\n if (!session) {\n return { error: '会话不存在' };\n }\n return { session };\n })\n\n // 创建会话\n .post('/sessions', async ({ body, headers }) => {\n const ctx = extractContext(headers as Record<string, string | undefined>);\n const input: CreateSessionInput = {\n id: crypto.randomUUID(),\n title: body.title || '新对话',\n model: body.model || 'doubao-seed-1-6-251015',\n mode: body.mode || 'agent',\n };\n const session = await storage.createSession(input, ctx);\n return { session };\n }, {\n body: SessionCreateSchema,\n })\n\n // 更新会话\n .patch('/sessions/:id', async ({ params, body, headers }) => {\n const ctx = extractContext(headers as Record<string, string | undefined>);\n await storage.updateSession(params.id, body, ctx);\n const session = await storage.getSession(params.id, ctx);\n return { session };\n }, {\n body: SessionUpdateSchema,\n })\n\n // 删除会话\n .delete('/sessions/:id', async ({ params, headers }) => {\n const ctx = extractContext(headers as Record<string, string | undefined>);\n await storage.deleteSession(params.id, ctx);\n return { success: true };\n })\n\n // ============ Messages API ============\n\n // 获取会话消息\n .get('/sessions/:id/messages', async ({ params, headers }) => {\n const ctx = extractContext(headers as Record<string, string | undefined>);\n const messages = await storage.getMessages(params.id, ctx);\n return { messages };\n })\n\n // 保存消息\n .post('/messages', async ({ body, headers }) => {\n const ctx = extractContext(headers as Record<string, string | undefined>);\n const input: CreateMessageInput = {\n id: crypto.randomUUID(),\n sessionId: body.sessionId,\n role: body.role,\n content: body.content,\n thinking: body.thinking || null,\n toolCalls: body.toolCalls || null,\n searchResults: body.searchResults || null,\n operationIds: body.operationIds || null,\n };\n const message = await storage.saveMessage(input, ctx);\n return { message };\n }, {\n body: MessageSaveSchema,\n })\n\n // 删除指定时间之后的消息(用于分叉)\n .delete('/sessions/:id/messages', async ({ params, query, headers }) => {\n const ctx = extractContext(headers as Record<string, string | undefined>);\n const timestamp = query.afterTimestamp ? parseInt(query.afterTimestamp) : 0;\n if (timestamp) {\n await storage.deleteMessagesAfter(params.id, new Date(timestamp), ctx);\n }\n return { success: true };\n }, {\n query: t.Object({\n afterTimestamp: t.Optional(t.String()),\n }),\n })\n\n // ============ Operations API ============\n\n // 获取会话操作日志\n .get('/sessions/:id/operations', async ({ params, headers }) => {\n const ctx = extractContext(headers as Record<string, string | undefined>);\n const operations = await storage.getOperations(params.id, ctx);\n return { operations };\n })\n\n // ============ Trash API ============\n\n // 获取回收站\n .get('/trash', async ({ headers }) => {\n const ctx = extractContext(headers as Record<string, string | undefined>);\n const items = await storage.getTrashItems?.(ctx) || [];\n return { items };\n })\n\n // 恢复回收站项目\n .post('/trash/:id/restore', async ({ params, headers }) => {\n const ctx = extractContext(headers as Record<string, string | undefined>);\n const item = await storage.restoreFromTrash?.(params.id, ctx);\n return { item };\n })\n\n // 健康检查\n .get('/health', () => ({ status: 'ok' }));\n}\n\n/**\n * 创建 Web Adapter(前端使用)\n */\nexport function createWebAdapter(baseUrl: string) {\n let abortController: AbortController | null = null;\n\n /** 通用请求头 */\n function getHeaders(ctx?: StorageContext): Record<string, string> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n if (ctx?.appId) headers['X-App-Id'] = ctx.appId;\n if (ctx?.userId) headers['X-User-Id'] = ctx.userId;\n return headers;\n }\n\n return {\n /** 获取可用模型 */\n async getModels() {\n const response = await fetch(`${baseUrl}/models`);\n return response.json();\n },\n\n /** 发送消息(流式) */\n async *sendMessage(\n message: string, \n options?: ChatOptions,\n images?: string[]\n ): AsyncGenerator<ChatProgress> {\n abortController = new AbortController();\n\n const url = new URL(`${baseUrl}/stream`);\n url.searchParams.set('message', message);\n \n if (images?.length) url.searchParams.set('images', images.join(','));\n if (options?.mode) url.searchParams.set('mode', options.mode);\n if (options?.model) url.searchParams.set('model', options.model);\n if (options?.provider) url.searchParams.set('provider', options.provider);\n if (options?.enableWebSearch !== undefined) {\n url.searchParams.set('enableWebSearch', String(options.enableWebSearch));\n }\n if (options?.thinkingMode !== undefined) {\n url.searchParams.set('thinkingMode', options.thinkingMode);\n }\n if (options?.thinkingBudget !== undefined) {\n url.searchParams.set('thinkingBudget', String(options.thinkingBudget));\n }\n\n const response = await fetch(url.toString(), {\n signal: abortController.signal,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP error: ${response.status}`);\n }\n\n const reader = response.body!.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const progress = JSON.parse(line.slice(6)) as ChatProgress;\n yield progress;\n }\n }\n }\n },\n\n /** 中断当前请求 */\n async cancel() {\n abortController?.abort();\n await fetch(`${baseUrl}/abort`, { method: 'POST' });\n },\n\n /** 清空 Agent 对话历史 */\n async clearAgentHistory() {\n await fetch(`${baseUrl}/clear-agent`, { method: 'POST' });\n },\n\n /** 获取 Agent 对话历史 */\n async getAgentHistory() {\n const response = await fetch(`${baseUrl}/agent-history`);\n return response.json();\n },\n\n /** 设置工作目录 */\n async setWorkingDir(dir: string) {\n await fetch(`${baseUrl}/working-dir`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ dir }),\n });\n },\n\n // ============ Sessions ============\n\n /** 获取会话列表 */\n async getSessions(ctx?: StorageContext) {\n const response = await fetch(`${baseUrl}/sessions`, {\n headers: getHeaders(ctx),\n });\n return response.json();\n },\n\n /** 获取单个会话 */\n async getSession(id: string, ctx?: StorageContext) {\n const response = await fetch(`${baseUrl}/sessions/${id}`, {\n headers: getHeaders(ctx),\n });\n return response.json();\n },\n\n /** 创建会话 */\n async createSession(data: { title?: string; model?: string; mode?: string }, ctx?: StorageContext) {\n const response = await fetch(`${baseUrl}/sessions`, {\n method: 'POST',\n headers: getHeaders(ctx),\n body: JSON.stringify(data),\n });\n return response.json();\n },\n\n /** 更新会话 */\n async updateSession(id: string, data: { title?: string; model?: string; mode?: string }, ctx?: StorageContext) {\n const response = await fetch(`${baseUrl}/sessions/${id}`, {\n method: 'PATCH',\n headers: getHeaders(ctx),\n body: JSON.stringify(data),\n });\n return response.json();\n },\n\n /** 删除会话 */\n async deleteSession(id: string, ctx?: StorageContext) {\n await fetch(`${baseUrl}/sessions/${id}`, {\n method: 'DELETE',\n headers: getHeaders(ctx),\n });\n },\n\n // ============ Messages ============\n\n /** 获取会话消息 */\n async getMessages(sessionId: string, ctx?: StorageContext) {\n const response = await fetch(`${baseUrl}/sessions/${sessionId}/messages`, {\n headers: getHeaders(ctx),\n });\n return response.json();\n },\n\n /** 保存消息 */\n async saveMessage(data: {\n sessionId: string;\n role: 'user' | 'assistant';\n content: string;\n thinking?: string;\n toolCalls?: string;\n searchResults?: string;\n }, ctx?: StorageContext) {\n const response = await fetch(`${baseUrl}/messages`, {\n method: 'POST',\n headers: getHeaders(ctx),\n body: JSON.stringify(data),\n });\n return response.json();\n },\n };\n}\n\n// 导出类型\nexport type { \n AgentConfig, \n ChatProgress, \n ChatOptions,\n ChatMode,\n ModelProvider,\n StorageAdapter,\n StorageContext,\n SessionRecord,\n MessageRecord,\n};\n\nexport { AVAILABLE_MODELS };\n"]}