augure 0.7.0 → 0.8.0
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 +532 -73
- package/package.json +11 -10
package/dist/bin.js
CHANGED
|
@@ -223,7 +223,22 @@ var AppConfigSchema = z.object({
|
|
|
223
223
|
password: z.string()
|
|
224
224
|
})
|
|
225
225
|
}).optional(),
|
|
226
|
-
github: z.object({ token: z.string() }).optional()
|
|
226
|
+
github: z.object({ token: z.string() }).optional(),
|
|
227
|
+
browser: z.object({
|
|
228
|
+
provider: z.enum(["local", "browserbase"]),
|
|
229
|
+
browserbase: z.object({
|
|
230
|
+
apiKey: z.string().min(1),
|
|
231
|
+
projectId: z.string().optional()
|
|
232
|
+
}).optional(),
|
|
233
|
+
defaults: z.object({
|
|
234
|
+
timeout: z.number().int().positive().optional(),
|
|
235
|
+
headless: z.boolean().optional(),
|
|
236
|
+
viewport: z.object({
|
|
237
|
+
width: z.number().int().positive(),
|
|
238
|
+
height: z.number().int().positive()
|
|
239
|
+
}).optional()
|
|
240
|
+
}).optional()
|
|
241
|
+
}).optional()
|
|
227
242
|
}),
|
|
228
243
|
security: z.object({
|
|
229
244
|
sandboxOnly: z.boolean(),
|
|
@@ -261,6 +276,10 @@ var AppConfigSchema = z.object({
|
|
|
261
276
|
runtime: z.enum(["vm", "docker", "auto"]).default("auto"),
|
|
262
277
|
timeout: z.number().int().positive().default(30),
|
|
263
278
|
memoryLimit: z.number().int().positive().default(128)
|
|
279
|
+
}).optional(),
|
|
280
|
+
approval: z.object({
|
|
281
|
+
enabled: z.boolean(),
|
|
282
|
+
timeoutMs: z.number().int().positive().default(12e4)
|
|
264
283
|
}).optional()
|
|
265
284
|
});
|
|
266
285
|
function interpolateEnvVars(raw) {
|
|
@@ -607,7 +626,7 @@ var VmExecutor = class {
|
|
|
607
626
|
|
|
608
627
|
// ../code-mode/dist/docker-sandbox.js
|
|
609
628
|
var DOCKER_HARNESS = `
|
|
610
|
-
import { readFile } from "node:fs/promises";
|
|
629
|
+
import { readFile, writeFile, unlink } from "node:fs/promises";
|
|
611
630
|
|
|
612
631
|
const __logs = [];
|
|
613
632
|
const __originalLog = console.log;
|
|
@@ -616,12 +635,28 @@ console.warn = (...args) => __logs.push("[warn] " + args.map(String).join(" "));
|
|
|
616
635
|
console.error = (...args) => __logs.push("[error] " + args.map(String).join(" "));
|
|
617
636
|
|
|
618
637
|
let __toolCalls = 0;
|
|
638
|
+
let __reqId = 0;
|
|
619
639
|
|
|
640
|
+
const __BRIDGE_TIMEOUT = 120_000;
|
|
620
641
|
const api = new Proxy({}, {
|
|
621
642
|
get: (_target, toolName) => {
|
|
622
|
-
return async () => {
|
|
643
|
+
return async (args) => {
|
|
623
644
|
__toolCalls++;
|
|
624
|
-
|
|
645
|
+
const id = String(++__reqId);
|
|
646
|
+
const reqPath = \`/workspace/.bridge-req-\${id}.json\`;
|
|
647
|
+
const respPath = \`/workspace/.bridge-resp-\${id}.json\`;
|
|
648
|
+
await writeFile(reqPath, JSON.stringify({ id, tool: String(toolName), args }));
|
|
649
|
+
const deadline = Date.now() + __BRIDGE_TIMEOUT;
|
|
650
|
+
while (Date.now() < deadline) {
|
|
651
|
+
try {
|
|
652
|
+
const data = await readFile(respPath, "utf-8");
|
|
653
|
+
await unlink(respPath);
|
|
654
|
+
return JSON.parse(data);
|
|
655
|
+
} catch {
|
|
656
|
+
await new Promise(r => setTimeout(r, 50));
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
throw new Error(\`Bridge timeout: tool "\${String(toolName)}" did not respond within \${__BRIDGE_TIMEOUT}ms\`);
|
|
625
660
|
};
|
|
626
661
|
}
|
|
627
662
|
});
|
|
@@ -648,11 +683,37 @@ try {
|
|
|
648
683
|
}));
|
|
649
684
|
}
|
|
650
685
|
`;
|
|
686
|
+
function sleep(ms) {
|
|
687
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
688
|
+
}
|
|
689
|
+
function parseFiles(stdout) {
|
|
690
|
+
return stdout.split("\n").map((l) => l.trim()).filter((l) => l.startsWith("/workspace/.bridge-req-") && l.endsWith(".json"));
|
|
691
|
+
}
|
|
651
692
|
var DockerExecutor = class {
|
|
652
693
|
config;
|
|
653
694
|
constructor(config) {
|
|
654
695
|
this.config = config;
|
|
655
696
|
}
|
|
697
|
+
async pollBridge(container, abortSignal) {
|
|
698
|
+
while (!abortSignal.aborted) {
|
|
699
|
+
try {
|
|
700
|
+
const ls = await container.exec("ls /workspace/.bridge-req-*.json 2>/dev/null || true");
|
|
701
|
+
const files = parseFiles(ls.stdout);
|
|
702
|
+
for (const reqFile of files) {
|
|
703
|
+
const reqJson = await container.exec(`cat ${reqFile}`);
|
|
704
|
+
const req = JSON.parse(reqJson.stdout);
|
|
705
|
+
const result = await this.config.registry.execute(req.tool, req.args);
|
|
706
|
+
const respFile = reqFile.replace("bridge-req", "bridge-resp");
|
|
707
|
+
const respB64 = Buffer.from(JSON.stringify(result)).toString("base64");
|
|
708
|
+
const tmpFile = `${respFile}.tmp`;
|
|
709
|
+
await container.exec(`sh -c 'echo "${respB64}" | base64 -d > ${tmpFile} && mv ${tmpFile} ${respFile}'`);
|
|
710
|
+
await container.exec(`rm ${reqFile}`);
|
|
711
|
+
}
|
|
712
|
+
} catch {
|
|
713
|
+
}
|
|
714
|
+
await sleep(100);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
656
717
|
async execute(code) {
|
|
657
718
|
const start = Date.now();
|
|
658
719
|
let container;
|
|
@@ -679,10 +740,14 @@ var DockerExecutor = class {
|
|
|
679
740
|
await container.exec(`sh -c 'echo "${codeB64}" | base64 -d > /workspace/user-code.js'`);
|
|
680
741
|
const harnessB64 = Buffer.from(DOCKER_HARNESS).toString("base64");
|
|
681
742
|
await container.exec(`sh -c 'echo "${harnessB64}" | base64 -d > /workspace/harness.ts'`);
|
|
743
|
+
const abortController = new AbortController();
|
|
744
|
+
const bridgePromise = this.pollBridge(container, abortController.signal);
|
|
682
745
|
const execResult = await container.exec("npx tsx /workspace/harness.ts", {
|
|
683
746
|
timeout: this.config.timeout,
|
|
684
747
|
cwd: "/workspace"
|
|
685
748
|
});
|
|
749
|
+
abortController.abort();
|
|
750
|
+
await bridgePromise;
|
|
686
751
|
if (execResult.exitCode === 0 && execResult.stdout.trim()) {
|
|
687
752
|
try {
|
|
688
753
|
const lastLine = execResult.stdout.trim().split("\n").pop();
|
|
@@ -937,6 +1002,18 @@ var Agent = class {
|
|
|
937
1002
|
for (const toolCall of response.toolCalls) {
|
|
938
1003
|
const toolStart = Date.now();
|
|
939
1004
|
this.log.debug(`Tool: ${toolCall.name}`);
|
|
1005
|
+
const registeredTool = this.config.tools.get(toolCall.name);
|
|
1006
|
+
if (registeredTool?.riskLevel === "high" && this.config.approvalGate) {
|
|
1007
|
+
const approved = await this.config.approvalGate.request(incoming.userId, toolCall.name, toolCall.arguments);
|
|
1008
|
+
if (!approved) {
|
|
1009
|
+
history.push({
|
|
1010
|
+
role: "tool",
|
|
1011
|
+
content: "Tool call rejected by user.",
|
|
1012
|
+
toolCallId: toolCall.id
|
|
1013
|
+
});
|
|
1014
|
+
continue;
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
940
1017
|
let result;
|
|
941
1018
|
if (codeModeTool && toolCall.name === "execute_code") {
|
|
942
1019
|
result = await codeModeTool.execute(toolCall.arguments, {});
|
|
@@ -1151,6 +1228,60 @@ var ContextGuard = class {
|
|
|
1151
1228
|
}
|
|
1152
1229
|
};
|
|
1153
1230
|
|
|
1231
|
+
// ../core/dist/approval.js
|
|
1232
|
+
import { randomUUID } from "crypto";
|
|
1233
|
+
var ApprovalGate = class {
|
|
1234
|
+
pending = /* @__PURE__ */ new Map();
|
|
1235
|
+
channel;
|
|
1236
|
+
timeoutMs;
|
|
1237
|
+
log;
|
|
1238
|
+
constructor(config) {
|
|
1239
|
+
this.channel = config.channel;
|
|
1240
|
+
this.timeoutMs = config.timeoutMs ?? 12e4;
|
|
1241
|
+
this.log = config.logger ?? noopLogger;
|
|
1242
|
+
if (this.channel.onApprovalResponse) {
|
|
1243
|
+
this.channel.onApprovalResponse((response) => {
|
|
1244
|
+
const entry = this.pending.get(response.requestId);
|
|
1245
|
+
if (entry) {
|
|
1246
|
+
this.pending.delete(response.requestId);
|
|
1247
|
+
entry.resolve(response.approved);
|
|
1248
|
+
}
|
|
1249
|
+
});
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
async request(userId, toolName, args) {
|
|
1253
|
+
if (!this.channel.sendApprovalRequest) {
|
|
1254
|
+
this.log.warn(`Channel does not support approval requests \u2014 auto-approving ${toolName}`);
|
|
1255
|
+
return true;
|
|
1256
|
+
}
|
|
1257
|
+
const requestId = randomUUID();
|
|
1258
|
+
const argsStr = JSON.stringify(args, null, 2);
|
|
1259
|
+
const text = `Tool "${toolName}" requires approval.
|
|
1260
|
+
|
|
1261
|
+
Arguments:
|
|
1262
|
+
${argsStr}`;
|
|
1263
|
+
const buttons = [
|
|
1264
|
+
{ label: "Approve", callbackData: `approve:${requestId}` },
|
|
1265
|
+
{ label: "Reject", callbackData: `reject:${requestId}` }
|
|
1266
|
+
];
|
|
1267
|
+
const resultPromise = new Promise((resolve5) => {
|
|
1268
|
+
const timer = setTimeout(() => {
|
|
1269
|
+
this.pending.delete(requestId);
|
|
1270
|
+
this.log.warn(`Approval timed out for ${toolName} (request ${requestId})`);
|
|
1271
|
+
resolve5(false);
|
|
1272
|
+
}, this.timeoutMs);
|
|
1273
|
+
this.pending.set(requestId, {
|
|
1274
|
+
resolve: (approved) => {
|
|
1275
|
+
clearTimeout(timer);
|
|
1276
|
+
resolve5(approved);
|
|
1277
|
+
}
|
|
1278
|
+
});
|
|
1279
|
+
});
|
|
1280
|
+
await this.channel.sendApprovalRequest(userId, text, buttons, requestId);
|
|
1281
|
+
return resultPromise;
|
|
1282
|
+
}
|
|
1283
|
+
};
|
|
1284
|
+
|
|
1154
1285
|
// ../core/dist/logger.js
|
|
1155
1286
|
import { styleText } from "util";
|
|
1156
1287
|
var LEVELS = {
|
|
@@ -1202,7 +1333,7 @@ function createLogger(opts = {}) {
|
|
|
1202
1333
|
}
|
|
1203
1334
|
|
|
1204
1335
|
// ../channels/dist/telegram/telegram.js
|
|
1205
|
-
import { Bot } from "grammy";
|
|
1336
|
+
import { Bot, InlineKeyboard } from "grammy";
|
|
1206
1337
|
|
|
1207
1338
|
// ../channels/dist/pipeline.js
|
|
1208
1339
|
function createOutgoingPipeline(middlewares, send) {
|
|
@@ -1420,6 +1551,7 @@ var TelegramChannel = class {
|
|
|
1420
1551
|
bot;
|
|
1421
1552
|
allowedUsers;
|
|
1422
1553
|
handlers = [];
|
|
1554
|
+
approvalHandlers = [];
|
|
1423
1555
|
sendPipeline;
|
|
1424
1556
|
log;
|
|
1425
1557
|
constructor(config) {
|
|
@@ -1448,6 +1580,31 @@ var TelegramChannel = class {
|
|
|
1448
1580
|
}
|
|
1449
1581
|
});
|
|
1450
1582
|
registerMediaHandlers(this.bot, (id) => this.isUserAllowed(id), this.handlers, (userId, ts) => this.handleRejected(userId, Math.floor(ts.getTime() / 1e3), config.rejectMessage));
|
|
1583
|
+
this.bot.on("callback_query:data", async (ctx) => {
|
|
1584
|
+
if (!this.isUserAllowed(ctx.from.id)) {
|
|
1585
|
+
await ctx.answerCallbackQuery({ text: "Not authorized" });
|
|
1586
|
+
return;
|
|
1587
|
+
}
|
|
1588
|
+
const data = ctx.callbackQuery.data;
|
|
1589
|
+
const match = /^(approve|reject):(.+)$/.exec(data);
|
|
1590
|
+
if (!match)
|
|
1591
|
+
return;
|
|
1592
|
+
const [, action, requestId] = match;
|
|
1593
|
+
const approved = action === "approve";
|
|
1594
|
+
const userId = String(ctx.from.id);
|
|
1595
|
+
await ctx.answerCallbackQuery({ text: approved ? "Approved" : "Rejected" });
|
|
1596
|
+
try {
|
|
1597
|
+
await ctx.editMessageReplyMarkup({ reply_markup: void 0 });
|
|
1598
|
+
const originalText = ctx.callbackQuery.message && "text" in ctx.callbackQuery.message ? ctx.callbackQuery.message.text ?? "" : "";
|
|
1599
|
+
await ctx.editMessageText(`${originalText}
|
|
1600
|
+
|
|
1601
|
+
${approved ? "Approved" : "Rejected"}`);
|
|
1602
|
+
} catch {
|
|
1603
|
+
}
|
|
1604
|
+
for (const handler2 of this.approvalHandlers) {
|
|
1605
|
+
handler2({ requestId, approved, userId });
|
|
1606
|
+
}
|
|
1607
|
+
});
|
|
1451
1608
|
const convertAndSend = async (msg) => {
|
|
1452
1609
|
const htmlText = markdownToTelegramHtml(msg.text);
|
|
1453
1610
|
const replyOpts = msg.replyTo ? { reply_parameters: { message_id: Number(msg.replyTo) } } : {};
|
|
@@ -1485,6 +1642,18 @@ var TelegramChannel = class {
|
|
|
1485
1642
|
async send(message) {
|
|
1486
1643
|
await this.sendPipeline(message);
|
|
1487
1644
|
}
|
|
1645
|
+
async sendApprovalRequest(userId, text, buttons, _requestId) {
|
|
1646
|
+
const keyboard = new InlineKeyboard();
|
|
1647
|
+
for (const btn of buttons) {
|
|
1648
|
+
keyboard.text(btn.label, btn.callbackData);
|
|
1649
|
+
}
|
|
1650
|
+
await this.bot.api.sendMessage(Number(userId), text, {
|
|
1651
|
+
reply_markup: keyboard
|
|
1652
|
+
});
|
|
1653
|
+
}
|
|
1654
|
+
onApprovalResponse(handler2) {
|
|
1655
|
+
this.approvalHandlers.push(handler2);
|
|
1656
|
+
}
|
|
1488
1657
|
};
|
|
1489
1658
|
|
|
1490
1659
|
// ../tools/dist/registry.js
|
|
@@ -2192,6 +2361,7 @@ var emailTool = {
|
|
|
2192
2361
|
var sandboxExecTool = {
|
|
2193
2362
|
name: "sandbox_exec",
|
|
2194
2363
|
description: "Execute a shell command in an isolated Docker container. Returns stdout, stderr, and exit code.",
|
|
2364
|
+
riskLevel: "high",
|
|
2195
2365
|
parameters: {
|
|
2196
2366
|
type: "object",
|
|
2197
2367
|
properties: {
|
|
@@ -2265,6 +2435,7 @@ function shellEscape(s) {
|
|
|
2265
2435
|
var opencodeTool = {
|
|
2266
2436
|
name: "opencode",
|
|
2267
2437
|
description: "Run a code agent (claude-code, opencode, codex CLI) in a Docker container to perform a coding task.",
|
|
2438
|
+
riskLevel: "high",
|
|
2268
2439
|
configCheck: (ctx) => ctx.config.sandbox.codeAgent ? null : "This tool requires sandbox.codeAgent configuration. See https://augure.dev/docs/sandbox",
|
|
2269
2440
|
parameters: {
|
|
2270
2441
|
type: "object",
|
|
@@ -6345,6 +6516,248 @@ var githubTool = {
|
|
|
6345
6516
|
}
|
|
6346
6517
|
};
|
|
6347
6518
|
|
|
6519
|
+
// ../tools/dist/browser.js
|
|
6520
|
+
function createBrowserTool(manager) {
|
|
6521
|
+
return {
|
|
6522
|
+
name: "browser",
|
|
6523
|
+
description: "AI-powered browser automation. Open a session, then use natural language to interact with web pages. Actions: open (creates session), navigate, act (click/type/interact), extract (get structured data), observe (discover elements), screenshot, close. Use 'act' with natural language instructions instead of CSS selectors. Use 'extract' with an instruction describing what data to get. Always close sessions when done.",
|
|
6524
|
+
parameters: {
|
|
6525
|
+
type: "object",
|
|
6526
|
+
properties: {
|
|
6527
|
+
action: {
|
|
6528
|
+
type: "string",
|
|
6529
|
+
enum: ["open", "navigate", "act", "extract", "observe", "screenshot", "close"],
|
|
6530
|
+
description: "The browser action to perform"
|
|
6531
|
+
},
|
|
6532
|
+
session: {
|
|
6533
|
+
type: "string",
|
|
6534
|
+
description: "Session ID from 'open'. Required for all actions except 'open'."
|
|
6535
|
+
},
|
|
6536
|
+
url: {
|
|
6537
|
+
type: "string",
|
|
6538
|
+
description: "URL to navigate to. Used with 'open' and 'navigate'."
|
|
6539
|
+
},
|
|
6540
|
+
instruction: {
|
|
6541
|
+
type: "string",
|
|
6542
|
+
description: "Natural language instruction for act/extract/observe. Examples: 'click the search button', 'extract all product prices and titles', 'find the login form'."
|
|
6543
|
+
},
|
|
6544
|
+
schema: {
|
|
6545
|
+
type: "object",
|
|
6546
|
+
description: "JSON schema for structured extraction with 'extract'. Optional."
|
|
6547
|
+
},
|
|
6548
|
+
variables: {
|
|
6549
|
+
type: "object",
|
|
6550
|
+
description: "Variables for sensitive data in 'act'. Use %varName% in instruction. Example: instruction='type %password%', variables={password: 'secret'}"
|
|
6551
|
+
}
|
|
6552
|
+
},
|
|
6553
|
+
required: ["action"]
|
|
6554
|
+
},
|
|
6555
|
+
configCheck: (ctx) => {
|
|
6556
|
+
if (!ctx.config.tools?.browser) {
|
|
6557
|
+
return "Browser tool requires tools.browser config in augure.json5. Set provider to 'local' for Playwright or 'browserbase' for cloud.";
|
|
6558
|
+
}
|
|
6559
|
+
if (ctx.config.tools.browser.provider === "browserbase" && !ctx.config.tools.browser.browserbase?.apiKey) {
|
|
6560
|
+
return "Browserbase provider requires tools.browser.browserbase.apiKey";
|
|
6561
|
+
}
|
|
6562
|
+
return null;
|
|
6563
|
+
},
|
|
6564
|
+
execute: async (params, _ctx) => {
|
|
6565
|
+
const p = params;
|
|
6566
|
+
if (p.action !== "open" && !p.session) {
|
|
6567
|
+
return { success: false, output: "Missing 'session' \u2014 open a session first with action: 'open'" };
|
|
6568
|
+
}
|
|
6569
|
+
if (["act", "extract", "observe"].includes(p.action) && !p.instruction) {
|
|
6570
|
+
return { success: false, output: `Missing 'instruction' for action '${p.action}'` };
|
|
6571
|
+
}
|
|
6572
|
+
try {
|
|
6573
|
+
switch (p.action) {
|
|
6574
|
+
case "open": {
|
|
6575
|
+
const sessionId = await manager.open(p.url);
|
|
6576
|
+
return { success: true, output: `Session ${sessionId} opened.${p.url ? ` Navigated to ${p.url}` : ""}` };
|
|
6577
|
+
}
|
|
6578
|
+
case "navigate": {
|
|
6579
|
+
if (!p.url)
|
|
6580
|
+
return { success: false, output: "Missing 'url' for navigate" };
|
|
6581
|
+
await manager.navigate(p.session, p.url);
|
|
6582
|
+
return { success: true, output: `Navigated to ${p.url}` };
|
|
6583
|
+
}
|
|
6584
|
+
case "act": {
|
|
6585
|
+
const result = await manager.act(p.session, p.instruction, p.variables);
|
|
6586
|
+
return { success: result.success, output: result.message || "Action completed" };
|
|
6587
|
+
}
|
|
6588
|
+
case "extract": {
|
|
6589
|
+
const data = await manager.extract(p.session, p.instruction, p.schema);
|
|
6590
|
+
const output = typeof data === "string" ? data : JSON.stringify(data, null, 2);
|
|
6591
|
+
return { success: true, output };
|
|
6592
|
+
}
|
|
6593
|
+
case "observe": {
|
|
6594
|
+
const elements = await manager.observe(p.session, p.instruction);
|
|
6595
|
+
return {
|
|
6596
|
+
success: true,
|
|
6597
|
+
output: elements.length > 0 ? elements.map((e) => `- ${e.description} (${e.selector})`).join("\n") : "No matching elements found"
|
|
6598
|
+
};
|
|
6599
|
+
}
|
|
6600
|
+
case "screenshot": {
|
|
6601
|
+
const base64 = await manager.screenshot(p.session);
|
|
6602
|
+
return {
|
|
6603
|
+
success: true,
|
|
6604
|
+
output: "Screenshot captured",
|
|
6605
|
+
artifacts: [{ type: "image", name: "screenshot.png", content: base64 }]
|
|
6606
|
+
};
|
|
6607
|
+
}
|
|
6608
|
+
case "close": {
|
|
6609
|
+
await manager.close(p.session);
|
|
6610
|
+
return { success: true, output: `Session ${p.session} closed` };
|
|
6611
|
+
}
|
|
6612
|
+
default:
|
|
6613
|
+
return { success: false, output: `Unknown action: ${p.action}` };
|
|
6614
|
+
}
|
|
6615
|
+
} catch (err2) {
|
|
6616
|
+
return {
|
|
6617
|
+
success: false,
|
|
6618
|
+
output: `Browser error: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
6619
|
+
};
|
|
6620
|
+
}
|
|
6621
|
+
}
|
|
6622
|
+
};
|
|
6623
|
+
}
|
|
6624
|
+
|
|
6625
|
+
// ../browser/dist/session-manager.js
|
|
6626
|
+
import { Stagehand } from "@browserbasehq/stagehand";
|
|
6627
|
+
|
|
6628
|
+
// ../browser/dist/provider.js
|
|
6629
|
+
var PROVIDER_BASE_URLS = {
|
|
6630
|
+
openrouter: "https://openrouter.ai/api/v1",
|
|
6631
|
+
anthropic: "https://api.anthropic.com/v1",
|
|
6632
|
+
openai: "https://api.openai.com/v1"
|
|
6633
|
+
};
|
|
6634
|
+
function createStagehandConfig(config, llm) {
|
|
6635
|
+
const baseURL = PROVIDER_BASE_URLS[llm.provider];
|
|
6636
|
+
return {
|
|
6637
|
+
env: config.provider === "local" ? "LOCAL" : "BROWSERBASE",
|
|
6638
|
+
apiKey: config.browserbase?.apiKey,
|
|
6639
|
+
projectId: config.browserbase?.projectId,
|
|
6640
|
+
model: {
|
|
6641
|
+
modelName: llm.model,
|
|
6642
|
+
apiKey: llm.apiKey,
|
|
6643
|
+
...baseURL ? { baseURL } : {}
|
|
6644
|
+
},
|
|
6645
|
+
localBrowserLaunchOptions: config.provider === "local" ? {
|
|
6646
|
+
headless: config.defaults?.headless ?? true,
|
|
6647
|
+
viewport: config.defaults?.viewport ?? { width: 1280, height: 720 }
|
|
6648
|
+
} : void 0,
|
|
6649
|
+
domSettleTimeout: (config.defaults?.timeout ?? 30) * 1e3,
|
|
6650
|
+
verbose: 0,
|
|
6651
|
+
disablePino: true
|
|
6652
|
+
};
|
|
6653
|
+
}
|
|
6654
|
+
|
|
6655
|
+
// ../browser/dist/session-manager.js
|
|
6656
|
+
var BrowserSessionManager = class {
|
|
6657
|
+
sessions = /* @__PURE__ */ new Map();
|
|
6658
|
+
config;
|
|
6659
|
+
llm;
|
|
6660
|
+
ttlMs;
|
|
6661
|
+
log;
|
|
6662
|
+
counter = 0;
|
|
6663
|
+
constructor(opts) {
|
|
6664
|
+
this.config = opts.config;
|
|
6665
|
+
this.llm = opts.llm;
|
|
6666
|
+
this.ttlMs = opts.ttlMs ?? 12e4;
|
|
6667
|
+
this.log = opts.logger ?? noopLogger;
|
|
6668
|
+
}
|
|
6669
|
+
async open(url) {
|
|
6670
|
+
const id = `s_${Date.now()}_${++this.counter}`;
|
|
6671
|
+
const stagehandConfig = createStagehandConfig(this.config, this.llm);
|
|
6672
|
+
const stagehand = new Stagehand(stagehandConfig);
|
|
6673
|
+
await stagehand.init();
|
|
6674
|
+
if (url) {
|
|
6675
|
+
const page = stagehand.context.activePage();
|
|
6676
|
+
if (!page)
|
|
6677
|
+
throw new Error(`No active page after init for session ${id}`);
|
|
6678
|
+
await page.goto(url, { waitUntil: "domcontentloaded" });
|
|
6679
|
+
}
|
|
6680
|
+
const timer = setTimeout(() => {
|
|
6681
|
+
this.log.warn(`Browser session ${id} expired (TTL ${this.ttlMs}ms)`);
|
|
6682
|
+
this.close(id).catch(() => {
|
|
6683
|
+
});
|
|
6684
|
+
}, this.ttlMs);
|
|
6685
|
+
this.sessions.set(id, { stagehand, timer });
|
|
6686
|
+
this.log.info(`Browser session ${id} opened`);
|
|
6687
|
+
return id;
|
|
6688
|
+
}
|
|
6689
|
+
async navigate(sessionId, url) {
|
|
6690
|
+
const entry = this.getSession(sessionId);
|
|
6691
|
+
this.resetTtl(sessionId, entry);
|
|
6692
|
+
const page = entry.stagehand.context.activePage();
|
|
6693
|
+
if (!page)
|
|
6694
|
+
throw new Error(`No active page for session ${sessionId}`);
|
|
6695
|
+
await page.goto(url, { waitUntil: "domcontentloaded" });
|
|
6696
|
+
}
|
|
6697
|
+
async act(sessionId, instruction, variables) {
|
|
6698
|
+
const entry = this.getSession(sessionId);
|
|
6699
|
+
this.resetTtl(sessionId, entry);
|
|
6700
|
+
const result = await entry.stagehand.act(instruction, variables ? { variables } : void 0);
|
|
6701
|
+
return { success: result.success, message: result.message ?? result.actionDescription ?? "" };
|
|
6702
|
+
}
|
|
6703
|
+
async extract(sessionId, instruction, schema) {
|
|
6704
|
+
const entry = this.getSession(sessionId);
|
|
6705
|
+
this.resetTtl(sessionId, entry);
|
|
6706
|
+
if (schema) {
|
|
6707
|
+
return entry.stagehand.extract(instruction, schema);
|
|
6708
|
+
}
|
|
6709
|
+
return entry.stagehand.extract(instruction);
|
|
6710
|
+
}
|
|
6711
|
+
async observe(sessionId, instruction) {
|
|
6712
|
+
const entry = this.getSession(sessionId);
|
|
6713
|
+
this.resetTtl(sessionId, entry);
|
|
6714
|
+
const actions2 = await entry.stagehand.observe(instruction);
|
|
6715
|
+
return actions2.map((a) => ({
|
|
6716
|
+
description: a.description ?? "",
|
|
6717
|
+
selector: a.selector ?? ""
|
|
6718
|
+
}));
|
|
6719
|
+
}
|
|
6720
|
+
async screenshot(sessionId) {
|
|
6721
|
+
const entry = this.getSession(sessionId);
|
|
6722
|
+
this.resetTtl(sessionId, entry);
|
|
6723
|
+
const page = entry.stagehand.context.activePage();
|
|
6724
|
+
if (!page)
|
|
6725
|
+
throw new Error(`No active page for session ${sessionId}`);
|
|
6726
|
+
const buffer = await page.screenshot();
|
|
6727
|
+
return Buffer.from(buffer).toString("base64");
|
|
6728
|
+
}
|
|
6729
|
+
async close(sessionId) {
|
|
6730
|
+
const entry = this.sessions.get(sessionId);
|
|
6731
|
+
if (!entry)
|
|
6732
|
+
return;
|
|
6733
|
+
clearTimeout(entry.timer);
|
|
6734
|
+
this.sessions.delete(sessionId);
|
|
6735
|
+
try {
|
|
6736
|
+
await entry.stagehand.close();
|
|
6737
|
+
} catch {
|
|
6738
|
+
}
|
|
6739
|
+
this.log.info(`Browser session ${sessionId} closed`);
|
|
6740
|
+
}
|
|
6741
|
+
async closeAll() {
|
|
6742
|
+
const ids = [...this.sessions.keys()];
|
|
6743
|
+
await Promise.all(ids.map((id) => this.close(id)));
|
|
6744
|
+
}
|
|
6745
|
+
getSession(sessionId) {
|
|
6746
|
+
const entry = this.sessions.get(sessionId);
|
|
6747
|
+
if (!entry)
|
|
6748
|
+
throw new Error(`Unknown or expired: no browser session ${sessionId}`);
|
|
6749
|
+
return entry;
|
|
6750
|
+
}
|
|
6751
|
+
resetTtl(sessionId, entry) {
|
|
6752
|
+
clearTimeout(entry.timer);
|
|
6753
|
+
entry.timer = setTimeout(() => {
|
|
6754
|
+
this.log.warn(`Browser session ${sessionId} expired (TTL ${this.ttlMs}ms)`);
|
|
6755
|
+
this.close(sessionId).catch(() => {
|
|
6756
|
+
});
|
|
6757
|
+
}, this.ttlMs);
|
|
6758
|
+
}
|
|
6759
|
+
};
|
|
6760
|
+
|
|
6348
6761
|
// ../core/dist/main.js
|
|
6349
6762
|
import Dockerode from "dockerode";
|
|
6350
6763
|
|
|
@@ -6846,15 +7259,25 @@ ${content}`;
|
|
|
6846
7259
|
// ../scheduler/dist/cron.js
|
|
6847
7260
|
import { createTask, validate } from "node-cron";
|
|
6848
7261
|
var CronScheduler = class {
|
|
6849
|
-
store;
|
|
6850
7262
|
jobs = /* @__PURE__ */ new Map();
|
|
6851
7263
|
tasks = /* @__PURE__ */ new Map();
|
|
6852
7264
|
timers = /* @__PURE__ */ new Map();
|
|
6853
7265
|
handlers = [];
|
|
6854
7266
|
persistChain = Promise.resolve();
|
|
6855
7267
|
running = false;
|
|
6856
|
-
|
|
6857
|
-
|
|
7268
|
+
store;
|
|
7269
|
+
log;
|
|
7270
|
+
constructor(storeOrOpts) {
|
|
7271
|
+
if (storeOrOpts && "save" in storeOrOpts) {
|
|
7272
|
+
this.store = storeOrOpts;
|
|
7273
|
+
this.log = noopLogger;
|
|
7274
|
+
} else if (storeOrOpts) {
|
|
7275
|
+
const opts = storeOrOpts;
|
|
7276
|
+
this.store = opts.store;
|
|
7277
|
+
this.log = opts.logger ?? noopLogger;
|
|
7278
|
+
} else {
|
|
7279
|
+
this.log = noopLogger;
|
|
7280
|
+
}
|
|
6858
7281
|
}
|
|
6859
7282
|
onJobTrigger(handler2) {
|
|
6860
7283
|
this.handlers.push(handler2);
|
|
@@ -6870,20 +7293,24 @@ var CronScheduler = class {
|
|
|
6870
7293
|
throw new Error(`Invalid runAt date: ${job.runAt}`);
|
|
6871
7294
|
}
|
|
6872
7295
|
this.jobs.set(job.id, job);
|
|
6873
|
-
|
|
7296
|
+
this.log.info(`Added job ${job.id} (${job.cron ? `cron: ${job.cron}` : `runAt: ${job.runAt}`})`);
|
|
6874
7297
|
if (job.enabled && job.cron) {
|
|
6875
7298
|
const task = createTask(job.cron, () => {
|
|
6876
|
-
|
|
6877
|
-
|
|
7299
|
+
this.log.info(`Cron fired for job ${job.id}`);
|
|
7300
|
+
this.executeHandlers(job).catch((err2) => this.log.error(`Cron job ${job.id} handler failed:`, err2));
|
|
6878
7301
|
});
|
|
6879
7302
|
if (this.running) {
|
|
6880
7303
|
task.start();
|
|
6881
|
-
|
|
7304
|
+
this.log.debug(`Started cron task for ${job.id} immediately (scheduler already running)`);
|
|
6882
7305
|
}
|
|
6883
7306
|
this.tasks.set(job.id, task);
|
|
6884
7307
|
}
|
|
6885
|
-
if (
|
|
6886
|
-
this.
|
|
7308
|
+
if (job.enabled && job.runAt && !job.cron) {
|
|
7309
|
+
if (this.running) {
|
|
7310
|
+
this.scheduleOneShot(job);
|
|
7311
|
+
} else {
|
|
7312
|
+
this.log.warn(`Scheduler not running \u2014 one-shot job ${job.id} will be scheduled on start()`);
|
|
7313
|
+
}
|
|
6887
7314
|
}
|
|
6888
7315
|
this.persist();
|
|
6889
7316
|
}
|
|
@@ -6899,7 +7326,7 @@ var CronScheduler = class {
|
|
|
6899
7326
|
this.timers.delete(id);
|
|
6900
7327
|
}
|
|
6901
7328
|
this.jobs.delete(id);
|
|
6902
|
-
|
|
7329
|
+
this.log.debug(`Removed job ${id}`);
|
|
6903
7330
|
this.persist();
|
|
6904
7331
|
}
|
|
6905
7332
|
listJobs() {
|
|
@@ -6916,10 +7343,10 @@ var CronScheduler = class {
|
|
|
6916
7343
|
if (!this.store)
|
|
6917
7344
|
return;
|
|
6918
7345
|
const jobs = await this.store.load();
|
|
6919
|
-
|
|
7346
|
+
this.log.info(`Loading ${jobs.length} persisted jobs`);
|
|
6920
7347
|
for (const job of jobs) {
|
|
6921
7348
|
if (job.runAt && Date.parse(job.runAt) <= Date.now()) {
|
|
6922
|
-
|
|
7349
|
+
this.log.debug(`Skipping expired one-shot job ${job.id} (runAt: ${job.runAt})`);
|
|
6923
7350
|
continue;
|
|
6924
7351
|
}
|
|
6925
7352
|
this.addJob(job);
|
|
@@ -6927,10 +7354,10 @@ var CronScheduler = class {
|
|
|
6927
7354
|
}
|
|
6928
7355
|
start() {
|
|
6929
7356
|
this.running = true;
|
|
6930
|
-
|
|
7357
|
+
this.log.info(`Starting with ${this.tasks.size} cron tasks and ${this.handlers.length} handlers`);
|
|
6931
7358
|
for (const [id, task] of this.tasks) {
|
|
6932
7359
|
task.start();
|
|
6933
|
-
|
|
7360
|
+
this.log.debug(`Started cron task: ${id}`);
|
|
6934
7361
|
}
|
|
6935
7362
|
for (const job of this.jobs.values()) {
|
|
6936
7363
|
if (job.enabled && job.runAt && !job.cron) {
|
|
@@ -6939,6 +7366,7 @@ var CronScheduler = class {
|
|
|
6939
7366
|
}
|
|
6940
7367
|
}
|
|
6941
7368
|
stop() {
|
|
7369
|
+
this.log.info("Scheduler stopped");
|
|
6942
7370
|
this.running = false;
|
|
6943
7371
|
for (const task of this.tasks.values()) {
|
|
6944
7372
|
task.stop();
|
|
@@ -6951,16 +7379,14 @@ var CronScheduler = class {
|
|
|
6951
7379
|
scheduleOneShot(job) {
|
|
6952
7380
|
const delayMs = Date.parse(job.runAt) - Date.now();
|
|
6953
7381
|
if (delayMs <= 0) {
|
|
6954
|
-
|
|
7382
|
+
this.log.warn(`One-shot job ${job.id} already expired (delay: ${delayMs}ms), skipping`);
|
|
6955
7383
|
return;
|
|
6956
7384
|
}
|
|
6957
|
-
|
|
7385
|
+
this.log.info(`Scheduled one-shot job ${job.id} in ${Math.round(delayMs / 1e3)}s (${job.runAt})`);
|
|
6958
7386
|
const timer = setTimeout(() => {
|
|
6959
|
-
|
|
7387
|
+
this.log.info(`One-shot job ${job.id} firing now`);
|
|
6960
7388
|
this.timers.delete(job.id);
|
|
6961
|
-
|
|
6962
|
-
this.removeJob(job.id);
|
|
6963
|
-
});
|
|
7389
|
+
this.executeHandlers(job).then(() => this.removeJob(job.id)).catch((err2) => this.log.error(`One-shot job ${job.id} handler failed:`, err2));
|
|
6964
7390
|
}, delayMs);
|
|
6965
7391
|
this.timers.set(job.id, timer);
|
|
6966
7392
|
}
|
|
@@ -6971,7 +7397,7 @@ var CronScheduler = class {
|
|
|
6971
7397
|
this.persistChain = this.persistChain.then(() => this.store.save(jobs));
|
|
6972
7398
|
}
|
|
6973
7399
|
async executeHandlers(job) {
|
|
6974
|
-
|
|
7400
|
+
this.log.debug(`Executing ${this.handlers.length} handlers for job ${job.id}`);
|
|
6975
7401
|
for (const handler2 of this.handlers) {
|
|
6976
7402
|
await handler2(job);
|
|
6977
7403
|
}
|
|
@@ -8081,6 +8507,7 @@ function createSkillTools(deps) {
|
|
|
8081
8507
|
const manageSkillTool = {
|
|
8082
8508
|
name: "manage_skill",
|
|
8083
8509
|
description: "Manage a skill: pause, resume, or delete it",
|
|
8510
|
+
riskLevel: "high",
|
|
8084
8511
|
parameters: {
|
|
8085
8512
|
type: "object",
|
|
8086
8513
|
properties: {
|
|
@@ -8468,9 +8895,26 @@ async function startAgent(configPath, opts) {
|
|
|
8468
8895
|
tools.register(sandboxExecTool);
|
|
8469
8896
|
tools.register(opencodeTool);
|
|
8470
8897
|
tools.register(githubTool);
|
|
8898
|
+
let browserManager;
|
|
8899
|
+
if (config.tools?.browser) {
|
|
8900
|
+
const browserLlm = config.llm.coding ?? config.llm.default;
|
|
8901
|
+
browserManager = new BrowserSessionManager({
|
|
8902
|
+
config: config.tools.browser,
|
|
8903
|
+
llm: {
|
|
8904
|
+
provider: browserLlm.provider ?? config.llm.default.provider,
|
|
8905
|
+
apiKey: browserLlm.apiKey ?? config.llm.default.apiKey,
|
|
8906
|
+
model: browserLlm.model ?? config.llm.default.model,
|
|
8907
|
+
maxTokens: browserLlm.maxTokens ?? config.llm.default.maxTokens
|
|
8908
|
+
},
|
|
8909
|
+
ttlMs: 12e4,
|
|
8910
|
+
logger: log.child("browser")
|
|
8911
|
+
});
|
|
8912
|
+
tools.register(createBrowserTool(browserManager));
|
|
8913
|
+
log.info("Browser tool registered", { provider: config.tools.browser.provider });
|
|
8914
|
+
}
|
|
8471
8915
|
const jobStorePath = resolve(configPath, "..", "jobs.json");
|
|
8472
8916
|
const jobStore = new JobStore(jobStorePath);
|
|
8473
|
-
const scheduler = new CronScheduler(jobStore);
|
|
8917
|
+
const scheduler = new CronScheduler({ store: jobStore, logger: log.child("scheduler") });
|
|
8474
8918
|
await scheduler.loadPersistedJobs();
|
|
8475
8919
|
log.info(`Loaded ${scheduler.listJobs().length} persisted jobs`);
|
|
8476
8920
|
for (const job of config.scheduler.jobs) {
|
|
@@ -8498,7 +8942,8 @@ async function startAgent(configPath, opts) {
|
|
|
8498
8942
|
const skillRunner = new SkillRunner({
|
|
8499
8943
|
pool,
|
|
8500
8944
|
manager: skillManager,
|
|
8501
|
-
defaults: config.sandbox.defaults
|
|
8945
|
+
defaults: config.sandbox.defaults,
|
|
8946
|
+
browserManager
|
|
8502
8947
|
});
|
|
8503
8948
|
const skillTester = new SkillTester({
|
|
8504
8949
|
pool,
|
|
@@ -8616,6 +9061,15 @@ async function startAgent(configPath, opts) {
|
|
|
8616
9061
|
reservedForOutput: config.llm.default.maxTokens ?? 8192
|
|
8617
9062
|
});
|
|
8618
9063
|
const systemPrompt = config.skills ? BASE_SYSTEM_PROMPT + SKILLS_PROMPT : BASE_SYSTEM_PROMPT;
|
|
9064
|
+
const activeChannel = telegram;
|
|
9065
|
+
const approvalGate = config.approval?.enabled && activeChannel ? new ApprovalGate({
|
|
9066
|
+
channel: activeChannel,
|
|
9067
|
+
timeoutMs: config.approval.timeoutMs,
|
|
9068
|
+
logger: log.child("approval")
|
|
9069
|
+
}) : void 0;
|
|
9070
|
+
if (approvalGate) {
|
|
9071
|
+
log.info(`Approval gate enabled (timeout: ${config.approval.timeoutMs ?? 12e4}ms)`);
|
|
9072
|
+
}
|
|
8619
9073
|
const agent = new Agent({
|
|
8620
9074
|
llm,
|
|
8621
9075
|
tools,
|
|
@@ -8627,8 +9081,51 @@ async function startAgent(configPath, opts) {
|
|
|
8627
9081
|
guard,
|
|
8628
9082
|
modelName: config.llm.default.model,
|
|
8629
9083
|
logger: log.child("agent"),
|
|
8630
|
-
codeModeExecutor
|
|
9084
|
+
codeModeExecutor,
|
|
9085
|
+
approvalGate
|
|
9086
|
+
});
|
|
9087
|
+
const heartbeatIntervalMs = parseInterval(config.scheduler.heartbeatInterval);
|
|
9088
|
+
const heartbeat = new Heartbeat({
|
|
9089
|
+
llm: monitoringLLM,
|
|
9090
|
+
memory,
|
|
9091
|
+
intervalMs: heartbeatIntervalMs,
|
|
9092
|
+
logger: log.child("heartbeat"),
|
|
9093
|
+
onAction: async (action) => {
|
|
9094
|
+
log.info(`Heartbeat action: ${action}`);
|
|
9095
|
+
const response = await agent.handleMessage({
|
|
9096
|
+
id: `heartbeat-${Date.now()}`,
|
|
9097
|
+
channelType: "system",
|
|
9098
|
+
userId: "system",
|
|
9099
|
+
text: `[Heartbeat] ${action}`,
|
|
9100
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
9101
|
+
});
|
|
9102
|
+
log.debug(`Heartbeat response: ${response.slice(0, 200)}`);
|
|
9103
|
+
}
|
|
8631
9104
|
});
|
|
9105
|
+
scheduler.onJobTrigger(async (job) => {
|
|
9106
|
+
log.info(`Job triggered: ${job.id}`);
|
|
9107
|
+
const response = await agent.handleMessage({
|
|
9108
|
+
id: `job-${job.id}-${Date.now()}`,
|
|
9109
|
+
channelType: "system",
|
|
9110
|
+
userId: "system",
|
|
9111
|
+
text: job.prompt,
|
|
9112
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
9113
|
+
});
|
|
9114
|
+
if (telegram && config.channels.telegram?.enabled) {
|
|
9115
|
+
const userId = config.channels.telegram.allowedUsers[0];
|
|
9116
|
+
if (userId !== void 0) {
|
|
9117
|
+
await telegram.send({
|
|
9118
|
+
channelType: "telegram",
|
|
9119
|
+
userId: String(userId),
|
|
9120
|
+
text: response
|
|
9121
|
+
});
|
|
9122
|
+
}
|
|
9123
|
+
}
|
|
9124
|
+
log.debug(`Job ${job.id} completed`);
|
|
9125
|
+
});
|
|
9126
|
+
scheduler.start();
|
|
9127
|
+
heartbeat.start();
|
|
9128
|
+
log.info(`Scheduler started: ${scheduler.listJobs().length} jobs, heartbeat every ${config.scheduler.heartbeatInterval}`);
|
|
8632
9129
|
if (config.channels.telegram?.enabled) {
|
|
8633
9130
|
const telegramLog = log.child("telegram");
|
|
8634
9131
|
telegram = new TelegramChannel({
|
|
@@ -8676,51 +9173,8 @@ async function startAgent(configPath, opts) {
|
|
|
8676
9173
|
});
|
|
8677
9174
|
}
|
|
8678
9175
|
});
|
|
8679
|
-
|
|
8680
|
-
log.info("Telegram bot started");
|
|
9176
|
+
log.info("Telegram bot starting...");
|
|
8681
9177
|
}
|
|
8682
|
-
const heartbeatIntervalMs = parseInterval(config.scheduler.heartbeatInterval);
|
|
8683
|
-
const heartbeat = new Heartbeat({
|
|
8684
|
-
llm: monitoringLLM,
|
|
8685
|
-
memory,
|
|
8686
|
-
intervalMs: heartbeatIntervalMs,
|
|
8687
|
-
logger: log.child("heartbeat"),
|
|
8688
|
-
onAction: async (action) => {
|
|
8689
|
-
log.info(`Heartbeat action: ${action}`);
|
|
8690
|
-
const response = await agent.handleMessage({
|
|
8691
|
-
id: `heartbeat-${Date.now()}`,
|
|
8692
|
-
channelType: "system",
|
|
8693
|
-
userId: "system",
|
|
8694
|
-
text: `[Heartbeat] ${action}`,
|
|
8695
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
8696
|
-
});
|
|
8697
|
-
log.debug(`Heartbeat response: ${response.slice(0, 200)}`);
|
|
8698
|
-
}
|
|
8699
|
-
});
|
|
8700
|
-
scheduler.onJobTrigger(async (job) => {
|
|
8701
|
-
log.info(`Job triggered: ${job.id}`);
|
|
8702
|
-
const response = await agent.handleMessage({
|
|
8703
|
-
id: `job-${job.id}-${Date.now()}`,
|
|
8704
|
-
channelType: "system",
|
|
8705
|
-
userId: "system",
|
|
8706
|
-
text: job.prompt,
|
|
8707
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
8708
|
-
});
|
|
8709
|
-
if (telegram && config.channels.telegram?.enabled) {
|
|
8710
|
-
const userId = config.channels.telegram.allowedUsers[0];
|
|
8711
|
-
if (userId !== void 0) {
|
|
8712
|
-
await telegram.send({
|
|
8713
|
-
channelType: "telegram",
|
|
8714
|
-
userId: String(userId),
|
|
8715
|
-
text: response
|
|
8716
|
-
});
|
|
8717
|
-
}
|
|
8718
|
-
}
|
|
8719
|
-
log.debug(`Job ${job.id} completed`);
|
|
8720
|
-
});
|
|
8721
|
-
scheduler.start();
|
|
8722
|
-
heartbeat.start();
|
|
8723
|
-
log.info(`Scheduler started: ${scheduler.listJobs().length} jobs, heartbeat every ${config.scheduler.heartbeatInterval}`);
|
|
8724
9178
|
const updateTimers = [];
|
|
8725
9179
|
if (skillUpdater && config.updates?.skills?.checkInterval) {
|
|
8726
9180
|
const su = skillUpdater;
|
|
@@ -8773,6 +9227,8 @@ Run: \`npm update -g augure\``
|
|
|
8773
9227
|
scheduler.stop();
|
|
8774
9228
|
if (telegram)
|
|
8775
9229
|
await telegram.stop();
|
|
9230
|
+
if (browserManager)
|
|
9231
|
+
await browserManager.closeAll();
|
|
8776
9232
|
await pool.destroyAll();
|
|
8777
9233
|
await audit.close();
|
|
8778
9234
|
log.info("All containers destroyed");
|
|
@@ -8780,6 +9236,9 @@ Run: \`npm update -g augure\``
|
|
|
8780
9236
|
};
|
|
8781
9237
|
process.on("SIGINT", shutdown);
|
|
8782
9238
|
process.on("SIGTERM", shutdown);
|
|
9239
|
+
if (telegram) {
|
|
9240
|
+
await telegram.start();
|
|
9241
|
+
}
|
|
8783
9242
|
}
|
|
8784
9243
|
|
|
8785
9244
|
// src/commands/start.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "augure",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Augure — your proactive AI agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -22,20 +22,21 @@
|
|
|
22
22
|
"gray-matter": "^4.0.3",
|
|
23
23
|
"json5": "^2.2.3",
|
|
24
24
|
"node-cron": "^4.2.1",
|
|
25
|
-
"zod": "^4.3.6"
|
|
25
|
+
"zod": "^4.3.6",
|
|
26
|
+
"@browserbasehq/stagehand": "^3.0.0"
|
|
26
27
|
},
|
|
27
28
|
"devDependencies": {
|
|
28
29
|
"@types/dockerode": "^4.0.1",
|
|
29
30
|
"@types/node-cron": "^3.0.11",
|
|
30
31
|
"tsup": "^8.5.1",
|
|
31
|
-
"@augure/channels": "0.
|
|
32
|
-
"@augure/core": "0.
|
|
33
|
-
"@augure/
|
|
34
|
-
"@augure/scheduler": "0.1.
|
|
35
|
-
"@augure/
|
|
36
|
-
"@augure/
|
|
37
|
-
"@augure/
|
|
38
|
-
"@augure/
|
|
32
|
+
"@augure/channels": "0.2.0",
|
|
33
|
+
"@augure/core": "0.8.0",
|
|
34
|
+
"@augure/memory": "0.0.7",
|
|
35
|
+
"@augure/scheduler": "0.1.5",
|
|
36
|
+
"@augure/sandbox": "0.1.4",
|
|
37
|
+
"@augure/skills": "0.1.5",
|
|
38
|
+
"@augure/tools": "0.4.1",
|
|
39
|
+
"@augure/types": "0.5.0"
|
|
39
40
|
},
|
|
40
41
|
"keywords": [
|
|
41
42
|
"ai",
|