@cicctencent/agent-server 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/automation/node-task-runtime.d.ts.map +1 -1
- package/dist/cjs/automation/node-task-runtime.js +196 -8
- package/dist/cjs/automation/node-task-runtime.js.map +1 -1
- package/dist/cjs/automation/node-task-validator.d.ts +10 -0
- package/dist/cjs/automation/node-task-validator.d.ts.map +1 -1
- package/dist/cjs/automation/node-task-validator.js +10 -0
- package/dist/cjs/automation/node-task-validator.js.map +1 -1
- package/dist/cjs/automation/python-prelude.d.ts +1 -1
- package/dist/cjs/automation/python-prelude.d.ts.map +1 -1
- package/dist/cjs/automation/python-prelude.js +196 -1
- package/dist/cjs/automation/python-prelude.js.map +1 -1
- package/dist/cjs/automation/python-task-runtime.d.ts.map +1 -1
- package/dist/cjs/automation/python-task-runtime.js +56 -4
- package/dist/cjs/automation/python-task-runtime.js.map +1 -1
- package/dist/cjs/sandbox/sandbox-prelude.d.ts +1 -1
- package/dist/cjs/sandbox/sandbox-prelude.d.ts.map +1 -1
- package/dist/cjs/sandbox/sandbox-prelude.js +55 -0
- package/dist/cjs/sandbox/sandbox-prelude.js.map +1 -1
- package/dist/esm/automation/node-task-runtime.d.ts.map +1 -1
- package/dist/esm/automation/node-task-runtime.js +196 -8
- package/dist/esm/automation/node-task-runtime.js.map +1 -1
- package/dist/esm/automation/node-task-validator.d.ts +10 -0
- package/dist/esm/automation/node-task-validator.d.ts.map +1 -1
- package/dist/esm/automation/node-task-validator.js +10 -0
- package/dist/esm/automation/node-task-validator.js.map +1 -1
- package/dist/esm/automation/python-prelude.d.ts +1 -1
- package/dist/esm/automation/python-prelude.d.ts.map +1 -1
- package/dist/esm/automation/python-prelude.js +196 -1
- package/dist/esm/automation/python-prelude.js.map +1 -1
- package/dist/esm/automation/python-task-runtime.d.ts.map +1 -1
- package/dist/esm/automation/python-task-runtime.js +56 -4
- package/dist/esm/automation/python-task-runtime.js.map +1 -1
- package/dist/esm/sandbox/sandbox-prelude.d.ts +1 -1
- package/dist/esm/sandbox/sandbox-prelude.d.ts.map +1 -1
- package/dist/esm/sandbox/sandbox-prelude.js +55 -0
- package/dist/esm/sandbox/sandbox-prelude.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-task-runtime.d.ts","sourceRoot":"","sources":["../../../src/automation/node-task-runtime.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,6BAA6B,EAC7B,sBAAsB,EACtB,wBAAwB,EACxB,yBAAyB,EAC1B,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAoC,6BAA6B,EAAE,MAAM,wBAAwB,CAAC;AAEzG,MAAM,WAAW,4BAA4B;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,6BAA6B,CAAC;CACjD;AAaD,qBAAa,2BAA2B;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAgC;gBAEpD,OAAO,GAAE,4BAAiC;IAKhD,OAAO,CACX,WAAW,EAAE,yBAAyB,EACtC,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,6BAA6B,CAAC;IAqEzC;;;OAGG;IACG,aAAa,CACjB,WAAW,EAAE,yBAAyB,EACtC,OAAO,EAAE,wBAAwB,EACjC,SAAS,GAAE;QACT,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;QAChD,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;QAClC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;QACnC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,6BAA6B,KAAK,IAAI,CAAC;QAC3D,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;KAChC,GACL,OAAO,CAAC,6BAA6B,CAAC;IAyEzC,8CAA8C;IAC9C,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,QAAQ;IAahB,OAAO,CAAC,YAAY;IAYpB,OAAO,CAAC,oBAAoB;IAQ5B,OAAO,CAAC,oBAAoB;
|
|
1
|
+
{"version":3,"file":"node-task-runtime.d.ts","sourceRoot":"","sources":["../../../src/automation/node-task-runtime.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,6BAA6B,EAC7B,sBAAsB,EACtB,wBAAwB,EACxB,yBAAyB,EAC1B,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAoC,6BAA6B,EAAE,MAAM,wBAAwB,CAAC;AAEzG,MAAM,WAAW,4BAA4B;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,6BAA6B,CAAC;CACjD;AAaD,qBAAa,2BAA2B;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAgC;gBAEpD,OAAO,GAAE,4BAAiC;IAKhD,OAAO,CACX,WAAW,EAAE,yBAAyB,EACtC,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,6BAA6B,CAAC;IAqEzC;;;OAGG;IACG,aAAa,CACjB,WAAW,EAAE,yBAAyB,EACtC,OAAO,EAAE,wBAAwB,EACjC,SAAS,GAAE;QACT,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;QAChD,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;QAClC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;QACnC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,6BAA6B,KAAK,IAAI,CAAC;QAC3D,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;KAChC,GACL,OAAO,CAAC,6BAA6B,CAAC;IAyEzC,8CAA8C;IAC9C,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,QAAQ;IAahB,OAAO,CAAC,YAAY;IAYpB,OAAO,CAAC,oBAAoB;IAQ5B,OAAO,CAAC,oBAAoB;IAwU5B,+CAA+C;IAC/C,OAAO,CAAC,cAAc;IAqBtB,gEAAgE;IAChE,OAAO,CAAC,YAAY;IASpB,wDAAwD;IACxD,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,kBAAkB;CAgB3B;AAID,wBAAgB,8BAA8B,IAAI,2BAA2B,CAG5E"}
|
|
@@ -237,6 +237,27 @@ function __log(level, message, meta) {
|
|
|
237
237
|
// 实时输出日志标记行,确保超时/崩溃时也能解析到已收集的日志
|
|
238
238
|
process.stdout.write('__LOG__' + JSON.stringify(entry) + '\n');
|
|
239
239
|
}
|
|
240
|
+
// 去除 Agent 返回文本中的 \`\`\`json 代码围栏,便于 json 模式解析
|
|
241
|
+
function _stripFence(t) {
|
|
242
|
+
let s = (t || '').replace(/^\s*/, '');
|
|
243
|
+
const bt = String.fromCharCode(96);
|
|
244
|
+
const fence = bt + bt + bt;
|
|
245
|
+
if (s.indexOf(fence) === 0) {
|
|
246
|
+
const nl = s.indexOf('\n');
|
|
247
|
+
s = nl >= 0 ? s.substring(nl + 1) : s.substring(3);
|
|
248
|
+
const end = s.lastIndexOf(fence);
|
|
249
|
+
if (end >= 0) s = s.substring(0, end);
|
|
250
|
+
s = s.replace(/^\s*/, '').replace(/\s*$/, '');
|
|
251
|
+
}
|
|
252
|
+
return s;
|
|
253
|
+
}
|
|
254
|
+
// 产物大小上限(单文件默认 5MB)
|
|
255
|
+
const ARTIFACT_MAX_BYTES = 5 * 1024 * 1024;
|
|
256
|
+
function __artifactGuard(content) {
|
|
257
|
+
const size = Buffer.isBuffer(content) ? content.length : Buffer.byteLength(String(content));
|
|
258
|
+
if (size > ARTIFACT_MAX_BYTES) throw new Error('产物体积超限(最大 ' + ARTIFACT_MAX_BYTES + ' 字节): 实际 ' + size);
|
|
259
|
+
return content;
|
|
260
|
+
}
|
|
240
261
|
// Auto-load sandbox prelude as global \`sb\` (HTTP, file I/O, data, date, table, logger)
|
|
241
262
|
try { global.sb = require('./_prelude'); } catch(e) { /* prelude not available */ }
|
|
242
263
|
for (const [file, content] of Object.entries(__task.sourceFiles || {})) {
|
|
@@ -251,6 +272,7 @@ const context = {
|
|
|
251
272
|
runId: __payload.runId,
|
|
252
273
|
inputs: __payload.inputs || {},
|
|
253
274
|
env: __payload.env || {},
|
|
275
|
+
secrets: __payload.env || {},
|
|
254
276
|
workspace: __payload.workspace,
|
|
255
277
|
libs: __payload.libs || {},
|
|
256
278
|
agentEndpoint: __payload.agentEndpoint,
|
|
@@ -307,7 +329,15 @@ const context = {
|
|
|
307
329
|
}
|
|
308
330
|
}
|
|
309
331
|
});
|
|
310
|
-
res.on('end', () => {
|
|
332
|
+
res.on('end', () => {
|
|
333
|
+
if (taskFailed) { reject(new Error('Agent task failed: ' + (taskError || 'unknown'))); return; }
|
|
334
|
+
if (opts.json) {
|
|
335
|
+
try { resolve(JSON.parse(_stripFence(finalText))); }
|
|
336
|
+
catch (e) { reject(new Error('Agent 返回内容不是合法 JSON: ' + finalText.slice(0, 200))); return; }
|
|
337
|
+
} else {
|
|
338
|
+
resolve(finalText);
|
|
339
|
+
}
|
|
340
|
+
});
|
|
311
341
|
res.on('error', reject);
|
|
312
342
|
});
|
|
313
343
|
req.on('error', reject);
|
|
@@ -316,6 +346,96 @@ const context = {
|
|
|
316
346
|
req.end();
|
|
317
347
|
});
|
|
318
348
|
},
|
|
349
|
+
stream: async function* (prompt, opts) {
|
|
350
|
+
opts = opts || {};
|
|
351
|
+
const endpoint = __payload.agentEndpoint;
|
|
352
|
+
if (!endpoint) throw new Error('Agent endpoint not configured');
|
|
353
|
+
const timeout = opts.timeout || 600000;
|
|
354
|
+
const u = new URL(endpoint);
|
|
355
|
+
const lib = u.protocol === 'https:' ? require('https') : require('http');
|
|
356
|
+
const body = JSON.stringify({
|
|
357
|
+
jsonrpc: '2.0',
|
|
358
|
+
id: opts.id || 1,
|
|
359
|
+
method: 'tasks/sendSubscribe',
|
|
360
|
+
params: {
|
|
361
|
+
message: { role: 'user', parts: [{ kind: 'text', text: String(prompt) }] },
|
|
362
|
+
contextId: opts.contextId,
|
|
363
|
+
profile: opts.profile,
|
|
364
|
+
},
|
|
365
|
+
});
|
|
366
|
+
let last = '';
|
|
367
|
+
let queue = [];
|
|
368
|
+
let resolveNext = null;
|
|
369
|
+
let finished = false;
|
|
370
|
+
let failedErr = null;
|
|
371
|
+
const enqueue = (item) => { if (resolveNext) { const r = resolveNext; resolveNext = null; r(item); } else { queue.push(item); } };
|
|
372
|
+
const finish = () => { finished = true; if (resolveNext) { const r = resolveNext; resolveNext = null; r(null); } };
|
|
373
|
+
const fail = (err) => { failedErr = err; if (resolveNext) { const r = resolveNext; resolveNext = null; r(null); } };
|
|
374
|
+
const req = lib.request(u, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'text/event-stream' } }, (res) => {
|
|
375
|
+
if (res.statusCode && res.statusCode >= 400) {
|
|
376
|
+
let t = '';
|
|
377
|
+
res.on('data', c => t += c);
|
|
378
|
+
res.on('end', () => fail(new Error('Agent call failed (HTTP ' + res.statusCode + '): ' + t.slice(0, 200))));
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
res.setEncoding('utf-8');
|
|
382
|
+
let buf = '', taskFailed = false, taskError = null;
|
|
383
|
+
res.on('data', (chunk) => {
|
|
384
|
+
buf += chunk;
|
|
385
|
+
let idx;
|
|
386
|
+
while ((idx = buf.indexOf('\n\n')) >= 0) {
|
|
387
|
+
const ev = buf.slice(0, idx);
|
|
388
|
+
buf = buf.slice(idx + 2);
|
|
389
|
+
for (const line of ev.split('\n')) {
|
|
390
|
+
if (!line.startsWith('data:')) continue;
|
|
391
|
+
const s = line.slice(5).trim();
|
|
392
|
+
if (!s) continue;
|
|
393
|
+
let msg; try { msg = JSON.parse(s); } catch { continue; }
|
|
394
|
+
const r = msg.result || {};
|
|
395
|
+
if (r.type === 'error') {
|
|
396
|
+
const m = r.data && r.data.message ? r.data.message : String(r.data);
|
|
397
|
+
res.destroy();
|
|
398
|
+
fail(new Error('Agent error: ' + m));
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
let t = '';
|
|
402
|
+
if (r.type === 'message' && r.data && r.data.parts) {
|
|
403
|
+
for (const p of r.data.parts) if ((p.kind === 'text' || p.type === 'text') && p.text) t = p.text;
|
|
404
|
+
} else if (r.type === 'task' && r.data && r.data.state === 'failed') {
|
|
405
|
+
taskFailed = true; taskError = r.data.error;
|
|
406
|
+
}
|
|
407
|
+
if (t) {
|
|
408
|
+
if (t.startsWith(last)) { const delta = t.slice(last.length); if (delta) enqueue(delta); }
|
|
409
|
+
else enqueue(t);
|
|
410
|
+
last = t;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
res.on('end', () => {
|
|
416
|
+
if (taskFailed) { fail(new Error('Agent task failed: ' + (taskError || 'unknown'))); return; }
|
|
417
|
+
if (opts.json && last) {
|
|
418
|
+
try { enqueue(JSON.parse(_stripFence(last))); }
|
|
419
|
+
catch (e) { fail(new Error('Agent 返回内容不是合法 JSON: ' + last.slice(0, 200))); return; }
|
|
420
|
+
}
|
|
421
|
+
finish();
|
|
422
|
+
});
|
|
423
|
+
res.on('error', (e) => fail(e));
|
|
424
|
+
});
|
|
425
|
+
req.on('error', (e) => fail(e));
|
|
426
|
+
req.setTimeout(timeout, () => { req.destroy(); fail(new Error('Agent call timed out')); });
|
|
427
|
+
req.write(body);
|
|
428
|
+
req.end();
|
|
429
|
+
while (true) {
|
|
430
|
+
if (queue.length) { const item = queue.shift(); if (item === null) break; yield item; continue; }
|
|
431
|
+
if (finished) break;
|
|
432
|
+
if (failedErr) throw failedErr;
|
|
433
|
+
const item = await new Promise((res) => { resolveNext = res; });
|
|
434
|
+
if (item === null) break;
|
|
435
|
+
if (item !== undefined) yield item;
|
|
436
|
+
}
|
|
437
|
+
if (failedErr) throw failedErr;
|
|
438
|
+
},
|
|
319
439
|
},
|
|
320
440
|
logger: {
|
|
321
441
|
debug: (message, meta) => __log('debug', message, meta),
|
|
@@ -324,34 +444,102 @@ const context = {
|
|
|
324
444
|
error: (message, meta) => __log('error', message, meta),
|
|
325
445
|
},
|
|
326
446
|
artifacts: {
|
|
327
|
-
writeText:
|
|
447
|
+
writeText: (file, content) => {
|
|
448
|
+
const target = path.resolve(process.cwd(), file);
|
|
449
|
+
const relative = path.relative(process.cwd(), target);
|
|
450
|
+
if (relative.startsWith('..') || path.isAbsolute(relative)) throw new Error('Unsafe artifact path: ' + file);
|
|
451
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
452
|
+
fs.writeFileSync(target, __artifactGuard(String(content)), 'utf-8');
|
|
453
|
+
},
|
|
454
|
+
write_text: (file, content) => {
|
|
328
455
|
const target = path.resolve(process.cwd(), file);
|
|
329
456
|
const relative = path.relative(process.cwd(), target);
|
|
330
457
|
if (relative.startsWith('..') || path.isAbsolute(relative)) throw new Error('Unsafe artifact path: ' + file);
|
|
331
458
|
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
332
|
-
fs.writeFileSync(target, String(content), 'utf-8');
|
|
459
|
+
fs.writeFileSync(target, __artifactGuard(String(content)), 'utf-8');
|
|
333
460
|
},
|
|
334
|
-
writeJson:
|
|
461
|
+
writeJson: (file, data) => {
|
|
335
462
|
const target = path.resolve(process.cwd(), file);
|
|
336
463
|
const relative = path.relative(process.cwd(), target);
|
|
337
464
|
if (relative.startsWith('..') || path.isAbsolute(relative)) throw new Error('Unsafe artifact path: ' + file);
|
|
338
465
|
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
339
|
-
fs.writeFileSync(target, JSON.stringify(data, null, 2), 'utf-8');
|
|
466
|
+
fs.writeFileSync(target, __artifactGuard(JSON.stringify(data, null, 2)), 'utf-8');
|
|
467
|
+
},
|
|
468
|
+
write_json: (file, data) => {
|
|
469
|
+
const target = path.resolve(process.cwd(), file);
|
|
470
|
+
const relative = path.relative(process.cwd(), target);
|
|
471
|
+
if (relative.startsWith('..') || path.isAbsolute(relative)) throw new Error('Unsafe artifact path: ' + file);
|
|
472
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
473
|
+
fs.writeFileSync(target, __artifactGuard(JSON.stringify(data, null, 2)), 'utf-8');
|
|
474
|
+
},
|
|
475
|
+
readText: (file) => {
|
|
476
|
+
const target = path.resolve(process.cwd(), file);
|
|
477
|
+
const relative = path.relative(process.cwd(), target);
|
|
478
|
+
if (relative.startsWith('..') || path.isAbsolute(relative)) throw new Error('Unsafe artifact path: ' + file);
|
|
479
|
+
return fs.readFileSync(target, 'utf-8');
|
|
480
|
+
},
|
|
481
|
+
read_text: (file) => {
|
|
482
|
+
const target = path.resolve(process.cwd(), file);
|
|
483
|
+
const relative = path.relative(process.cwd(), target);
|
|
484
|
+
if (relative.startsWith('..') || path.isAbsolute(relative)) throw new Error('Unsafe artifact path: ' + file);
|
|
485
|
+
return fs.readFileSync(target, 'utf-8');
|
|
486
|
+
},
|
|
487
|
+
readJson: (file) => {
|
|
488
|
+
const target = path.resolve(process.cwd(), file);
|
|
489
|
+
const relative = path.relative(process.cwd(), target);
|
|
490
|
+
if (relative.startsWith('..') || path.isAbsolute(relative)) throw new Error('Unsafe artifact path: ' + file);
|
|
491
|
+
return JSON.parse(fs.readFileSync(target, 'utf-8'));
|
|
492
|
+
},
|
|
493
|
+
read_json: (file) => {
|
|
494
|
+
const target = path.resolve(process.cwd(), file);
|
|
495
|
+
const relative = path.relative(process.cwd(), target);
|
|
496
|
+
if (relative.startsWith('..') || path.isAbsolute(relative)) throw new Error('Unsafe artifact path: ' + file);
|
|
497
|
+
return JSON.parse(fs.readFileSync(target, 'utf-8'));
|
|
340
498
|
},
|
|
341
499
|
},
|
|
342
500
|
};
|
|
501
|
+
function __validateInputs(schema, inputs) {
|
|
502
|
+
if (!schema || typeof schema !== 'object') return;
|
|
503
|
+
const props = schema.properties || {};
|
|
504
|
+
const required = schema.required || [];
|
|
505
|
+
if (typeof inputs !== 'object' || inputs === null || Array.isArray(inputs)) throw new Error('inputs 必须是对象,但收到 ' + (Array.isArray(inputs) ? 'array' : typeof inputs));
|
|
506
|
+
const typeCheck = {
|
|
507
|
+
string: (v) => typeof v === 'string',
|
|
508
|
+
number: (v) => typeof v === 'number',
|
|
509
|
+
integer: (v) => typeof v === 'number' && Number.isInteger(v),
|
|
510
|
+
boolean: (v) => typeof v === 'boolean',
|
|
511
|
+
array: (v) => Array.isArray(v),
|
|
512
|
+
object: (v) => typeof v === 'object' && v !== null && !Array.isArray(v),
|
|
513
|
+
};
|
|
514
|
+
for (const key of required) if (!(key in inputs)) throw new Error('缺少必填输入项: ' + key);
|
|
515
|
+
for (const key of Object.keys(inputs)) {
|
|
516
|
+
if (props[key] && props[key].type && typeCheck[props[key].type]) {
|
|
517
|
+
if (!typeCheck[props[key].type](inputs[key])) throw new Error('输入项 ' + key + ' 类型错误:期望 ' + props[key].type + ',实际 ' + typeof inputs[key]);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
const __start = Date.now();
|
|
343
522
|
Promise.resolve()
|
|
344
|
-
.then(() =>
|
|
523
|
+
.then(() => {
|
|
524
|
+
const schema = __task.inputsSchema || ((__task.metadata && __task.metadata.inputsSchema) || null);
|
|
525
|
+
__validateInputs(schema, __payload.inputs || {});
|
|
526
|
+
return require(path.resolve(process.cwd(), __task.entry));
|
|
527
|
+
})
|
|
345
528
|
.then(mod => {
|
|
346
529
|
if (!mod || typeof mod.run !== 'function') throw new Error('Node automation entry must export run(context)');
|
|
347
530
|
return mod.run(context);
|
|
348
531
|
})
|
|
349
532
|
.then(result => {
|
|
533
|
+
const durationMs = Date.now() - __start;
|
|
534
|
+
__log('info', 'task finished', { durationMs });
|
|
350
535
|
console.log('__NODE_AUTOMATION_RESULT__' + JSON.stringify({ result }));
|
|
351
536
|
})
|
|
352
537
|
.catch(error => {
|
|
353
|
-
|
|
354
|
-
|
|
538
|
+
const durationMs = Date.now() - __start;
|
|
539
|
+
const message = error && error.message ? error.message : String(error);
|
|
540
|
+
const retryable = error instanceof Error && /timeout|ECONN|ENOTFOUND|ETIMEDOUT|Agent call failed|Agent task failed/.test(message);
|
|
541
|
+
__log('error', message, { durationMs });
|
|
542
|
+
console.error('__NODE_AUTOMATION_ERROR__' + JSON.stringify({ message, type: error && error.name, code: 'TASK_EXECUTION_FAILED', retryable, durationMs }));
|
|
355
543
|
process.exitCode = 1;
|
|
356
544
|
});
|
|
357
545
|
`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-task-runtime.js","sourceRoot":"","sources":["../../../src/automation/node-task-runtime.ts"],"names":[],"mappings":";AAAA,+DAA+D;AAC/D,6CAA6C;AAC7C,+DAA+D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"node-task-runtime.js","sourceRoot":"","sources":["../../../src/automation/node-task-runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,5 +3,15 @@ import type { NodeAutomationTaskPackage, NodeAutomationValidationResult } from '
|
|
|
3
3
|
export declare function setAutomationCodeMaxTimeoutMs(ms: number): void;
|
|
4
4
|
/** 获取代码任务 timeoutMs 上限 */
|
|
5
5
|
export declare function getAutomationCodeMaxTimeoutMs(): number;
|
|
6
|
+
/**
|
|
7
|
+
* 允许使用的能力(新增违禁规则时请勿误伤这些 API,Node / Python 两端一致):
|
|
8
|
+
* - context.agent.ask(prompt, opts?) / context.agent.stream(prompt, opts?) # opts.json 支持结构化输出
|
|
9
|
+
* - context.secrets / context.env # 白名单凭证/环境变量(禁止 JSON.stringify(process.env) 整体打印)
|
|
10
|
+
* - sb.cache(key, ttl).get(factory) / sb.uuid() / sb.hash() / sb.sleep() / sb.random*()
|
|
11
|
+
* - context.artifacts.writeText/writeJson/readText/readJson # 含单文件 5MB 体积上限
|
|
12
|
+
* - taskPackage.inputsSchema 运行前校验输入
|
|
13
|
+
* 注:agent.stream 在 Node 使用 for await + require('http'/'https')、Python 使用生成器 + urllib,
|
|
14
|
+
* 这些内部实现位于运行时引导脚本,不在用户入口代码中,不会被本校验器扫描。
|
|
15
|
+
*/
|
|
6
16
|
export declare function validateNodeAutomationTaskPackage(taskPackage: NodeAutomationTaskPackage): NodeAutomationValidationResult;
|
|
7
17
|
//# sourceMappingURL=node-task-validator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-task-validator.d.ts","sourceRoot":"","sources":["../../../src/automation/node-task-validator.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,yBAAyB,EAEzB,8BAA8B,EAC/B,MAAM,yBAAyB,CAAC;AAWjC,mCAAmC;AACnC,wBAAgB,6BAA6B,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE9D;AAED,0BAA0B;AAC1B,wBAAgB,6BAA6B,IAAI,MAAM,CAEtD;AAaD,wBAAgB,iCAAiC,CAC/C,WAAW,EAAE,yBAAyB,GACrC,8BAA8B,CAsDhC"}
|
|
1
|
+
{"version":3,"file":"node-task-validator.d.ts","sourceRoot":"","sources":["../../../src/automation/node-task-validator.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,yBAAyB,EAEzB,8BAA8B,EAC/B,MAAM,yBAAyB,CAAC;AAWjC,mCAAmC;AACnC,wBAAgB,6BAA6B,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE9D;AAED,0BAA0B;AAC1B,wBAAgB,6BAA6B,IAAI,MAAM,CAEtD;AAaD;;;;;;;;;GASG;AAEH,wBAAgB,iCAAiC,CAC/C,WAAW,EAAE,yBAAyB,GACrC,8BAA8B,CAsDhC"}
|
|
@@ -33,6 +33,16 @@ const FORBIDDEN_PATTERNS = [
|
|
|
33
33
|
{ code: 'forbidden-python-eval', pattern: /\b(?:eval|exec)\s*\(/, message: 'Python 任务代码不能使用 eval/exec 执行动态代码。' },
|
|
34
34
|
{ code: 'forbidden-python-absolute-write', pattern: /open\s*\(\s*['"]\/(?!(?:tmp|sandbox))/, message: 'Python 任务代码不能写入沙箱外的绝对路径,请使用相对路径输出产物。' },
|
|
35
35
|
];
|
|
36
|
+
/**
|
|
37
|
+
* 允许使用的能力(新增违禁规则时请勿误伤这些 API,Node / Python 两端一致):
|
|
38
|
+
* - context.agent.ask(prompt, opts?) / context.agent.stream(prompt, opts?) # opts.json 支持结构化输出
|
|
39
|
+
* - context.secrets / context.env # 白名单凭证/环境变量(禁止 JSON.stringify(process.env) 整体打印)
|
|
40
|
+
* - sb.cache(key, ttl).get(factory) / sb.uuid() / sb.hash() / sb.sleep() / sb.random*()
|
|
41
|
+
* - context.artifacts.writeText/writeJson/readText/readJson # 含单文件 5MB 体积上限
|
|
42
|
+
* - taskPackage.inputsSchema 运行前校验输入
|
|
43
|
+
* 注:agent.stream 在 Node 使用 for await + require('http'/'https')、Python 使用生成器 + urllib,
|
|
44
|
+
* 这些内部实现位于运行时引导脚本,不在用户入口代码中,不会被本校验器扫描。
|
|
45
|
+
*/
|
|
36
46
|
function validateNodeAutomationTaskPackage(taskPackage) {
|
|
37
47
|
const issues = [];
|
|
38
48
|
if (!taskPackage.id)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-task-validator.js","sourceRoot":"","sources":["../../../src/automation/node-task-validator.ts"],"names":[],"mappings":";AAAA,+DAA+D;AAC/D,sCAAsC;AACtC,+DAA+D;;AAkB/D,sEAEC;AAGD,sEAEC;
|
|
1
|
+
{"version":3,"file":"node-task-validator.js","sourceRoot":"","sources":["../../../src/automation/node-task-validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
* Python 基础能力库源码。
|
|
3
3
|
* 运行时会将 __AGENT_ENDPOINT__ 替换为真实的 A2A JSON-RPC 端点 URL。
|
|
4
4
|
*/
|
|
5
|
-
export declare const PYTHON_PRELUDE_SOURCE = "# -*- coding: utf-8 -*-\n\"\"\"\nSandbox Prelude for Python automation tasks.\nAuto-imported as `sb` in every task script.\nMirrors the Node.js global.sb capabilities.\n\"\"\"\nimport os\nimport sys\nimport json\nimport csv\nimport io\nimport time\nimport datetime as _dt\nimport urllib.request\nimport urllib.error\nimport urllib.parse\nfrom typing import Any, Dict, List, Optional\n\n# Agent \u8C03\u7528\u7AEF\u70B9\uFF08\u7531\u8FD0\u884C\u65F6\u6CE8\u5165\uFF09\n_AGENT_ENDPOINT = \"__AGENT_ENDPOINT__\"\n_AGENT_CONFIGURED = bool(_AGENT_ENDPOINT)\n\n\nclass _Logger:\n def __init__(self, sink):\n self._sink = sink\n\n def debug(self, message, meta=None):\n self._sink(\"debug\", message, meta)\n\n def info(self, message, meta=None):\n self._sink(\"info\", message, meta)\n\n def warn(self, message, meta=None):\n self._sink(\"warn\", message, meta)\n\n def error(self, message, meta=None):\n self._sink(\"error\", message, meta)\n\n\n# ===== HTTP =====\n\ndef fetch(url, options=None, timeout=30):\n \"\"\"HTTP \u8BF7\u6C42\uFF0C\u8FD4\u56DE {status, headers, data, text}\u3002\"\"\"\n options = options or {}\n method = options.get(\"method\", \"GET\").upper()\n headers = dict(options.get(\"headers\") or {})\n headers.setdefault(\"User-Agent\", \"workai-sandbox/1.0\")\n params = options.get(\"params\")\n if params:\n query = urllib.parse.urlencode(params)\n url = url + (\"&\" if \"?\" in url else \"?\") + query\n body = options.get(\"body\")\n json_body = options.get(\"json\")\n data = None\n if json_body is not None:\n data = json.dumps(json_body).encode(\"utf-8\")\n headers.setdefault(\"Content-Type\", \"application/json\")\n elif body is not None:\n if isinstance(body, str):\n data = body.encode(\"utf-8\")\n elif isinstance(body, (bytes, bytearray)):\n data = bytes(body)\n else:\n data = json.dumps(body).encode(\"utf-8\")\n headers.setdefault(\"Content-Type\", \"application/json\")\n req = urllib.request.Request(url, data=data, headers=headers, method=method)\n try:\n with urllib.request.urlopen(req, timeout=timeout) as resp:\n status = resp.status\n resp_headers = dict(resp.headers)\n text = resp.read().decode(\"utf-8\", errors=\"replace\")\n except urllib.error.HTTPError as e:\n status = e.code\n resp_headers = dict(e.headers) if e.headers else {}\n text = e.read().decode(\"utf-8\", errors=\"replace\") if e.fp else \"\"\n parsed = text\n ct = (resp_headers.get(\"Content-Type\") or \"\").lower()\n if \"application/json\" in ct or \"+json\" in ct:\n try:\n parsed = json.loads(text)\n except Exception:\n pass\n return {\"status\": status, \"headers\": resp_headers, \"data\": parsed, \"text\": text}\n\n\ndef get(url, options=None, timeout=30):\n return fetch(url, dict(options or {}, method=\"GET\"), timeout)\n\n\ndef post(url, body=None, options=None, timeout=30):\n opts = dict(options or {}, method=\"POST\")\n if isinstance(body, (dict, list)):\n opts[\"json\"] = body\n else:\n opts[\"body\"] = body\n return fetch(url, opts, timeout)\n\n\n# ===== File I/O =====\n\ndef read_text(file_path, encoding=\"utf-8\"):\n with open(file_path, \"r\", encoding=encoding) as f:\n return f.read()\n\n\ndef write_text(file_path, content, encoding=\"utf-8\"):\n _ensure_parent(file_path)\n with open(file_path, \"w\", encoding=encoding) as f:\n f.write(content)\n\n\ndef append_text(file_path, content, encoding=\"utf-8\"):\n _ensure_parent(file_path)\n with open(file_path, \"a\", encoding=encoding) as f:\n f.write(content)\n\n\ndef read_json(file_path):\n with open(file_path, \"r\", encoding=\"utf-8\") as f:\n return json.load(f)\n\n\ndef write_json(file_path, data, indent=2):\n _ensure_parent(file_path)\n with open(file_path, \"w\", encoding=\"utf-8\") as f:\n json.dump(data, f, ensure_ascii=False, indent=indent)\n\n\ndef read_csv(file_path):\n with open(file_path, \"r\", encoding=\"utf-8\", newline=\"\") as f:\n return list(csv.DictReader(f))\n\n\ndef write_csv(file_path, rows):\n _ensure_parent(file_path)\n if not rows:\n with open(file_path, \"w\", encoding=\"utf-8\", newline=\"\") as f:\n f.write(\"\")\n return\n with open(file_path, \"w\", encoding=\"utf-8\", newline=\"\") as f:\n writer = csv.DictWriter(f, fieldnames=list(rows[0].keys()))\n writer.writeheader()\n writer.writerows(rows)\n\n\ndef exists(file_path):\n return os.path.exists(file_path)\n\n\ndef list_dir(dir_path=\".\"):\n return os.listdir(dir_path)\n\n\ndef _ensure_parent(file_path):\n parent = os.path.dirname(os.path.abspath(file_path))\n os.makedirs(parent, exist_ok=True)\n\n\n# ===== Data helpers =====\n\ndef stats(values):\n values = [v for v in values if v is not None]\n n = len(values)\n if n == 0:\n return {\"count\": 0, \"sum\": 0, \"avg\": 0, \"min\": None, \"max\": None}\n s = sum(values)\n return {\"count\": n, \"sum\": s, \"avg\": s / n, \"min\": min(values), \"max\": max(values)}\n\n\ndef sum_of(values):\n return sum(v for v in values if v is not None)\n\n\ndef avg(values):\n vals = [v for v in values if v is not None]\n return sum(vals) / len(vals) if vals else 0\n\n\ndef group_by(rows, key):\n result = {}\n for row in rows:\n k = row.get(key) if isinstance(row, dict) else getattr(row, key, None)\n result.setdefault(k, []).append(row)\n return result\n\n\ndef sort_by(rows, key, reverse=False):\n return sorted(rows, key=lambda r: (r.get(key) if isinstance(r, dict) else getattr(r, key, None)), reverse=reverse)\n\n\ndef unique(values):\n seen = []\n for v in values:\n if v not in seen:\n seen.append(v)\n return seen\n\n\ndef chunk(values, size):\n return [values[i:i + size] for i in range(0, len(values), size)]\n\n\n# ===== Date helpers =====\n\ndef now():\n return _dt.datetime.now()\n\n\ndef format_date(dt, fmt=\"%Y-%m-%d %H:%M:%S\"):\n if isinstance(dt, (int, float)):\n dt = _dt.datetime.fromtimestamp(dt)\n if isinstance(dt, str):\n dt = _dt.datetime.fromisoformat(dt)\n return dt.strftime(fmt)\n\n\ndef parse_date(text, fmt=None):\n if fmt:\n return _dt.datetime.strptime(text, fmt)\n return _dt.datetime.fromisoformat(text)\n\n\ndef days_go(n):\n return _dt.datetime.now() - _dt.timedelta(days=n)\n\n\ndef days_later(n):\n return _dt.datetime.now() + _dt.timedelta(days=n)\n\n\n# ===== Agent =====\n\nclass _Agent:\n \"\"\"\u8C03\u7528\u5E73\u53F0 Agent \u80FD\u529B\uFF08\u57FA\u4E8E A2A JSON-RPC\uFF09\u3002\"\"\"\n\n def ask(self, prompt, options=None):\n \"\"\"\u5411 Agent \u53D1\u9001\u63D0\u793A\u8BCD\u5E76\u540C\u6B65\u7B49\u5F85\u6587\u672C\u56DE\u590D\u3002\n\n \u91C7\u7528 A2A \u6D41\u5F0F\u534F\u8BAE\uFF08tasks/sendSubscribe + SSE\uFF09\uFF1A\n - \u6D41\u5F0F\u9010 token \u8FD4\u56DE\uFF0C\u907F\u514D\u975E\u6D41\u5F0F HTTP \u957F\u7B49\u5F85\u8D85\u65F6\uFF1B\n - \u670D\u52A1\u7AEF\u6BCF 3s \u53D1\u9001\u5FC3\u8DF3\uFF0C\u4FDD\u6301\u8FDE\u63A5\u6D3B\u8DC3\uFF1B\n - timeout \u4E3A\u5355\u6B21\u8BFB\u53D6\u8D85\u65F6\uFF08\u9ED8\u8BA4 600s\uFF09\uFF0C\u6D41\u5F0F\u5FC3\u8DF3\u4FDD\u8BC1\u4E0D\u4F1A\u56E0\u7A7A\u95F2\u800C\u8D85\u65F6\u3002\n \"\"\"\n if not _AGENT_CONFIGURED:\n raise RuntimeError(\"Agent endpoint not configured\")\n options = options or {}\n timeout = options.get(\"timeout\", 600)\n payload = {\n \"jsonrpc\": \"2.0\",\n \"id\": options.get(\"id\", 1),\n \"method\": \"tasks/sendSubscribe\",\n \"params\": {\n \"message\": {\n \"role\": \"user\",\n \"parts\": [{\"kind\": \"text\", \"text\": str(prompt)}],\n },\n \"contextId\": options.get(\"contextId\"),\n \"profile\": options.get(\"profile\"),\n },\n }\n data = json.dumps(payload).encode(\"utf-8\")\n req = urllib.request.Request(\n _AGENT_ENDPOINT,\n data=data,\n headers={\n \"Content-Type\": \"application/json\",\n \"Accept\": \"text/event-stream\",\n \"User-Agent\": \"workai-sandbox/1.0\",\n },\n method=\"POST\",\n )\n final_text = \"\"\n task_failed = False\n task_error = None\n try:\n resp = urllib.request.urlopen(req, timeout=timeout)\n except urllib.error.HTTPError as e:\n raise RuntimeError(\"Agent call failed (HTTP %s)\" % e.code)\n try:\n for raw in resp:\n line = raw.decode(\"utf-8\", errors=\"replace\").strip()\n if not line.startswith(\"data:\"):\n continue\n payload_str = line[5:].strip()\n if not payload_str:\n continue\n try:\n msg = json.loads(payload_str)\n except Exception:\n continue\n result = msg.get(\"result\") or {}\n etype = result.get(\"type\")\n edata = result.get(\"data\")\n if etype == \"message\" and isinstance(edata, dict):\n for p in (edata.get(\"parts\") or []):\n if (p.get(\"kind\") == \"text\" or p.get(\"type\") == \"text\") and p.get(\"text\"):\n final_text = p[\"text\"]\n elif etype == \"error\":\n err_msg = edata.get(\"message\") if isinstance(edata, dict) else str(edata)\n raise RuntimeError(\"Agent error: %s\" % err_msg)\n elif etype == \"task\" and isinstance(edata, dict) and edata.get(\"state\") == \"failed\":\n task_failed = True\n task_error = edata.get(\"error\")\n finally:\n try:\n resp.close()\n except Exception:\n pass\n if task_failed:\n raise RuntimeError(\"Agent task failed: %s\" % (task_error or \"unknown\"))\n return final_text\n\n\nagent = _Agent()\n";
|
|
5
|
+
export declare const PYTHON_PRELUDE_SOURCE = "# -*- coding: utf-8 -*-\n\"\"\"\nSandbox Prelude for Python automation tasks.\nAuto-imported as `sb` in every task script.\nMirrors the Node.js global.sb capabilities.\n\"\"\"\nimport os\nimport sys\nimport json\nimport csv\nimport io\nimport time\nimport datetime as _dt\nimport urllib.request\nimport urllib.error\nimport urllib.parse\nimport threading\nimport hashlib\nimport uuid as _uuid\nimport random as _random\nfrom typing import Any, Dict, List, Optional\n\n# Agent \u8C03\u7528\u7AEF\u70B9\uFF08\u7531\u8FD0\u884C\u65F6\u6CE8\u5165\uFF09\n_AGENT_ENDPOINT = \"__AGENT_ENDPOINT__\"\n_AGENT_CONFIGURED = bool(_AGENT_ENDPOINT)\n\n# \u5185\u5B58\u7F13\u5B58\uFF08\u5E26 TTL\uFF09\uFF0C\u7528\u4E8E sb.cache\n_CACHE_STORE: Dict[str, Any] = {}\n_CACHE_LOCK = threading.Lock()\n\n\nclass _Logger:\n def __init__(self, sink):\n self._sink = sink\n\n def debug(self, message, meta=None):\n self._sink(\"debug\", message, meta)\n\n def info(self, message, meta=None):\n self._sink(\"info\", message, meta)\n\n def warn(self, message, meta=None):\n self._sink(\"warn\", message, meta)\n\n def error(self, message, meta=None):\n self._sink(\"error\", message, meta)\n\n\n# ===== HTTP =====\n\ndef fetch(url, options=None, timeout=30):\n \"\"\"HTTP \u8BF7\u6C42\uFF0C\u8FD4\u56DE {status, headers, data, text}\u3002\"\"\"\n options = options or {}\n method = options.get(\"method\", \"GET\").upper()\n headers = dict(options.get(\"headers\") or {})\n headers.setdefault(\"User-Agent\", \"workai-sandbox/1.0\")\n params = options.get(\"params\")\n if params:\n query = urllib.parse.urlencode(params)\n url = url + (\"&\" if \"?\" in url else \"?\") + query\n body = options.get(\"body\")\n json_body = options.get(\"json\")\n data = None\n if json_body is not None:\n data = json.dumps(json_body).encode(\"utf-8\")\n headers.setdefault(\"Content-Type\", \"application/json\")\n elif body is not None:\n if isinstance(body, str):\n data = body.encode(\"utf-8\")\n elif isinstance(body, (bytes, bytearray)):\n data = bytes(body)\n else:\n data = json.dumps(body).encode(\"utf-8\")\n headers.setdefault(\"Content-Type\", \"application/json\")\n req = urllib.request.Request(url, data=data, headers=headers, method=method)\n try:\n with urllib.request.urlopen(req, timeout=timeout) as resp:\n status = resp.status\n resp_headers = dict(resp.headers)\n text = resp.read().decode(\"utf-8\", errors=\"replace\")\n except urllib.error.HTTPError as e:\n status = e.code\n resp_headers = dict(e.headers) if e.headers else {}\n text = e.read().decode(\"utf-8\", errors=\"replace\") if e.fp else \"\"\n parsed = text\n ct = (resp_headers.get(\"Content-Type\") or \"\").lower()\n if \"application/json\" in ct or \"+json\" in ct:\n try:\n parsed = json.loads(text)\n except Exception:\n pass\n return {\"status\": status, \"headers\": resp_headers, \"data\": parsed, \"text\": text}\n\n\ndef get(url, options=None, timeout=30):\n return fetch(url, dict(options or {}, method=\"GET\"), timeout)\n\n\ndef post(url, body=None, options=None, timeout=30):\n opts = dict(options or {}, method=\"POST\")\n if isinstance(body, (dict, list)):\n opts[\"json\"] = body\n else:\n opts[\"body\"] = body\n return fetch(url, opts, timeout)\n\n\n# ===== File I/O =====\n\ndef read_text(file_path, encoding=\"utf-8\"):\n with open(file_path, \"r\", encoding=encoding) as f:\n return f.read()\n\n\ndef write_text(file_path, content, encoding=\"utf-8\"):\n _ensure_parent(file_path)\n with open(file_path, \"w\", encoding=encoding) as f:\n f.write(content)\n\n\ndef append_text(file_path, content, encoding=\"utf-8\"):\n _ensure_parent(file_path)\n with open(file_path, \"a\", encoding=encoding) as f:\n f.write(content)\n\n\ndef read_json(file_path):\n with open(file_path, \"r\", encoding=\"utf-8\") as f:\n return json.load(f)\n\n\ndef write_json(file_path, data, indent=2):\n _ensure_parent(file_path)\n with open(file_path, \"w\", encoding=\"utf-8\") as f:\n json.dump(data, f, ensure_ascii=False, indent=indent)\n\n\ndef read_csv(file_path):\n with open(file_path, \"r\", encoding=\"utf-8\", newline=\"\") as f:\n return list(csv.DictReader(f))\n\n\ndef write_csv(file_path, rows):\n _ensure_parent(file_path)\n if not rows:\n with open(file_path, \"w\", encoding=\"utf-8\", newline=\"\") as f:\n f.write(\"\")\n return\n with open(file_path, \"w\", encoding=\"utf-8\", newline=\"\") as f:\n writer = csv.DictWriter(f, fieldnames=list(rows[0].keys()))\n writer.writeheader()\n writer.writerows(rows)\n\n\ndef exists(file_path):\n return os.path.exists(file_path)\n\n\ndef list_dir(dir_path=\".\"):\n return os.listdir(dir_path)\n\n\ndef _ensure_parent(file_path):\n parent = os.path.dirname(os.path.abspath(file_path))\n os.makedirs(parent, exist_ok=True)\n\n\n# ===== Data helpers =====\n\ndef stats(values):\n values = [v for v in values if v is not None]\n n = len(values)\n if n == 0:\n return {\"count\": 0, \"sum\": 0, \"avg\": 0, \"min\": None, \"max\": None}\n s = sum(values)\n return {\"count\": n, \"sum\": s, \"avg\": s / n, \"min\": min(values), \"max\": max(values)}\n\n\ndef sum_of(values):\n return sum(v for v in values if v is not None)\n\n\ndef avg(values):\n vals = [v for v in values if v is not None]\n return sum(vals) / len(vals) if vals else 0\n\n\ndef group_by(rows, key):\n result = {}\n for row in rows:\n k = row.get(key) if isinstance(row, dict) else getattr(row, key, None)\n result.setdefault(k, []).append(row)\n return result\n\n\ndef sort_by(rows, key, reverse=False):\n return sorted(rows, key=lambda r: (r.get(key) if isinstance(r, dict) else getattr(r, key, None)), reverse=reverse)\n\n\ndef unique(values):\n seen = []\n for v in values:\n if v not in seen:\n seen.append(v)\n return seen\n\n\ndef chunk(values, size):\n return [values[i:i + size] for i in range(0, len(values), size)]\n\n\n# ===== Date helpers =====\n\ndef now():\n return _dt.datetime.now()\n\n\ndef format_date(dt, fmt=\"%Y-%m-%d %H:%M:%S\"):\n if isinstance(dt, (int, float)):\n dt = _dt.datetime.fromtimestamp(dt)\n if isinstance(dt, str):\n dt = _dt.datetime.fromisoformat(dt)\n return dt.strftime(fmt)\n\n\ndef parse_date(text, fmt=None):\n if fmt:\n return _dt.datetime.strptime(text, fmt)\n return _dt.datetime.fromisoformat(text)\n\n\ndef days_ago(n):\n return _dt.datetime.now() - _dt.timedelta(days=n)\n\n\n# \u517C\u5BB9\u65E7\u540D\uFF08\u6587\u6863\u4E0E\u793A\u4F8B\u7EDF\u4E00\u4F7F\u7528 sb.days_ago\uFF09\ndays_go = days_ago\n\n\ndef days_later(n):\n return _dt.datetime.now() + _dt.timedelta(days=n)\n\n\n# ===== \u5DE5\u5177\u51FD\u6570\uFF08Util\uFF09 =====\n\ndef sleep(seconds):\n \"\"\"\u963B\u585E\u5F53\u524D\u534F\u7A0B/\u7EBF\u7A0B\u6307\u5B9A\u79D2\u6570\u3002\"\"\"\n time.sleep(seconds)\n\n\ndef uuid() -> str:\n \"\"\"\u751F\u6210 UUID4 \u5B57\u7B26\u4E32\u3002\"\"\"\n return str(_uuid.uuid4())\n\n\ndef hash(value, algo=\"sha256\") -> str:\n \"\"\"\u8BA1\u7B97\u5B57\u7B26\u4E32/\u5BF9\u8C61\u7684\u54C8\u5E0C\uFF08\u9ED8\u8BA4 sha256\uFF09\u3002\"\"\"\n h = hashlib.new(algo)\n h.update(str(value).encode(\"utf-8\"))\n return h.hexdigest()\n\n\ndef random_int(min_value=0, max_value=100) -> int:\n \"\"\"\u8FD4\u56DE [min_value, max_value] \u533A\u95F4\u5185\u7684\u968F\u673A\u6574\u6570\u3002\"\"\"\n return _random.randint(min_value, max_value)\n\n\ndef random_choice(seq):\n \"\"\"\u4ECE\u5E8F\u5217\u4E2D\u968F\u673A\u53D6\u4E00\u4E2A\u5143\u7D20\u3002\"\"\"\n return _random.choice(seq)\n\n\ndef random_float(min_value=0.0, max_value=1.0) -> float:\n \"\"\"\u8FD4\u56DE [min_value, max_value] \u533A\u95F4\u5185\u7684\u968F\u673A\u6D6E\u70B9\u6570\u3002\"\"\"\n return _random.uniform(min_value, max_value)\n\n\ndef cache(key: str, ttl: Optional[float] = None):\n \"\"\"\u5E26 TTL \u7684\u5185\u5B58\u7F13\u5B58\u8BBF\u95EE\u5668\u3002\n\n \u7528\u6CD5\uFF1A\n hits = sb.cache(\"api:hot\", ttl=60).get(lambda: sb.get(\"/hot\").get(\"data\"))\n sb.cache(\"api:hot\").clear() # \u6E05\u9664\u8BE5 key\n\n ttl \u4E3A None \u8868\u793A\u6C38\u4E0D\u8FC7\u671F\uFF08\u8FDB\u7A0B\u5185\uFF09\u3002\n \u8FD4\u56DE\u5BF9\u8C61\u542B get(factory) / clear() \u4E24\u4E2A\u65B9\u6CD5\u3002\n \"\"\"\n class _CacheEntry:\n __slots__ = (\"value\", \"expire_at\")\n def __init__(self, value, expire_at):\n self.value = value\n self.expire_at = expire_at\n\n def _get(factory):\n now_ts = time.time()\n with _CACHE_LOCK:\n entry = _CACHE_STORE.get(key)\n if entry is not None and (entry.expire_at is None or entry.expire_at > now_ts):\n return entry.value\n value = factory() if callable(factory) else factory\n _CACHE_STORE[key] = _CacheEntry(value, now_ts + ttl if ttl else None)\n return value\n\n def _clear():\n with _CACHE_LOCK:\n _CACHE_STORE.pop(key, None)\n\n return type(\"CacheHandle\", (), {\"get\": _get, \"clear\": _clear})()\n\n\n# ===== Agent =====\n\nclass _Agent:\n \"\"\"\u8C03\u7528\u5E73\u53F0 Agent \u80FD\u529B\uFF08\u57FA\u4E8E A2A JSON-RPC\uFF09\u3002\"\"\"\n\n def ask(self, prompt, options=None):\n \"\"\"\u5411 Agent \u53D1\u9001\u63D0\u793A\u8BCD\u5E76\u540C\u6B65\u7B49\u5F85\u6587\u672C\u56DE\u590D\u3002\n\n \u91C7\u7528 A2A \u6D41\u5F0F\u534F\u8BAE\uFF08tasks/sendSubscribe + SSE\uFF09\uFF1A\n - \u6D41\u5F0F\u9010 token \u8FD4\u56DE\uFF0C\u907F\u514D\u975E\u6D41\u5F0F HTTP \u957F\u7B49\u5F85\u8D85\u65F6\uFF1B\n - \u670D\u52A1\u7AEF\u6BCF 3s \u53D1\u9001\u5FC3\u8DF3\uFF0C\u4FDD\u6301\u8FDE\u63A5\u6D3B\u8DC3\uFF1B\n - timeout \u4E3A\u5355\u6B21\u8BFB\u53D6\u8D85\u65F6\uFF08\u9ED8\u8BA4 600s\uFF09\uFF0C\u6D41\u5F0F\u5FC3\u8DF3\u4FDD\u8BC1\u4E0D\u4F1A\u56E0\u7A7A\u95F2\u800C\u8D85\u65F6\u3002\n\n options:\n - timeout : \u5355\u6B21\u8BFB\u53D6\u8D85\u65F6\uFF08\u79D2\uFF09\n - contextId : \u4F1A\u8BDD\u4E0A\u4E0B\u6587 id\uFF08\u7528\u4E8E\u591A\u8F6E\u8BB0\u5FC6\uFF09\n - profile : Agent profile\uFF08\u540D\u79F0\u6216 id\uFF09\n - json : True \u65F6\u628A\u6700\u7EC8\u6587\u672C\u6309 JSON \u89E3\u6790\u5E76\u8FD4\u56DE\u5BF9\u8C61\uFF08\u81EA\u52A8\u53BB\u9664 ``` \u4EE3\u7801\u56F4\u680F\uFF09\n \"\"\"\n if not _AGENT_CONFIGURED:\n raise RuntimeError(\"Agent endpoint not configured\")\n options = options or {}\n timeout = options.get(\"timeout\", 600)\n json_mode = options.get(\"json\", False)\n payload = {\n \"jsonrpc\": \"2.0\",\n \"id\": options.get(\"id\", 1),\n \"method\": \"tasks/sendSubscribe\",\n \"params\": {\n \"message\": {\n \"role\": \"user\",\n \"parts\": [{\"kind\": \"text\", \"text\": str(prompt)}],\n },\n \"contextId\": options.get(\"contextId\"),\n \"profile\": options.get(\"profile\"),\n },\n }\n data = json.dumps(payload).encode(\"utf-8\")\n req = urllib.request.Request(\n _AGENT_ENDPOINT,\n data=data,\n headers={\n \"Content-Type\": \"application/json\",\n \"Accept\": \"text/event-stream\",\n \"User-Agent\": \"workai-sandbox/1.0\",\n },\n method=\"POST\",\n )\n final_text = \"\"\n task_failed = False\n task_error = None\n try:\n resp = urllib.request.urlopen(req, timeout=timeout)\n except urllib.error.HTTPError as e:\n raise RuntimeError(\"Agent call failed (HTTP %s)\" % e.code)\n try:\n for raw in resp:\n line = raw.decode(\"utf-8\", errors=\"replace\").strip()\n if not line.startswith(\"data:\"):\n continue\n payload_str = line[5:].strip()\n if not payload_str:\n continue\n try:\n msg = json.loads(payload_str)\n except Exception:\n continue\n result = msg.get(\"result\") or {}\n etype = result.get(\"type\")\n edata = result.get(\"data\")\n if etype == \"message\" and isinstance(edata, dict):\n for p in (edata.get(\"parts\") or []):\n if (p.get(\"kind\") == \"text\" or p.get(\"type\") == \"text\") and p.get(\"text\"):\n final_text = p[\"text\"]\n elif etype == \"error\":\n err_msg = edata.get(\"message\") if isinstance(edata, dict) else str(edata)\n raise RuntimeError(\"Agent error: %s\" % err_msg)\n elif etype == \"task\" and isinstance(edata, dict) and edata.get(\"state\") == \"failed\":\n task_failed = True\n task_error = edata.get(\"error\")\n finally:\n try:\n resp.close()\n except Exception:\n pass\n if task_failed:\n raise RuntimeError(\"Agent task failed: %s\" % (task_error or \"unknown\"))\n if json_mode:\n return _parse_json_text(final_text)\n return final_text\n\n def stream(self, prompt, options=None):\n \"\"\"\u6D41\u5F0F\u8C03\u7528 Agent\uFF0C\u589E\u91CF yield \u6587\u672C\u7247\u6BB5\uFF08delta\uFF09\u3002\n\n A2A \u7684 message \u4E8B\u4EF6\u901A\u5E38\u643A\u5E26\u300C\u5230\u76EE\u524D\u4E3A\u6B62\u7684\u5B8C\u6574\u6587\u672C\u300D\uFF0C\u6545\u4E0E\u524D\u4E00\u6B21\u6587\u672C\u505A\u524D\u7F00\n \u6BD4\u8F83\uFF0C\u53EA\u8F93\u51FA\u65B0\u589E\u90E8\u5206\uFF08delta\uFF09\uFF0C\u907F\u514D\u91CD\u590D\u3002\n\n options \u540C ask\uFF08timeout / contextId / profile / json\uFF09\u3002\n json=True \u65F6\uFF0C\u6D41\u5F0F\u7ED3\u675F\u540E\u989D\u5916 yield \u4E00\u6B21\u89E3\u6790\u540E\u7684\u5BF9\u8C61\uFF08\u6700\u540E\u4E00\u6B21 yield \u4E3A dict\uFF09\u3002\n \"\"\"\n if not _AGENT_CONFIGURED:\n raise RuntimeError(\"Agent endpoint not configured\")\n options = options or {}\n timeout = options.get(\"timeout\", 600)\n json_mode = options.get(\"json\", False)\n payload = {\n \"jsonrpc\": \"2.0\",\n \"id\": options.get(\"id\", 1),\n \"method\": \"tasks/sendSubscribe\",\n \"params\": {\n \"message\": {\n \"role\": \"user\",\n \"parts\": [{\"kind\": \"text\", \"text\": str(prompt)}],\n },\n \"contextId\": options.get(\"contextId\"),\n \"profile\": options.get(\"profile\"),\n },\n }\n data = json.dumps(payload).encode(\"utf-8\")\n req = urllib.request.Request(\n _AGENT_ENDPOINT,\n data=data,\n headers={\n \"Content-Type\": \"application/json\",\n \"Accept\": \"text/event-stream\",\n\n \"User-Agent\": \"workai-sandbox/1.0\",\n },\n method=\"POST\",\n )\n last = \"\"\n buf = b\"\"\n try:\n resp = urllib.request.urlopen(req, timeout=timeout)\n except urllib.error.HTTPError as e:\n raise RuntimeError(\"Agent call failed (HTTP %s)\" % e.code)\n try:\n for raw in resp:\n buf += raw\n while b\"\n\n\" in buf:\n block, buf = buf.split(b\"\n\n\", 1)\n text = block.decode(\"utf-8\", errors=\"replace\")\n for line in text.splitlines():\n if not line.startswith(\"data:\"):\n continue\n payload_str = line[5:].strip()\n if not payload_str:\n continue\n try:\n msg = json.loads(payload_str)\n except Exception:\n continue\n result = msg.get(\"result\") or {}\n etype = result.get(\"type\")\n edata = result.get(\"data\")\n if etype == \"error\":\n err_msg = edata.get(\"message\") if isinstance(edata, dict) else str(edata)\n raise RuntimeError(\"Agent error: %s\" % err_msg)\n t = \"\"\n if etype == \"message\" and isinstance(edata, dict):\n for p in (edata.get(\"parts\") or []):\n if (p.get(\"kind\") == \"text\" or p.get(\"type\") == \"text\") and p.get(\"text\"):\n t = p[\"text\"]\n elif etype == \"task\" and isinstance(edata, dict) and edata.get(\"state\") == \"failed\":\n raise RuntimeError(\"Agent task failed: %s\" % (edata.get(\"error\") or \"unknown\"))\n if not t:\n continue\n # \u524D\u7F00\u5DEE\u91CF\uFF1A\u53EA\u8F93\u51FA\u65B0\u589E\u5185\u5BB9\n if t.startswith(last):\n delta = t[len(last):]\n if delta:\n yield delta\n else:\n yield t\n last = t\n finally:\n try:\n resp.close()\n except Exception:\n pass\n if json_mode and last:\n yield _parse_json_text(last)\n\n\ndef _parse_json_text(text):\n \"\"\"\u628A Agent \u8FD4\u56DE\u6587\u672C\u6309 JSON \u89E3\u6790\uFF08\u81EA\u52A8\u53BB\u9664 ```json \u4EE3\u7801\u56F4\u680F\uFF09\u3002\"\"\"\n s = (text or \"\").strip()\n if s.startswith(\"```\"):\n # \u53BB\u9664\u9996\u884C\u56F4\u680F\uFF08```json / ```\uFF09\n s = s.split(\"\n\", 1)[1] if \"\n\" in s else s[3:]\n if s.endswith(\"```\"):\n s = s[:-3]\n s = s.strip()\n try:\n return json.loads(s)\n except Exception:\n raise RuntimeError(\"Agent \u8FD4\u56DE\u5185\u5BB9\u4E0D\u662F\u5408\u6CD5 JSON: %s\" % s[:200])\n\n\nagent = _Agent()\n";
|
|
6
6
|
//# sourceMappingURL=python-prelude.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"python-prelude.d.ts","sourceRoot":"","sources":["../../../src/automation/python-prelude.ts"],"names":[],"mappings":"AAQA;;;GAGG;AACH,eAAO,MAAM,qBAAqB,
|
|
1
|
+
{"version":3,"file":"python-prelude.d.ts","sourceRoot":"","sources":["../../../src/automation/python-prelude.ts"],"names":[],"mappings":"AAQA;;;GAGG;AACH,eAAO,MAAM,qBAAqB,ymlBA8fjC,CAAC"}
|