@downcity/agent 1.1.152 → 1.1.157

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 (64) hide show
  1. package/bin/agent/local/services/AgentAssemblyService.d.ts.map +1 -1
  2. package/bin/agent/local/services/AgentAssemblyService.js +1 -0
  3. package/bin/agent/local/services/AgentAssemblyService.js.map +1 -1
  4. package/bin/executor/composer/system/default/assets/plugin.prompt.d.ts +1 -1
  5. package/bin/executor/composer/system/default/assets/plugin.prompt.d.ts.map +1 -1
  6. package/bin/executor/composer/system/default/assets/plugin.prompt.js +1 -1
  7. package/bin/executor/composer/system/default/assets/plugin.prompt.js.map +1 -1
  8. package/bin/executor/tools/plugin/PluginToolBridge.d.ts +6 -2
  9. package/bin/executor/tools/plugin/PluginToolBridge.d.ts.map +1 -1
  10. package/bin/executor/tools/plugin/PluginToolBridge.js +71 -17
  11. package/bin/executor/tools/plugin/PluginToolBridge.js.map +1 -1
  12. package/bin/executor/tools/plugin/PluginToolDefinition.d.ts +11 -0
  13. package/bin/executor/tools/plugin/PluginToolDefinition.d.ts.map +1 -1
  14. package/bin/executor/tools/plugin/PluginToolDefinition.js +12 -3
  15. package/bin/executor/tools/plugin/PluginToolDefinition.js.map +1 -1
  16. package/bin/executor/tools/plugin/PluginToolSchemas.d.ts +4 -0
  17. package/bin/executor/tools/plugin/PluginToolSchemas.d.ts.map +1 -1
  18. package/bin/executor/tools/plugin/PluginToolSchemas.js +11 -1
  19. package/bin/executor/tools/plugin/PluginToolSchemas.js.map +1 -1
  20. package/bin/executor/tools/plugin/types/PluginTool.d.ts +37 -0
  21. package/bin/executor/tools/plugin/types/PluginTool.d.ts.map +1 -1
  22. package/bin/index.d.ts +3 -1
  23. package/bin/index.d.ts.map +1 -1
  24. package/bin/index.js +1 -0
  25. package/bin/index.js.map +1 -1
  26. package/bin/plugin/core/PluginActionFactory.d.ts +99 -0
  27. package/bin/plugin/core/PluginActionFactory.d.ts.map +1 -0
  28. package/bin/plugin/core/PluginActionFactory.js +59 -0
  29. package/bin/plugin/core/PluginActionFactory.js.map +1 -0
  30. package/bin/plugin/core/PluginActionRunner.d.ts.map +1 -1
  31. package/bin/plugin/core/PluginActionRunner.js +14 -1
  32. package/bin/plugin/core/PluginActionRunner.js.map +1 -1
  33. package/bin/plugin/core/PluginLocalExecution.d.ts.map +1 -1
  34. package/bin/plugin/core/PluginLocalExecution.js +15 -1
  35. package/bin/plugin/core/PluginLocalExecution.js.map +1 -1
  36. package/bin/plugin/core/PluginRegistry.d.ts +18 -1
  37. package/bin/plugin/core/PluginRegistry.d.ts.map +1 -1
  38. package/bin/plugin/core/PluginRegistry.js +74 -1
  39. package/bin/plugin/core/PluginRegistry.js.map +1 -1
  40. package/bin/plugin/types/Plugin.d.ts +2 -2
  41. package/bin/plugin/types/Plugin.d.ts.map +1 -1
  42. package/bin/types/plugin/PluginAction.d.ts +40 -2
  43. package/bin/types/plugin/PluginAction.d.ts.map +1 -1
  44. package/bin/types/plugin/PluginRuntime.d.ts +44 -0
  45. package/bin/types/plugin/PluginRuntime.d.ts.map +1 -1
  46. package/package.json +3 -3
  47. package/scripts/image-plugin-job.test.mjs +308 -32
  48. package/scripts/plugin-tool-bridge.test.mjs +199 -0
  49. package/src/agent/local/services/AgentAssemblyService.ts +1 -0
  50. package/src/executor/composer/system/default/assets/plugin.prompt.ts +1 -1
  51. package/src/executor/composer/system/default/assets/plugin.prompt.ts.txt +3 -2
  52. package/src/executor/tools/plugin/PluginToolBridge.ts +84 -18
  53. package/src/executor/tools/plugin/PluginToolDefinition.ts +25 -4
  54. package/src/executor/tools/plugin/PluginToolSchemas.ts +12 -1
  55. package/src/executor/tools/plugin/types/PluginTool.ts +40 -0
  56. package/src/index.ts +11 -0
  57. package/src/plugin/core/PluginActionFactory.ts +185 -0
  58. package/src/plugin/core/PluginActionRunner.ts +14 -1
  59. package/src/plugin/core/PluginLocalExecution.ts +15 -1
  60. package/src/plugin/core/PluginRegistry.ts +89 -1
  61. package/src/plugin/types/Plugin.ts +5 -0
  62. package/src/types/plugin/PluginAction.ts +43 -2
  63. package/src/types/plugin/PluginRuntime.ts +44 -0
  64. package/tsconfig.tsbuildinfo +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"PluginRuntime.d.ts","sourceRoot":"","sources":["../../../src/types/plugin/PluginRuntime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PluginRuntime.d.ts","sourceRoot":"","sources":["../../../src/types/plugin/PluginRuntime.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@downcity/agent",
3
- "version": "1.1.152",
3
+ "version": "1.1.157",
4
4
  "type": "module",
5
5
  "description": "Downcity Agent 运行时 — 单 Agent 执行壳与本机 RPC 能力",
6
6
  "main": "./bin/index.js",
@@ -17,8 +17,8 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "@ai-sdk/openai-compatible": "^2.0.48",
20
- "@downcity/shell": "^0.1.30",
21
- "@downcity/type": "0.1.64",
20
+ "@downcity/shell": "^0.1.33",
21
+ "@downcity/type": "0.1.67",
22
22
  "@larksuiteoapi/node-sdk": "^1.66.0",
23
23
  "ai": "^6.0.193",
24
24
  "commander": "^15.0.0",
@@ -1,16 +1,20 @@
1
1
  /**
2
- * @file 验证 ImagePlugin 对 Agent 保持直接生图体验。
2
+ * @file 验证 ImagePlugin 的两步式图片任务协议。
3
3
  *
4
4
  * 关键点(中文)
5
- * - Agent 只调用 `generate` action。
6
- * - 插件内部调用注入的 image_create / image_result 任务函数并轮询。
7
- * - 成功后返回 UIMessage,后续由 plugin bridge 落盘 file parts。
5
+ * - 插件只暴露 image_create / image_result 两个任务 action。
6
+ * - image_result 只读取一次当前状态,不在 plugin 层等待终态。
7
+ * - 成功图片仍以 UIMessage 返回,后续由 plugin bridge 落盘 file parts。
8
8
  */
9
9
 
10
10
  import test from "node:test";
11
11
  import assert from "node:assert/strict";
12
+ import fs from "node:fs/promises";
13
+ import os from "node:os";
14
+ import path from "node:path";
12
15
 
13
- import { ImagePlugin } from "../bin/index.js";
16
+ import { ImagePlugin } from "../../plugins/bin/index.js";
17
+ import { createAgentPluginRegistry } from "../bin/agent/local/AgentPluginFactory.js";
14
18
 
15
19
  function create_image_message() {
16
20
  return {
@@ -27,54 +31,326 @@ function create_image_message() {
27
31
  };
28
32
  }
29
33
 
30
- test("ImagePlugin generate creates and polls image jobs", async () => {
34
+ function create_context(rootPath = process.cwd()) {
35
+ return { rootPath };
36
+ }
37
+
38
+ function create_registry(plugin, rootPath = process.cwd()) {
39
+ return createAgentPluginRegistry({
40
+ plugins: [plugin],
41
+ get_context: () => create_context(rootPath),
42
+ });
43
+ }
44
+
45
+ test("ImagePlugin exposes only job-style image actions", async () => {
46
+ const plugin = new ImagePlugin({
47
+ image_create: () => ({ job_id: "img_1", status: "queued", poll_after_ms: 1 }),
48
+ image_result: () => ({ job_id: "img_1", status: "queued", poll_after_ms: 1 }),
49
+ });
50
+
51
+ assert.equal("image_create" in plugin.actions, true);
52
+ assert.equal("image_result" in plugin.actions, true);
53
+ assert.equal("models" in plugin.actions, true);
54
+ assert.equal("generate" in plugin.actions, false);
55
+ });
56
+
57
+ test("ImagePlugin image_create returns image job", async () => {
58
+ const plugin = new ImagePlugin({
59
+ image_create: (input) => ({
60
+ job_id: "img_1",
61
+ status: "queued",
62
+ poll_after_ms: 1,
63
+ metadata: { prompt: input.prompt },
64
+ }),
65
+ image_result: () => ({ job_id: "img_1", status: "queued", poll_after_ms: 1 }),
66
+ });
67
+
68
+ const result = await plugin.actions.image_create.execute({
69
+ context: create_context(),
70
+ payload: { prompt: "draw" },
71
+ pluginName: "image",
72
+ actionName: "image_create",
73
+ });
74
+
75
+ assert.equal(result.success, true);
76
+ assert.equal(result.data.job_id, "img_1");
77
+ assert.equal(result.data.status, "queued");
78
+ });
79
+
80
+ test("ImagePlugin models lists image-capable models", async () => {
81
+ const plugin = new ImagePlugin({
82
+ list_models: () => [
83
+ {
84
+ id: "text_1",
85
+ name: "Text",
86
+ description: "text only",
87
+ modalities: ["text"],
88
+ tags: ["general"],
89
+ meta: {},
90
+ },
91
+ {
92
+ id: "image_1",
93
+ name: "Image",
94
+ description: "image model",
95
+ modalities: ["image"],
96
+ tags: ["creative"],
97
+ meta: { provider: "test" },
98
+ default_modalities: ["image"],
99
+ },
100
+ ],
101
+ image_create: () => ({ job_id: "img_1", status: "queued", poll_after_ms: 1 }),
102
+ image_result: () => ({ job_id: "img_1", status: "queued", poll_after_ms: 1 }),
103
+ });
104
+
105
+ const result = await plugin.actions.models.execute({
106
+ context: create_context(),
107
+ payload: {},
108
+ pluginName: "image",
109
+ actionName: "models",
110
+ });
111
+
112
+ assert.equal(result.success, true);
113
+ assert.equal(result.data.default_model_id, "image_1");
114
+ assert.deepEqual(result.data.items.map((item) => item.id), ["image_1"]);
115
+ assert.equal(result.data.items[0].meta.provider, "test");
116
+ });
117
+
118
+ test("ImagePlugin exposes action metadata through plugin registry", async () => {
119
+ const plugin = new ImagePlugin({
120
+ image_create: () => ({ job_id: "img_1", status: "queued", poll_after_ms: 1 }),
121
+ image_result: () => ({ job_id: "img_1", status: "queued", poll_after_ms: 1 }),
122
+ });
123
+ const registry = create_registry(plugin);
124
+
125
+ const metadata = registry.read({
126
+ plugin: "image",
127
+ action: "image_create",
128
+ });
129
+
130
+ assert.equal(metadata.name, "image");
131
+ assert.equal(metadata.actions.length, 1);
132
+ assert.equal(metadata.actions[0].name, "image_create");
133
+ assert.equal(metadata.actions[0].has_input_schema, true);
134
+ assert.match(metadata.actions[0].description, /Create an async image job/);
135
+ assert.equal(metadata.actions[0].examples[0].payload.prompt.includes("rainy city"), true);
136
+ });
137
+
138
+ test("ImagePlugin image_result reads pending state once", async () => {
31
139
  const calls = [];
32
- const message = create_image_message();
33
140
  const plugin = new ImagePlugin({
34
- min_poll_interval_ms: 1,
35
- image_create: (input) => {
36
- calls.push(["create", input.prompt]);
37
- return { job_id: "img_1", status: "queued", poll_after_ms: 1 };
38
- },
141
+ image_create: () => ({ job_id: "img_1", status: "queued", poll_after_ms: 1 }),
39
142
  image_result: (input) => {
40
- calls.push(["result", input.job_id]);
41
- return calls.length === 2
42
- ? { job_id: input.job_id, status: "running", poll_after_ms: 1 }
43
- : { job_id: input.job_id, status: "succeeded", result: message, poll_after_ms: 1 };
143
+ calls.push(input.job_id);
144
+ return {
145
+ job_id: input.job_id,
146
+ status: "running",
147
+ message: "upstream pending",
148
+ poll_after_ms: 1,
149
+ };
44
150
  },
45
151
  });
46
152
 
47
- const result = await plugin.actions.generate.execute({
48
- context: {},
49
- payload: { prompt: "draw" },
153
+ const result = await plugin.actions.image_result.execute({
154
+ context: create_context(),
155
+ payload: { job_id: "img_1" },
156
+ pluginName: "image",
157
+ actionName: "image_result",
158
+ });
159
+
160
+ assert.equal(result.success, true);
161
+ assert.equal(result.data.job_id, "img_1");
162
+ assert.equal(result.data.status, "running");
163
+ assert.equal(result.data.message, "upstream pending");
164
+ assert.deepEqual(calls, ["img_1"]);
165
+ });
166
+
167
+ test("ImagePlugin image_result returns final message when succeeded", async () => {
168
+ const message = create_image_message();
169
+ const plugin = new ImagePlugin({
170
+ image_create: () => ({ job_id: "img_1", status: "queued", poll_after_ms: 1 }),
171
+ image_result: (input) => ({
172
+ job_id: input.job_id,
173
+ status: "succeeded",
174
+ result: message,
175
+ poll_after_ms: 1,
176
+ }),
177
+ });
178
+
179
+ const result = await plugin.actions.image_result.execute({
180
+ context: create_context(),
181
+ payload: { job_id: "img_1" },
50
182
  pluginName: "image",
51
- actionName: "generate",
183
+ actionName: "image_result",
52
184
  });
53
185
 
54
186
  assert.equal(result.success, true);
55
187
  assert.equal(result.data.role, "assistant");
56
188
  assert.equal(result.data.parts[0].type, "file");
57
- assert.deepEqual(calls, [
58
- ["create", "draw"],
59
- ["result", "img_1"],
60
- ["result", "img_1"],
61
- ]);
62
189
  });
63
190
 
64
- test("ImagePlugin generate reports image failure", async () => {
191
+ test("ImagePlugin image_result reports failed terminal job", async () => {
65
192
  const plugin = new ImagePlugin({
66
- min_poll_interval_ms: 1,
67
193
  image_create: () => ({ job_id: "img_1", status: "queued", poll_after_ms: 1 }),
68
- image_result: () => ({ job_id: "img_1", status: "failed", error: "provider failed", poll_after_ms: 1 }),
194
+ image_result: (input) => ({
195
+ job_id: input.job_id,
196
+ status: "failed",
197
+ error: "provider failed",
198
+ poll_after_ms: 1,
199
+ }),
69
200
  });
70
201
 
71
- const result = await plugin.actions.generate.execute({
72
- context: {},
73
- payload: { prompt: "draw" },
202
+ const result = await plugin.actions.image_result.execute({
203
+ context: create_context(),
204
+ payload: { job_id: "img_1" },
74
205
  pluginName: "image",
75
- actionName: "generate",
206
+ actionName: "image_result",
76
207
  });
77
208
 
78
209
  assert.equal(result.success, false);
79
210
  assert.match(result.error, /provider failed/);
211
+ assert.equal(result.data.job_id, "img_1");
212
+ });
213
+
214
+ test("ImagePlugin image_result payload is schema validated by registry", async () => {
215
+ const plugin = new ImagePlugin({
216
+ image_create: () => ({ job_id: "img_1", status: "queued", poll_after_ms: 1 }),
217
+ image_result: () => ({ job_id: "img_1", status: "queued", poll_after_ms: 1 }),
218
+ });
219
+ const registry = create_registry(plugin);
220
+
221
+ const result = await registry.runAction({
222
+ plugin: "image",
223
+ action: "image_result",
224
+ payload: {},
225
+ });
226
+
227
+ assert.equal(result.success, false);
228
+ assert.match(result.error, /Invalid payload/);
229
+ });
230
+
231
+ test("ImagePlugin image_create converts local content image paths", async () => {
232
+ const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "downcity-image-plugin-content-"));
233
+ try {
234
+ await fs.writeFile(path.join(tempDir, "input.png"), Buffer.from("png"));
235
+ let captured_input;
236
+ const plugin = new ImagePlugin({
237
+ image_create: (input) => {
238
+ captured_input = input;
239
+ return { job_id: "img_1", status: "queued", poll_after_ms: 1 };
240
+ },
241
+ image_result: () => ({ job_id: "img_1", status: "queued", poll_after_ms: 1 }),
242
+ });
243
+
244
+ const result = await plugin.actions.image_create.execute({
245
+ context: create_context(tempDir),
246
+ payload: {
247
+ content: [
248
+ { type: "text", text: "change background" },
249
+ { type: "image", url: "./input.png" },
250
+ ],
251
+ },
252
+ pluginName: "image",
253
+ actionName: "image_create",
254
+ });
255
+
256
+ assert.equal(result.success, true);
257
+ assert.equal(captured_input.messages[0].content[0].text, "change background");
258
+ assert.match(captured_input.messages[0].content[1].data_url, /^data:image\/png;base64,/);
259
+ assert.equal(captured_input.messages[0].content[1].media_type, "image/png");
260
+ assert.equal("content" in captured_input, false);
261
+ assert.equal("prompt" in captured_input, false);
262
+ } finally {
263
+ await fs.rm(tempDir, { recursive: true, force: true });
264
+ }
265
+ });
266
+
267
+ test("ImagePlugin image_create uses content instead of prompt when both exist", async () => {
268
+ let captured_input;
269
+ const plugin = new ImagePlugin({
270
+ image_create: (input) => {
271
+ captured_input = input;
272
+ return { job_id: "img_1", status: "queued", poll_after_ms: 1 };
273
+ },
274
+ image_result: () => ({ job_id: "img_1", status: "queued", poll_after_ms: 1 }),
275
+ });
276
+
277
+ const result = await plugin.actions.image_create.execute({
278
+ context: create_context(),
279
+ payload: {
280
+ prompt: "ignore this prompt",
281
+ content: [{ type: "text", text: "use this content" }],
282
+ },
283
+ pluginName: "image",
284
+ actionName: "image_create",
285
+ });
286
+
287
+ assert.equal(result.success, true);
288
+ assert.equal(captured_input.messages[0].content[0].text, "use this content");
289
+ assert.equal("prompt" in captured_input, false);
290
+ });
291
+
292
+ test("ImagePlugin image_create keeps remote content image URLs", async () => {
293
+ let captured_input;
294
+ const plugin = new ImagePlugin({
295
+ image_create: (input) => {
296
+ captured_input = input;
297
+ return { job_id: "img_1", status: "queued", poll_after_ms: 1 };
298
+ },
299
+ image_result: () => ({ job_id: "img_1", status: "queued", poll_after_ms: 1 }),
300
+ });
301
+
302
+ const result = await plugin.actions.image_create.execute({
303
+ context: create_context(),
304
+ payload: {
305
+ content: [
306
+ { type: "text", text: "use this style" },
307
+ { type: "image", url: "https://example.com/input.webp", media_type: "image/webp" },
308
+ ],
309
+ },
310
+ pluginName: "image",
311
+ actionName: "image_create",
312
+ });
313
+
314
+ assert.equal(result.success, true);
315
+ assert.equal(captured_input.messages[0].content[1].url, "https://example.com/input.webp");
316
+ assert.equal(captured_input.messages[0].content[1].media_type, "image/webp");
317
+ });
318
+
319
+ test("ImagePlugin image_create rejects legacy messages and data URLs", async () => {
320
+ const plugin = new ImagePlugin({
321
+ image_create: () => ({ job_id: "img_1", status: "queued", poll_after_ms: 1 }),
322
+ image_result: () => ({ job_id: "img_1", status: "queued", poll_after_ms: 1 }),
323
+ });
324
+
325
+ const messages_result = await plugin.actions.image_create.execute({
326
+ context: create_context(),
327
+ payload: {
328
+ messages: [
329
+ {
330
+ role: "user",
331
+ content: [{ type: "text", text: "legacy" }],
332
+ },
333
+ ],
334
+ },
335
+ pluginName: "image",
336
+ actionName: "image_create",
337
+ });
338
+
339
+ assert.equal(messages_result.success, false);
340
+ assert.match(messages_result.error, /messages is not supported/);
341
+
342
+ const data_url_result = await plugin.actions.image_create.execute({
343
+ context: create_context(),
344
+ payload: {
345
+ content: [
346
+ { type: "text", text: "edit this" },
347
+ { type: "image", url: "data:image/png;base64,cG5n" },
348
+ ],
349
+ },
350
+ pluginName: "image",
351
+ actionName: "image_create",
352
+ });
353
+
354
+ assert.equal(data_url_result.success, false);
355
+ assert.match(data_url_result.error, /does not accept data URLs/);
80
356
  });
@@ -0,0 +1,199 @@
1
+ /**
2
+ * @file 验证 plugin tool bridge 会把生成文件摘要为可打开路径。
3
+ *
4
+ * 关键点(中文)
5
+ * - assistant message 仍然使用 `resources://` URL,避免历史暴露本机路径。
6
+ * - tool result 额外返回本机绝对路径,便于模型与用户明确知道文件位置。
7
+ */
8
+
9
+ import test from "node:test";
10
+ import assert from "node:assert/strict";
11
+ import os from "node:os";
12
+ import path from "node:path";
13
+ import fs from "node:fs/promises";
14
+
15
+ import {
16
+ invokePluginCallTool,
17
+ invokePluginReadTool,
18
+ setPluginToolRuntime,
19
+ } from "../bin/executor/tools/plugin/PluginToolBridge.js";
20
+ import { withSessionRunScope } from "../bin/executor/SessionRunScope.js";
21
+ import { createAction, createPlugin } from "../bin/plugin/core/PluginActionFactory.js";
22
+ import { createAgentPluginRegistry } from "../bin/agent/local/AgentPluginFactory.js";
23
+ import { z } from "zod";
24
+
25
+ function create_run_context(project_root) {
26
+ return {
27
+ sessionId: "session_test",
28
+ projectRoot: project_root,
29
+ injectedUserMessages: [],
30
+ deferredPersistedUserMessages: [],
31
+ pendingAssistantFileParts: [],
32
+ };
33
+ }
34
+
35
+ test("invokePluginCallTool returns absolute paths for materialized file parts", async () => {
36
+ const project_root = await fs.mkdtemp(
37
+ path.join(os.tmpdir(), "downcity-agent-plugin-tool-files-"),
38
+ );
39
+ const bytes = Buffer.from("png-bytes-for-plugin-tool", "utf8");
40
+
41
+ setPluginToolRuntime({
42
+ list: () => [],
43
+ read: () => ({ plugins: [] }),
44
+ availability: async () => ({ enabled: true, available: true, reasons: [] }),
45
+ runAction: async () => ({
46
+ success: true,
47
+ message: "image generated",
48
+ data: {
49
+ id: "msg_image_test",
50
+ role: "assistant",
51
+ parts: [
52
+ {
53
+ type: "file",
54
+ mediaType: "image/png",
55
+ filename: "image.png",
56
+ url: `data:image/png;base64,${bytes.toString("base64")}`,
57
+ },
58
+ ],
59
+ },
60
+ }),
61
+ pipeline: async (_, value) => value,
62
+ guard: async () => {},
63
+ effect: async () => {},
64
+ resolve: async () => {
65
+ throw new Error("not implemented");
66
+ },
67
+ });
68
+
69
+ const run_context = create_run_context(project_root);
70
+ const result = await withSessionRunScope({ runContext: run_context }, () =>
71
+ invokePluginCallTool({
72
+ plugin: "image",
73
+ action: "image_result",
74
+ payload: { job_id: "img_1" },
75
+ }),
76
+ );
77
+
78
+ assert.equal(result.success, true);
79
+ assert.equal(result.assistant_file_count, 1);
80
+ assert.equal(result.files?.length, 1);
81
+ assert.match(result.files[0].url, /^resources:\/\/\.downcity\/resources\//);
82
+ assert.equal(path.isAbsolute(result.files[0].path), true);
83
+ assert.equal(
84
+ path.dirname(result.files[0].path),
85
+ path.join(project_root, ".downcity", "resources"),
86
+ );
87
+ assert.deepEqual(await fs.readFile(result.files[0].path), bytes);
88
+ assert.equal("data" in result, false);
89
+
90
+ const pending_parts = run_context.pendingAssistantFileParts;
91
+ assert.equal(pending_parts.length, 1);
92
+ assert.equal(pending_parts[0].url, result.files[0].url);
93
+ });
94
+
95
+ test("invokePluginReadTool returns plugin action metadata", async () => {
96
+ setPluginToolRuntime({
97
+ list: () => [],
98
+ read: () => ({
99
+ name: "image",
100
+ title: "Image",
101
+ description: "Create images",
102
+ actions: [
103
+ {
104
+ name: "image_create",
105
+ description: "Create image job",
106
+ has_input_schema: true,
107
+ input_schema: {
108
+ type: "object",
109
+ properties: {
110
+ prompt: { type: "string" },
111
+ },
112
+ },
113
+ examples: [
114
+ {
115
+ title: "Text-only image",
116
+ payload: { prompt: "draw" },
117
+ },
118
+ ],
119
+ allow_when_disabled: false,
120
+ has_command: false,
121
+ has_api: false,
122
+ },
123
+ ],
124
+ }),
125
+ availability: async () => ({ enabled: true, available: true, reasons: [] }),
126
+ runAction: async () => ({ success: false, error: "not used" }),
127
+ pipeline: async (_, value) => value,
128
+ guard: async () => {},
129
+ effect: async () => {},
130
+ resolve: async () => {
131
+ throw new Error("not implemented");
132
+ },
133
+ });
134
+
135
+ const result = await invokePluginReadTool({
136
+ plugin: "image",
137
+ action: "image_create",
138
+ });
139
+
140
+ assert.equal(result.success, true);
141
+ assert.equal(result.data.name, "image");
142
+ assert.equal(result.data.actions[0].name, "image_create");
143
+ assert.equal(result.data.actions[0].has_input_schema, true);
144
+ assert.equal(result.data.actions[0].examples[0].payload.prompt, "draw");
145
+ });
146
+
147
+ test("PluginRegistry validates action payload with metadata schema", async () => {
148
+ const plugin = createPlugin({
149
+ name: "demo",
150
+ title: "Demo",
151
+ description: "Demo plugin",
152
+ actions: {
153
+ echo: createAction({
154
+ description: "Echo text",
155
+ input_schema: {
156
+ zod: z.object({
157
+ text: z.string(),
158
+ }),
159
+ json_schema: {
160
+ type: "object",
161
+ required: ["text"],
162
+ properties: {
163
+ text: { type: "string" },
164
+ },
165
+ },
166
+ },
167
+ execute: async ({ input }) => ({
168
+ success: true,
169
+ data: { text: input.text },
170
+ message: "echoed",
171
+ }),
172
+ }),
173
+ },
174
+ });
175
+ const registry = createAgentPluginRegistry({
176
+ plugins: [plugin],
177
+ get_context: () => ({ rootPath: process.cwd() }),
178
+ });
179
+
180
+ const metadata = registry.read({ plugin: "demo", action: "echo" });
181
+ assert.equal(metadata.actions[0].description, "Echo text");
182
+ assert.equal(metadata.actions[0].has_input_schema, true);
183
+
184
+ const invalid = await registry.runAction({
185
+ plugin: "demo",
186
+ action: "echo",
187
+ payload: {},
188
+ });
189
+ assert.equal(invalid.success, false);
190
+ assert.match(invalid.error, /Invalid payload/);
191
+
192
+ const valid = await registry.runAction({
193
+ plugin: "demo",
194
+ action: "echo",
195
+ payload: { text: "hello" },
196
+ });
197
+ assert.equal(valid.success, true);
198
+ assert.equal(valid.data.text, "hello");
199
+ });
@@ -184,6 +184,7 @@ export class AgentAssemblyService {
184
184
  });
185
185
  const plugins = plugin_registry;
186
186
  if (this.should_register_plugin_call_tool(plugin_instances)) {
187
+ tools.plugin_read = tools.plugin_read || plugin_tools.plugin_read;
187
188
  tools.plugin_call = tools.plugin_call || plugin_tools.plugin_call;
188
189
  }
189
190
  const resolve_session_model = this.resolve_session_model;
@@ -4,6 +4,6 @@
4
4
  */
5
5
 
6
6
  // Source: src/executor/composer/system/default/assets/plugin.prompt.ts.txt
7
- const TEXT_MODULE_CONTENT = "# Plugin State\n\n你正在一个基于 plugin 的执行环境中工作。\n\n## Plugin 调用规则\n\n- 当你需要使用 plugin 能力时,优先通过可用的 tool 调用 plugin action。\n- 若当前工具集中存在 `plugin_call`,使用 `plugin_call({ plugin, action, payload })` 触发对应 plugin action。\n- `plugin_call.plugin` 是 plugin 名称,例如 `skill`、`task`、`memory`、`contact`。\n- `plugin_call.action` 是 action 名称,例如 `list`、`lookup`、`create`、`run`。\n- `plugin_call.payload` 是结构化 JSON payload;没有参数时传 `{}`。\n- ActionSchedule 是 Agent 内部用于延迟执行 plugin action 的能力,不是独立 plugin。\n\n## 可用 plugin 概览\n\n- 当前内建托管 plugin:`shell` / `chat` / `task` / `memory` / `contact`。\n- 当前内建本地 plugin:`auth` / `skill`。\n\n具体 plugin 能力以该 plugin action system 提示为准。\n";
7
+ const TEXT_MODULE_CONTENT = "# Plugin State\n\n你正在一个基于 plugin 的执行环境中工作。\n\n## Plugin 调用规则\n\n- 当你需要使用 plugin 能力时,优先通过可用的 tool 调用 plugin action。\n- 若当前工具集中存在 `plugin_read`,在不确定 plugin action、参数 schema 或示例时,先使用 `plugin_read({ plugin, action? })` 读取 metadata。\n- 若当前工具集中存在 `plugin_call`,使用 `plugin_call({ plugin, action, payload })` 触发对应 plugin action。\n- `plugin_call.plugin` 是 plugin 名称,例如 `skill`、`task`、`memory`、`contact`。\n- `plugin_call.action` 是 action 名称,例如 `list`、`lookup`、`create`、`run`。\n- `plugin_call.payload` 是结构化 JSON payload;没有参数时传 `{}`。如果 action metadata 声明了 input schema,payload 必须符合 schema。\n- ActionSchedule 是 Agent 内部用于延迟执行 plugin action 的能力,不是独立 plugin。\n\n## 可用 plugin 概览\n\n- 当前内建托管 plugin:`shell` / `chat` / `task` / `memory` / `contact`。\n- 当前内建本地 plugin:`auth` / `skill`。\n\n具体 plugin 能力以 `plugin_read` 返回的 action metadata 和该 plugin 的 system 提示为准。\n";
8
8
 
9
9
  export default TEXT_MODULE_CONTENT;
@@ -5,10 +5,11 @@
5
5
  ## Plugin 调用规则
6
6
 
7
7
  - 当你需要使用 plugin 能力时,优先通过可用的 tool 调用 plugin action。
8
+ - 若当前工具集中存在 `plugin_read`,在不确定 plugin action、参数 schema 或示例时,先使用 `plugin_read({ plugin, action? })` 读取 metadata。
8
9
  - 若当前工具集中存在 `plugin_call`,使用 `plugin_call({ plugin, action, payload })` 触发对应 plugin action。
9
10
  - `plugin_call.plugin` 是 plugin 名称,例如 `skill`、`task`、`memory`、`contact`。
10
11
  - `plugin_call.action` 是 action 名称,例如 `list`、`lookup`、`create`、`run`。
11
- - `plugin_call.payload` 是结构化 JSON payload;没有参数时传 `{}`。
12
+ - `plugin_call.payload` 是结构化 JSON payload;没有参数时传 `{}`。如果 action metadata 声明了 input schema,payload 必须符合 schema。
12
13
  - ActionSchedule 是 Agent 内部用于延迟执行 plugin action 的能力,不是独立 plugin。
13
14
 
14
15
  ## 可用 plugin 概览
@@ -16,4 +17,4 @@
16
17
  - 当前内建托管 plugin:`shell` / `chat` / `task` / `memory` / `contact`。
17
18
  - 当前内建本地 plugin:`auth` / `skill`。
18
19
 
19
- 具体 plugin 能力以该 plugin action system 提示为准。
20
+ 具体 plugin 能力以 `plugin_read` 返回的 action metadata 和该 plugin 的 system 提示为准。