@cicctencent/agent-server 0.2.27 → 0.2.30

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 (55) hide show
  1. package/dist/cjs/automation/index.d.ts +5 -0
  2. package/dist/cjs/automation/index.d.ts.map +1 -0
  3. package/dist/cjs/automation/index.js +12 -0
  4. package/dist/cjs/automation/index.js.map +1 -0
  5. package/dist/cjs/automation/node-task-library.d.ts +11 -0
  6. package/dist/cjs/automation/node-task-library.d.ts.map +1 -0
  7. package/dist/cjs/automation/node-task-library.js +46 -0
  8. package/dist/cjs/automation/node-task-library.js.map +1 -0
  9. package/dist/cjs/automation/node-task-runtime.d.ts +19 -0
  10. package/dist/cjs/automation/node-task-runtime.d.ts.map +1 -0
  11. package/dist/cjs/automation/node-task-runtime.js +237 -0
  12. package/dist/cjs/automation/node-task-runtime.js.map +1 -0
  13. package/dist/cjs/automation/node-task-validator.d.ts +3 -0
  14. package/dist/cjs/automation/node-task-validator.d.ts.map +1 -0
  15. package/dist/cjs/automation/node-task-validator.js +57 -0
  16. package/dist/cjs/automation/node-task-validator.js.map +1 -0
  17. package/dist/cjs/index.d.ts +2 -0
  18. package/dist/cjs/index.d.ts.map +1 -1
  19. package/dist/cjs/index.js +27 -20
  20. package/dist/cjs/index.js.map +1 -1
  21. package/dist/cjs/model/automation.d.ts +19 -1
  22. package/dist/cjs/model/automation.d.ts.map +1 -1
  23. package/dist/cjs/tool/tools/automation.d.ts.map +1 -1
  24. package/dist/cjs/tool/tools/automation.js +484 -12
  25. package/dist/cjs/tool/tools/automation.js.map +1 -1
  26. package/dist/cjs/types.d.ts +5 -0
  27. package/dist/cjs/types.d.ts.map +1 -1
  28. package/dist/esm/automation/index.d.ts +5 -0
  29. package/dist/esm/automation/index.d.ts.map +1 -0
  30. package/dist/esm/automation/index.js +4 -0
  31. package/dist/esm/automation/index.js.map +1 -0
  32. package/dist/esm/automation/node-task-library.d.ts +11 -0
  33. package/dist/esm/automation/node-task-library.d.ts.map +1 -0
  34. package/dist/esm/automation/node-task-library.js +41 -0
  35. package/dist/esm/automation/node-task-library.js.map +1 -0
  36. package/dist/esm/automation/node-task-runtime.d.ts +19 -0
  37. package/dist/esm/automation/node-task-runtime.d.ts.map +1 -0
  38. package/dist/esm/automation/node-task-runtime.js +199 -0
  39. package/dist/esm/automation/node-task-runtime.js.map +1 -0
  40. package/dist/esm/automation/node-task-validator.d.ts +3 -0
  41. package/dist/esm/automation/node-task-validator.d.ts.map +1 -0
  42. package/dist/esm/automation/node-task-validator.js +54 -0
  43. package/dist/esm/automation/node-task-validator.js.map +1 -0
  44. package/dist/esm/index.d.ts +2 -0
  45. package/dist/esm/index.d.ts.map +1 -1
  46. package/dist/esm/index.js +2 -0
  47. package/dist/esm/index.js.map +1 -1
  48. package/dist/esm/model/automation.d.ts +19 -1
  49. package/dist/esm/model/automation.d.ts.map +1 -1
  50. package/dist/esm/tool/tools/automation.d.ts.map +1 -1
  51. package/dist/esm/tool/tools/automation.js +484 -12
  52. package/dist/esm/tool/tools/automation.js.map +1 -1
  53. package/dist/esm/types.d.ts +5 -0
  54. package/dist/esm/types.d.ts.map +1 -1
  55. package/package.json +9 -9
@@ -1,5 +1,5 @@
1
1
  /** 自动化任务运行状态 */
2
- export type AutomationStatus = 'idle' | 'running' | 'success' | 'error';
2
+ export type AutomationStatus = 'idle' | 'running' | 'success' | 'error' | 'cancelled';
3
3
  /** 自动化定时任务实体 */
4
4
  export interface AutomationEntity {
5
5
  id: number;
@@ -16,6 +16,12 @@ export interface AutomationEntity {
16
16
  nextRunAt?: string;
17
17
  createdAt: string;
18
18
  updatedAt: string;
19
+ /** 运行时类型:prompt(Agent 指令型)| nodejs(Code 代码型) */
20
+ runtime?: 'prompt' | 'nodejs';
21
+ /** Code 型任务包 */
22
+ codePackage?: import('@cicctencent/agent-core').NodeAutomationTaskPackage;
23
+ /** 代码版本 */
24
+ version?: string;
19
25
  }
20
26
  /** 自动化任务执行记录 */
21
27
  export interface AutomationRunEntity {
@@ -30,5 +36,17 @@ export interface AutomationRunEntity {
30
36
  finishedAt: string;
31
37
  duration: number;
32
38
  sessionId: string;
39
+ /** 运行时类型 */
40
+ runtime?: string;
41
+ /** Code 型任务 stdout */
42
+ stdout?: string;
43
+ /** Code 型任务 stderr */
44
+ stderr?: string;
45
+ /** Code 型任务退出码 */
46
+ exitCode?: number;
47
+ /** Code 型任务日志 */
48
+ logs?: import('@cicctencent/agent-core').NodeAutomationLogEntry[];
49
+ /** Code 型任务产物 */
50
+ artifacts?: string[];
33
51
  }
34
52
  //# sourceMappingURL=automation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"automation.d.ts","sourceRoot":"","sources":["../../../src/model/automation.ts"],"names":[],"mappings":"AAIA,gBAAgB;AAChB,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAExE,gBAAgB;AAChB,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,gBAAgB;AAChB,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,gBAAgB,CAAC;IACzB,WAAW,EAAE,UAAU,GAAG,QAAQ,CAAC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB"}
1
+ {"version":3,"file":"automation.d.ts","sourceRoot":"","sources":["../../../src/model/automation.ts"],"names":[],"mappings":"AAIA,gBAAgB;AAChB,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,WAAW,CAAC;AAEtF,gBAAgB;AAChB,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,OAAO,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC9B,gBAAgB;IAChB,WAAW,CAAC,EAAE,OAAO,yBAAyB,EAAE,yBAAyB,CAAC;IAC1E,WAAW;IACX,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,gBAAgB;AAChB,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,gBAAgB,CAAC;IACzB,WAAW,EAAE,UAAU,GAAG,QAAQ,CAAC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sBAAsB;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sBAAsB;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kBAAkB;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB;IACjB,IAAI,CAAC,EAAE,OAAO,yBAAyB,EAAE,sBAAsB,EAAE,CAAC;IAClE,iBAAiB;IACjB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB"}
@@ -1 +1 @@
1
- {"version":3,"file":"automation.d.ts","sourceRoot":"","sources":["../../../../src/tool/tools/automation.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAI9D,wBAAgB,qBAAqB,IAAI,cAAc,EAAE,CAsJxD"}
1
+ {"version":3,"file":"automation.d.ts","sourceRoot":"","sources":["../../../../src/tool/tools/automation.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAM9D,wBAAgB,qBAAqB,IAAI,cAAc,EAAE,CAmnBxD"}
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  // ============================================================
3
- // 自动化任务工具:create_automation, list_automations, delete_automation
3
+ // 自动化任务工具:create_automation, create_code_automation,
4
+ // trial_run_automation, list_automations, delete_automation,
5
+ // stop_automation
4
6
  // ============================================================
5
7
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
8
  if (k2 === undefined) k2 = k;
@@ -38,29 +40,55 @@ var __importStar = (this && this.__importStar) || (function () {
38
40
  Object.defineProperty(exports, "__esModule", { value: true });
39
41
  exports.createAutomationTools = createAutomationTools;
40
42
  const app_stores_ts_1 = require("../../store/app-stores.js");
43
+ const index_ts_1 = require("../../automation/index.js");
41
44
  function createAutomationTools() {
42
45
  return [
43
46
  // ---- create_automation ----
44
- // 创建定时自动化任务(cron 表达式 + Agent prompt)
47
+ // 创建定时自动化任务(Prompt 型或 Code 型)
45
48
  {
46
49
  definition: {
47
50
  type: 'function',
48
51
  function: {
49
52
  name: 'create_automation',
50
- description: 'Create a scheduled automation task that runs an Agent prompt on a cron schedule. ' +
51
- 'The task will automatically trigger at the specified time and execute the prompt as a new Agent session. ' +
52
- 'Common cron examples: "0 9 * * *" (daily 9AM), "0 9 * * 1" (every Monday 9AM), "*/30 * * * *" (every 30 min). ' +
53
- 'Use this to set up recurring reports, monitoring, data sync, or any periodic Agent task.',
53
+ description: 'Create a scheduled automation task that runs on a cron schedule. ' +
54
+ 'By default creates a Prompt-type task (runs an Agent prompt). ' +
55
+ 'Set runtime="nodejs" to create a Code-type task that executes JavaScript code in a sandboxed container. ' +
56
+ 'For Code-type tasks, you must provide codePackage with entry and sourceFiles. ' +
57
+ 'Common cron examples: "0 9 * * *" (daily 9AM), "0 9 * * 1" (every Monday 9AM), "*/30 * * * *" (every 30 min).',
54
58
  parameters: {
55
59
  type: 'object',
56
60
  properties: {
57
61
  name: { type: 'string', description: 'Task name (e.g. "Daily Summary Report")' },
58
62
  description: { type: 'string', description: 'Task description (optional)' },
59
63
  schedule: { type: 'string', description: 'Cron expression (5 fields: min hour day month weekday). e.g. "0 9 * * *" for daily at 9AM' },
60
- prompt: { type: 'string', description: 'The Agent prompt to execute when the task triggers. This should be a complete instruction, e.g. "Generate a summary of today\'s key metrics and send it via email to admin@example.com"' },
64
+ prompt: { type: 'string', description: 'The Agent prompt to execute when the task triggers (for Prompt-type tasks). This should be a complete instruction, e.g. "Generate a summary of today\'s key metrics and send it via email to admin@example.com"' },
65
+ runtime: { type: 'string', enum: ['prompt', 'nodejs'], description: 'Task runtime type. "prompt" (default) runs an Agent prompt; "nodejs" runs JavaScript code in a sandboxed container.' },
66
+ codePackage: {
67
+ type: 'object',
68
+ description: 'Required for Code-type (runtime="nodejs") tasks. Contains the task code package.',
69
+ properties: {
70
+ entry: { type: 'string', description: 'Entry file name, e.g. "index.js"' },
71
+ sourceFiles: {
72
+ type: 'object',
73
+ description: 'Map of filename to file content. e.g. {"index.js": "module.exports.run = async function(ctx) { ... }"}',
74
+ },
75
+ version: { type: 'string', description: 'Code package version (default: "1.0.0")' },
76
+ dependencies: { type: 'object', description: 'npm dependencies, e.g. {"axios": "^1.0.0"}' },
77
+ requiredLibraries: { type: 'array', items: { type: 'string' }, description: 'Names of registered base libraries to inject into the task context' },
78
+ runtimeConfig: {
79
+ type: 'object',
80
+ description: 'Runtime configuration',
81
+ properties: {
82
+ timeoutMs: { type: 'number', description: 'Execution timeout in milliseconds (default: 60000)' },
83
+ memoryLimitMb: { type: 'number', description: 'Memory limit in MB' },
84
+ envKeys: { type: 'array', items: { type: 'string' }, description: 'Whitelist of environment variable keys' },
85
+ },
86
+ },
87
+ },
88
+ },
61
89
  enabled: { type: 'boolean', description: 'Whether to enable the task immediately (default: true)' },
62
90
  },
63
- required: ['name', 'schedule', 'prompt'],
91
+ required: ['name', 'schedule'],
64
92
  },
65
93
  },
66
94
  },
@@ -71,6 +99,41 @@ function createAutomationTools() {
71
99
  if (!cron.validate(schedule)) {
72
100
  return `ERROR: Invalid cron expression "${schedule}". Use 5-field format: min hour day month weekday.\nExamples: "0 9 * * *" (daily 9AM), "0 9 * * 1" (Monday 9AM), "*/30 * * * *" (every 30min)`;
73
101
  }
102
+ const runtime = args.runtime || 'prompt';
103
+ // Code 型任务必须有 codePackage
104
+ if (runtime === 'nodejs') {
105
+ if (!args.codePackage) {
106
+ return `ERROR: Code-type (runtime="nodejs") tasks require a "codePackage" parameter with "entry" and "sourceFiles".\nExample:\n{\n "runtime": "nodejs",\n "codePackage": {\n "entry": "index.js",\n "sourceFiles": {\n "index.js": "module.exports.run = async function(ctx) { ctx.logger.info('Hello'); return { ok: true }; }"\n }\n }\n}`;
107
+ }
108
+ // 构建并校验 codePackage
109
+ const codePackage = buildCodePackage(args.codePackage, args.name);
110
+ const validation = (0, index_ts_1.validateNodeAutomationTaskPackage)(codePackage);
111
+ if (!validation.valid) {
112
+ const issues = validation.issues.map(i => ` - [${i.severity}] ${i.code}: ${i.message}`).join('\n');
113
+ return `ERROR: Code package validation failed:\n${issues}`;
114
+ }
115
+ const store = (0, app_stores_ts_1.getAutomationStore)();
116
+ const item = store.create({
117
+ name: args.name,
118
+ description: args.description || '',
119
+ schedule,
120
+ prompt: args.prompt || `Code task: ${args.name}`,
121
+ enabled: args.enabled !== false,
122
+ lastStatus: 'idle',
123
+ runtime: 'nodejs',
124
+ codePackage,
125
+ version: codePackage.version,
126
+ });
127
+ const automationProvider = ctx.custom?.automationProvider;
128
+ if (automationProvider?.refreshScheduler) {
129
+ automationProvider.refreshScheduler();
130
+ }
131
+ return `Code automation created successfully!\n Name: ${item.name}\n Schedule: ${schedule}\n ID: ${item.id}\n Runtime: nodejs\n Entry: ${codePackage.entry}\n Version: ${codePackage.version}\n Enabled: ${item.enabled}\n\nThe task will trigger automatically according to the schedule.`;
132
+ }
133
+ // Prompt 型任务
134
+ if (!args.prompt) {
135
+ return `ERROR: Prompt-type tasks require a "prompt" parameter.`;
136
+ }
74
137
  const store = (0, app_stores_ts_1.getAutomationStore)();
75
138
  const item = store.create({
76
139
  name: args.name,
@@ -79,8 +142,8 @@ function createAutomationTools() {
79
142
  prompt: args.prompt,
80
143
  enabled: args.enabled !== false,
81
144
  lastStatus: 'idle',
145
+ runtime: 'prompt',
82
146
  });
83
- // 通过 SPI Provider 刷新调度器
84
147
  const automationProvider = ctx.custom?.automationProvider;
85
148
  if (automationProvider?.refreshScheduler) {
86
149
  automationProvider.refreshScheduler();
@@ -94,6 +157,338 @@ function createAutomationTools() {
94
157
  category: 'builtin',
95
158
  concurrent: false,
96
159
  },
160
+ // ---- get_automation_environment ----
161
+ // 查询 Code 型任务执行环境(可用库、API、安全规则、代码模板)
162
+ {
163
+ definition: {
164
+ type: 'function',
165
+ function: {
166
+ name: 'get_automation_environment',
167
+ description: 'Get the Code automation execution environment info BEFORE writing task code. ' +
168
+ 'Returns available base libraries (with names, descriptions, and APIs), the context API shape, ' +
169
+ 'security rules (forbidden patterns), sandbox constraints, and a multi-file code template. ' +
170
+ 'Always call this first when creating Code-type automation tasks to ensure generated code matches the environment.',
171
+ parameters: {
172
+ type: 'object',
173
+ properties: {
174
+ detail: { type: 'string', enum: ['summary', 'full'], description: 'Level of detail. "summary" (default) returns library names + descriptions; "full" also returns library API signatures and code templates.' },
175
+ },
176
+ },
177
+ },
178
+ },
179
+ executor: async (args) => {
180
+ try {
181
+ const registry = (0, index_ts_1.getNodeAutomationLibraryRegistry)();
182
+ const libraries = registry.list();
183
+ const detail = args.detail || 'summary';
184
+ const lines = [];
185
+ lines.push('=== Code Automation Execution Environment ===\n');
186
+ // 1. 可用基础库
187
+ lines.push('## Available Base Libraries');
188
+ if (libraries.length === 0) {
189
+ lines.push(' (none registered)');
190
+ }
191
+ else {
192
+ for (const lib of libraries) {
193
+ lines.push(` - ${lib.name} v${lib.version}: ${lib.description || '(no description)'}`);
194
+ if (lib.permissions?.length) {
195
+ lines.push(` Permissions: ${lib.permissions.join(', ')}`);
196
+ }
197
+ }
198
+ }
199
+ lines.push('');
200
+ // 2. Context API
201
+ lines.push('## Context API (run function receives this)');
202
+ lines.push(' context = {');
203
+ lines.push(' taskId: number | string // Task ID');
204
+ lines.push(' inputs: Record<string, unknown> // Input parameters');
205
+ lines.push(' env: Record<string, string> // Whitelisted env vars');
206
+ lines.push(' logger: { debug, info, warn, error } // Structured logger');
207
+ lines.push(' artifacts: { writeText(path, content), writeJson(path, data) } // File output');
208
+ lines.push(' libs: Record<string, unknown> // Injected base libraries (by name)');
209
+ lines.push(' workspace: Record<string, unknown> | undefined // Workspace context');
210
+ lines.push(' }');
211
+ lines.push('');
212
+ // 3. 安全规则
213
+ lines.push('## Security Rules (forbidden in task code)');
214
+ lines.push(' - Cannot require/import "child_process" — use libs instead');
215
+ lines.push(' - Cannot write to absolute paths (writeFile("/...")) — use context.artifacts');
216
+ lines.push(' - Cannot dump process.env (JSON.stringify(process.env))');
217
+ lines.push(' - Cannot run npm/pnpm/yarn install at runtime');
218
+ lines.push(' - Source file paths must be relative, no ".." traversal');
219
+ lines.push('');
220
+ // 4. 沙箱约束
221
+ lines.push('## Sandbox Constraints');
222
+ lines.push(' - Runtime: Node.js (CommonJS, .cjs)');
223
+ lines.push(' - Timeout: 1000ms ~ 600000ms (default: 60000ms)');
224
+ lines.push(' - Entry file must export: module.exports.run = async function(context) { ... }');
225
+ lines.push(' - Multiple files supported via sourceFiles map');
226
+ lines.push(' - Files can require() each other by relative path');
227
+ lines.push('');
228
+ // 5. 完整模板
229
+ if (detail === 'full') {
230
+ lines.push('## Multi-File Code Template');
231
+ lines.push('```javascript');
232
+ lines.push('// === index.js (entry) ===');
233
+ lines.push('const { analyzeStocks } = require("./analyzer.js");');
234
+ lines.push('');
235
+ lines.push('module.exports.run = async function(context) {');
236
+ lines.push(' const { inputs, logger, libs, artifacts } = context;');
237
+ lines.push(' logger.info("Task started", { taskId: context.taskId });');
238
+ lines.push('');
239
+ lines.push(' // Use injected libraries:');
240
+ lines.push(' // const http = libs.http; // if requiredLibraries includes "http"');
241
+ lines.push(' // const resp = await http.get("https://api.example.com/data");');
242
+ lines.push('');
243
+ lines.push(' const result = await analyzeStocks(inputs.symbols || []);');
244
+ lines.push('');
245
+ lines.push(' // Write output artifacts:');
246
+ lines.push(' await artifacts.writeJson("result.json", result);');
247
+ lines.push('');
248
+ lines.push(' return { success: true, count: result.length };');
249
+ lines.push('};');
250
+ lines.push('');
251
+ lines.push('// === analyzer.js (helper module) ===');
252
+ lines.push('async function analyzeStocks(symbols) {');
253
+ lines.push(' // Business logic here');
254
+ lines.push(' return symbols.map(s => ({ symbol: s, score: Math.random() }));');
255
+ lines.push('}');
256
+ lines.push('module.exports = { analyzeStocks };');
257
+ lines.push('```');
258
+ lines.push('');
259
+ lines.push('## How to create multi-file tasks:');
260
+ lines.push(' Use create_code_automation with the "files" parameter:');
261
+ lines.push(' {');
262
+ lines.push(' "name": "Stock Analysis",');
263
+ lines.push(' "schedule": "*/10 * * * *",');
264
+ lines.push(' "entry": "index.js",');
265
+ lines.push(' "files": {');
266
+ lines.push(' "index.js": "const { analyzeStocks } = require(\'./analyzer.js\'); ...",');
267
+ lines.push(' "analyzer.js": "async function analyzeStocks(symbols) { ... } module.exports = { analyzeStocks };"');
268
+ lines.push(' },');
269
+ lines.push(' "requiredLibraries": ["http", "data"]');
270
+ lines.push(' }');
271
+ }
272
+ return lines.join('\n');
273
+ }
274
+ catch (e) {
275
+ return `ERROR getting environment: ${e.message || e}`;
276
+ }
277
+ },
278
+ category: 'builtin',
279
+ concurrent: true,
280
+ },
281
+ // ---- create_code_automation ----
282
+ // 便捷工具:创建 Code 型自动化任务(支持单文件和多文件)
283
+ {
284
+ definition: {
285
+ type: 'function',
286
+ function: {
287
+ name: 'create_code_automation',
288
+ description: 'Create a Code-type automation task that runs JavaScript code on a cron schedule. ' +
289
+ 'The code runs in a sandboxed NodeJS container with access to registered base libraries. ' +
290
+ 'The entry code must export a run(context) function that receives { inputs, env, logger, artifacts, libs, workspace }. ' +
291
+ 'Supports multi-file projects: use "files" (map of filename to content) for complex tasks, or "code" (single string) for simple tasks. ' +
292
+ 'TIP: Call get_automation_environment first to discover available libraries, APIs, and security rules.',
293
+ parameters: {
294
+ type: 'object',
295
+ properties: {
296
+ name: { type: 'string', description: 'Task name (e.g. "Stock Analysis Every 10min")' },
297
+ description: { type: 'string', description: 'Task description (optional)' },
298
+ schedule: { type: 'string', description: 'Cron expression (5 fields). e.g. "*/10 * * * *" for every 10 min' },
299
+ code: { type: 'string', description: 'JavaScript code for a SINGLE-FILE task entry. Use this for simple tasks. Must export run(context). Mutually exclusive with "files".' },
300
+ files: {
301
+ type: 'object',
302
+ description: 'Multi-file project: map of filename to file content. Use this for complex tasks requiring multiple modules. ' +
303
+ 'Files can require() each other by relative path. Example: {"index.js": "const { analyze } = require(\'./analyzer.js\'); ...", "analyzer.js": "..."}. ' +
304
+ 'Mutually exclusive with "code".',
305
+ },
306
+ entry: { type: 'string', description: 'Entry file name (default: "index.js"). Must match a key in "files" or be the name for "code".' },
307
+ version: { type: 'string', description: 'Code package version (default: "1.0.0")' },
308
+ requiredLibraries: { type: 'array', items: { type: 'string' }, description: 'Names of registered base libraries to inject (e.g. ["http", "data", "datetime"]). Call get_automation_environment to see available libraries.' },
309
+ timeoutMs: { type: 'number', description: 'Execution timeout in milliseconds (default: 60000, max: 600000)' },
310
+ enabled: { type: 'boolean', description: 'Whether to enable the task immediately (default: true)' },
311
+ },
312
+ required: ['name', 'schedule'],
313
+ },
314
+ },
315
+ },
316
+ executor: async (args, ctx) => {
317
+ try {
318
+ const cron = await Promise.resolve().then(() => __importStar(require('node-cron')));
319
+ const schedule = args.schedule;
320
+ if (!cron.validate(schedule)) {
321
+ return `ERROR: Invalid cron expression "${schedule}".`;
322
+ }
323
+ const entry = args.entry || 'index.js';
324
+ // 构建 sourceFiles:支持 code(单文件)或 files(多文件)
325
+ let sourceFiles;
326
+ if (args.files && typeof args.files === 'object') {
327
+ sourceFiles = args.files;
328
+ if (!sourceFiles[entry]) {
329
+ return `ERROR: Entry file "${entry}" not found in "files". Available files: ${Object.keys(sourceFiles).join(', ')}`;
330
+ }
331
+ }
332
+ else if (args.code) {
333
+ sourceFiles = { [entry]: args.code };
334
+ }
335
+ else {
336
+ return `ERROR: Either "code" (single file) or "files" (multi-file) must be provided.`;
337
+ }
338
+ const codePackage = {
339
+ id: String(Date.now()),
340
+ name: args.name,
341
+ version: args.version || '1.0.0',
342
+ runtime: 'nodejs',
343
+ entry,
344
+ sourceFiles,
345
+ requiredLibraries: args.requiredLibraries,
346
+ runtimeConfig: args.timeoutMs ? { timeoutMs: args.timeoutMs } : undefined,
347
+ };
348
+ // 校验
349
+ const validation = (0, index_ts_1.validateNodeAutomationTaskPackage)(codePackage);
350
+ if (!validation.valid) {
351
+ const issues = validation.issues.map(i => ` - [${i.severity}] ${i.code}: ${i.message}`).join('\n');
352
+ return `ERROR: Code validation failed:\n${issues}`;
353
+ }
354
+ const store = (0, app_stores_ts_1.getAutomationStore)();
355
+ const item = store.create({
356
+ name: args.name,
357
+ description: args.description || '',
358
+ schedule,
359
+ prompt: `Code task: ${args.name}`,
360
+ enabled: args.enabled !== false,
361
+ lastStatus: 'idle',
362
+ runtime: 'nodejs',
363
+ codePackage,
364
+ version: codePackage.version,
365
+ });
366
+ const automationProvider = ctx.custom?.automationProvider;
367
+ if (automationProvider?.refreshScheduler) {
368
+ automationProvider.refreshScheduler();
369
+ }
370
+ const fileCount = Object.keys(sourceFiles).length;
371
+ return `Code automation created successfully!\n Name: ${item.name}\n Schedule: ${schedule}\n ID: ${item.id}\n Runtime: nodejs\n Entry: ${entry}\n Files: ${fileCount} (${Object.keys(sourceFiles).join(', ')})\n Version: ${codePackage.version}\n Enabled: ${item.enabled}\n\nThe task code will run in a sandboxed NodeJS container on the schedule.`;
372
+ }
373
+ catch (e) {
374
+ return `ERROR creating code automation: ${e.message || e}`;
375
+ }
376
+ },
377
+ category: 'builtin',
378
+ concurrent: false,
379
+ },
380
+ // ---- trial_run_automation ----
381
+ // 试运行 Code 型任务(校验 + 执行,不保存记录,支持多文件)
382
+ {
383
+ definition: {
384
+ type: 'function',
385
+ function: {
386
+ name: 'trial_run_automation',
387
+ description: 'Trial-run a Code-type automation task without saving a run record. ' +
388
+ 'Validates the code package and executes it in the sandbox, returning stdout, stderr, exit code, logs, and result. ' +
389
+ 'Supports multi-file projects via "files" parameter. ' +
390
+ 'If automationId is provided, uses the stored codePackage (can override with code/files); otherwise uses provided code/files.',
391
+ parameters: {
392
+ type: 'object',
393
+ properties: {
394
+ automationId: { type: 'number', description: 'Existing automation task ID to trial-run (uses its stored codePackage)' },
395
+ code: { type: 'string', description: 'Single-file code to trial-run (mutually exclusive with "files")' },
396
+ files: { type: 'object', description: 'Multi-file project: map of filename to content (mutually exclusive with "code")' },
397
+ entry: { type: 'string', description: 'Entry file name (default: "index.js")' },
398
+ inputs: { type: 'object', description: 'Input parameters to pass to the task run(context) function' },
399
+ timeoutMs: { type: 'number', description: 'Execution timeout in milliseconds (default: 30000)' },
400
+ },
401
+ },
402
+ },
403
+ },
404
+ executor: async (args) => {
405
+ try {
406
+ let codePackage;
407
+ const entry = args.entry || 'index.js';
408
+ if (args.automationId) {
409
+ // 使用已存储的 codePackage
410
+ const store = (0, app_stores_ts_1.getAutomationStore)();
411
+ const automation = store.findById(Number(args.automationId));
412
+ if (!automation) {
413
+ return `ERROR: Automation task with ID ${args.automationId} not found.`;
414
+ }
415
+ if (!automation.codePackage) {
416
+ return `ERROR: Automation task "${automation.name}" (ID: ${args.automationId}) is not a Code-type task.`;
417
+ }
418
+ codePackage = automation.codePackage;
419
+ // 如果提供了 code 或 files,覆盖源码
420
+ if (args.files) {
421
+ codePackage = { ...codePackage, entry, sourceFiles: args.files };
422
+ }
423
+ else if (args.code) {
424
+ codePackage = { ...codePackage, entry, sourceFiles: { ...codePackage.sourceFiles, [entry]: args.code } };
425
+ }
426
+ }
427
+ else if (args.files) {
428
+ // 多文件试运行
429
+ codePackage = {
430
+ id: `trial_${Date.now()}`,
431
+ version: '0.0.0-trial',
432
+ runtime: 'nodejs',
433
+ entry,
434
+ sourceFiles: args.files,
435
+ };
436
+ }
437
+ else if (args.code) {
438
+ // 单文件试运行
439
+ codePackage = {
440
+ id: `trial_${Date.now()}`,
441
+ version: '0.0.0-trial',
442
+ runtime: 'nodejs',
443
+ entry,
444
+ sourceFiles: { [entry]: args.code },
445
+ };
446
+ }
447
+ else {
448
+ return `ERROR: Either "automationId", "code", or "files" must be provided.`;
449
+ }
450
+ // 校验
451
+ const validation = (0, index_ts_1.validateNodeAutomationTaskPackage)(codePackage);
452
+ if (!validation.valid) {
453
+ const issues = validation.issues.map(i => ` - [${i.severity}] ${i.code}: ${i.message}`).join('\n');
454
+ return `Validation FAILED:\n${issues}`;
455
+ }
456
+ // 执行
457
+ const result = await (0, index_ts_1.getNodeAutomationRuntimeRunner)().execute(codePackage, {
458
+ taskId: Number(args.automationId) || 0,
459
+ inputs: args.inputs || {},
460
+ env: {},
461
+ timeoutMs: args.timeoutMs || 30000,
462
+ });
463
+ const lines = [];
464
+ lines.push(`Trial run completed.`);
465
+ lines.push(` Exit code: ${result.exitCode}`);
466
+ lines.push(` Duration: ${result.duration}ms`);
467
+ if (result.stdout)
468
+ lines.push(` stdout:\n${result.stdout.slice(0, 2000)}`);
469
+ if (result.stderr)
470
+ lines.push(` stderr:\n${result.stderr.slice(0, 2000)}`);
471
+ if (result.logs && result.logs.length > 0) {
472
+ lines.push(` Logs:`);
473
+ for (const log of result.logs.slice(0, 50)) {
474
+ lines.push(` [${log.level}] ${log.message}`);
475
+ }
476
+ }
477
+ if (result.artifacts && result.artifacts.length > 0) {
478
+ lines.push(` Artifacts: ${result.artifacts.join(', ')}`);
479
+ }
480
+ if (result.result !== undefined) {
481
+ lines.push(` Result: ${JSON.stringify(result.result).slice(0, 2000)}`);
482
+ }
483
+ return lines.join('\n');
484
+ }
485
+ catch (e) {
486
+ return `ERROR during trial run: ${e.message || e}`;
487
+ }
488
+ },
489
+ category: 'builtin',
490
+ concurrent: false,
491
+ },
97
492
  // ---- list_automations ----
98
493
  // 列出所有自动化任务
99
494
  {
@@ -101,7 +496,7 @@ function createAutomationTools() {
101
496
  type: 'function',
102
497
  function: {
103
498
  name: 'list_automations',
104
- description: 'List all scheduled automation tasks. Returns task details including name, schedule, prompt, status, and last run time. ' +
499
+ description: 'List all scheduled automation tasks. Returns task details including name, schedule, runtime type, prompt/code info, status, and last run time. ' +
105
500
  'Use this to review existing automations before creating or modifying them.',
106
501
  parameters: {
107
502
  type: 'object',
@@ -124,7 +519,18 @@ function createAutomationTools() {
124
519
  const lines = items.map((i, idx) => {
125
520
  const parts = [`[${idx + 1}] ${i.name} (ID: ${i.id})`];
126
521
  parts.push(` Schedule: ${i.schedule}`);
127
- parts.push(` Prompt: ${(i.prompt || '').slice(0, 100)}${i.prompt?.length > 100 ? '...' : ''}`);
522
+ parts.push(` Runtime: ${i.runtime || 'prompt'}`);
523
+ if (i.runtime === 'nodejs') {
524
+ parts.push(` Entry: ${i.codePackage?.entry || 'index.js'}`);
525
+ parts.push(` Version: ${i.version || '1.0.0'}`);
526
+ if (i.codePackage?.requiredLibraries?.length) {
527
+ parts.push(` Libraries: ${i.codePackage.requiredLibraries.join(', ')}`);
528
+ }
529
+ }
530
+ else {
531
+ const promptPreview = (i.prompt || '').slice(0, 100);
532
+ parts.push(` Prompt: ${promptPreview}${i.prompt?.length > 100 ? '...' : ''}`);
533
+ }
128
534
  parts.push(` Enabled: ${i.enabled}`);
129
535
  if (i.lastRunAt)
130
536
  parts.push(` Last run: ${i.lastRunAt} (${i.lastStatus})`);
@@ -161,7 +567,7 @@ function createAutomationTools() {
161
567
  },
162
568
  executor: async (args, ctx) => {
163
569
  try {
164
- const id = args.id;
570
+ const id = Number(args.id);
165
571
  const store = (0, app_stores_ts_1.getAutomationStore)();
166
572
  const existing = store.findById(id);
167
573
  if (!existing) {
@@ -182,6 +588,72 @@ function createAutomationTools() {
182
588
  category: 'builtin',
183
589
  concurrent: false,
184
590
  },
591
+ // ---- stop_automation ----
592
+ // 停止正在运行的自动化任务(中止执行 + 禁用调度)
593
+ {
594
+ definition: {
595
+ type: 'function',
596
+ function: {
597
+ name: 'stop_automation',
598
+ description: 'Stop a running automation task. Aborts the current execution (for Prompt-type tasks, aborts the Agent engine; for Code-type tasks, marks as cancelled) ' +
599
+ 'and disables the task from future scheduled runs. ' +
600
+ 'Use this when the user asks to stop/cancel/abort a task. ' +
601
+ 'If running inside an automation task context, the ID is auto-detected — no need to provide it. ' +
602
+ 'Use list_automations first if you need to find the task ID in other cases.',
603
+ parameters: {
604
+ type: 'object',
605
+ properties: {
606
+ id: { type: 'number', description: 'The automation task ID to stop. If omitted, uses the current automation context ID.' },
607
+ },
608
+ },
609
+ },
610
+ },
611
+ executor: async (args, ctx) => {
612
+ try {
613
+ // 优先使用参数中的 id,否则从上下文中获取当前自动化任务 ID
614
+ const id = args.id != null ? Number(args.id) : ctx.custom?.automationId;
615
+ if (id == null || isNaN(id)) {
616
+ return `ERROR: No automation task ID provided and no automation context found. Use list_automations to find the task ID.`;
617
+ }
618
+ const store = (0, app_stores_ts_1.getAutomationStore)();
619
+ const existing = store.findById(id);
620
+ if (!existing) {
621
+ return `ERROR: Automation task with ID ${id} not found.`;
622
+ }
623
+ // 优先通过 AutomationProvider 停止(能中止正在运行的 Agent 执行)
624
+ const automationProvider = ctx.custom?.automationProvider;
625
+ if (automationProvider?.stopAutomation) {
626
+ const result = await automationProvider.stopAutomation(id);
627
+ return result.message;
628
+ }
629
+ // Fallback:仅禁用任务 + 停止调度
630
+ store.patch(id, { enabled: false, lastStatus: 'cancelled' });
631
+ if (automationProvider?.refreshScheduler) {
632
+ automationProvider.refreshScheduler();
633
+ }
634
+ return `Automation task "${existing.name}" (ID: ${id}) has been disabled. Note: could not abort active execution (no stopAutomation provider).`;
635
+ }
636
+ catch (e) {
637
+ return `ERROR stopping automation: ${e.message || e}`;
638
+ }
639
+ },
640
+ category: 'builtin',
641
+ concurrent: false,
642
+ },
185
643
  ];
186
644
  }
645
+ /** 从工具参数构建 NodeAutomationTaskPackage */
646
+ function buildCodePackage(args, name) {
647
+ return {
648
+ id: String(Date.now()),
649
+ name,
650
+ version: args.version || '1.0.0',
651
+ runtime: 'nodejs',
652
+ entry: args.entry || 'index.js',
653
+ sourceFiles: args.sourceFiles || {},
654
+ dependencies: args.dependencies,
655
+ requiredLibraries: args.requiredLibraries,
656
+ runtimeConfig: args.runtimeConfig,
657
+ };
658
+ }
187
659
  //# sourceMappingURL=automation.js.map