augure 0.5.1 → 0.6.1
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/bin.js +491 -6
- package/package.json +21 -20
package/dist/bin.js
CHANGED
|
@@ -135,6 +135,11 @@ var AppConfigSchema = z.object({
|
|
|
135
135
|
checkInterval: z.string().min(1).default("24h"),
|
|
136
136
|
notifyChannel: z.string().min(1).default("telegram")
|
|
137
137
|
}).optional()
|
|
138
|
+
}).optional(),
|
|
139
|
+
codeMode: z.object({
|
|
140
|
+
runtime: z.enum(["vm", "docker", "auto"]).default("auto"),
|
|
141
|
+
timeout: z.number().int().positive().default(30),
|
|
142
|
+
memoryLimit: z.number().int().positive().default(128)
|
|
138
143
|
}).optional()
|
|
139
144
|
});
|
|
140
145
|
function interpolateEnvVars(raw) {
|
|
@@ -180,6 +185,7 @@ var OpenRouterClient = class {
|
|
|
180
185
|
}
|
|
181
186
|
async chat(messages, tools) {
|
|
182
187
|
this.log.debug(`Request: model=${this.model} messages=${messages.length} tools=${tools?.length ?? 0}`);
|
|
188
|
+
const fetchStart = Date.now();
|
|
183
189
|
const response = await fetch(`${this.baseUrl}/chat/completions`, {
|
|
184
190
|
method: "POST",
|
|
185
191
|
headers: {
|
|
@@ -213,7 +219,7 @@ var OpenRouterClient = class {
|
|
|
213
219
|
}
|
|
214
220
|
const data = await response.json();
|
|
215
221
|
const choice = data.choices[0];
|
|
216
|
-
this.log.debug(`Response: ${response.status} ${data.usage.prompt_tokens}+${data.usage.completion_tokens} tokens`);
|
|
222
|
+
this.log.debug(`Response: ${response.status} ${data.usage.prompt_tokens}+${data.usage.completion_tokens} tokens in ${Date.now() - fetchStart}ms`);
|
|
217
223
|
return {
|
|
218
224
|
content: choice.message.content ?? "",
|
|
219
225
|
toolCalls: (choice.message.tool_calls ?? []).map((tc) => {
|
|
@@ -267,6 +273,403 @@ ${memoryContent}`;
|
|
|
267
273
|
return messages;
|
|
268
274
|
}
|
|
269
275
|
|
|
276
|
+
// ../code-mode/dist/typegen.js
|
|
277
|
+
var JSON_TO_TS = {
|
|
278
|
+
string: "string",
|
|
279
|
+
number: "number",
|
|
280
|
+
integer: "number",
|
|
281
|
+
boolean: "boolean",
|
|
282
|
+
array: "unknown[]",
|
|
283
|
+
object: "Record<string, unknown>"
|
|
284
|
+
};
|
|
285
|
+
function sanitizeName(name) {
|
|
286
|
+
return name.replace(/[-. ]/g, "_");
|
|
287
|
+
}
|
|
288
|
+
function toPascalCase(name) {
|
|
289
|
+
return sanitizeName(name).split("_").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
|
|
290
|
+
}
|
|
291
|
+
function mapType(schema) {
|
|
292
|
+
const t = schema.type;
|
|
293
|
+
if (schema.enum) {
|
|
294
|
+
return schema.enum.map((v) => `"${v}"`).join(" | ");
|
|
295
|
+
}
|
|
296
|
+
return JSON_TO_TS[t ?? "string"] ?? "unknown";
|
|
297
|
+
}
|
|
298
|
+
function generateDeclarations(registry) {
|
|
299
|
+
const tools = registry.list();
|
|
300
|
+
const blocks = [];
|
|
301
|
+
const apiEntries = [];
|
|
302
|
+
for (const tool of tools) {
|
|
303
|
+
const safeName = sanitizeName(tool.name);
|
|
304
|
+
const interfaceName = `${toPascalCase(tool.name)}Input`;
|
|
305
|
+
const params = tool.parameters;
|
|
306
|
+
const properties = params.properties ?? {};
|
|
307
|
+
const required = new Set(params.required ?? []);
|
|
308
|
+
const fields = [];
|
|
309
|
+
for (const [key, schema] of Object.entries(properties)) {
|
|
310
|
+
const optional = required.has(key) ? "" : "?";
|
|
311
|
+
const tsType = mapType(schema);
|
|
312
|
+
const desc = schema.description;
|
|
313
|
+
if (desc) {
|
|
314
|
+
fields.push(` /** ${desc} */
|
|
315
|
+
${key}${optional}: ${tsType};`);
|
|
316
|
+
} else {
|
|
317
|
+
fields.push(` ${key}${optional}: ${tsType};`);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
blocks.push(`interface ${interfaceName} {
|
|
321
|
+
${fields.join("\n")}
|
|
322
|
+
}`);
|
|
323
|
+
apiEntries.push(` /** ${tool.description} */
|
|
324
|
+
${safeName}: (input: ${interfaceName}) => Promise<{ success: boolean; output: string }>;`);
|
|
325
|
+
}
|
|
326
|
+
const apiBlock = `declare const api: {
|
|
327
|
+
${apiEntries.join("\n")}
|
|
328
|
+
};`;
|
|
329
|
+
return [...blocks, "", apiBlock].join("\n");
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// ../code-mode/dist/bridge.js
|
|
333
|
+
function createBridgeHandler(registry) {
|
|
334
|
+
return async (toolName, input) => {
|
|
335
|
+
try {
|
|
336
|
+
return await registry.execute(toolName, input);
|
|
337
|
+
} catch (err2) {
|
|
338
|
+
return {
|
|
339
|
+
success: false,
|
|
340
|
+
output: `Bridge error calling ${toolName}: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
function generateHarnessCode(userCode) {
|
|
346
|
+
return `
|
|
347
|
+
const __logs = [];
|
|
348
|
+
const __originalLog = console.log;
|
|
349
|
+
const __originalWarn = console.warn;
|
|
350
|
+
const __originalError = console.error;
|
|
351
|
+
console.log = (...args) => __logs.push(args.map(String).join(" "));
|
|
352
|
+
console.warn = (...args) => __logs.push("[warn] " + args.map(String).join(" "));
|
|
353
|
+
console.error = (...args) => __logs.push("[error] " + args.map(String).join(" "));
|
|
354
|
+
|
|
355
|
+
let __toolCalls = 0;
|
|
356
|
+
|
|
357
|
+
const api = new Proxy({}, {
|
|
358
|
+
get: (_target, toolName) => {
|
|
359
|
+
return async (input) => {
|
|
360
|
+
__toolCalls++;
|
|
361
|
+
return await __bridge(String(toolName), input);
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
async function __run() {
|
|
367
|
+
${userCode}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
try {
|
|
371
|
+
const __result = await __run();
|
|
372
|
+
__originalLog(JSON.stringify({
|
|
373
|
+
success: true,
|
|
374
|
+
output: __result,
|
|
375
|
+
logs: __logs,
|
|
376
|
+
toolCalls: __toolCalls,
|
|
377
|
+
}));
|
|
378
|
+
} catch (err) {
|
|
379
|
+
__originalLog(JSON.stringify({
|
|
380
|
+
success: false,
|
|
381
|
+
error: err.message ?? String(err),
|
|
382
|
+
logs: __logs,
|
|
383
|
+
toolCalls: __toolCalls,
|
|
384
|
+
}));
|
|
385
|
+
}
|
|
386
|
+
`;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// ../code-mode/dist/vm-sandbox.js
|
|
390
|
+
import { createContext, runInContext } from "vm";
|
|
391
|
+
import { transform } from "esbuild";
|
|
392
|
+
var VmExecutor = class {
|
|
393
|
+
registry;
|
|
394
|
+
config;
|
|
395
|
+
constructor(registry, config) {
|
|
396
|
+
this.registry = registry;
|
|
397
|
+
this.config = config;
|
|
398
|
+
}
|
|
399
|
+
async execute(code) {
|
|
400
|
+
const start = performance.now();
|
|
401
|
+
try {
|
|
402
|
+
const harnessTs = generateHarnessCode(code);
|
|
403
|
+
const { code: harnessJs } = await transform(harnessTs, {
|
|
404
|
+
loader: "ts",
|
|
405
|
+
target: "es2024"
|
|
406
|
+
});
|
|
407
|
+
const bridgeHandler = createBridgeHandler(this.registry);
|
|
408
|
+
const consoleLogs = [];
|
|
409
|
+
const captureConsole = {
|
|
410
|
+
log: (...args) => consoleLogs.push(args.map(String).join(" ")),
|
|
411
|
+
warn: (...args) => consoleLogs.push("[warn] " + args.map(String).join(" ")),
|
|
412
|
+
error: (...args) => consoleLogs.push("[error] " + args.map(String).join(" "))
|
|
413
|
+
};
|
|
414
|
+
const context = createContext({
|
|
415
|
+
console: captureConsole,
|
|
416
|
+
__bridge: bridgeHandler,
|
|
417
|
+
JSON,
|
|
418
|
+
String,
|
|
419
|
+
Number,
|
|
420
|
+
Boolean,
|
|
421
|
+
Array,
|
|
422
|
+
Object,
|
|
423
|
+
Error,
|
|
424
|
+
Promise,
|
|
425
|
+
Map,
|
|
426
|
+
Set,
|
|
427
|
+
parseInt,
|
|
428
|
+
parseFloat,
|
|
429
|
+
isNaN,
|
|
430
|
+
isFinite,
|
|
431
|
+
setTimeout,
|
|
432
|
+
Date,
|
|
433
|
+
RegExp,
|
|
434
|
+
Math,
|
|
435
|
+
Symbol,
|
|
436
|
+
Uint8Array,
|
|
437
|
+
TextEncoder,
|
|
438
|
+
TextDecoder,
|
|
439
|
+
Buffer,
|
|
440
|
+
URL,
|
|
441
|
+
URLSearchParams
|
|
442
|
+
});
|
|
443
|
+
const wrappedCode = `(async () => { ${harnessJs} })()`;
|
|
444
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
445
|
+
const timer = setTimeout(() => reject(new Error("Timeout: code execution exceeded time limit")), this.config.timeout);
|
|
446
|
+
timer.unref?.();
|
|
447
|
+
});
|
|
448
|
+
const resultPromise = runInContext(wrappedCode, context, {
|
|
449
|
+
timeout: this.config.timeout
|
|
450
|
+
});
|
|
451
|
+
await Promise.race([resultPromise, timeoutPromise]);
|
|
452
|
+
const durationMs = performance.now() - start;
|
|
453
|
+
const lastLine = consoleLogs[consoleLogs.length - 1];
|
|
454
|
+
if (!lastLine) {
|
|
455
|
+
return {
|
|
456
|
+
success: false,
|
|
457
|
+
output: void 0,
|
|
458
|
+
logs: consoleLogs,
|
|
459
|
+
error: "No output produced by code execution",
|
|
460
|
+
durationMs,
|
|
461
|
+
toolCalls: 0
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
const parsed = JSON.parse(lastLine);
|
|
465
|
+
return {
|
|
466
|
+
success: parsed.success,
|
|
467
|
+
output: parsed.output,
|
|
468
|
+
logs: parsed.logs,
|
|
469
|
+
error: parsed.error,
|
|
470
|
+
durationMs,
|
|
471
|
+
toolCalls: parsed.toolCalls
|
|
472
|
+
};
|
|
473
|
+
} catch (err2) {
|
|
474
|
+
const durationMs = performance.now() - start;
|
|
475
|
+
return {
|
|
476
|
+
success: false,
|
|
477
|
+
output: void 0,
|
|
478
|
+
logs: [],
|
|
479
|
+
error: err2 instanceof Error ? err2.message : String(err2),
|
|
480
|
+
durationMs,
|
|
481
|
+
toolCalls: 0
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
// ../code-mode/dist/docker-sandbox.js
|
|
488
|
+
var DOCKER_HARNESS = `
|
|
489
|
+
import { readFile } from "node:fs/promises";
|
|
490
|
+
|
|
491
|
+
const __logs = [];
|
|
492
|
+
const __originalLog = console.log;
|
|
493
|
+
console.log = (...args) => __logs.push(args.map(String).join(" "));
|
|
494
|
+
console.warn = (...args) => __logs.push("[warn] " + args.map(String).join(" "));
|
|
495
|
+
console.error = (...args) => __logs.push("[error] " + args.map(String).join(" "));
|
|
496
|
+
|
|
497
|
+
let __toolCalls = 0;
|
|
498
|
+
|
|
499
|
+
const api = new Proxy({}, {
|
|
500
|
+
get: (_target, toolName) => {
|
|
501
|
+
return async () => {
|
|
502
|
+
__toolCalls++;
|
|
503
|
+
return { success: false, output: "Tool calls not yet supported in Docker executor" };
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
const __userCode = await readFile("/workspace/user-code.js", "utf-8");
|
|
509
|
+
const __fn = new Function("api", "__logs",
|
|
510
|
+
"return (async () => { " + __userCode + " })();"
|
|
511
|
+
);
|
|
512
|
+
|
|
513
|
+
try {
|
|
514
|
+
const __result = await __fn(api, __logs);
|
|
515
|
+
__originalLog(JSON.stringify({
|
|
516
|
+
success: true,
|
|
517
|
+
output: __result,
|
|
518
|
+
logs: __logs,
|
|
519
|
+
toolCalls: __toolCalls,
|
|
520
|
+
}));
|
|
521
|
+
} catch (err) {
|
|
522
|
+
__originalLog(JSON.stringify({
|
|
523
|
+
success: false,
|
|
524
|
+
error: err.message ?? String(err),
|
|
525
|
+
logs: __logs,
|
|
526
|
+
toolCalls: __toolCalls,
|
|
527
|
+
}));
|
|
528
|
+
}
|
|
529
|
+
`;
|
|
530
|
+
var DockerExecutor = class {
|
|
531
|
+
config;
|
|
532
|
+
constructor(config) {
|
|
533
|
+
this.config = config;
|
|
534
|
+
}
|
|
535
|
+
async execute(code) {
|
|
536
|
+
const start = Date.now();
|
|
537
|
+
let container;
|
|
538
|
+
try {
|
|
539
|
+
container = await this.config.pool.acquire({
|
|
540
|
+
trust: "sandboxed",
|
|
541
|
+
timeout: this.config.timeout,
|
|
542
|
+
memory: this.config.memoryLimit,
|
|
543
|
+
cpu: this.config.cpuLimit
|
|
544
|
+
});
|
|
545
|
+
} catch (err2) {
|
|
546
|
+
return {
|
|
547
|
+
success: false,
|
|
548
|
+
output: void 0,
|
|
549
|
+
logs: [],
|
|
550
|
+
toolCalls: 0,
|
|
551
|
+
error: `Failed to acquire container: ${err2 instanceof Error ? err2.message : String(err2)}`,
|
|
552
|
+
durationMs: Date.now() - start
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
try {
|
|
556
|
+
await container.exec("mkdir -p /workspace");
|
|
557
|
+
const codeB64 = Buffer.from(code).toString("base64");
|
|
558
|
+
await container.exec(`sh -c 'echo "${codeB64}" | base64 -d > /workspace/user-code.js'`);
|
|
559
|
+
const harnessB64 = Buffer.from(DOCKER_HARNESS).toString("base64");
|
|
560
|
+
await container.exec(`sh -c 'echo "${harnessB64}" | base64 -d > /workspace/harness.ts'`);
|
|
561
|
+
const execResult = await container.exec("npx tsx /workspace/harness.ts", {
|
|
562
|
+
timeout: this.config.timeout,
|
|
563
|
+
cwd: "/workspace"
|
|
564
|
+
});
|
|
565
|
+
if (execResult.exitCode === 0 && execResult.stdout.trim()) {
|
|
566
|
+
try {
|
|
567
|
+
const lastLine = execResult.stdout.trim().split("\n").pop();
|
|
568
|
+
const parsed = JSON.parse(lastLine);
|
|
569
|
+
return {
|
|
570
|
+
success: parsed.success,
|
|
571
|
+
output: parsed.output,
|
|
572
|
+
logs: parsed.logs ?? [],
|
|
573
|
+
error: parsed.error,
|
|
574
|
+
durationMs: Date.now() - start,
|
|
575
|
+
toolCalls: parsed.toolCalls ?? 0
|
|
576
|
+
};
|
|
577
|
+
} catch {
|
|
578
|
+
return {
|
|
579
|
+
success: true,
|
|
580
|
+
output: execResult.stdout.trim(),
|
|
581
|
+
logs: [],
|
|
582
|
+
durationMs: Date.now() - start,
|
|
583
|
+
toolCalls: 0
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
return {
|
|
588
|
+
success: false,
|
|
589
|
+
output: void 0,
|
|
590
|
+
logs: [],
|
|
591
|
+
toolCalls: 0,
|
|
592
|
+
error: execResult.stderr || execResult.stdout || "Unknown error",
|
|
593
|
+
durationMs: Date.now() - start
|
|
594
|
+
};
|
|
595
|
+
} catch (err2) {
|
|
596
|
+
return {
|
|
597
|
+
success: false,
|
|
598
|
+
output: void 0,
|
|
599
|
+
logs: [],
|
|
600
|
+
toolCalls: 0,
|
|
601
|
+
error: err2 instanceof Error ? err2.message : String(err2),
|
|
602
|
+
durationMs: Date.now() - start
|
|
603
|
+
};
|
|
604
|
+
} finally {
|
|
605
|
+
await this.config.pool.release(container);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
};
|
|
609
|
+
|
|
610
|
+
// ../code-mode/dist/tool.js
|
|
611
|
+
function createCodeModeTool(registry, executor) {
|
|
612
|
+
const declarations = generateDeclarations(registry);
|
|
613
|
+
return {
|
|
614
|
+
name: "execute_code",
|
|
615
|
+
description: `Execute TypeScript code with access to the agent's APIs. Write the body of an async function.
|
|
616
|
+
|
|
617
|
+
Available APIs:
|
|
618
|
+
|
|
619
|
+
\`\`\`typescript
|
|
620
|
+
${declarations}
|
|
621
|
+
\`\`\`
|
|
622
|
+
|
|
623
|
+
Each API call returns { success: boolean, output: string }.
|
|
624
|
+
Use console.log() for intermediate output. Return your final result.`,
|
|
625
|
+
parameters: {
|
|
626
|
+
type: "object",
|
|
627
|
+
properties: {
|
|
628
|
+
code: {
|
|
629
|
+
type: "string",
|
|
630
|
+
description: "The body of an async TypeScript function. Use the 'api' object to call tools."
|
|
631
|
+
}
|
|
632
|
+
},
|
|
633
|
+
required: ["code"]
|
|
634
|
+
},
|
|
635
|
+
execute: async (params) => {
|
|
636
|
+
const { code } = params;
|
|
637
|
+
const result = await executor.execute(code);
|
|
638
|
+
if (result.success) {
|
|
639
|
+
const parts = [];
|
|
640
|
+
if (result.logs.length > 0) {
|
|
641
|
+
parts.push(`[logs]
|
|
642
|
+
${result.logs.join("\n")}`);
|
|
643
|
+
}
|
|
644
|
+
parts.push(typeof result.output === "string" ? result.output : JSON.stringify(result.output));
|
|
645
|
+
return { success: true, output: parts.join("\n\n") };
|
|
646
|
+
}
|
|
647
|
+
return {
|
|
648
|
+
success: false,
|
|
649
|
+
output: result.error ?? "Code execution failed"
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// ../code-mode/dist/auto-executor.js
|
|
656
|
+
var AutoExecutor = class {
|
|
657
|
+
primary;
|
|
658
|
+
fallback;
|
|
659
|
+
constructor(primary, fallback) {
|
|
660
|
+
this.primary = primary;
|
|
661
|
+
this.fallback = fallback;
|
|
662
|
+
}
|
|
663
|
+
async execute(code) {
|
|
664
|
+
try {
|
|
665
|
+
const result = await this.primary.execute(code);
|
|
666
|
+
return result;
|
|
667
|
+
} catch {
|
|
668
|
+
return this.fallback.execute(code);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
};
|
|
672
|
+
|
|
270
673
|
// ../core/dist/audit.js
|
|
271
674
|
import { appendFile, mkdir } from "fs/promises";
|
|
272
675
|
import { join } from "path";
|
|
@@ -348,7 +751,23 @@ var Agent = class {
|
|
|
348
751
|
}
|
|
349
752
|
const maxLoops = this.config.maxToolLoops ?? 10;
|
|
350
753
|
let loopCount = 0;
|
|
754
|
+
let totalInputTokens = 0;
|
|
755
|
+
let totalOutputTokens = 0;
|
|
756
|
+
let totalToolCalls = 0;
|
|
351
757
|
const toolSchemas = this.config.tools.toFunctionSchemas();
|
|
758
|
+
let effectiveSchemas = toolSchemas;
|
|
759
|
+
let codeModeTool;
|
|
760
|
+
if (this.config.codeModeExecutor) {
|
|
761
|
+
codeModeTool = createCodeModeTool(this.config.tools, this.config.codeModeExecutor);
|
|
762
|
+
effectiveSchemas = [{
|
|
763
|
+
type: "function",
|
|
764
|
+
function: {
|
|
765
|
+
name: codeModeTool.name,
|
|
766
|
+
description: codeModeTool.description,
|
|
767
|
+
parameters: codeModeTool.parameters
|
|
768
|
+
}
|
|
769
|
+
}];
|
|
770
|
+
}
|
|
352
771
|
while (loopCount < maxLoops) {
|
|
353
772
|
const messages = assembleContext({
|
|
354
773
|
systemPrompt: this.config.systemPrompt,
|
|
@@ -357,7 +776,9 @@ var Agent = class {
|
|
|
357
776
|
persona: this.config.persona
|
|
358
777
|
});
|
|
359
778
|
this.log.debug(`LLM call #${loopCount + 1} (${messages.length} messages)`);
|
|
360
|
-
const response = await this.config.llm.chat(messages,
|
|
779
|
+
const response = await this.config.llm.chat(messages, effectiveSchemas);
|
|
780
|
+
totalInputTokens += response.usage.inputTokens;
|
|
781
|
+
totalOutputTokens += response.usage.outputTokens;
|
|
361
782
|
if (response.toolCalls.length === 0) {
|
|
362
783
|
history.push({
|
|
363
784
|
role: "assistant",
|
|
@@ -380,6 +801,7 @@ var Agent = class {
|
|
|
380
801
|
success: true
|
|
381
802
|
});
|
|
382
803
|
}
|
|
804
|
+
this.log.info(`\u2500\u2500 ${totalInputTokens}+${totalOutputTokens} tokens | ${loopCount + 1} LLM calls | ${totalToolCalls} tool calls | ${Date.now() - start}ms`);
|
|
383
805
|
if (this.config.ingester) {
|
|
384
806
|
this.config.ingester.ingest(history).catch((err2) => this.log.error("Ingestion error:", err2));
|
|
385
807
|
}
|
|
@@ -390,10 +812,16 @@ var Agent = class {
|
|
|
390
812
|
content: response.content || "",
|
|
391
813
|
toolCalls: response.toolCalls
|
|
392
814
|
});
|
|
815
|
+
totalToolCalls += response.toolCalls.length;
|
|
393
816
|
for (const toolCall of response.toolCalls) {
|
|
394
817
|
const toolStart = Date.now();
|
|
395
818
|
this.log.debug(`Tool: ${toolCall.name}`);
|
|
396
|
-
|
|
819
|
+
let result;
|
|
820
|
+
if (codeModeTool && toolCall.name === "execute_code") {
|
|
821
|
+
result = await codeModeTool.execute(toolCall.arguments, {});
|
|
822
|
+
} else {
|
|
823
|
+
result = await this.config.tools.execute(toolCall.name, toolCall.arguments);
|
|
824
|
+
}
|
|
397
825
|
this.log.debug(`Tool ${toolCall.name}: ${result.success ? "ok" : "fail"} (${Date.now() - toolStart}ms)`);
|
|
398
826
|
history.push({
|
|
399
827
|
role: "tool",
|
|
@@ -2303,6 +2731,7 @@ var CronScheduler = class {
|
|
|
2303
2731
|
timers = /* @__PURE__ */ new Map();
|
|
2304
2732
|
handlers = [];
|
|
2305
2733
|
persistChain = Promise.resolve();
|
|
2734
|
+
running = false;
|
|
2306
2735
|
constructor(store) {
|
|
2307
2736
|
this.store = store;
|
|
2308
2737
|
}
|
|
@@ -2320,12 +2749,21 @@ var CronScheduler = class {
|
|
|
2320
2749
|
throw new Error(`Invalid runAt date: ${job.runAt}`);
|
|
2321
2750
|
}
|
|
2322
2751
|
this.jobs.set(job.id, job);
|
|
2752
|
+
console.log(`[scheduler] Added job ${job.id} (${job.cron ? `cron: ${job.cron}` : `runAt: ${job.runAt}`})`);
|
|
2323
2753
|
if (job.enabled && job.cron) {
|
|
2324
2754
|
const task = createTask(job.cron, () => {
|
|
2755
|
+
console.log(`[scheduler] Cron fired for job ${job.id}`);
|
|
2325
2756
|
void this.executeHandlers(job);
|
|
2326
2757
|
});
|
|
2758
|
+
if (this.running) {
|
|
2759
|
+
task.start();
|
|
2760
|
+
console.log(`[scheduler] Started cron task for ${job.id} immediately (scheduler already running)`);
|
|
2761
|
+
}
|
|
2327
2762
|
this.tasks.set(job.id, task);
|
|
2328
2763
|
}
|
|
2764
|
+
if (this.running && job.enabled && job.runAt && !job.cron) {
|
|
2765
|
+
this.scheduleOneShot(job);
|
|
2766
|
+
}
|
|
2329
2767
|
this.persist();
|
|
2330
2768
|
}
|
|
2331
2769
|
removeJob(id) {
|
|
@@ -2340,6 +2778,7 @@ var CronScheduler = class {
|
|
|
2340
2778
|
this.timers.delete(id);
|
|
2341
2779
|
}
|
|
2342
2780
|
this.jobs.delete(id);
|
|
2781
|
+
console.log(`[scheduler] Removed job ${id}`);
|
|
2343
2782
|
this.persist();
|
|
2344
2783
|
}
|
|
2345
2784
|
listJobs() {
|
|
@@ -2356,16 +2795,21 @@ var CronScheduler = class {
|
|
|
2356
2795
|
if (!this.store)
|
|
2357
2796
|
return;
|
|
2358
2797
|
const jobs = await this.store.load();
|
|
2798
|
+
console.log(`[scheduler] Loading ${jobs.length} persisted jobs`);
|
|
2359
2799
|
for (const job of jobs) {
|
|
2360
2800
|
if (job.runAt && Date.parse(job.runAt) <= Date.now()) {
|
|
2801
|
+
console.log(`[scheduler] Skipping expired one-shot job ${job.id} (runAt: ${job.runAt})`);
|
|
2361
2802
|
continue;
|
|
2362
2803
|
}
|
|
2363
2804
|
this.addJob(job);
|
|
2364
2805
|
}
|
|
2365
2806
|
}
|
|
2366
2807
|
start() {
|
|
2367
|
-
|
|
2808
|
+
this.running = true;
|
|
2809
|
+
console.log(`[scheduler] Starting with ${this.tasks.size} cron tasks and ${this.handlers.length} handlers`);
|
|
2810
|
+
for (const [id, task] of this.tasks) {
|
|
2368
2811
|
task.start();
|
|
2812
|
+
console.log(`[scheduler] Started cron task: ${id}`);
|
|
2369
2813
|
}
|
|
2370
2814
|
for (const job of this.jobs.values()) {
|
|
2371
2815
|
if (job.enabled && job.runAt && !job.cron) {
|
|
@@ -2374,6 +2818,7 @@ var CronScheduler = class {
|
|
|
2374
2818
|
}
|
|
2375
2819
|
}
|
|
2376
2820
|
stop() {
|
|
2821
|
+
this.running = false;
|
|
2377
2822
|
for (const task of this.tasks.values()) {
|
|
2378
2823
|
task.stop();
|
|
2379
2824
|
}
|
|
@@ -2384,9 +2829,13 @@ var CronScheduler = class {
|
|
|
2384
2829
|
}
|
|
2385
2830
|
scheduleOneShot(job) {
|
|
2386
2831
|
const delayMs = Date.parse(job.runAt) - Date.now();
|
|
2387
|
-
if (delayMs <= 0)
|
|
2832
|
+
if (delayMs <= 0) {
|
|
2833
|
+
console.log(`[scheduler] One-shot job ${job.id} already expired (delay: ${delayMs}ms), skipping`);
|
|
2388
2834
|
return;
|
|
2835
|
+
}
|
|
2836
|
+
console.log(`[scheduler] Scheduled one-shot job ${job.id} in ${Math.round(delayMs / 1e3)}s (${job.runAt})`);
|
|
2389
2837
|
const timer = setTimeout(() => {
|
|
2838
|
+
console.log(`[scheduler] One-shot job ${job.id} firing now`);
|
|
2390
2839
|
this.timers.delete(job.id);
|
|
2391
2840
|
void this.executeHandlers(job).then(() => {
|
|
2392
2841
|
this.removeJob(job.id);
|
|
@@ -2401,6 +2850,7 @@ var CronScheduler = class {
|
|
|
2401
2850
|
this.persistChain = this.persistChain.then(() => this.store.save(jobs));
|
|
2402
2851
|
}
|
|
2403
2852
|
async executeHandlers(job) {
|
|
2853
|
+
console.log(`[scheduler] Executing ${this.handlers.length} handlers for job ${job.id}`);
|
|
2404
2854
|
for (const handler of this.handlers) {
|
|
2405
2855
|
await handler(job);
|
|
2406
2856
|
}
|
|
@@ -3977,6 +4427,40 @@ async function startAgent(configPath, opts) {
|
|
|
3977
4427
|
log.info(`Skills initialized: ${skillsPath}`);
|
|
3978
4428
|
}
|
|
3979
4429
|
tools.setContext({ config, memory, scheduler, pool });
|
|
4430
|
+
let codeModeExecutor;
|
|
4431
|
+
if (config.codeMode) {
|
|
4432
|
+
const cmConfig = config.codeMode;
|
|
4433
|
+
if (cmConfig.runtime === "vm") {
|
|
4434
|
+
codeModeExecutor = new VmExecutor(tools, {
|
|
4435
|
+
timeout: cmConfig.timeout * 1e3,
|
|
4436
|
+
// VmExecutor expects ms
|
|
4437
|
+
memoryLimit: cmConfig.memoryLimit
|
|
4438
|
+
});
|
|
4439
|
+
} else if (cmConfig.runtime === "docker") {
|
|
4440
|
+
codeModeExecutor = new DockerExecutor({
|
|
4441
|
+
registry: tools,
|
|
4442
|
+
pool,
|
|
4443
|
+
timeout: cmConfig.timeout,
|
|
4444
|
+
// DockerExecutor expects seconds
|
|
4445
|
+
memoryLimit: config.sandbox.defaults.memoryLimit,
|
|
4446
|
+
cpuLimit: config.sandbox.defaults.cpuLimit
|
|
4447
|
+
});
|
|
4448
|
+
} else {
|
|
4449
|
+
const vmExec = new VmExecutor(tools, {
|
|
4450
|
+
timeout: cmConfig.timeout * 1e3,
|
|
4451
|
+
memoryLimit: cmConfig.memoryLimit
|
|
4452
|
+
});
|
|
4453
|
+
const dockerExec = new DockerExecutor({
|
|
4454
|
+
registry: tools,
|
|
4455
|
+
pool,
|
|
4456
|
+
timeout: cmConfig.timeout,
|
|
4457
|
+
memoryLimit: config.sandbox.defaults.memoryLimit,
|
|
4458
|
+
cpuLimit: config.sandbox.defaults.cpuLimit
|
|
4459
|
+
});
|
|
4460
|
+
codeModeExecutor = new AutoExecutor(vmExec, dockerExec);
|
|
4461
|
+
}
|
|
4462
|
+
log.info(`Code Mode enabled: runtime=${cmConfig.runtime}, timeout=${cmConfig.timeout}s`);
|
|
4463
|
+
}
|
|
3980
4464
|
const auditConfig = config.audit ?? { path: "./logs", enabled: true };
|
|
3981
4465
|
const auditPath = resolve(configPath, "..", auditConfig.path);
|
|
3982
4466
|
const audit = auditConfig.enabled ? new FileAuditLogger(auditPath, log.child("audit")) : new NullAuditLogger();
|
|
@@ -4020,7 +4504,8 @@ async function startAgent(configPath, opts) {
|
|
|
4020
4504
|
audit,
|
|
4021
4505
|
guard,
|
|
4022
4506
|
modelName: config.llm.default.model,
|
|
4023
|
-
logger: log.child("agent")
|
|
4507
|
+
logger: log.child("agent"),
|
|
4508
|
+
codeModeExecutor
|
|
4024
4509
|
});
|
|
4025
4510
|
if (config.channels.telegram?.enabled) {
|
|
4026
4511
|
const telegramLog = log.child("telegram");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "augure",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Augure — your proactive AI agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -12,18 +12,10 @@
|
|
|
12
12
|
"engines": {
|
|
13
13
|
"node": ">=22.0.0"
|
|
14
14
|
},
|
|
15
|
-
"scripts": {
|
|
16
|
-
"build": "tsup",
|
|
17
|
-
"dev": "tsup --watch",
|
|
18
|
-
"test": "vitest run",
|
|
19
|
-
"test:unit": "vitest run",
|
|
20
|
-
"typecheck": "tsc --noEmit",
|
|
21
|
-
"lint": "eslint src/",
|
|
22
|
-
"clean": "rm -rf dist .turbo"
|
|
23
|
-
},
|
|
24
15
|
"dependencies": {
|
|
25
16
|
"citty": "^0.2.1",
|
|
26
17
|
"dockerode": "^4.0.9",
|
|
18
|
+
"esbuild": "^0.25.0",
|
|
27
19
|
"grammy": "^1.40.0",
|
|
28
20
|
"imapflow": "^1.2.10",
|
|
29
21
|
"nodemailer": "^6.10.1",
|
|
@@ -33,17 +25,17 @@
|
|
|
33
25
|
"zod": "^4.3.6"
|
|
34
26
|
},
|
|
35
27
|
"devDependencies": {
|
|
36
|
-
"@augure/channels": "workspace:*",
|
|
37
|
-
"@augure/core": "workspace:*",
|
|
38
|
-
"@augure/memory": "workspace:*",
|
|
39
|
-
"@augure/sandbox": "workspace:*",
|
|
40
|
-
"@augure/scheduler": "workspace:*",
|
|
41
|
-
"@augure/skills": "workspace:*",
|
|
42
|
-
"@augure/tools": "workspace:*",
|
|
43
|
-
"@augure/types": "workspace:*",
|
|
44
28
|
"@types/dockerode": "^4.0.1",
|
|
45
29
|
"@types/node-cron": "^3.0.11",
|
|
46
|
-
"tsup": "^8.5.1"
|
|
30
|
+
"tsup": "^8.5.1",
|
|
31
|
+
"@augure/channels": "0.1.3",
|
|
32
|
+
"@augure/core": "0.4.0",
|
|
33
|
+
"@augure/scheduler": "0.1.2",
|
|
34
|
+
"@augure/memory": "0.0.5",
|
|
35
|
+
"@augure/sandbox": "0.1.2",
|
|
36
|
+
"@augure/skills": "0.1.3",
|
|
37
|
+
"@augure/tools": "0.1.1",
|
|
38
|
+
"@augure/types": "0.3.0"
|
|
47
39
|
},
|
|
48
40
|
"keywords": [
|
|
49
41
|
"ai",
|
|
@@ -61,5 +53,14 @@
|
|
|
61
53
|
},
|
|
62
54
|
"publishConfig": {
|
|
63
55
|
"access": "public"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"build": "tsup",
|
|
59
|
+
"dev": "tsup --watch",
|
|
60
|
+
"test": "vitest run",
|
|
61
|
+
"test:unit": "vitest run",
|
|
62
|
+
"typecheck": "tsc --noEmit",
|
|
63
|
+
"lint": "eslint src/",
|
|
64
|
+
"clean": "rm -rf dist .turbo"
|
|
64
65
|
}
|
|
65
|
-
}
|
|
66
|
+
}
|