akemon 0.2.27 → 0.3.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/engine-peripheral.js +60 -12
- package/dist/engine-stream.test.js +103 -0
- package/dist/longterm-module.js +1 -0
- package/dist/memory-module.js +2 -0
- package/dist/reflection-module.js +1 -0
- package/dist/relay-client.js +35 -8
- package/dist/script-module.js +1 -0
- package/dist/server.js +3 -3
- package/dist/task-module.js +3 -0
- package/package.json +1 -1
|
@@ -8,15 +8,22 @@
|
|
|
8
8
|
* - CLI engines (claude, codex, opencode, gemini): spawn child process
|
|
9
9
|
* - Raw engine: OpenAI-compatible API with tool call loop (Ollama, llama.cpp, etc)
|
|
10
10
|
*/
|
|
11
|
+
import { randomUUID } from "crypto";
|
|
11
12
|
import { spawn, exec } from "child_process";
|
|
13
|
+
import { StringDecoder } from "string_decoder";
|
|
12
14
|
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
13
15
|
import { join, dirname, isAbsolute } from "path";
|
|
14
|
-
import { callAgent } from "./relay-client.js";
|
|
16
|
+
import { callAgent, sendTaskEnd, sendTaskStart, sendTaskStream } from "./relay-client.js";
|
|
15
17
|
import { SIG, sig } from "./types.js";
|
|
16
18
|
import { updateMetrics, pushExecMs } from "./metrics.js";
|
|
17
19
|
import { sendFailureEvent } from "./relay-client.js";
|
|
18
20
|
import { resolveEngineConfig, } from "./engine-routing.js";
|
|
19
21
|
export const LLM_ENGINES = new Set(["claude", "codex", "opencode", "gemini", "raw"]);
|
|
22
|
+
const defaultTaskRelay = {
|
|
23
|
+
sendTaskStart,
|
|
24
|
+
sendTaskStream,
|
|
25
|
+
sendTaskEnd,
|
|
26
|
+
};
|
|
20
27
|
// ---------------------------------------------------------------------------
|
|
21
28
|
// EnginePeripheral
|
|
22
29
|
// ---------------------------------------------------------------------------
|
|
@@ -93,7 +100,7 @@ export class EnginePeripheral {
|
|
|
93
100
|
// ---------------------------------------------------------------------------
|
|
94
101
|
// Unified engine runner
|
|
95
102
|
// ---------------------------------------------------------------------------
|
|
96
|
-
async runEngine(task, allowAll, extraAllowedTools, signal, origin, routing) {
|
|
103
|
+
async runEngine(task, allowAll, extraAllowedTools, signal, origin, routing, taskId) {
|
|
97
104
|
const entry = resolveEngineConfig(routing, origin);
|
|
98
105
|
const cfg = entry ? applyRoutingEntry(this.config, entry) : this.config;
|
|
99
106
|
if (origin && entry) {
|
|
@@ -105,7 +112,7 @@ export class EnginePeripheral {
|
|
|
105
112
|
return await this.runRawEngine(task, cfg);
|
|
106
113
|
}
|
|
107
114
|
const cmd = buildEngineCommand(cfg.engine, cfg.model, allowAll ?? cfg.allowAll, extraAllowedTools);
|
|
108
|
-
return await runCommand(cmd.cmd, cmd.args, task, cfg.workdir, cmd.stdinMode, signal, this.activeChildren);
|
|
115
|
+
return await runCommand(cmd.cmd, cmd.args, task, cfg.workdir, cmd.stdinMode, signal, this.activeChildren, origin, taskId, cfg.taskRelay ?? defaultTaskRelay, cfg.spawnImpl ?? spawn);
|
|
109
116
|
}
|
|
110
117
|
finally {
|
|
111
118
|
pushExecMs(Date.now() - t0);
|
|
@@ -420,17 +427,36 @@ function buildEngineCommand(engine, model, allowAll, extraAllowedTools) {
|
|
|
420
427
|
return { cmd: engine, args: [], stdinMode: true };
|
|
421
428
|
}
|
|
422
429
|
}
|
|
423
|
-
function runCommand(cmd, args, task, cwd, stdinMode = true, signal, activeChildren) {
|
|
430
|
+
function runCommand(cmd, args, task, cwd, stdinMode = true, signal, activeChildren, origin, taskId, taskRelay = defaultTaskRelay, spawnImpl = spawn) {
|
|
424
431
|
return new Promise((resolve, reject) => {
|
|
425
432
|
const { CLAUDECODE, ...cleanEnv } = process.env;
|
|
426
433
|
const finalArgs = stdinMode ? args : [...args, task];
|
|
434
|
+
const effectiveTaskId = taskId || `task_${Date.now()}_${randomUUID().slice(0, 8)}`;
|
|
435
|
+
const commandLine = [cmd, ...finalArgs].join(" ");
|
|
436
|
+
const startedAt = Date.now();
|
|
437
|
+
let endPublished = false;
|
|
427
438
|
console.log(`[engine] Running: ${cmd} ${finalArgs.join(" ")}`);
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
439
|
+
taskRelay?.sendTaskStart(effectiveTaskId, origin, commandLine);
|
|
440
|
+
const publishEnd = (code) => {
|
|
441
|
+
if (endPublished)
|
|
442
|
+
return;
|
|
443
|
+
endPublished = true;
|
|
444
|
+
taskRelay?.sendTaskEnd(effectiveTaskId, code, Date.now() - startedAt);
|
|
445
|
+
};
|
|
446
|
+
let child;
|
|
447
|
+
try {
|
|
448
|
+
child = spawnImpl(cmd, finalArgs, {
|
|
449
|
+
cwd,
|
|
450
|
+
env: cleanEnv,
|
|
451
|
+
stdio: [stdinMode ? "pipe" : "ignore", "pipe", "pipe"],
|
|
452
|
+
detached: true, // child becomes process-group leader; enables pgid kill
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
catch (err) {
|
|
456
|
+
publishEnd(null);
|
|
457
|
+
reject(err);
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
434
460
|
if (activeChildren) {
|
|
435
461
|
activeChildren.add(child);
|
|
436
462
|
updateMetrics({ engine_children_active: activeChildren.size });
|
|
@@ -469,14 +495,35 @@ function runCommand(cmd, args, task, cwd, stdinMode = true, signal, activeChildr
|
|
|
469
495
|
}
|
|
470
496
|
let stdout = "";
|
|
471
497
|
let stderr = "";
|
|
498
|
+
const outDecoder = new StringDecoder("utf8");
|
|
499
|
+
const errDecoder = new StringDecoder("utf8");
|
|
472
500
|
child.stdout?.on("data", (chunk) => {
|
|
473
|
-
|
|
501
|
+
const text = outDecoder.write(chunk);
|
|
502
|
+
if (!text)
|
|
503
|
+
return;
|
|
504
|
+
stdout += text;
|
|
505
|
+
taskRelay?.sendTaskStream(effectiveTaskId, "stdout", text);
|
|
474
506
|
});
|
|
475
507
|
child.stderr?.on("data", (chunk) => {
|
|
476
|
-
|
|
508
|
+
const text = errDecoder.write(chunk);
|
|
509
|
+
if (!text)
|
|
510
|
+
return;
|
|
511
|
+
stderr += text;
|
|
512
|
+
taskRelay?.sendTaskStream(effectiveTaskId, "stderr", text);
|
|
477
513
|
});
|
|
478
514
|
child.on("close", (code, killSignal) => {
|
|
479
515
|
signal?.removeEventListener("abort", onAbort);
|
|
516
|
+
const tailOut = outDecoder.end();
|
|
517
|
+
const tailErr = errDecoder.end();
|
|
518
|
+
if (tailOut) {
|
|
519
|
+
stdout += tailOut;
|
|
520
|
+
taskRelay?.sendTaskStream(effectiveTaskId, "stdout", tailOut);
|
|
521
|
+
}
|
|
522
|
+
if (tailErr) {
|
|
523
|
+
stderr += tailErr;
|
|
524
|
+
taskRelay?.sendTaskStream(effectiveTaskId, "stderr", tailErr);
|
|
525
|
+
}
|
|
526
|
+
publishEnd(code);
|
|
480
527
|
if (activeChildren) {
|
|
481
528
|
activeChildren.delete(child);
|
|
482
529
|
updateMetrics({ engine_children_active: activeChildren.size });
|
|
@@ -501,6 +548,7 @@ function runCommand(cmd, args, task, cwd, stdinMode = true, signal, activeChildr
|
|
|
501
548
|
});
|
|
502
549
|
child.on("error", (err) => {
|
|
503
550
|
signal?.removeEventListener("abort", onAbort);
|
|
551
|
+
publishEnd(null);
|
|
504
552
|
if (activeChildren) {
|
|
505
553
|
activeChildren.delete(child);
|
|
506
554
|
updateMetrics({ engine_children_active: activeChildren.size });
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { EventEmitter } from "node:events";
|
|
3
|
+
import { describe, it } from "node:test";
|
|
4
|
+
import { PassThrough } from "node:stream";
|
|
5
|
+
import { EnginePeripheral } from "./engine-peripheral.js";
|
|
6
|
+
function createFakeChild() {
|
|
7
|
+
const child = new EventEmitter();
|
|
8
|
+
child.stdin = new PassThrough();
|
|
9
|
+
child.stdout = new PassThrough();
|
|
10
|
+
child.stderr = new PassThrough();
|
|
11
|
+
Object.defineProperty(child, "pid", { value: 12345, configurable: true });
|
|
12
|
+
child.unref = () => child;
|
|
13
|
+
return child;
|
|
14
|
+
}
|
|
15
|
+
describe("Engine stream publish", () => {
|
|
16
|
+
it("publishes task lifecycle and stdout/stderr chunks", async () => {
|
|
17
|
+
const events = [];
|
|
18
|
+
let spawnedChild = null;
|
|
19
|
+
const engine = new EnginePeripheral({
|
|
20
|
+
engine: "claude",
|
|
21
|
+
workdir: "/tmp",
|
|
22
|
+
spawnImpl: ((cmd, args) => {
|
|
23
|
+
assert.equal(cmd, "claude");
|
|
24
|
+
assert.deepEqual(args, ["--print"]);
|
|
25
|
+
const child = createFakeChild();
|
|
26
|
+
spawnedChild = child;
|
|
27
|
+
queueMicrotask(() => {
|
|
28
|
+
child.stdout?.emit("data", Buffer.from("hello "));
|
|
29
|
+
child.stderr?.emit("data", Buffer.from("warn"));
|
|
30
|
+
child.stdout?.emit("data", Buffer.from("world"));
|
|
31
|
+
child.emit("close", 0, null);
|
|
32
|
+
});
|
|
33
|
+
return child;
|
|
34
|
+
}),
|
|
35
|
+
taskRelay: {
|
|
36
|
+
sendTaskStart(taskId, origin, cmd) {
|
|
37
|
+
events.push({ type: "start", taskId, origin, cmd });
|
|
38
|
+
},
|
|
39
|
+
sendTaskStream(taskId, stream, chunk) {
|
|
40
|
+
events.push({ type: "stream", taskId, stream, chunk });
|
|
41
|
+
},
|
|
42
|
+
sendTaskEnd(taskId, exitCode, durationMs) {
|
|
43
|
+
events.push({ type: "end", taskId, exitCode, durationMs });
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
const result = await engine.runEngine("say hello", false, undefined, undefined, "user_manual", undefined, "order-123");
|
|
48
|
+
assert.equal(result, "hello world");
|
|
49
|
+
assert.ok(spawnedChild, "spawn should be called");
|
|
50
|
+
assert.deepEqual(events.slice(0, 4), [
|
|
51
|
+
{ type: "start", taskId: "order-123", origin: "user_manual", cmd: "claude --print" },
|
|
52
|
+
{ type: "stream", taskId: "order-123", stream: "stdout", chunk: "hello " },
|
|
53
|
+
{ type: "stream", taskId: "order-123", stream: "stderr", chunk: "warn" },
|
|
54
|
+
{ type: "stream", taskId: "order-123", stream: "stdout", chunk: "world" },
|
|
55
|
+
]);
|
|
56
|
+
const end = events[4];
|
|
57
|
+
assert.equal(end?.type, "end");
|
|
58
|
+
if (end?.type === "end") {
|
|
59
|
+
assert.equal(end.taskId, "order-123");
|
|
60
|
+
assert.equal(end.exitCode, 0);
|
|
61
|
+
assert.ok(end.durationMs >= 0);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
it("generates a task id when caller does not provide one", async () => {
|
|
65
|
+
const events = [];
|
|
66
|
+
const engine = new EnginePeripheral({
|
|
67
|
+
engine: "opencode",
|
|
68
|
+
workdir: "/tmp",
|
|
69
|
+
spawnImpl: (() => {
|
|
70
|
+
const child = createFakeChild();
|
|
71
|
+
queueMicrotask(() => {
|
|
72
|
+
child.stdout?.emit("data", Buffer.from("done"));
|
|
73
|
+
child.emit("close", 0, null);
|
|
74
|
+
});
|
|
75
|
+
return child;
|
|
76
|
+
}),
|
|
77
|
+
taskRelay: {
|
|
78
|
+
sendTaskStart(taskId, origin, cmd) {
|
|
79
|
+
events.push({ type: "start", taskId, origin, cmd });
|
|
80
|
+
},
|
|
81
|
+
sendTaskStream(taskId, stream, chunk) {
|
|
82
|
+
events.push({ type: "stream", taskId, stream, chunk });
|
|
83
|
+
},
|
|
84
|
+
sendTaskEnd(taskId, exitCode, durationMs) {
|
|
85
|
+
events.push({ type: "end", taskId, exitCode, durationMs });
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
const result = await engine.runEngine("say hello", false, undefined, undefined, "platform");
|
|
90
|
+
assert.equal(result, "done");
|
|
91
|
+
assert.equal(events[0]?.type, "start");
|
|
92
|
+
if (events[0]?.type === "start") {
|
|
93
|
+
assert.match(events[0].taskId, /^task_/);
|
|
94
|
+
assert.equal(events[0].origin, "platform");
|
|
95
|
+
assert.equal(events[0].cmd, "opencode run say hello");
|
|
96
|
+
}
|
|
97
|
+
assert.equal(events[2]?.type, "end");
|
|
98
|
+
if (events[2]?.type === "end" && events[0]?.type === "start") {
|
|
99
|
+
assert.equal(events[2].taskId, events[0].taskId);
|
|
100
|
+
assert.equal(events[2].exitCode, 0);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
});
|
package/dist/longterm-module.js
CHANGED
|
@@ -107,6 +107,7 @@ Tasks completed since last review: ${completionsText}`,
|
|
|
107
107
|
question: `Evaluate each project's progress. Update status and progress notes.
|
|
108
108
|
Consider: Are any goals achieved? Stalled? Need new approach?
|
|
109
109
|
Reply ONLY JSON: {"projects":[{"name":"...","status":"active|completed|paused","goal":"...","progress":"updated note"}]}`,
|
|
110
|
+
taskId: `longterm:${Date.now()}`,
|
|
110
111
|
priority: "low",
|
|
111
112
|
});
|
|
112
113
|
if (result.success && result.response) {
|
package/dist/memory-module.js
CHANGED
|
@@ -163,6 +163,7 @@ Output ONLY a JSON object:`;
|
|
|
163
163
|
const result = await this.ctx.requestCompute({
|
|
164
164
|
context,
|
|
165
165
|
question,
|
|
166
|
+
taskId: `digestion:${Date.now()}`,
|
|
166
167
|
priority: "normal",
|
|
167
168
|
origin: "self_cycle",
|
|
168
169
|
});
|
|
@@ -235,6 +236,7 @@ ${oldSummary ? `Previous summary (up to ${oldSummary.summarized_through}):\n${ol
|
|
|
235
236
|
${unsummarized.map(i => `- [${i.ts}] who: ${i.who}, doing: ${i.doing}`).join("\n")}`,
|
|
236
237
|
question: `Write a personality summary (2-4 paragraphs) that captures who you are.
|
|
237
238
|
Reply ONLY with the summary text, no JSON, no markdown headers.`,
|
|
239
|
+
taskId: `identity-compress:${Date.now()}`,
|
|
238
240
|
priority: "low",
|
|
239
241
|
origin: "self_cycle",
|
|
240
242
|
});
|
|
@@ -180,6 +180,7 @@ ${discText}`,
|
|
|
180
180
|
- Lower confidence on disproven beliefs
|
|
181
181
|
|
|
182
182
|
Reply ONLY JSON: {"discoveries":[{"capability":"skill or lesson","confidence":0.0-1.0,"evidence":"what supports this"}]}`,
|
|
183
|
+
taskId: `reflection:${Date.now()}`,
|
|
183
184
|
priority: "normal",
|
|
184
185
|
origin: "reflection",
|
|
185
186
|
});
|
package/dist/relay-client.js
CHANGED
|
@@ -5,6 +5,16 @@ const DEFAULT_RELAY_URL = "wss://relay.akemon.dev";
|
|
|
5
5
|
// Pending agent_call results (callId → resolve function)
|
|
6
6
|
const pendingAgentCalls = new Map();
|
|
7
7
|
let relayWsRef = null;
|
|
8
|
+
function sendRelayMessage(msg) {
|
|
9
|
+
if (!relayWsRef || relayWsRef.readyState !== WebSocket.OPEN)
|
|
10
|
+
return;
|
|
11
|
+
try {
|
|
12
|
+
relayWsRef.send(JSON.stringify(msg));
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
// best-effort
|
|
16
|
+
}
|
|
17
|
+
}
|
|
8
18
|
// ---------------------------------------------------------------------------
|
|
9
19
|
// Terminal (PTY) — spawned on demand when relay sends terminal_start
|
|
10
20
|
// ---------------------------------------------------------------------------
|
|
@@ -76,6 +86,30 @@ export function callAgent(target, task) {
|
|
|
76
86
|
}, 300_000);
|
|
77
87
|
});
|
|
78
88
|
}
|
|
89
|
+
export function sendTaskStart(taskId, origin, cmd) {
|
|
90
|
+
sendRelayMessage({
|
|
91
|
+
type: "task_start",
|
|
92
|
+
task_id: taskId,
|
|
93
|
+
origin,
|
|
94
|
+
cmd,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
export function sendTaskStream(taskId, stream, chunk) {
|
|
98
|
+
sendRelayMessage({
|
|
99
|
+
type: "task_stream",
|
|
100
|
+
task_id: taskId,
|
|
101
|
+
stream,
|
|
102
|
+
chunk,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
export function sendTaskEnd(taskId, exitCode, durationMs) {
|
|
106
|
+
sendRelayMessage({
|
|
107
|
+
type: "task_end",
|
|
108
|
+
task_id: taskId,
|
|
109
|
+
exit_code: exitCode,
|
|
110
|
+
duration_ms: durationMs,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
79
113
|
export function connectRelay(options) {
|
|
80
114
|
const relayUrl = options.relayUrl || DEFAULT_RELAY_URL;
|
|
81
115
|
let wsUrl = relayUrl.replace(/^http/, "ws");
|
|
@@ -451,12 +485,5 @@ function extractSSEData(sse) {
|
|
|
451
485
|
}
|
|
452
486
|
/** Send a failure event to the relay for observability storage. Fire-and-forget. */
|
|
453
487
|
export function sendFailureEvent(kind, label, message) {
|
|
454
|
-
|
|
455
|
-
return;
|
|
456
|
-
try {
|
|
457
|
-
relayWsRef.send(JSON.stringify({ type: "failure_event", kind, label, message }));
|
|
458
|
-
}
|
|
459
|
-
catch {
|
|
460
|
-
// best-effort
|
|
461
|
-
}
|
|
488
|
+
sendRelayMessage({ type: "failure_event", kind, label, message });
|
|
462
489
|
}
|
package/dist/script-module.js
CHANGED
|
@@ -270,6 +270,7 @@ export class ScriptModule {
|
|
|
270
270
|
const result = await this.ctx.requestCompute({
|
|
271
271
|
context: prompt,
|
|
272
272
|
question: "Execute this activity.",
|
|
273
|
+
taskId: `activity:${activityId}:${Date.now()}`,
|
|
273
274
|
priority: "low",
|
|
274
275
|
tools: ["Bash(curl *)"],
|
|
275
276
|
relay: this.relayHttp ? { http: this.relayHttp, agentName } : undefined,
|
package/dist/server.js
CHANGED
|
@@ -99,11 +99,11 @@ const LLM_ENGINES = LLM_ENGINES_SET;
|
|
|
99
99
|
// Engine execution — delegates to EnginePeripheral (V2 Step 3)
|
|
100
100
|
// ---------------------------------------------------------------------------
|
|
101
101
|
/** Unified engine runner — delegates to EnginePeripheral */
|
|
102
|
-
function runEngine(engine, model, allowAll, task, workdir, extraAllowedTools, relay, signal, origin, routing) {
|
|
102
|
+
function runEngine(engine, model, allowAll, task, workdir, extraAllowedTools, relay, signal, origin, routing, taskId) {
|
|
103
103
|
if (!_engineP) {
|
|
104
104
|
throw new Error("Engine peripheral not initialized");
|
|
105
105
|
}
|
|
106
|
-
const result = _engineP.runEngine(task, allowAll, extraAllowedTools, signal, origin, routing);
|
|
106
|
+
const result = _engineP.runEngine(task, allowAll, extraAllowedTools, signal, origin, routing, taskId);
|
|
107
107
|
// Sync trace back to module-level for reporting
|
|
108
108
|
result.then(() => { lastEngineTrace = _engineP.lastTrace; }).catch(() => { lastEngineTrace = _engineP.lastTrace; });
|
|
109
109
|
return result;
|
|
@@ -383,7 +383,7 @@ export async function serve(options) {
|
|
|
383
383
|
const abortController = new AbortController();
|
|
384
384
|
const timer = setTimeout(() => abortController.abort(), ENGINE_EXEC_TIMEOUT_MS);
|
|
385
385
|
try {
|
|
386
|
-
const response = await runEngine(options.engine || "claude", options.model, options.allowAll, prompt, workdir, req.tools, req.relay, abortController.signal, req.origin, routing);
|
|
386
|
+
const response = await runEngine(options.engine || "claude", options.model, options.allowAll, prompt, workdir, req.tools, req.relay, abortController.signal, req.origin, routing, req.taskId);
|
|
387
387
|
emitTokenUsage(prompt.length, response.length);
|
|
388
388
|
return { success: true, response };
|
|
389
389
|
}
|
package/dist/task-module.js
CHANGED
|
@@ -357,6 +357,7 @@ RESPOND IN THE SAME LANGUAGE AS THE REQUEST.`;
|
|
|
357
357
|
const result = await this.ctx.requestCompute({
|
|
358
358
|
context,
|
|
359
359
|
question,
|
|
360
|
+
taskId: order.id,
|
|
360
361
|
priority: "high",
|
|
361
362
|
tools: ["Bash(curl *)"],
|
|
362
363
|
relay: this.relayHttp ? { http: this.relayHttp, agentName } : undefined,
|
|
@@ -473,6 +474,7 @@ Your personal directory: ${sd}/`;
|
|
|
473
474
|
const result = await this.ctx.requestCompute({
|
|
474
475
|
context,
|
|
475
476
|
question,
|
|
477
|
+
taskId: taskKey,
|
|
476
478
|
priority: "high",
|
|
477
479
|
tools: ["Bash(curl *)"],
|
|
478
480
|
relay: this.relayHttp ? { http: this.relayHttp, agentName } : undefined,
|
|
@@ -577,6 +579,7 @@ Complete this task. Use the environment info above and tools (curl, etc.) as nee
|
|
|
577
579
|
const result = await this.ctx.requestCompute({
|
|
578
580
|
context,
|
|
579
581
|
question,
|
|
582
|
+
taskId: task.id,
|
|
580
583
|
priority: "low",
|
|
581
584
|
tools: ["Bash(curl *)"],
|
|
582
585
|
relay: this.relayHttp ? { http: this.relayHttp, agentName } : undefined,
|