mu-agent-bridge 1.0.71 → 1.0.78
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/README.md +17 -10
- package/dist/src-ts/agent.js +35 -0
- package/dist/src-ts/channel-sessions.js +3 -2
- package/dist/src-ts/cli.js +67 -37
- package/dist/src-ts/control-server.js +12 -30
- package/dist/src-ts/core-updater.js +141 -33
- package/dist/src-ts/daemon-process.js +2 -1
- package/dist/src-ts/dsh-agent.js +31 -13
- package/dist/src-ts/http-agent.js +36 -0
- package/dist/src-ts/plugin-catalog.js +11 -2
- package/dist/src-ts/plugin-manager.js +351 -50
- package/dist/src-ts/plugins/abweb/index.js +1 -1
- package/dist/src-ts/plugins/abweb/public/app.js +73 -5
- package/dist/src-ts/plugins/abweb/public/index.html +15 -0
- package/dist/src-ts/plugins/abweb/public/style.css +4 -0
- package/dist/src-ts/plugins/aun/attachments.js +3 -21
- package/dist/src-ts/plugins/aun/index.js +155 -21
- package/dist/src-ts/plugins/aun/messages.js +4 -1
- package/dist/src-ts/plugins/aun/public/app.js +2 -1
- package/dist/src-ts/plugins/aun/public/index.html +1 -1
- package/dist/src-ts/plugins/cdp-draft.js +5 -2
- package/dist/src-ts/plugins/chatgpt/cdp-client.js +26 -12
- package/dist/src-ts/plugins/chatgpt/index.js +80 -19
- package/dist/src-ts/plugins/claude-cli/index.js +19 -2
- package/dist/src-ts/plugins/codex-cli/index.js +19 -2
- package/dist/src-ts/plugins/desktop-launch.js +44 -3
- package/dist/src-ts/plugins/doubao/cdp-client.js +234 -45
- package/dist/src-ts/plugins/doubao/index.js +152 -8
- package/dist/src-ts/plugins/doubao/native-task.js +134 -0
- package/dist/src-ts/plugins/dsh/cdp-client.js +334 -0
- package/dist/src-ts/plugins/dsh/index.js +172 -21
- package/dist/src-ts/plugins/dsh/session-history.js +31 -3
- package/dist/src-ts/plugins/feishu/index.js +1 -1
- package/dist/src-ts/plugins/local-cli/agent.js +74 -9
- package/dist/src-ts/plugins/personal-assistant/claude-cli-model.js +30 -0
- package/dist/src-ts/plugins/personal-assistant/coordination.js +57 -0
- package/dist/src-ts/plugins/personal-assistant/index.js +263 -0
- package/dist/src-ts/plugins/personal-assistant/model-client.js +181 -0
- package/dist/src-ts/plugins/personal-assistant/owner-context.js +56 -0
- package/dist/src-ts/plugins/personal-assistant/remote-ability.js +176 -0
- package/dist/src-ts/plugins/personal-assistant/session-memory.js +124 -0
- package/dist/src-ts/plugins/personal-assistant/tools.js +167 -0
- package/dist/src-ts/plugins/qwenwork/cdp-client.js +90 -18
- package/dist/src-ts/plugins/qwenwork/index.js +139 -24
- package/dist/src-ts/plugins/workbuddy/cdp-client.js +353 -82
- package/dist/src-ts/plugins/workbuddy/index.js +124 -41
- package/dist/src-ts/plugins/zcode/cdp-client.js +500 -0
- package/dist/src-ts/plugins/zcode/index.js +97 -0
- package/dist/src-ts/session-management.js +132 -14
- package/dist/src-ts/version-manager.js +6 -3
- package/dist/tests-ts/abweb-cli.test.js +10 -2
- package/dist/tests-ts/abweb-model-config.test.js +73 -0
- package/dist/tests-ts/agent.test.js +27 -0
- package/dist/tests-ts/aun-attachments.test.js +19 -17
- package/dist/tests-ts/aun-default-owner-page.test.js +2 -1
- package/dist/tests-ts/aun-messages.test.js +20 -0
- package/dist/tests-ts/aun-plugin.test.js +292 -19
- package/dist/tests-ts/bundled-package.test.js +12 -2
- package/dist/tests-ts/cdp-draft-recovery.test.js +182 -3
- package/dist/tests-ts/channel-sessions.test.js +27 -0
- package/dist/tests-ts/chatgpt-plugin.test.js +118 -0
- package/dist/tests-ts/control-server.test.js +56 -0
- package/dist/tests-ts/core-updater.test.js +215 -46
- package/dist/tests-ts/daemon-process.test.js +126 -1
- package/dist/tests-ts/desktop-launch.test.js +73 -0
- package/dist/tests-ts/doubao-native-task.test.js +237 -0
- package/dist/tests-ts/doubao-plugin.test.js +773 -12
- package/dist/tests-ts/dsh-agent.test.js +157 -8
- package/dist/tests-ts/dsh-cdp.test.js +148 -0
- package/dist/tests-ts/dsh-history.test.js +37 -0
- package/dist/tests-ts/feishu-plugin.test.js +1 -1
- package/dist/tests-ts/http-agent.test.js +18 -0
- package/dist/tests-ts/installer-assets.test.js +1 -1
- package/dist/tests-ts/local-cli.test.js +146 -1
- package/dist/tests-ts/model-provider-cancellation.test.js +152 -0
- package/dist/tests-ts/native-session-management.test.js +8 -7
- package/dist/tests-ts/personal-assistant-coordination.test.js +92 -0
- package/dist/tests-ts/personal-assistant-extensions.test.js +35 -0
- package/dist/tests-ts/personal-assistant-memory.test.js +117 -0
- package/dist/tests-ts/personal-assistant-owner-context.test.js +107 -0
- package/dist/tests-ts/personal-assistant-remote-ability.test.js +123 -0
- package/dist/tests-ts/personal-assistant.test.js +663 -0
- package/dist/tests-ts/platform-integration.test.js +183 -1
- package/dist/tests-ts/plugin-catalog.test.js +12 -2
- package/dist/tests-ts/plugin-manager.test.js +356 -4
- package/dist/tests-ts/plugin-upgrade-deadline.test.js +354 -0
- package/dist/tests-ts/publish-packages.test.js +42 -0
- package/dist/tests-ts/qwenwork-plugin.test.js +135 -1
- package/dist/tests-ts/qwenwork-reconnect.test.js +195 -0
- package/dist/tests-ts/qwenwork-sse.test.js +33 -0
- package/dist/tests-ts/session-access-defaults.test.js +112 -0
- package/dist/tests-ts/session-management.test.js +159 -4
- package/dist/tests-ts/version-manager.test.js +40 -0
- package/dist/tests-ts/workbuddy-cdp-recovery.test.js +311 -0
- package/dist/tests-ts/workbuddy-plugin.test.js +499 -4
- package/dist/tests-ts/zcode-cdp.test.js +894 -0
- package/dist/tests-ts/zcode-plugin.test.js +396 -0
- package/package.json +1 -1
- package/plugins/abweb/dist/src-ts/agent.js +35 -0
- package/plugins/abweb/dist/src-ts/plugins/abweb/index.js +1 -1
- package/plugins/abweb/dist/src-ts/plugins/abweb/public/app.js +73 -5
- package/plugins/abweb/dist/src-ts/plugins/abweb/public/app.ts +57 -5
- package/plugins/abweb/dist/src-ts/plugins/abweb/public/index.html +15 -0
- package/plugins/abweb/dist/src-ts/plugins/abweb/public/style.css +4 -0
- package/plugins/abweb/package.json +1 -1
- package/plugins/abweb/plugin.json +1 -1
- package/plugins/aun/config.schema.json +1 -1
- package/plugins/aun/dist/src-ts/agent.js +35 -0
- package/plugins/aun/dist/src-ts/plugins/aun/attachments.js +3 -21
- package/plugins/aun/dist/src-ts/plugins/aun/index.js +155 -21
- package/plugins/aun/dist/src-ts/plugins/aun/messages.js +4 -1
- package/plugins/aun/dist/src-ts/plugins/aun/public/app.js +2 -1
- package/plugins/aun/dist/src-ts/plugins/aun/public/index.html +1 -1
- package/plugins/aun/package.json +1 -1
- package/plugins/aun/plugin.json +1 -1
- package/plugins/chatgpt/dist/src-ts/agent.js +35 -0
- package/plugins/chatgpt/dist/src-ts/plugins/cdp-draft.js +5 -2
- package/plugins/chatgpt/dist/src-ts/plugins/chatgpt/cdp-client.js +26 -12
- package/plugins/chatgpt/dist/src-ts/plugins/chatgpt/index.js +80 -19
- package/plugins/chatgpt/dist/src-ts/plugins/desktop-launch.js +44 -3
- package/plugins/chatgpt/package.json +1 -1
- package/plugins/chatgpt/plugin.json +1 -1
- package/plugins/claude-cli/dist/src-ts/agent.js +35 -0
- package/plugins/claude-cli/dist/src-ts/plugins/claude-cli/index.js +19 -2
- package/plugins/claude-cli/dist/src-ts/plugins/local-cli/agent.js +74 -9
- package/plugins/claude-cli/package.json +1 -1
- package/plugins/claude-cli/plugin.json +3 -2
- package/plugins/codex-cli/dist/src-ts/agent.js +35 -0
- package/plugins/codex-cli/dist/src-ts/plugins/codex-cli/index.js +19 -2
- package/plugins/codex-cli/dist/src-ts/plugins/local-cli/agent.js +74 -9
- package/plugins/codex-cli/package.json +1 -1
- package/plugins/codex-cli/plugin.json +3 -2
- package/plugins/doubao/config.schema.json +2 -1
- package/plugins/doubao/dist/src-ts/agent.js +35 -0
- package/plugins/doubao/dist/src-ts/plugins/desktop-launch.js +44 -3
- package/plugins/doubao/dist/src-ts/plugins/doubao/cdp-client.js +234 -45
- package/plugins/doubao/dist/src-ts/plugins/doubao/index.js +152 -8
- package/plugins/doubao/dist/src-ts/plugins/doubao/native-task.js +134 -0
- package/plugins/doubao/package.json +1 -1
- package/plugins/doubao/plugin.json +3 -2
- package/plugins/dsh/config.schema.json +5 -2
- package/plugins/dsh/dist/src-ts/agent.js +35 -0
- package/plugins/dsh/dist/src-ts/dsh-agent.js +31 -13
- package/plugins/dsh/dist/src-ts/plugins/desktop-launch.js +44 -3
- package/plugins/dsh/dist/src-ts/plugins/dsh/cdp-client.js +334 -0
- package/plugins/dsh/dist/src-ts/plugins/dsh/index.js +172 -21
- package/plugins/dsh/dist/src-ts/plugins/dsh/session-history.js +31 -3
- package/plugins/dsh/package.json +1 -1
- package/plugins/dsh/plugin.json +3 -2
- package/plugins/feishu/dist/src-ts/agent.js +35 -0
- package/plugins/feishu/dist/src-ts/plugins/feishu/index.js +1 -1
- package/plugins/feishu/package.json +1 -1
- package/plugins/feishu/plugin.json +1 -1
- package/plugins/personal-assistant/config.schema.json +23 -0
- package/plugins/personal-assistant/dist/src-ts/agent.js +69 -0
- package/plugins/personal-assistant/dist/src-ts/attachments.js +62 -0
- package/plugins/personal-assistant/dist/src-ts/plugin.js +13 -0
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/claude-cli-model.js +30 -0
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/coordination.js +57 -0
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/index.js +263 -0
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/model-client.js +181 -0
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/owner-context.js +56 -0
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/remote-ability.js +176 -0
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/session-memory.js +124 -0
- package/plugins/personal-assistant/dist/src-ts/plugins/personal-assistant/tools.js +167 -0
- package/plugins/personal-assistant/package.json +39 -0
- package/plugins/personal-assistant/plugin.json +15 -0
- package/plugins/qwenwork/dist/src-ts/agent.js +35 -0
- package/plugins/qwenwork/dist/src-ts/plugins/cdp-draft.js +5 -2
- package/plugins/qwenwork/dist/src-ts/plugins/desktop-launch.js +44 -3
- package/plugins/qwenwork/dist/src-ts/plugins/qwenwork/cdp-client.js +90 -18
- package/plugins/qwenwork/dist/src-ts/plugins/qwenwork/index.js +139 -24
- package/plugins/qwenwork/package.json +1 -1
- package/plugins/qwenwork/plugin.json +3 -2
- package/plugins/workbuddy/config.schema.json +1 -1
- package/plugins/workbuddy/dist/src-ts/agent.js +35 -0
- package/plugins/workbuddy/dist/src-ts/plugins/desktop-launch.js +44 -3
- package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/cdp-client.js +353 -82
- package/plugins/workbuddy/dist/src-ts/plugins/workbuddy/index.js +124 -41
- package/plugins/workbuddy/package.json +1 -1
- package/plugins/workbuddy/plugin.json +3 -2
- package/plugins/zcode/config.schema.json +13 -0
- package/plugins/zcode/dist/src-ts/agent.js +69 -0
- package/plugins/zcode/dist/src-ts/attachments.js +62 -0
- package/plugins/zcode/dist/src-ts/plugin.js +13 -0
- package/plugins/zcode/dist/src-ts/plugins/desktop-launch.js +238 -0
- package/plugins/zcode/dist/src-ts/plugins/workbuddy/cdp-client.js +896 -0
- package/plugins/zcode/dist/src-ts/plugins/workbuddy/cli-client.js +39 -0
- package/plugins/zcode/dist/src-ts/plugins/workbuddy/desktop-launch.js +10 -0
- package/plugins/zcode/dist/src-ts/plugins/workbuddy/index.js +567 -0
- package/plugins/zcode/dist/src-ts/plugins/workbuddy/session-history.js +121 -0
- package/plugins/zcode/dist/src-ts/plugins/zcode/cdp-client.js +500 -0
- package/plugins/zcode/dist/src-ts/plugins/zcode/index.js +97 -0
- package/plugins/zcode/package.json +16 -0
- package/plugins/zcode/plugin.json +11 -0
|
@@ -50,6 +50,38 @@ const dsh_1 = require("../src-ts/plugins/dsh");
|
|
|
50
50
|
strict_1.default.deepEqual(plugin.sessionOperations, ["new"]);
|
|
51
51
|
strict_1.default.equal(plugin.attachmentInput, true);
|
|
52
52
|
});
|
|
53
|
+
(0, node_test_1.default)("DSH 插件通过桌面 CDP 发送并返回真实会话标识", async () => {
|
|
54
|
+
const calls = [];
|
|
55
|
+
const client = {
|
|
56
|
+
connect: async () => { calls.push("connect"); },
|
|
57
|
+
close: () => { calls.push("close"); },
|
|
58
|
+
connected: () => true,
|
|
59
|
+
activeSession: async () => "",
|
|
60
|
+
createSession: async () => { calls.push("new"); return "dsh-session-7"; },
|
|
61
|
+
activateSession: async (id) => { calls.push(`select:${id}`); },
|
|
62
|
+
complete: async (request) => { calls.push(`send:${request.task}`); return { text: "桌面回复" }; },
|
|
63
|
+
};
|
|
64
|
+
const plugin = Reflect.construct(dsh_1.DshPlugin, [{ client }]);
|
|
65
|
+
await plugin.activate({ config: {} });
|
|
66
|
+
const response = await plugin.handle({ task: "CDP 历史可见性测试", sessionId: "logical-id", newSession: true });
|
|
67
|
+
strict_1.default.deepEqual(calls, ["connect", "new", "send:CDP 历史可见性测试"]);
|
|
68
|
+
strict_1.default.deepEqual(response, { text: "桌面回复", sessionId: "dsh-session-7" });
|
|
69
|
+
strict_1.default.deepEqual(await plugin.health(), { status: "ready", details: { transport: "cdp", port: 9226, connected: true } });
|
|
70
|
+
await plugin.deactivate();
|
|
71
|
+
});
|
|
72
|
+
(0, node_test_1.default)("DSH 插件不能在 CDP 断开时回退到后台 CLI", async () => {
|
|
73
|
+
const calls = [];
|
|
74
|
+
const client = {
|
|
75
|
+
connect: async () => { throw new Error("DSH CDP 端口不可达"); },
|
|
76
|
+
close: () => { calls.push("close"); },
|
|
77
|
+
connected: () => false,
|
|
78
|
+
};
|
|
79
|
+
const plugin = Reflect.construct(dsh_1.DshPlugin, [{ client }]);
|
|
80
|
+
await strict_1.default.rejects(plugin.activate({ config: {} }), /DSH CDP 端口不可达/);
|
|
81
|
+
strict_1.default.equal((await plugin.health()).status, "failed");
|
|
82
|
+
strict_1.default.deepEqual((await plugin.health()).details, { transport: "cdp", port: 9226, connected: false });
|
|
83
|
+
strict_1.default.deepEqual(calls, ["close"]);
|
|
84
|
+
});
|
|
53
85
|
function fakeSpawn(_file, _args, _options) {
|
|
54
86
|
const child = new node_events_1.EventEmitter();
|
|
55
87
|
child.stdin = { end: (task) => { child.task = task; queueMicrotask(() => { child.stdout.emit("data", `{"type":"session","sessionId":"session-1"}\n`); child.stdout.emit("data", `{"type":"final","text":"hello from model"}\n`); child.emit("close", 0); }); } };
|
|
@@ -62,6 +94,30 @@ function fakeSpawn(_file, _args, _options) {
|
|
|
62
94
|
const agent = new dsh_agent_1.DshAgent({ patchPath: "patch.yml", paths: { executable: "dsh.exe", cli: "cli.js", patch: "patch.yml" }, spawn: fakeSpawn });
|
|
63
95
|
strict_1.default.deepEqual(await agent.send({ task: "hi" }), { text: "hello from model", sessionId: "session-1" });
|
|
64
96
|
});
|
|
97
|
+
(0, node_test_1.default)("DSH 纯文字请求不追加附件处理说明", async () => {
|
|
98
|
+
let task = "";
|
|
99
|
+
const spawn = (file, args, options) => {
|
|
100
|
+
const child = fakeSpawn(file, args, options);
|
|
101
|
+
const end = child.stdin.end;
|
|
102
|
+
child.stdin.end = (value) => { task = value; end(value); };
|
|
103
|
+
return child;
|
|
104
|
+
};
|
|
105
|
+
await new dsh_agent_1.DshAgent({ patchPath: "patch.yml", paths: { executable: "dsh.exe", cli: "cli.js", patch: "patch.yml" }, spawn }).send({ task: "只回答这一句" });
|
|
106
|
+
strict_1.default.equal(task, "只回答这一句");
|
|
107
|
+
});
|
|
108
|
+
(0, node_test_1.default)("DSH 为支持附件回复的通道提供回传目录但不声明空输入", async () => {
|
|
109
|
+
let task = "";
|
|
110
|
+
const spawn = (file, args, options) => {
|
|
111
|
+
const child = fakeSpawn(file, args, options);
|
|
112
|
+
const end = child.stdin.end;
|
|
113
|
+
child.stdin.end = (value) => { task = value; end(value); };
|
|
114
|
+
return child;
|
|
115
|
+
};
|
|
116
|
+
await new dsh_agent_1.DshAgent({ patchPath: "patch.yml", paths: { executable: "dsh.exe", cli: "cli.js", patch: "patch.yml" }, spawn }).send({ task: "生成报告", attachmentOutput: true });
|
|
117
|
+
strict_1.default.match(task, /附件传输:\n\{"outputDirectory":"/);
|
|
118
|
+
strict_1.default.doesNotMatch(task, /"inputs":\[\]/);
|
|
119
|
+
strict_1.default.match(task, /写入.*outputDirectory.*present/);
|
|
120
|
+
});
|
|
65
121
|
(0, node_test_1.default)("DSH agent includes a session id when continuing", async () => {
|
|
66
122
|
let captured = [];
|
|
67
123
|
const spawn = (file, args, options) => { captured = args; return fakeSpawn(file, args, options); };
|
|
@@ -77,6 +133,18 @@ function fakeSpawn(_file, _args, _options) {
|
|
|
77
133
|
strict_1.default.equal(captured.includes("--session-id"), false);
|
|
78
134
|
strict_1.default.equal(response.sessionId, "session-1");
|
|
79
135
|
});
|
|
136
|
+
(0, node_test_1.default)("DSH 模型入口只发送决策提示,不追加普通附件任务指令", async () => {
|
|
137
|
+
let input = "";
|
|
138
|
+
const spawn = (file, args, options) => {
|
|
139
|
+
const child = fakeSpawn(file, args, options);
|
|
140
|
+
const end = child.stdin.end;
|
|
141
|
+
child.stdin.end = (task) => { input = task; end(task); };
|
|
142
|
+
return child;
|
|
143
|
+
};
|
|
144
|
+
const agent = new dsh_agent_1.DshAgent({ patchPath: "patch.yml", paths: { executable: "dsh.exe", cli: "cli.js", patch: "patch.yml" }, spawn });
|
|
145
|
+
await agent.send({ task: "只返回结构化决策" }, true);
|
|
146
|
+
strict_1.default.equal(input, "只返回结构化决策");
|
|
147
|
+
});
|
|
80
148
|
(0, node_test_1.default)("DSH 新会话缺少真实 ID 时拒绝用逻辑 ID 冒充创建成功", async () => {
|
|
81
149
|
const spawn = () => {
|
|
82
150
|
const child = fakeSpawn("", [], {});
|
|
@@ -89,6 +157,25 @@ function fakeSpawn(_file, _args, _options) {
|
|
|
89
157
|
const agent = new dsh_agent_1.DshAgent({ patchPath: "patch.yml", paths: { executable: "dsh.exe", cli: "cli.js", patch: "patch.yml" }, spawn });
|
|
90
158
|
await strict_1.default.rejects(agent.send({ task: "首条消息", sessionId: "logical-id", newSession: true }), /未返回真实新会话标识/);
|
|
91
159
|
});
|
|
160
|
+
(0, node_test_1.default)("DSH 取消时只终止本次启动的 CLI 子进程", async () => {
|
|
161
|
+
let child;
|
|
162
|
+
let killed = 0;
|
|
163
|
+
const spawn = () => {
|
|
164
|
+
child = new node_events_1.EventEmitter();
|
|
165
|
+
child.stdin = { end: () => undefined };
|
|
166
|
+
child.stdout = new node_events_1.EventEmitter();
|
|
167
|
+
child.stderr = new node_events_1.EventEmitter();
|
|
168
|
+
child.kill = () => { killed++; queueMicrotask(() => child.emit("close", null)); return true; };
|
|
169
|
+
return child;
|
|
170
|
+
};
|
|
171
|
+
const agent = new dsh_agent_1.DshAgent({ patchPath: "patch.yml", paths: { executable: "dsh.exe", cli: "cli.js", patch: "patch.yml" }, spawn, defaultTimeoutMs: 20 });
|
|
172
|
+
const controller = new AbortController();
|
|
173
|
+
const task = agent.send({ task: "长任务", signal: controller.signal });
|
|
174
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
175
|
+
controller.abort(new Error("模型请求已取消"));
|
|
176
|
+
await strict_1.default.rejects(task, /模型请求已取消/);
|
|
177
|
+
strict_1.default.equal(killed, 1);
|
|
178
|
+
});
|
|
92
179
|
(0, node_test_1.default)("DSH 附件先落盘供真实工具读取,成功 present 后回传原字节与 MIME 并清理临时目录", async () => {
|
|
93
180
|
const { readFile, copyFile, access } = await Promise.resolve().then(() => __importStar(require("node:fs/promises")));
|
|
94
181
|
const { join } = await Promise.resolve().then(() => __importStar(require("node:path")));
|
|
@@ -178,13 +265,14 @@ function presentSpawn(prepare, status = "completed", text = "已完成") {
|
|
|
178
265
|
const withoutPresent = await new dsh_agent_1.DshAgent({ patchPath: "patch.yml", paths: { executable: "dsh.exe", cli: "cli.js", patch: "patch.yml" }, spawn: fakeSpawn }).send({ task: "只读取", attachments: [input] });
|
|
179
266
|
strict_1.default.equal(withoutPresent.attachments, undefined);
|
|
180
267
|
});
|
|
181
|
-
(0, node_test_1.default)("DSH
|
|
268
|
+
(0, node_test_1.default)("DSH 为支持附件回复的通道生成并回传无输入文件", async () => {
|
|
182
269
|
const spawn = presentSpawn(async (block) => {
|
|
270
|
+
strict_1.default.equal(block.inputs, undefined);
|
|
183
271
|
const path = (0, node_path_1.join)(block.outputDirectory, "result.txt");
|
|
184
272
|
await (await Promise.resolve().then(() => __importStar(require("node:fs/promises")))).writeFile(path, "生成文件");
|
|
185
273
|
return [path];
|
|
186
274
|
});
|
|
187
|
-
const response = await new dsh_agent_1.DshAgent({ patchPath: "patch.yml", paths: { executable: "dsh.exe", cli: "cli.js", patch: "patch.yml" }, spawn }).send({ task: "创建文本文件并回传" });
|
|
275
|
+
const response = await new dsh_agent_1.DshAgent({ patchPath: "patch.yml", paths: { executable: "dsh.exe", cli: "cli.js", patch: "patch.yml" }, spawn }).send({ task: "创建文本文件并回传", attachmentOutput: true });
|
|
188
276
|
strict_1.default.equal(Buffer.from(response.attachments[0].data).toString(), "生成文件");
|
|
189
277
|
});
|
|
190
278
|
(0, node_test_1.default)("DSH 允许只有成功交付附件的空正文回复", async () => {
|
|
@@ -193,7 +281,7 @@ function presentSpawn(prepare, status = "completed", text = "已完成") {
|
|
|
193
281
|
await (await Promise.resolve().then(() => __importStar(require("node:fs/promises")))).writeFile(path, "附件正文");
|
|
194
282
|
return [path];
|
|
195
283
|
}, "completed", "");
|
|
196
|
-
const response = await new dsh_agent_1.DshAgent({ patchPath: "patch.yml", paths: { executable: "dsh.exe", cli: "cli.js", patch: "patch.yml" }, spawn }).send({ task: "只回传文件" });
|
|
284
|
+
const response = await new dsh_agent_1.DshAgent({ patchPath: "patch.yml", paths: { executable: "dsh.exe", cli: "cli.js", patch: "patch.yml" }, spawn }).send({ task: "只回传文件", attachmentOutput: true });
|
|
197
285
|
strict_1.default.equal(response.text, "");
|
|
198
286
|
strict_1.default.equal(response.attachments?.length, 1);
|
|
199
287
|
});
|
|
@@ -216,6 +304,7 @@ function presentSpawn(prepare, status = "completed", text = "已完成") {
|
|
|
216
304
|
}
|
|
217
305
|
});
|
|
218
306
|
(0, node_test_1.default)("DSH 拒绝回传超量和超大附件", async () => {
|
|
307
|
+
const input = { kind: "file", data: Buffer.from("输入"), filename: "输入.txt", contentType: "text/plain" };
|
|
219
308
|
for (const limit of ["count", "size"]) {
|
|
220
309
|
const spawn = presentSpawn(async (block) => {
|
|
221
310
|
const path = (0, node_path_1.join)(block.outputDirectory, "large.txt");
|
|
@@ -225,7 +314,7 @@ function presentSpawn(prepare, status = "completed", text = "已完成") {
|
|
|
225
314
|
await truncate(path, 32 * 1024 * 1024 + 1);
|
|
226
315
|
return limit === "count" ? Array.from({ length: 9 }, (_, index) => (0, node_path_1.join)(block.outputDirectory, `${index}.txt`)) : [path];
|
|
227
316
|
});
|
|
228
|
-
await strict_1.default.rejects(new dsh_agent_1.DshAgent({ patchPath: "patch.yml", paths: { executable: "dsh.exe", cli: "cli.js", patch: "patch.yml" }, spawn }).send({ task: "回传文件" }), /最多|大小/);
|
|
317
|
+
await strict_1.default.rejects(new dsh_agent_1.DshAgent({ patchPath: "patch.yml", paths: { executable: "dsh.exe", cli: "cli.js", patch: "patch.yml" }, spawn }).send({ task: "回传文件", attachments: [input] }), /最多|大小/);
|
|
229
318
|
}
|
|
230
319
|
});
|
|
231
320
|
(0, node_test_1.default)("DSH 使用发现的真实安装路径构建 CLI 路径,启动前拒绝不存在的程序", async () => {
|
|
@@ -237,10 +326,6 @@ function presentSpawn(prepare, status = "completed", text = "已完成") {
|
|
|
237
326
|
const paths = await (0, dsh_paths_1.resolveDshPaths)("patch.yml", executable);
|
|
238
327
|
strict_1.default.equal(paths.executable, executable);
|
|
239
328
|
strict_1.default.equal(paths.cli, (0, node_path_1.join)(root, "resources", "app.asar", "dsh", "node_modules", "@deepseek-ai", "dsh-desktop-host", "lib", "cli.js"));
|
|
240
|
-
const plugin = new dsh_1.DshPlugin();
|
|
241
|
-
await plugin.activate({ config: { executablePath: executable } });
|
|
242
|
-
strict_1.default.equal(plugin.agent.paths.executable, executable);
|
|
243
|
-
await plugin.deactivate();
|
|
244
329
|
process.env.DSH_INSTALL_DIR = root;
|
|
245
330
|
strict_1.default.equal((await (0, dsh_paths_1.resolveDshPaths)("patch.yml")).executable, executable);
|
|
246
331
|
await (0, promises_1.rm)(executable);
|
|
@@ -255,3 +340,67 @@ function presentSpawn(prepare, status = "completed", text = "已完成") {
|
|
|
255
340
|
await (0, promises_1.rm)(root, { recursive: true, force: true });
|
|
256
341
|
}
|
|
257
342
|
});
|
|
343
|
+
(0, node_test_1.default)("DSH 模型排队取消立即返回,桌面请求完成前不启动模型 CLI", async () => {
|
|
344
|
+
let release;
|
|
345
|
+
const sent = [];
|
|
346
|
+
const plugin = new dsh_1.DshPlugin({ client: {
|
|
347
|
+
connect: async () => undefined, close() { }, connected: () => true,
|
|
348
|
+
activeSession: async () => "desktop-session", createSession: async () => "desktop-session", activateSession: async () => undefined,
|
|
349
|
+
complete: async (request) => { sent.push(request); if (request.task === "用户任务")
|
|
350
|
+
await new Promise(resolve => { release = resolve; }); return { text: "回复" }; },
|
|
351
|
+
} });
|
|
352
|
+
await plugin.activate({ config: {} });
|
|
353
|
+
plugin.agent = { send: async () => { throw new Error("排队取消后不应调用模型 CLI"); } };
|
|
354
|
+
const running = plugin.handle({ task: "用户任务" });
|
|
355
|
+
await new Promise(resolve => setImmediate(resolve));
|
|
356
|
+
const controller = new AbortController();
|
|
357
|
+
let error;
|
|
358
|
+
const model = plugin.modelProvider.complete({ prompt: "不应发送", sessionId: "pa-queued", timeoutMs: 5000, signal: controller.signal }).catch((value) => { error = value; });
|
|
359
|
+
controller.abort(new Error("排队取消"));
|
|
360
|
+
await new Promise(resolve => setImmediate(resolve));
|
|
361
|
+
const canceledImmediately = Boolean(error);
|
|
362
|
+
release();
|
|
363
|
+
await Promise.all([running, model]);
|
|
364
|
+
await plugin.handle({ task: "用户续聊" });
|
|
365
|
+
await plugin.deactivate();
|
|
366
|
+
strict_1.default.equal(canceledImmediately, true);
|
|
367
|
+
strict_1.default.match(error.stage, /queue/);
|
|
368
|
+
strict_1.default.deepEqual(sent, [{ task: "用户任务" }, { task: "用户续聊" }]);
|
|
369
|
+
});
|
|
370
|
+
(0, node_test_1.default)("DSH 模型会话在重载后恢复,普通桌面任务不调用 CLI 或写入模型映射", async () => {
|
|
371
|
+
const directory = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "dsh-model-session-"));
|
|
372
|
+
const executablePath = (0, node_path_1.join)(directory, "DeepSeek Harness.exe");
|
|
373
|
+
await (0, promises_1.writeFile)(executablePath, "");
|
|
374
|
+
const requests = [];
|
|
375
|
+
const desktopRequests = [];
|
|
376
|
+
const { mock } = await Promise.resolve().then(() => __importStar(require("node:test")));
|
|
377
|
+
const stub = mock.method(dsh_agent_1.DshAgent.prototype, "send", async (request, modelRequest) => {
|
|
378
|
+
strict_1.default.equal(modelRequest, true);
|
|
379
|
+
requests.push(request);
|
|
380
|
+
return { text: "模型回复", sessionId: "native-model-session" };
|
|
381
|
+
});
|
|
382
|
+
try {
|
|
383
|
+
for (let round = 0; round < 2; round++) {
|
|
384
|
+
const plugin = new dsh_1.DshPlugin({ client: {
|
|
385
|
+
connect: async () => undefined, close() { }, connected: () => true,
|
|
386
|
+
activeSession: async () => "ordinary-session", createSession: async () => "ordinary-session", activateSession: async () => undefined,
|
|
387
|
+
complete: async (request) => { desktopRequests.push(request.task); return { text: "桌面回复" }; },
|
|
388
|
+
} });
|
|
389
|
+
await plugin.activate({ config: { executablePath }, dataDir: directory });
|
|
390
|
+
await plugin.handle({ task: "普通用户任务", sessionId: "ordinary-session" });
|
|
391
|
+
strict_1.default.equal(plugin.agent, undefined);
|
|
392
|
+
await plugin.modelProvider.complete({ prompt: "模型提示", sessionId: "pa-logical", timeoutMs: 1000, signal: new AbortController().signal });
|
|
393
|
+
await plugin.deactivate();
|
|
394
|
+
}
|
|
395
|
+
strict_1.default.deepEqual(desktopRequests, ["普通用户任务", "普通用户任务"]);
|
|
396
|
+
strict_1.default.equal(requests.length, 2);
|
|
397
|
+
strict_1.default.equal(requests[0].newSession, true);
|
|
398
|
+
strict_1.default.equal(requests[1].sessionId, "native-model-session");
|
|
399
|
+
strict_1.default.equal(requests[1].newSession, undefined);
|
|
400
|
+
strict_1.default.deepEqual(JSON.parse(await (0, promises_1.readFile)((0, node_path_1.join)(directory, "model-provider-sessions.json"), "utf8")), { "pa-logical": "native-model-session" });
|
|
401
|
+
}
|
|
402
|
+
finally {
|
|
403
|
+
stub.mock.restore();
|
|
404
|
+
await (0, promises_1.rm)(directory, { recursive: true, force: true });
|
|
405
|
+
}
|
|
406
|
+
});
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
7
|
+
const node_test_1 = __importDefault(require("node:test"));
|
|
8
|
+
const cdp_client_1 = require("../src-ts/plugins/dsh/cdp-client");
|
|
9
|
+
class FakeWebSocket {
|
|
10
|
+
readyState = 0;
|
|
11
|
+
onopen;
|
|
12
|
+
onclose;
|
|
13
|
+
onerror;
|
|
14
|
+
onmessage;
|
|
15
|
+
sent = [];
|
|
16
|
+
state = { sessionId: "dsh-session-1", editorText: "", conversationText: "已有历史", busy: false, turnCount: 1, blank: false, pendingAttachments: [] };
|
|
17
|
+
flowNodes = [
|
|
18
|
+
{ kind: "user", text: "已有历史\n12:00", userText: "已有历史" },
|
|
19
|
+
{ kind: "assistant-step", part: "response", text: "旧回复" },
|
|
20
|
+
{ kind: "turn-tail", text: "12:00" },
|
|
21
|
+
];
|
|
22
|
+
messages = ["已有历史"];
|
|
23
|
+
pendingAttachmentLabel = "待发送附件";
|
|
24
|
+
inserted = "";
|
|
25
|
+
sessionRows = ["dsh-session-1", "dsh-session-2"];
|
|
26
|
+
constructor() { queueMicrotask(() => { this.readyState = 1; this.onopen?.(); }); }
|
|
27
|
+
send(raw) {
|
|
28
|
+
const request = JSON.parse(raw);
|
|
29
|
+
this.sent.push(request);
|
|
30
|
+
if (request.method === "Input.insertText") {
|
|
31
|
+
this.inserted = String(request.params.text);
|
|
32
|
+
this.state.editorText = this.inserted;
|
|
33
|
+
}
|
|
34
|
+
if (request.method === "Input.dispatchKeyEvent" && request.params.type === "keyDown" && request.params.key === "Enter") {
|
|
35
|
+
this.messages.push(this.inserted, "桌面模型回复");
|
|
36
|
+
this.flowNodes.push({ kind: "user", text: `${this.inserted}\n13:15`, userText: this.inserted }, { kind: "turn-process", text: "已完成\n已完成,用时 1 秒" }, { kind: "assistant-step", part: "reasoning", text: "内部思考" }, { kind: "assistant-step", part: "response", text: "桌面模型回复" }, { kind: "turn-tail", text: "13:15" });
|
|
37
|
+
this.state.conversationText = `${this.messages.join("\n\n")}\n13:15\n已完成,用时 1 秒\n13:15`;
|
|
38
|
+
this.state.editorText = "";
|
|
39
|
+
this.state.turnCount++;
|
|
40
|
+
}
|
|
41
|
+
if (request.method === "DOM.setFileInputFiles") {
|
|
42
|
+
this.state.pendingAttachments = request.params.files.map(path => path.replaceAll("\\", "/").split("/").at(-1));
|
|
43
|
+
}
|
|
44
|
+
const expression = String(request.params.expression);
|
|
45
|
+
const value = request.method === "Runtime.evaluate"
|
|
46
|
+
? expression.includes("[data-conversation-content]")
|
|
47
|
+
? JSON.stringify({ ...this.state, conversationText: expression.includes('[data-chat-flow-kind="user"]')
|
|
48
|
+
? this.flowNodes.filter(node => (node.kind === "user" || node.kind === "assistant-step") && node.part !== "reasoning").map(node => node.kind === "user" && expression.includes("conversation.user.text.node") ? node.userText : node.text).join("\n\n")
|
|
49
|
+
: this.flowNodes.map(node => node.text).join("\n\n"), pendingAttachments: expression.includes(`aria-label*=\"${this.pendingAttachmentLabel}\"`) ? this.state.pendingAttachments : [] })
|
|
50
|
+
: expression.includes("const id =")
|
|
51
|
+
? Function("document", `return ${expression}`)({ querySelectorAll: () => this.sessionRows.map(id => ({
|
|
52
|
+
getAttribute: (key) => key === "data-row-key" ? `session:${id}` : null,
|
|
53
|
+
matches: (selector) => selector.includes('[role="treeitem"]'),
|
|
54
|
+
closest: () => null,
|
|
55
|
+
click: () => { this.state.sessionId = id; },
|
|
56
|
+
})) })
|
|
57
|
+
: true
|
|
58
|
+
: undefined;
|
|
59
|
+
const result = request.method === "Runtime.evaluate" ? { result: { value } }
|
|
60
|
+
: request.method === "DOM.getDocument" ? { root: { nodeId: 1 } }
|
|
61
|
+
: request.method === "DOM.querySelector" ? { nodeId: 2 }
|
|
62
|
+
: {};
|
|
63
|
+
queueMicrotask(() => this.onmessage?.({ data: JSON.stringify({ id: request.id, result }) }));
|
|
64
|
+
}
|
|
65
|
+
close() { this.readyState = 3; this.onclose?.(); }
|
|
66
|
+
}
|
|
67
|
+
(0, node_test_1.default)("DSH CDP 只连接 DSH 会话页,并将用户原文提交到可见历史", async () => {
|
|
68
|
+
let socket;
|
|
69
|
+
const client = new cdp_client_1.DshCdpClient({
|
|
70
|
+
port: 9226,
|
|
71
|
+
fetchImpl: async () => new Response(JSON.stringify([{ type: "page", title: "DeepSeek Harness", url: "dsh-app://app/", webSocketDebuggerUrl: "ws://127.0.0.1:9226/devtools/page/dsh" }])),
|
|
72
|
+
webSocketFactory: () => (socket = new FakeWebSocket()),
|
|
73
|
+
});
|
|
74
|
+
await client.connect();
|
|
75
|
+
strict_1.default.equal(await client.activeSession(), "dsh-session-1");
|
|
76
|
+
const request = { task: "请只回答:CDP历史可见" };
|
|
77
|
+
const result = await client.complete(request);
|
|
78
|
+
strict_1.default.equal(socket?.inserted, request.task);
|
|
79
|
+
strict_1.default.equal(result.text, "桌面模型回复");
|
|
80
|
+
strict_1.default.ok(socket?.sent.some(item => item.method === "Input.dispatchKeyEvent" && item.params.key === "Enter"));
|
|
81
|
+
client.close();
|
|
82
|
+
});
|
|
83
|
+
(0, node_test_1.default)("DSH CDP 通过桌面文件控件上传真实附件", async () => {
|
|
84
|
+
let socket;
|
|
85
|
+
const client = new cdp_client_1.DshCdpClient({
|
|
86
|
+
port: 9226,
|
|
87
|
+
timeoutMs: 3_000,
|
|
88
|
+
fetchImpl: async () => new Response(JSON.stringify([{ type: "page", url: "dsh-app://app/", webSocketDebuggerUrl: "ws://127.0.0.1:9226/devtools/page/dsh" }])),
|
|
89
|
+
webSocketFactory: () => (socket = new FakeWebSocket()),
|
|
90
|
+
});
|
|
91
|
+
await client.connect();
|
|
92
|
+
const result = await client.complete({
|
|
93
|
+
task: "请分析这个文件",
|
|
94
|
+
attachments: [{ kind: "file", filename: "说明.txt", contentType: "text/plain", data: Buffer.from("真实文件内容") }],
|
|
95
|
+
});
|
|
96
|
+
strict_1.default.deepEqual(socket?.state.pendingAttachments, ["说明.txt"]);
|
|
97
|
+
strict_1.default.match(socket?.inserted ?? "", /请读取本条已上传附件:说明\.txt/);
|
|
98
|
+
strict_1.default.ok(socket?.sent.some(item => item.method === "DOM.setFileInputFiles"));
|
|
99
|
+
strict_1.default.equal(result.text, "桌面模型回复");
|
|
100
|
+
client.close();
|
|
101
|
+
});
|
|
102
|
+
(0, node_test_1.default)("DSH CDP 不连接其他 Electron 页面", async () => {
|
|
103
|
+
const client = new cdp_client_1.DshCdpClient({
|
|
104
|
+
port: 9226,
|
|
105
|
+
fetchImpl: async () => new Response(JSON.stringify([{ type: "page", title: "设置", url: "dsh-app://shell/update-dialog.html", webSocketDebuggerUrl: "ws://127.0.0.1:9226/devtools/page/other" }])),
|
|
106
|
+
webSocketFactory: () => { throw new Error("不能连接非 DSH 会话页面"); },
|
|
107
|
+
});
|
|
108
|
+
await strict_1.default.rejects(client.connect(), /未找到 DSH 桌面会话页/);
|
|
109
|
+
});
|
|
110
|
+
(0, node_test_1.default)("DSH CDP 点击侧栏 treeitem 恢复已有会话,并保护当前草稿和任务", async () => {
|
|
111
|
+
let socket;
|
|
112
|
+
const client = new cdp_client_1.DshCdpClient({
|
|
113
|
+
timeoutMs: 100,
|
|
114
|
+
fetchImpl: async () => new Response(JSON.stringify([{ type: "page", url: "dsh-app://app/", webSocketDebuggerUrl: "ws://127.0.0.1:9226/devtools/page/dsh" }])),
|
|
115
|
+
webSocketFactory: () => (socket = new FakeWebSocket()),
|
|
116
|
+
});
|
|
117
|
+
try {
|
|
118
|
+
await client.connect();
|
|
119
|
+
socket.state.editorText = "用户未发送的草稿";
|
|
120
|
+
await strict_1.default.rejects(client.activateSession("dsh-session-2"), /未发送内容或附件/);
|
|
121
|
+
strict_1.default.equal(await client.activeSession(), "dsh-session-1");
|
|
122
|
+
socket.state.editorText = "";
|
|
123
|
+
socket.state.busy = true;
|
|
124
|
+
await strict_1.default.rejects(client.activateSession("dsh-session-2"), /正在生成回复/);
|
|
125
|
+
socket.state.busy = false;
|
|
126
|
+
await client.activateSession("dsh-session-2");
|
|
127
|
+
strict_1.default.equal(await client.activeSession(), "dsh-session-2");
|
|
128
|
+
await strict_1.default.rejects(client.activateSession("不存在的会话"), /未找到可切换的会话/);
|
|
129
|
+
}
|
|
130
|
+
finally {
|
|
131
|
+
client.close();
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
(0, node_test_1.default)("DSH 新建允许桌面复用已确认的空白会话,拒绝复用历史会话", async () => {
|
|
135
|
+
let socket;
|
|
136
|
+
const client = new cdp_client_1.DshCdpClient({
|
|
137
|
+
timeoutMs: 100,
|
|
138
|
+
fetchImpl: async () => new Response(JSON.stringify([{ type: "page", url: "dsh-app://app/", webSocketDebuggerUrl: "ws://127.0.0.1:9226/devtools/page/dsh" }])),
|
|
139
|
+
webSocketFactory: () => (socket = new FakeWebSocket()),
|
|
140
|
+
});
|
|
141
|
+
await client.connect();
|
|
142
|
+
await strict_1.default.rejects(client.createSession(), /新会话状态未确认/);
|
|
143
|
+
socket.state.blank = true;
|
|
144
|
+
socket.state.turnCount = 0;
|
|
145
|
+
socket.state.conversationText = "探索未至之境";
|
|
146
|
+
strict_1.default.equal(await client.createSession(), "dsh-session-1");
|
|
147
|
+
client.close();
|
|
148
|
+
});
|
|
@@ -56,6 +56,43 @@ const event = (seq, type, data, time = "2026-10-21T02:00:00.000Z") => ({ seq, ty
|
|
|
56
56
|
await f.close();
|
|
57
57
|
}
|
|
58
58
|
});
|
|
59
|
+
(0, node_test_1.default)("DSH 日志返回工作目录、事件序号和本轮 present 文件", async () => {
|
|
60
|
+
const f = await fixture();
|
|
61
|
+
try {
|
|
62
|
+
await f.session("delivery", [
|
|
63
|
+
event(0, "user/message", { content: [{ type: "text", text: "旧请求" }] }),
|
|
64
|
+
event(1, "deliverables/presented", { turn: 1, callId: "present-1", files: [{ path: "report.txt" }] }),
|
|
65
|
+
]);
|
|
66
|
+
const state = await f.provider.readDeliveryState("session-delivery");
|
|
67
|
+
strict_1.default.deepEqual(state, { cwd: "C:\\project", sequence: 1, presented: [{ sequence: 1, paths: ["report.txt"] }] });
|
|
68
|
+
}
|
|
69
|
+
finally {
|
|
70
|
+
await f.close();
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
(0, node_test_1.default)("DSH 文件任务的作业生命周期事件不阻断附件与正文读取,未知事件仍拒绝交付", async () => {
|
|
74
|
+
const f = await fixture();
|
|
75
|
+
try {
|
|
76
|
+
const job = { jobId: "pwsh-test", owner: "session-jobs", kind: "pwsh", label: "不应回传的命令", startedAt: 1792512000000 };
|
|
77
|
+
const events = [
|
|
78
|
+
event(0, "user/message", { content: [{ type: "text", text: "生成文件" }] }),
|
|
79
|
+
event(1, "job/registered", job),
|
|
80
|
+
event(2, "job/settled", { ...job, finishedAt: 1792512001000, status: "completed", cause: "producer", producerReported: true, detail: "exit code: 0" }),
|
|
81
|
+
event(3, "deliverables/presented", { turn: 1, callId: "present-test", files: [{ path: "report.txt" }] }),
|
|
82
|
+
event(4, "assistant/message", { message: { content: [{ type: "text", text: "文件已生成" }] } }),
|
|
83
|
+
];
|
|
84
|
+
await f.session("jobs", events);
|
|
85
|
+
strict_1.default.deepEqual(await f.provider.readDeliveryState("session-jobs"), { cwd: "C:\\project", sequence: 4, presented: [{ sequence: 3, paths: ["report.txt"] }] });
|
|
86
|
+
const body = await f.provider.readSession({ sessionId: "session-jobs", limit: 10 });
|
|
87
|
+
strict_1.default.equal(body.supported && body.complete, true);
|
|
88
|
+
strict_1.default.deepEqual(body.supported && body.turns.map(turn => turn.text), ["生成文件", "文件已生成"]);
|
|
89
|
+
await f.session("jobs", [...events, event(5, "job/future-event", {})]);
|
|
90
|
+
await strict_1.default.rejects(f.provider.readDeliveryState("session-jobs"), /未知且不可安全忽略.*job\/future-event/);
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
await f.close();
|
|
94
|
+
}
|
|
95
|
+
});
|
|
59
96
|
(0, node_test_1.default)("DSH 遇到未知事件、未知代际或越界游标时显式报告不完整/拒绝", async () => {
|
|
60
97
|
const f = await fixture();
|
|
61
98
|
try {
|
|
@@ -231,7 +231,7 @@ const feishu_1 = require("../src-ts/plugins/feishu");
|
|
|
231
231
|
const manifest = JSON.parse(response.body);
|
|
232
232
|
strict_1.default.deepEqual(manifest.commands.map((command) => command.name), ["status", "list", "agents", "configure", "bind", "unbind"]);
|
|
233
233
|
strict_1.default.equal(manifest.protocolVersion, 1);
|
|
234
|
-
strict_1.default.equal(manifest.version,
|
|
234
|
+
strict_1.default.equal(manifest.version, plugin.manifest.version);
|
|
235
235
|
const run = async (...argv) => {
|
|
236
236
|
response.statusCode = 0;
|
|
237
237
|
await postCommands(node_stream_1.Readable.from([JSON.stringify({ protocolVersion: 1, argv })]), response);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
7
|
+
const node_test_1 = __importDefault(require("node:test"));
|
|
8
|
+
const http_agent_1 = require("../src-ts/http-agent");
|
|
9
|
+
(0, node_test_1.default)("HTTP 验收 Agent 解析 OpenAI 兼容响应", async () => {
|
|
10
|
+
const original = globalThis.fetch;
|
|
11
|
+
globalThis.fetch = (async () => new Response(JSON.stringify({ choices: [{ message: { content: "reply" } }] }), { status: 200 }));
|
|
12
|
+
try {
|
|
13
|
+
strict_1.default.deepEqual(await new http_agent_1.HttpAgent("http://127.0.0.1:1").send({ task: "hi" }), { text: "reply" });
|
|
14
|
+
}
|
|
15
|
+
finally {
|
|
16
|
+
globalThis.fetch = original;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
@@ -48,7 +48,7 @@ const node_util_1 = require("node:util");
|
|
|
48
48
|
strict_1.default.match(setup, /Get-Command npm\.cmd/);
|
|
49
49
|
strict_1.default.match(setup, /\$npmCommand\.Source prefix --global/);
|
|
50
50
|
strict_1.default.match(setup, /@\(\$nodeDirectory, \$npmDirectory, \$npmPrefix\)/);
|
|
51
|
-
strict_1.default.match(setup, /mu-agent-bridge
|
|
51
|
+
strict_1.default.match(setup, /mu-agent-bridge@\{1\} --engine-strict/);
|
|
52
52
|
strict_1.default.match(setup, /--prefer-online/);
|
|
53
53
|
strict_1.default.match(setup, /npm 安装遇到版本尚未同步或文件占用.*重试/);
|
|
54
54
|
strict_1.default.doesNotMatch(setup, /mu-agent-bridge@\d+\.\d+\.\d+/);
|