mu-agent-bridge 1.0.34 → 1.0.39

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.
Files changed (89) hide show
  1. package/README.md +4 -2
  2. package/dist/src-ts/channel-sessions.js +90 -24
  3. package/dist/src-ts/control-server.js +48 -7
  4. package/dist/src-ts/dsh-agent.js +141 -46
  5. package/dist/src-ts/headless-account.patch.yml +8 -1
  6. package/dist/src-ts/plugin-manager.js +69 -3
  7. package/dist/src-ts/plugins/aun/attachments.js +44 -13
  8. package/dist/src-ts/plugins/aun/index.js +5 -6
  9. package/dist/src-ts/plugins/chatgpt/cdp-client.js +342 -9
  10. package/dist/src-ts/plugins/chatgpt/index.js +127 -7
  11. package/dist/src-ts/plugins/desktop-launch.js +19 -0
  12. package/dist/src-ts/plugins/doubao/attachments.js +42 -0
  13. package/dist/src-ts/plugins/doubao/cdp-client.js +530 -48
  14. package/dist/src-ts/plugins/doubao/index.js +114 -25
  15. package/dist/src-ts/plugins/doubao/session-history.js +123 -0
  16. package/dist/src-ts/plugins/dsh/index.js +18 -2
  17. package/dist/src-ts/plugins/dsh/session-history.js +371 -0
  18. package/dist/src-ts/plugins/qwenwork/cdp-client.js +271 -10
  19. package/dist/src-ts/plugins/qwenwork/index.js +42 -3
  20. package/dist/src-ts/plugins/qwenwork/session-history.js +245 -0
  21. package/dist/src-ts/plugins/workbuddy/cdp-client.js +42 -2
  22. package/dist/src-ts/plugins/workbuddy/index.js +23 -3
  23. package/dist/src-ts/plugins/workbuddy/session-history.js +121 -0
  24. package/dist/src-ts/session-archive.js +509 -0
  25. package/dist/src-ts/session-history.js +2 -0
  26. package/dist/src-ts/session-management.js +665 -0
  27. package/dist/src-ts/session-summary.js +171 -0
  28. package/dist/tests-ts/aun-attachments.test.js +41 -3
  29. package/dist/tests-ts/aun-plugin.test.js +28 -5
  30. package/dist/tests-ts/bundled-package.test.js +3 -1
  31. package/dist/tests-ts/channel-sessions.test.js +255 -2
  32. package/dist/tests-ts/chatgpt-history.test.js +197 -0
  33. package/dist/tests-ts/chatgpt-plugin.test.js +279 -2
  34. package/dist/tests-ts/control-server.test.js +39 -0
  35. package/dist/tests-ts/desktop-launch.test.js +41 -0
  36. package/dist/tests-ts/doubao-history.test.js +172 -0
  37. package/dist/tests-ts/doubao-plugin.test.js +549 -2
  38. package/dist/tests-ts/dsh-agent.test.js +199 -0
  39. package/dist/tests-ts/dsh-history.test.js +165 -0
  40. package/dist/tests-ts/native-session-management.test.js +195 -0
  41. package/dist/tests-ts/plugin-manager.test.js +354 -4
  42. package/dist/tests-ts/qwenwork-history.test.js +339 -0
  43. package/dist/tests-ts/qwenwork-images.test.js +166 -0
  44. package/dist/tests-ts/qwenwork-plugin.test.js +40 -1
  45. package/dist/tests-ts/session-archive.test.js +422 -0
  46. package/dist/tests-ts/session-management.test.js +323 -0
  47. package/dist/tests-ts/session-summary.test.js +199 -0
  48. package/dist/tests-ts/workbuddy-history.test.js +256 -0
  49. package/dist/tests-ts/workbuddy-plugin.test.js +43 -0
  50. package/package.json +1 -1
  51. package/plugins/aun/dist/src-ts/plugins/aun/attachments.js +44 -13
  52. package/plugins/aun/dist/src-ts/plugins/aun/index.js +5 -6
  53. package/plugins/aun/package.json +1 -1
  54. package/plugins/aun/plugin.json +1 -1
  55. package/plugins/chatgpt/dist/src-ts/attachments.js +62 -0
  56. package/plugins/chatgpt/dist/src-ts/plugins/chatgpt/cdp-client.js +342 -9
  57. package/plugins/chatgpt/dist/src-ts/plugins/chatgpt/index.js +127 -7
  58. package/plugins/chatgpt/package.json +1 -1
  59. package/plugins/chatgpt/plugin.json +14 -1
  60. package/plugins/doubao/config.schema.json +3 -0
  61. package/plugins/doubao/dist/src-ts/attachments.js +62 -0
  62. package/plugins/doubao/dist/src-ts/plugins/desktop-launch.js +19 -0
  63. package/plugins/doubao/dist/src-ts/plugins/doubao/attachments.js +42 -0
  64. package/plugins/doubao/dist/src-ts/plugins/doubao/cdp-client.js +530 -48
  65. package/plugins/doubao/dist/src-ts/plugins/doubao/index.js +114 -25
  66. package/plugins/doubao/dist/src-ts/plugins/doubao/session-history.js +123 -0
  67. package/plugins/doubao/package.json +1 -1
  68. package/plugins/doubao/plugin.json +1 -1
  69. package/plugins/dsh/config.schema.json +2 -1
  70. package/plugins/dsh/dist/src-ts/attachments.js +62 -0
  71. package/plugins/dsh/dist/src-ts/dsh-agent.js +141 -46
  72. package/plugins/dsh/dist/src-ts/headless-account.patch.yml +8 -1
  73. package/plugins/dsh/dist/src-ts/plugins/dsh/index.js +18 -2
  74. package/plugins/dsh/dist/src-ts/plugins/dsh/session-history.js +371 -0
  75. package/plugins/dsh/package.json +5 -2
  76. package/plugins/dsh/plugin.json +1 -1
  77. package/plugins/qwenwork/dist/src-ts/attachments.js +62 -0
  78. package/plugins/qwenwork/dist/src-ts/plugins/desktop-launch.js +19 -0
  79. package/plugins/qwenwork/dist/src-ts/plugins/qwenwork/cdp-client.js +271 -10
  80. package/plugins/qwenwork/dist/src-ts/plugins/qwenwork/index.js +42 -3
  81. package/plugins/qwenwork/dist/src-ts/plugins/qwenwork/session-history.js +245 -0
  82. package/plugins/qwenwork/package.json +1 -1
  83. package/plugins/qwenwork/plugin.json +1 -1
  84. package/plugins/workbuddy/config.schema.json +1 -1
  85. package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/cdp-client.js +42 -2
  86. package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/index.js +23 -3
  87. package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/session-history.js +121 -0
  88. package/plugins/workbuddy/package.json +1 -1
  89. package/plugins/workbuddy/plugin.json +1 -1
@@ -1,12 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DoubaoPlugin = exports.doubaoManifest = void 0;
4
+ const promises_1 = require("node:fs/promises");
5
+ const node_path_1 = require("node:path");
4
6
  const cdp_client_1 = require("./cdp-client");
7
+ const session_history_1 = require("./session-history");
5
8
  const plugin_1 = require("../../plugin");
6
9
  const desktop_launch_1 = require("../desktop-launch");
7
10
  exports.doubaoManifest = {
8
11
  id: "doubao",
9
- version: "1.0.14",
12
+ version: "1.0.20",
10
13
  displayName: "豆包",
11
14
  entry: "dist/index.js",
12
15
  apiVersion: "1",
@@ -17,14 +20,36 @@ exports.doubaoManifest = {
17
20
  class DoubaoPlugin {
18
21
  injectedClient;
19
22
  manifest = exports.doubaoManifest;
23
+ attachmentInput = true;
24
+ sessionOperations = [];
25
+ sessionHistory;
20
26
  client;
21
27
  state = "stopped";
22
28
  message = "";
29
+ queue = Promise.resolve();
30
+ pending = 0;
31
+ bindings = new Map();
32
+ dataDir;
23
33
  constructor(injectedClient) {
24
34
  this.injectedClient = injectedClient;
25
35
  }
26
36
  disposer;
37
+ reconnect;
27
38
  async activate(context) {
39
+ this.dataDir = context.dataDir;
40
+ this.bindings.clear();
41
+ if (this.dataDir) {
42
+ try {
43
+ const saved = JSON.parse(await (0, promises_1.readFile)((0, node_path_1.join)(this.dataDir, "sessions.json"), "utf8"));
44
+ if (!saved || typeof saved !== "object" || Array.isArray(saved) || Object.values(saved).some(value => typeof value !== "string" || !/^\d*$/.test(value)))
45
+ throw new Error("豆包会话绑定记录无效");
46
+ this.bindings = new Map(Object.entries(saved));
47
+ }
48
+ catch (error) {
49
+ if (error.code !== "ENOENT")
50
+ throw error;
51
+ }
52
+ }
28
53
  this.client = this.injectedClient ?? new cdp_client_1.DoubaoCdpClient({
29
54
  port: (0, plugin_1.resolveRuntimePort)(context.config, context.runtime, "doubao", "DOUBAO_CDP_PORT", 9227),
30
55
  conversationId: typeof context.config.conversationId === "string" ? context.config.conversationId : undefined,
@@ -32,41 +57,54 @@ class DoubaoPlugin {
32
57
  pluginList: Array.isArray(context.config.pluginList) ? context.config.pluginList.filter((value) => typeof value === "string") : undefined,
33
58
  timeoutMs: typeof context.config.timeoutMs === "number" ? context.config.timeoutMs : undefined,
34
59
  });
60
+ this.sessionHistory = new session_history_1.DoubaoSessionHistoryProvider({
61
+ scope: `doubao:${(0, plugin_1.resolveRuntimePort)(context.config, context.runtime, "doubao", "DOUBAO_CDP_PORT", 9227)}`,
62
+ client: () => this.client,
63
+ });
64
+ this.sessionOperations = this.client.createSession && this.client.complete ? ["new"] : [];
65
+ this.reconnect = async () => {
66
+ try {
67
+ await this.client.connect();
68
+ }
69
+ catch (first) {
70
+ if (context.config.autoStart !== false && !this.injectedClient && process.platform === "win32") {
71
+ const port = (0, plugin_1.resolveRuntimePort)(context.config, context.runtime, "doubao", "DOUBAO_CDP_PORT", 9227);
72
+ const executable = await (0, desktop_launch_1.findWindowsExecutable)("Doubao.exe", typeof context.config.executablePath === "string" ? context.config.executablePath : undefined);
73
+ if (executable) {
74
+ context.logger?.warn?.(`正在启动豆包:${executable},等待 CDP ${port}`);
75
+ try {
76
+ await (0, desktop_launch_1.launchAndWait)(executable, [`--remote-debugging-port=${port}`], () => this.client.connect(), typeof context.config.startupTimeoutMs === "number" ? context.config.startupTimeoutMs : 30_000);
77
+ return;
78
+ }
79
+ catch (error) {
80
+ first = new Error(`已启动豆包,但 CDP ${port} 未就绪:${error instanceof Error ? error.message : String(error)}`);
81
+ }
82
+ }
83
+ else
84
+ first = new Error("未找到 Doubao.exe,请配置 executablePath");
85
+ }
86
+ throw first;
87
+ }
88
+ };
35
89
  try {
36
- await this.client.connect();
90
+ await this.reconnect();
37
91
  if (context.http)
38
92
  this.disposer = context.http.register({ method: "POST", path: "/doubao/v1/chat/completions", handler: (request, response) => this.handleHttp(request, response) }) || undefined;
39
93
  this.state = "ready";
40
94
  this.message = "";
41
95
  }
42
- catch (first) {
43
- if (context.config.autoStart !== false && !this.injectedClient && process.platform === "win32") {
44
- const port = (0, plugin_1.resolveRuntimePort)(context.config, context.runtime, "doubao", "DOUBAO_CDP_PORT", 9227);
45
- const executable = await (0, desktop_launch_1.findWindowsExecutable)("Doubao.exe", typeof context.config.executablePath === "string" ? context.config.executablePath : undefined);
46
- if (executable) {
47
- context.logger?.warn?.(`豆包已启动,等待 CDP ${port}`);
48
- try {
49
- await (0, desktop_launch_1.launchAndWait)(executable, [`--remote-debugging-port=${port}`], () => this.client.connect(), typeof context.config.startupTimeoutMs === "number" ? context.config.startupTimeoutMs : 30_000);
50
- this.state = "ready";
51
- this.message = "";
52
- return;
53
- }
54
- catch (error) {
55
- first = new Error(`已启动豆包,但 CDP ${port} 未就绪:${error instanceof Error ? error.message : String(error)}`);
56
- }
57
- }
58
- else
59
- first = new Error("未找到 Doubao.exe,请配置 executablePath");
60
- }
96
+ catch (error) {
61
97
  this.state = "failed";
62
- this.message = first instanceof Error ? first.message : String(first);
98
+ this.message = error instanceof Error ? error.message : String(error);
63
99
  context.logger?.warn?.(this.message);
64
- throw first;
100
+ throw error;
65
101
  }
66
102
  }
67
103
  async deactivate() {
104
+ await this.queue;
68
105
  this.disposer?.();
69
106
  this.disposer = undefined;
107
+ this.reconnect = undefined;
70
108
  await this.client?.close();
71
109
  this.client = undefined;
72
110
  this.state = "stopped";
@@ -76,10 +114,61 @@ class DoubaoPlugin {
76
114
  ? { status: "ready", details: { adapter: "doubao", cdp: true } }
77
115
  : { status: "degraded", message: this.message || "豆包 CDP 未连接", details: { adapter: "doubao", cdp: false } };
78
116
  }
79
- async handle(request) {
117
+ async controlSession(request) {
118
+ if (request.operation !== "new")
119
+ throw new Error(`豆包不支持会话操作:${String(request.operation)}`);
120
+ if (!request.sessionId?.trim())
121
+ throw new Error("豆包新会话缺少 sessionId");
122
+ if (this.pending)
123
+ throw new Error("豆包当前忙,无法创建新会话");
124
+ if (!this.sessionOperations.includes("new"))
125
+ throw new Error("豆包当前传输不支持新建会话");
126
+ return this.enqueue(async () => {
127
+ await this.ensureConnected();
128
+ await this.client.createSession(request.name);
129
+ await this.remember(request.sessionId, "");
130
+ return { text: "豆包已创建新会话", sessionId: request.sessionId };
131
+ });
132
+ }
133
+ async ensureConnected() {
80
134
  if (this.state !== "ready" || !this.client)
81
135
  throw new Error("豆包插件未就绪");
82
- return this.client.complete ? this.client.complete(request.task) : { text: await this.client.direct(request.task) };
136
+ if (!this.client.connected())
137
+ await this.reconnect?.();
138
+ }
139
+ async handle(request) {
140
+ return this.enqueue(async () => {
141
+ await this.ensureConnected();
142
+ const client = this.client;
143
+ if (request.attachments?.length && !client.complete)
144
+ throw new Error("当前豆包客户端不支持附件输入");
145
+ if (!client.complete)
146
+ return { text: await client.direct(request.task) };
147
+ const conversationId = request.sessionId ? this.bindings.get(request.sessionId) ?? "" : undefined;
148
+ const response = await client.complete(request.task, undefined, request.attachments, conversationId);
149
+ if (!request.sessionId)
150
+ return response;
151
+ if (!response.sessionId || !/^\d+$/.test(response.sessionId))
152
+ throw new Error("豆包未返回有效的服务端会话标识");
153
+ await this.remember(request.sessionId, response.sessionId);
154
+ return { ...response, sessionId: request.sessionId };
155
+ });
156
+ }
157
+ enqueue(task) {
158
+ this.pending++;
159
+ const run = this.queue.then(task);
160
+ this.queue = run.then(() => undefined, () => undefined);
161
+ return run.finally(() => { this.pending--; });
162
+ }
163
+ async remember(sessionId, conversationId) {
164
+ const next = new Map(this.bindings).set(sessionId, conversationId);
165
+ if (this.dataDir) {
166
+ await (0, promises_1.mkdir)(this.dataDir, { recursive: true });
167
+ const file = (0, node_path_1.join)(this.dataDir, "sessions.json");
168
+ await (0, promises_1.writeFile)(`${file}.tmp`, `${JSON.stringify(Object.fromEntries(next), null, 2)}\n`, { mode: 0o600 });
169
+ await (0, promises_1.rename)(`${file}.tmp`, file);
170
+ }
171
+ this.bindings = next;
83
172
  }
84
173
  async handleHttp(request, response) {
85
174
  let raw = "";
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DoubaoSessionHistoryProvider = void 0;
4
+ const unsupported = (reason) => ({ supported: false, reason });
5
+ class DoubaoSessionHistoryProvider {
6
+ options;
7
+ mode = "all";
8
+ limitation = "豆包通过原生历史目录和单会话消息链分页只读读取对话正文。";
9
+ listed = new Map();
10
+ listedSessions = new Map();
11
+ readAt = "";
12
+ snapshotAt = 0;
13
+ constructor(options) {
14
+ this.options = options;
15
+ }
16
+ get scope() { return this.options.scope; }
17
+ async listSessions(query) {
18
+ if (!Number.isInteger(query.limit) || query.limit < 1 || query.limit > 50)
19
+ return unsupported("豆包每页会话数量必须为 1–50");
20
+ if (query.cursor !== undefined && (typeof query.cursor !== "string" || !query.cursor.trim()))
21
+ return unsupported("豆包会话目录游标无效");
22
+ const client = this.options.client();
23
+ if (!client?.connected() || !client.listHistory)
24
+ return unsupported("豆包 CDP 未连接或当前客户端不提供只读历史目录接口");
25
+ try {
26
+ const page = await client.listHistory(query.cursor, query.limit);
27
+ if (!Array.isArray(page.conversations) || typeof page.complete !== "boolean" || !Array.isArray(page.missingReasons))
28
+ return unsupported("豆包会话目录格式无效");
29
+ if (query.cursor === undefined) {
30
+ this.listed.clear();
31
+ this.listedSessions.clear();
32
+ }
33
+ this.readAt = new Date().toISOString();
34
+ this.snapshotAt = Date.now();
35
+ for (const conversation of page.conversations) {
36
+ if (!conversation || typeof conversation.id !== "string" || !conversation.id || !Array.isArray(conversation.messages))
37
+ return unsupported("豆包会话目录包含无效条目");
38
+ this.listed.set(conversation.id, conversation);
39
+ this.listedSessions.set(conversation.id, { id: conversation.id, title: conversation.title, ...(conversation.updatedAt ? { updatedAt: conversation.updatedAt } : {}) });
40
+ }
41
+ const missingReasons = [...new Set(page.missingReasons)];
42
+ return {
43
+ supported: true,
44
+ sessions: page.conversations.map(item => ({ id: item.id, title: item.title, ...(item.updatedAt ? { updatedAt: item.updatedAt } : {}) })),
45
+ ...(page.nextCursor ? { nextCursor: page.nextCursor } : {}),
46
+ complete: page.complete,
47
+ missingReasons,
48
+ readAt: this.readAt,
49
+ };
50
+ }
51
+ catch (error) {
52
+ return unsupported("豆包历史目录读取失败,请检查桌面端接口或版本兼容性");
53
+ }
54
+ }
55
+ async readSession(query) {
56
+ if (!Number.isInteger(query.limit) || query.limit < 1 || query.limit > 100)
57
+ return unsupported("豆包每页消息数量必须为 1–100");
58
+ const since = query.since;
59
+ const sinceMs = since === undefined ? undefined : Date.parse(since);
60
+ if (since !== undefined && !Number.isFinite(sinceMs))
61
+ return unsupported("豆包会话正文起始时间无效");
62
+ let nativeCursor;
63
+ if (query.cursor !== undefined) {
64
+ const bound = query.cursor.match(/^db-read:(\d+):([1-9]\d*)$/);
65
+ if (bound) {
66
+ if (sinceMs !== Number(bound[1]))
67
+ return unsupported("豆包会话正文游标与起始时间不匹配");
68
+ nativeCursor = bound[2];
69
+ }
70
+ else if (/^[1-9]\d*$/.test(query.cursor) && sinceMs === undefined)
71
+ nativeCursor = query.cursor;
72
+ else
73
+ return unsupported("豆包会话正文游标无效");
74
+ }
75
+ const session = this.listedSessions.get(query.sessionId);
76
+ if (!session)
77
+ return unsupported("请先分页列出豆包会话目录,再读取该会话");
78
+ if (Date.now() - this.snapshotAt > 120_000) {
79
+ this.listed.clear();
80
+ this.listedSessions.clear();
81
+ return unsupported("豆包历史快照已过期,请重新列出会话目录");
82
+ }
83
+ const client = this.options.client();
84
+ if (!client?.connected() || !client.readHistory)
85
+ return unsupported("豆包 CDP 未连接或当前客户端不提供只读会话正文分页接口");
86
+ let page;
87
+ try {
88
+ page = await client.readHistory(query.sessionId, nativeCursor, query.limit, since);
89
+ }
90
+ catch {
91
+ return unsupported("豆包会话正文读取失败,请检查桌面端接口或版本兼容性");
92
+ }
93
+ if (page.conversationId !== query.sessionId || !Array.isArray(page.messages) || typeof page.hasMore !== "boolean" || typeof page.complete !== "boolean" || !Array.isArray(page.missingReasons))
94
+ return unsupported("豆包会话正文格式或会话身份无效");
95
+ if (page.nextCursor !== undefined && (!/^[1-9]\d*$/.test(page.nextCursor) || page.nextCursor === nativeCursor))
96
+ return unsupported("豆包会话正文返回无效或重复游标");
97
+ const pageTimes = page.messages.map(message => message.time ? Date.parse(message.time) : NaN).filter(Number.isFinite);
98
+ const oldest = pageTimes.length ? Math.min(...pageTimes) : undefined;
99
+ const reachedSince = sinceMs !== undefined && (page.reachedSince === true || oldest !== undefined && oldest < sinceMs);
100
+ const visible = sinceMs === undefined ? page.messages : page.messages.filter(message => !message.time || Date.parse(message.time) >= sinceMs);
101
+ const turns = visible.map(message => ({
102
+ ...(message.id ? { id: message.id } : {}),
103
+ role: message.role,
104
+ text: message.text,
105
+ ...(message.time ? { time: message.time } : {}),
106
+ }));
107
+ const missingReasons = [...page.missingReasons];
108
+ if (page.hasMore && !page.nextCursor && !reachedSince)
109
+ missingReasons.push("豆包会话正文仍有后续消息,但分页游标缺失。");
110
+ if (!turns.every(turn => Boolean(turn.id && turn.time)))
111
+ missingReasons.push("部分豆包消息缺少稳定标识或发送时间,无法确认正文完整性。");
112
+ return {
113
+ supported: true,
114
+ session,
115
+ turns,
116
+ ...(page.nextCursor && !reachedSince ? { nextCursor: sinceMs === undefined ? page.nextCursor : `db-read:${sinceMs}:${page.nextCursor}` } : {}),
117
+ complete: page.complete && (!page.hasMore || Boolean(page.nextCursor) || reachedSince) && missingReasons.length === 0,
118
+ missingReasons: [...new Set(missingReasons)],
119
+ readAt: this.readAt,
120
+ };
121
+ }
122
+ }
123
+ exports.DoubaoSessionHistoryProvider = DoubaoSessionHistoryProvider;
@@ -4,9 +4,10 @@ exports.DshPlugin = exports.dshManifest = void 0;
4
4
  const node_path_1 = require("node:path");
5
5
  const dsh_agent_1 = require("../../dsh-agent");
6
6
  const openai_adapter_1 = require("../qwenwork/openai-adapter");
7
+ const session_history_1 = require("./session-history");
7
8
  exports.dshManifest = {
8
9
  id: "dsh",
9
- version: "1.0.4",
10
+ version: "1.0.9",
10
11
  displayName: "DeepSeek Harness",
11
12
  entry: "dist/index.js",
12
13
  apiVersion: "1",
@@ -16,10 +17,14 @@ exports.dshManifest = {
16
17
  };
17
18
  class DshPlugin {
18
19
  manifest = exports.dshManifest;
20
+ attachmentInput = true;
21
+ sessionOperations = ["new"];
22
+ sessionHistory;
19
23
  agent;
20
24
  status = "failed";
21
25
  message = "插件尚未启动";
22
26
  adapter;
27
+ activeRequests = 0;
23
28
  unregister = [];
24
29
  async activate(context) {
25
30
  const configured = context.config.patchPath;
@@ -27,6 +32,10 @@ class DshPlugin {
27
32
  ? configured
28
33
  : (0, node_path_1.resolve)(__dirname, "..", "..", "headless-account.patch.yml");
29
34
  this.agent = new dsh_agent_1.DshAgent({ patchPath });
35
+ this.sessionHistory = new session_history_1.DshSessionHistoryProvider({
36
+ sessionsRoot: typeof context.config.sessionsRoot === "string" ? context.config.sessionsRoot : undefined,
37
+ unavailableReason: () => this.status !== "ready" ? "DSH 插件尚未就绪" : this.activeRequests ? "DSH 正在处理任务,暂不读取持久化历史" : "",
38
+ });
30
39
  this.adapter = new openai_adapter_1.OpenAIAdapter((prompt) => this.handle({ task: prompt, timeoutMs: 240_000 }).then((result) => result.text), { model: "dsh", prefix: "/dsh/v1", onExchange: (direction, text, peer, agentAid) => context.logger?.info?.("DSH 通信", { direction, text, peer, agentAid }) });
31
40
  if (context.http) {
32
41
  for (const [method, path] of [["GET", "/dsh/v1/models"], ["POST", "/dsh/v1/chat/completions"], ["OPTIONS", "/dsh/v1/chat/completions"]]) {
@@ -45,6 +54,7 @@ class DshPlugin {
45
54
  await this.adapter?.close();
46
55
  this.adapter = undefined;
47
56
  this.agent = undefined;
57
+ this.sessionHistory = undefined;
48
58
  this.status = "failed";
49
59
  this.message = "插件已停止";
50
60
  }
@@ -54,7 +64,13 @@ class DshPlugin {
54
64
  async handle(request) {
55
65
  if (!this.agent || this.status !== "ready")
56
66
  throw new Error("dsh 插件未就绪");
57
- return this.agent.send(request);
67
+ this.activeRequests++;
68
+ try {
69
+ return await this.agent.send(request);
70
+ }
71
+ finally {
72
+ this.activeRequests--;
73
+ }
58
74
  }
59
75
  }
60
76
  exports.DshPlugin = DshPlugin;