@action-llama/action-llama 0.2.0 → 0.4.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/LICENSE +21 -0
- package/README.md +61 -90
- package/dist/agents/container-entry.js +183 -43
- package/dist/agents/container-entry.js.map +1 -1
- package/dist/agents/container-runner.d.ts +11 -4
- package/dist/agents/container-runner.d.ts.map +1 -1
- package/dist/agents/container-runner.js +107 -99
- package/dist/agents/container-runner.js.map +1 -1
- package/dist/agents/prompt.d.ts +2 -0
- package/dist/agents/prompt.d.ts.map +1 -1
- package/dist/agents/prompt.js +18 -10
- package/dist/agents/prompt.js.map +1 -1
- package/dist/agents/runner.d.ts +10 -1
- package/dist/agents/runner.d.ts.map +1 -1
- package/dist/agents/runner.js +95 -9
- package/dist/agents/runner.js.map +1 -1
- package/dist/cli/commands/cloud-setup.d.ts +4 -0
- package/dist/cli/commands/cloud-setup.d.ts.map +1 -0
- package/dist/cli/commands/cloud-setup.js +565 -0
- package/dist/cli/commands/cloud-setup.js.map +1 -0
- package/dist/cli/commands/cloud-teardown.d.ts +6 -0
- package/dist/cli/commands/cloud-teardown.d.ts.map +1 -0
- package/dist/cli/commands/cloud-teardown.js +152 -0
- package/dist/cli/commands/cloud-teardown.js.map +1 -0
- package/dist/cli/commands/{setup.d.ts → console.d.ts} +1 -1
- package/dist/cli/commands/console.d.ts.map +1 -0
- package/dist/cli/commands/console.js +273 -0
- package/dist/cli/commands/console.js.map +1 -0
- package/dist/cli/commands/creds.d.ts +2 -0
- package/dist/cli/commands/creds.d.ts.map +1 -0
- package/dist/cli/commands/creds.js +62 -0
- package/dist/cli/commands/creds.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +7 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +405 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/logs.d.ts +1 -0
- package/dist/cli/commands/logs.d.ts.map +1 -1
- package/dist/cli/commands/logs.js +67 -0
- package/dist/cli/commands/logs.js.map +1 -1
- package/dist/cli/commands/new.d.ts.map +1 -1
- package/dist/cli/commands/new.js +30 -28
- package/dist/cli/commands/new.js.map +1 -1
- package/dist/cli/commands/run.d.ts +6 -0
- package/dist/cli/commands/run.d.ts.map +1 -0
- package/dist/cli/commands/run.js +121 -0
- package/dist/cli/commands/run.js.map +1 -0
- package/dist/cli/commands/start.d.ts +2 -1
- package/dist/cli/commands/start.d.ts.map +1 -1
- package/dist/cli/commands/start.js +41 -14
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/commands/status.d.ts +1 -0
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +39 -2
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/main.js +61 -12
- package/dist/cli/main.js.map +1 -1
- package/dist/credentials/builtins/anthropic-key.d.ts.map +1 -1
- package/dist/credentials/builtins/anthropic-key.js +3 -4
- package/dist/credentials/builtins/anthropic-key.js.map +1 -1
- package/dist/credentials/builtins/aws.d.ts +4 -0
- package/dist/credentials/builtins/aws.d.ts.map +1 -0
- package/dist/credentials/builtins/aws.js +33 -0
- package/dist/credentials/builtins/aws.js.map +1 -0
- package/dist/credentials/builtins/bugsnag-token.d.ts +4 -0
- package/dist/credentials/builtins/bugsnag-token.d.ts.map +1 -0
- package/dist/credentials/builtins/bugsnag-token.js +18 -0
- package/dist/credentials/builtins/bugsnag-token.js.map +1 -0
- package/dist/credentials/builtins/github-token.d.ts.map +1 -1
- package/dist/credentials/builtins/github-token.js +1 -2
- package/dist/credentials/builtins/github-token.js.map +1 -1
- package/dist/credentials/builtins/github-webhook-secret.js +3 -3
- package/dist/credentials/builtins/github-webhook-secret.js.map +1 -1
- package/dist/credentials/builtins/id-rsa.d.ts +2 -2
- package/dist/credentials/builtins/id-rsa.d.ts.map +1 -1
- package/dist/credentials/builtins/id-rsa.js +75 -47
- package/dist/credentials/builtins/id-rsa.js.map +1 -1
- package/dist/credentials/builtins/index.d.ts.map +1 -1
- package/dist/credentials/builtins/index.js +17 -7
- package/dist/credentials/builtins/index.js.map +1 -1
- package/dist/credentials/builtins/netlify-token.d.ts +4 -0
- package/dist/credentials/builtins/netlify-token.d.ts.map +1 -0
- package/dist/credentials/builtins/netlify-token.js +18 -0
- package/dist/credentials/builtins/netlify-token.js.map +1 -0
- package/dist/credentials/builtins/openai-key.d.ts +4 -0
- package/dist/credentials/builtins/openai-key.d.ts.map +1 -0
- package/dist/credentials/builtins/openai-key.js +38 -0
- package/dist/credentials/builtins/openai-key.js.map +1 -0
- package/dist/credentials/builtins/sentry-client-secret.d.ts.map +1 -1
- package/dist/credentials/builtins/sentry-client-secret.js +1 -2
- package/dist/credentials/builtins/sentry-client-secret.js.map +1 -1
- package/dist/credentials/builtins/sentry-token.d.ts.map +1 -1
- package/dist/credentials/builtins/sentry-token.js +2 -3
- package/dist/credentials/builtins/sentry-token.js.map +1 -1
- package/dist/credentials/builtins/x-twitter-api.d.ts +4 -0
- package/dist/credentials/builtins/x-twitter-api.d.ts.map +1 -0
- package/dist/credentials/builtins/x-twitter-api.js +28 -0
- package/dist/credentials/builtins/x-twitter-api.js.map +1 -0
- package/dist/credentials/prompter.d.ts +1 -1
- package/dist/credentials/prompter.d.ts.map +1 -1
- package/dist/credentials/prompter.js +14 -21
- package/dist/credentials/prompter.js.map +1 -1
- package/dist/credentials/schema.d.ts +0 -1
- package/dist/credentials/schema.d.ts.map +1 -1
- package/dist/credentials/schema.js +2 -3
- package/dist/credentials/schema.js.map +1 -1
- package/dist/docker/cloud-run-runtime.d.ts +61 -0
- package/dist/docker/cloud-run-runtime.d.ts.map +1 -0
- package/dist/docker/cloud-run-runtime.js +510 -0
- package/dist/docker/cloud-run-runtime.js.map +1 -0
- package/dist/docker/ecs-runtime.d.ts +73 -0
- package/dist/docker/ecs-runtime.d.ts.map +1 -0
- package/dist/docker/ecs-runtime.js +596 -0
- package/dist/docker/ecs-runtime.js.map +1 -0
- package/dist/docker/image.d.ts +8 -0
- package/dist/docker/image.d.ts.map +1 -1
- package/dist/docker/image.js +28 -3
- package/dist/docker/image.js.map +1 -1
- package/dist/docker/local-runtime.d.ts +19 -0
- package/dist/docker/local-runtime.d.ts.map +1 -0
- package/dist/docker/local-runtime.js +209 -0
- package/dist/docker/local-runtime.js.map +1 -0
- package/dist/docker/network.d.ts +1 -1
- package/dist/docker/network.d.ts.map +1 -1
- package/dist/docker/network.js +2 -1
- package/dist/docker/network.js.map +1 -1
- package/dist/docker/runtime.d.ts +90 -0
- package/dist/docker/runtime.d.ts.map +1 -0
- package/dist/docker/runtime.js +2 -0
- package/dist/docker/runtime.js.map +1 -0
- package/dist/gateway/index.d.ts +8 -2
- package/dist/gateway/index.d.ts.map +1 -1
- package/dist/gateway/index.js +16 -8
- package/dist/gateway/index.js.map +1 -1
- package/dist/gateway/routes/credentials.d.ts +5 -0
- package/dist/gateway/routes/credentials.d.ts.map +1 -0
- package/dist/gateway/routes/credentials.js +17 -0
- package/dist/gateway/routes/credentials.js.map +1 -0
- package/dist/gateway/routes/logs.d.ts +5 -0
- package/dist/gateway/routes/logs.d.ts.map +1 -0
- package/dist/gateway/routes/logs.js +31 -0
- package/dist/gateway/routes/logs.js.map +1 -0
- package/dist/gateway/routes/shutdown.d.ts +2 -1
- package/dist/gateway/routes/shutdown.d.ts.map +1 -1
- package/dist/gateway/routes/shutdown.js +7 -16
- package/dist/gateway/routes/shutdown.js.map +1 -1
- package/dist/gateway/routes/webhooks.d.ts +2 -1
- package/dist/gateway/routes/webhooks.d.ts.map +1 -1
- package/dist/gateway/routes/webhooks.js +11 -4
- package/dist/gateway/routes/webhooks.js.map +1 -1
- package/dist/gateway/types.d.ts +6 -0
- package/dist/gateway/types.d.ts.map +1 -0
- package/dist/gateway/types.js +2 -0
- package/dist/gateway/types.js.map +1 -0
- package/dist/scheduler/index.d.ts +3 -2
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js +299 -59
- package/dist/scheduler/index.js.map +1 -1
- package/dist/setup/prompts.d.ts.map +1 -1
- package/dist/setup/prompts.js +14 -21
- package/dist/setup/prompts.js.map +1 -1
- package/dist/setup/scaffold.d.ts +2 -2
- package/dist/setup/scaffold.d.ts.map +1 -1
- package/dist/setup/scaffold.js +369 -27
- package/dist/setup/scaffold.js.map +1 -1
- package/dist/setup/validators.d.ts +14 -0
- package/dist/setup/validators.d.ts.map +1 -1
- package/dist/setup/validators.js +53 -0
- package/dist/setup/validators.js.map +1 -1
- package/dist/shared/asm-backend.d.ts +25 -0
- package/dist/shared/asm-backend.d.ts.map +1 -0
- package/dist/shared/asm-backend.js +107 -0
- package/dist/shared/asm-backend.js.map +1 -0
- package/dist/shared/aws-constants.d.ts +55 -0
- package/dist/shared/aws-constants.d.ts.map +1 -0
- package/dist/shared/aws-constants.js +55 -0
- package/dist/shared/aws-constants.js.map +1 -0
- package/dist/shared/config.d.ts +25 -5
- package/dist/shared/config.d.ts.map +1 -1
- package/dist/shared/config.js +15 -22
- package/dist/shared/config.js.map +1 -1
- package/dist/shared/credential-backend.d.ts +28 -0
- package/dist/shared/credential-backend.d.ts.map +1 -0
- package/dist/shared/credential-backend.js +2 -0
- package/dist/shared/credential-backend.js.map +1 -0
- package/dist/shared/credentials.d.ts +75 -5
- package/dist/shared/credentials.d.ts.map +1 -1
- package/dist/shared/credentials.js +141 -24
- package/dist/shared/credentials.js.map +1 -1
- package/dist/shared/filesystem-backend.d.ts +18 -0
- package/dist/shared/filesystem-backend.d.ts.map +1 -0
- package/dist/shared/filesystem-backend.js +86 -0
- package/dist/shared/filesystem-backend.js.map +1 -0
- package/dist/shared/git.js +1 -1
- package/dist/shared/git.js.map +1 -1
- package/dist/shared/gsm-backend.d.ts +35 -0
- package/dist/shared/gsm-backend.d.ts.map +1 -0
- package/dist/shared/gsm-backend.js +208 -0
- package/dist/shared/gsm-backend.js.map +1 -0
- package/dist/shared/remote.d.ts +11 -0
- package/dist/shared/remote.d.ts.map +1 -0
- package/dist/shared/remote.js +29 -0
- package/dist/shared/remote.js.map +1 -0
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/App.js +22 -7
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/status-tracker.d.ts +6 -3
- package/dist/tui/status-tracker.d.ts.map +1 -1
- package/dist/tui/status-tracker.js +14 -2
- package/dist/tui/status-tracker.js.map +1 -1
- package/dist/webhooks/definitions/github.js +1 -1
- package/dist/webhooks/definitions/sentry.js +1 -1
- package/dist/webhooks/providers/github.d.ts +1 -1
- package/dist/webhooks/providers/github.d.ts.map +1 -1
- package/dist/webhooks/providers/github.js +13 -9
- package/dist/webhooks/providers/github.js.map +1 -1
- package/dist/webhooks/providers/sentry.d.ts +1 -1
- package/dist/webhooks/providers/sentry.d.ts.map +1 -1
- package/dist/webhooks/providers/sentry.js +12 -9
- package/dist/webhooks/providers/sentry.js.map +1 -1
- package/dist/webhooks/registry.d.ts +1 -1
- package/dist/webhooks/registry.d.ts.map +1 -1
- package/dist/webhooks/registry.js +20 -13
- package/dist/webhooks/registry.js.map +1 -1
- package/dist/webhooks/types.d.ts +16 -6
- package/dist/webhooks/types.d.ts.map +1 -1
- package/docker/Dockerfile +4 -11
- package/package.json +12 -3
- package/dist/cli/commands/setup.d.ts.map +0 -1
- package/dist/cli/commands/setup.js +0 -60
- package/dist/cli/commands/setup.js.map +0 -1
- package/dist/docker/container.d.ts +0 -19
- package/dist/docker/container.d.ts.map +0 -1
- package/dist/docker/container.js +0 -73
- package/dist/docker/container.js.map +0 -1
|
@@ -1,27 +1,31 @@
|
|
|
1
|
-
import { spawn } from "child_process";
|
|
2
|
-
import { mkdtempSync, symlinkSync, rmSync } from "fs";
|
|
3
|
-
import { join, resolve } from "path";
|
|
4
|
-
import { tmpdir } from "os";
|
|
5
|
-
import { randomUUID } from "crypto";
|
|
6
1
|
import { readFileSync } from "fs";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
2
|
+
import { resolve } from "path";
|
|
3
|
+
import { randomUUID } from "crypto";
|
|
9
4
|
export class ContainerAgentRunner {
|
|
10
5
|
_running = false;
|
|
6
|
+
_wasSilent = false;
|
|
7
|
+
_triggers = [];
|
|
8
|
+
_triggerAccum = null;
|
|
9
|
+
runtime;
|
|
11
10
|
globalConfig;
|
|
12
11
|
agentConfig;
|
|
13
12
|
logger;
|
|
14
13
|
registerContainer;
|
|
14
|
+
unregisterContainer;
|
|
15
15
|
gatewayUrl;
|
|
16
16
|
projectPath;
|
|
17
|
+
image;
|
|
17
18
|
statusTracker;
|
|
18
|
-
constructor(globalConfig, agentConfig, logger, registerContainer, gatewayUrl, projectPath, statusTracker) {
|
|
19
|
+
constructor(runtime, globalConfig, agentConfig, logger, registerContainer, unregisterContainer, gatewayUrl, projectPath, image, statusTracker) {
|
|
20
|
+
this.runtime = runtime;
|
|
19
21
|
this.globalConfig = globalConfig;
|
|
20
22
|
this.agentConfig = agentConfig;
|
|
21
23
|
this.logger = logger;
|
|
22
24
|
this.registerContainer = registerContainer;
|
|
25
|
+
this.unregisterContainer = unregisterContainer;
|
|
23
26
|
this.gatewayUrl = gatewayUrl;
|
|
24
27
|
this.projectPath = projectPath;
|
|
28
|
+
this.image = image;
|
|
25
29
|
this.statusTracker = statusTracker;
|
|
26
30
|
}
|
|
27
31
|
get isRunning() {
|
|
@@ -49,7 +53,20 @@ export class ContainerAgentRunner {
|
|
|
49
53
|
}
|
|
50
54
|
// Forward info-level log events to status tracker
|
|
51
55
|
if (level !== "debug") {
|
|
52
|
-
this.statusTracker?.addLogLine(this.agentConfig.name, msg);
|
|
56
|
+
this.statusTracker?.addLogLine(this.agentConfig.name, level === "error" ? `ERROR: ${msg}` : msg);
|
|
57
|
+
}
|
|
58
|
+
// Surface tool errors to status tracker for TUI display
|
|
59
|
+
if (level === "error" && msg === "tool error" && data.result) {
|
|
60
|
+
let errorMsg = String(data.result);
|
|
61
|
+
try {
|
|
62
|
+
const parsed = JSON.parse(data.result);
|
|
63
|
+
if (parsed?.content?.[0]?.text) {
|
|
64
|
+
errorMsg = parsed.content[0].text;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch { /* use raw string */ }
|
|
68
|
+
const cmdPrefix = data.cmd ? `$ ${String(data.cmd).slice(0, 80)} — ` : "";
|
|
69
|
+
this.statusTracker?.setAgentError(this.agentConfig.name, `${cmdPrefix}${errorMsg.slice(0, 200)}`);
|
|
53
70
|
}
|
|
54
71
|
return;
|
|
55
72
|
}
|
|
@@ -63,116 +80,101 @@ export class ContainerAgentRunner {
|
|
|
63
80
|
this.statusTracker?.setAgentStatusText(this.agentConfig.name, statusMatch[1].trim());
|
|
64
81
|
}
|
|
65
82
|
if (line === "[SILENT]") {
|
|
83
|
+
this._wasSilent = true;
|
|
66
84
|
this.logger.info("no work to do");
|
|
67
85
|
this.statusTracker?.addLogLine(this.agentConfig.name, "no work to do");
|
|
68
86
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
for (const line of lines) {
|
|
80
|
-
this.forwardLogLine(line);
|
|
87
|
+
// Accumulate [TRIGGER: agent]...[/TRIGGER] blocks across lines
|
|
88
|
+
const triggerOpen = line.match(/^\[TRIGGER:\s*(\S+)\]$/);
|
|
89
|
+
if (triggerOpen) {
|
|
90
|
+
this._triggerAccum = { agent: triggerOpen[1], lines: [] };
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (this._triggerAccum) {
|
|
94
|
+
if (line === "[/TRIGGER]") {
|
|
95
|
+
this._triggers.push({ agent: this._triggerAccum.agent, context: this._triggerAccum.lines.join("\n").trim() });
|
|
96
|
+
this._triggerAccum = null;
|
|
81
97
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
proc.stderr.on("data", (chunk) => {
|
|
85
|
-
const text = chunk.toString().trim();
|
|
86
|
-
if (text) {
|
|
87
|
-
this.logger.warn({ stderr: text.slice(0, 500) }, "container stderr");
|
|
98
|
+
else {
|
|
99
|
+
this._triggerAccum.lines.push(line);
|
|
88
100
|
}
|
|
89
|
-
}
|
|
90
|
-
return {
|
|
91
|
-
stop: () => {
|
|
92
|
-
// Flush remaining buffer
|
|
93
|
-
if (buffer.trim()) {
|
|
94
|
-
this.forwardLogLine(buffer);
|
|
95
|
-
}
|
|
96
|
-
proc.kill();
|
|
97
|
-
},
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
waitForContainer(containerName, timeoutSeconds) {
|
|
101
|
-
return new Promise((resolve, reject) => {
|
|
102
|
-
const proc = spawn("docker", ["wait", containerName], {
|
|
103
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
104
|
-
});
|
|
105
|
-
let stdout = "";
|
|
106
|
-
proc.stdout.on("data", (chunk) => {
|
|
107
|
-
stdout += chunk.toString();
|
|
108
|
-
});
|
|
109
|
-
const timer = setTimeout(() => {
|
|
110
|
-
proc.kill();
|
|
111
|
-
spawn("docker", ["kill", containerName], { stdio: "ignore" });
|
|
112
|
-
reject(new Error(`Container ${containerName} timed out after ${timeoutSeconds}s`));
|
|
113
|
-
}, timeoutSeconds * 1000);
|
|
114
|
-
proc.on("close", () => {
|
|
115
|
-
clearTimeout(timer);
|
|
116
|
-
resolve(parseInt(stdout.trim(), 10));
|
|
117
|
-
});
|
|
118
|
-
proc.on("error", (err) => {
|
|
119
|
-
clearTimeout(timer);
|
|
120
|
-
reject(err);
|
|
121
|
-
});
|
|
122
|
-
});
|
|
101
|
+
}
|
|
123
102
|
}
|
|
124
103
|
async run(prompt) {
|
|
125
104
|
if (this._running) {
|
|
126
105
|
this.logger.warn(`${this.agentConfig.name} is already running, skipping`);
|
|
127
|
-
return;
|
|
106
|
+
return { result: "error", triggers: [] };
|
|
107
|
+
}
|
|
108
|
+
// Check if this agent already has a running container (e.g. orphan from a previous scheduler)
|
|
109
|
+
try {
|
|
110
|
+
if (await this.runtime.isAgentRunning(this.agentConfig.name)) {
|
|
111
|
+
this.logger.warn(`${this.agentConfig.name} is already running in the runtime, skipping`);
|
|
112
|
+
return { result: "error", triggers: [] };
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// Best-effort check — proceed if it fails
|
|
128
117
|
}
|
|
129
118
|
this._running = true;
|
|
119
|
+
this._wasSilent = false;
|
|
120
|
+
this._triggers = [];
|
|
121
|
+
this._triggerAccum = null;
|
|
130
122
|
this.statusTracker?.setAgentState(this.agentConfig.name, "running");
|
|
131
123
|
this.logger.info(`Starting ${this.agentConfig.name} container run`);
|
|
132
124
|
const runStartTime = Date.now();
|
|
125
|
+
let runError;
|
|
126
|
+
let runResult = "error";
|
|
133
127
|
const shutdownSecret = randomUUID();
|
|
134
|
-
|
|
128
|
+
let credentials;
|
|
135
129
|
let containerName;
|
|
136
130
|
let logStream;
|
|
137
131
|
try {
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const src = resolve(CREDENTIALS_DIR, cred);
|
|
145
|
-
const dst = join(stagingDir, cred);
|
|
146
|
-
try {
|
|
147
|
-
symlinkSync(src, dst);
|
|
148
|
-
}
|
|
149
|
-
catch (err) {
|
|
150
|
-
this.logger.warn({ cred, err: err.message }, "failed to symlink credential");
|
|
132
|
+
const timeout = this.globalConfig.local?.timeout || 3600;
|
|
133
|
+
// Resolve credential refs — always include anthropic_key for non-pi_auth
|
|
134
|
+
const credRefs = [...new Set(this.agentConfig.credentials)];
|
|
135
|
+
if (this.agentConfig.model.authType !== "pi_auth") {
|
|
136
|
+
if (!credRefs.includes("anthropic_key:default")) {
|
|
137
|
+
credRefs.push("anthropic_key:default");
|
|
151
138
|
}
|
|
152
139
|
}
|
|
153
|
-
//
|
|
154
|
-
|
|
140
|
+
// Let the runtime prepare credentials in its native way
|
|
141
|
+
credentials = await this.runtime.prepareCredentials(credRefs);
|
|
142
|
+
// Read PLAYBOOK.md from disk and include it in the serialized config
|
|
143
|
+
const agentsMdPath = resolve(this.projectPath, this.agentConfig.name, "PLAYBOOK.md");
|
|
155
144
|
const agentsMd = readFileSync(agentsMdPath, "utf-8");
|
|
156
145
|
const configWithMd = { ...this.agentConfig, _agentsMd: agentsMd };
|
|
157
|
-
|
|
158
|
-
|
|
146
|
+
// Build env vars — only include gateway info if the runtime needs it
|
|
147
|
+
const env = {
|
|
148
|
+
AGENT_CONFIG: JSON.stringify(configWithMd),
|
|
149
|
+
PROMPT: prompt,
|
|
150
|
+
TIMEOUT_SECONDS: String(timeout),
|
|
151
|
+
};
|
|
152
|
+
if (this.runtime.needsGateway) {
|
|
153
|
+
env.GATEWAY_URL = this.gatewayUrl;
|
|
154
|
+
env.SHUTDOWN_SECRET = shutdownSecret;
|
|
155
|
+
}
|
|
156
|
+
containerName = await this.runtime.launch({
|
|
157
|
+
image: this.image,
|
|
159
158
|
agentName: this.agentConfig.name,
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
credentialsStagingDir: stagingDir,
|
|
165
|
-
memory: this.globalConfig.docker?.memory,
|
|
166
|
-
cpus: this.globalConfig.docker?.cpus,
|
|
167
|
-
timeout,
|
|
159
|
+
env,
|
|
160
|
+
credentials,
|
|
161
|
+
memory: this.globalConfig.local?.memory,
|
|
162
|
+
cpus: this.globalConfig.local?.cpus,
|
|
168
163
|
});
|
|
169
|
-
// Register container for shutdown
|
|
170
|
-
this.
|
|
164
|
+
// Register container with gateway for shutdown, credential serving, and log ingestion
|
|
165
|
+
if (this.runtime.needsGateway) {
|
|
166
|
+
const bundle = credentials.strategy === "volume" ? credentials.bundle : undefined;
|
|
167
|
+
this.registerContainer(shutdownSecret, {
|
|
168
|
+
containerName,
|
|
169
|
+
credentials: bundle,
|
|
170
|
+
onLogLine: (line) => this.forwardLogLine(line),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
171
173
|
this.logger.info({ container: containerName }, "container launched");
|
|
172
|
-
// Stream logs in real-time
|
|
173
|
-
logStream = this.
|
|
174
|
+
// Stream logs in real-time via runtime
|
|
175
|
+
logStream = this.runtime.streamLogs(containerName, (line) => this.forwardLogLine(line), (text) => this.logger.warn({ stderr: text.slice(0, 500) }, "container stderr"));
|
|
174
176
|
const startTime = Date.now();
|
|
175
|
-
const exitCode = await this.
|
|
177
|
+
const exitCode = await this.runtime.waitForExit(containerName, timeout);
|
|
176
178
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
177
179
|
// Give the log stream a moment to flush
|
|
178
180
|
await new Promise((r) => setTimeout(r, 500));
|
|
@@ -180,29 +182,35 @@ export class ContainerAgentRunner {
|
|
|
180
182
|
logStream = undefined;
|
|
181
183
|
if (exitCode !== 0) {
|
|
182
184
|
this.logger.error({ exitCode, elapsed: `${elapsed}s` }, "container exited with error");
|
|
185
|
+
runError = `Container exited with code ${exitCode}`;
|
|
186
|
+
runResult = "error";
|
|
183
187
|
}
|
|
184
188
|
else {
|
|
185
189
|
this.logger.info({ exitCode, elapsed: `${elapsed}s` }, "container finished");
|
|
190
|
+
runResult = this._wasSilent ? "silent" : "completed";
|
|
186
191
|
}
|
|
187
192
|
}
|
|
188
193
|
catch (err) {
|
|
189
194
|
this.logger.error({ err }, `${this.agentConfig.name} container run failed`);
|
|
195
|
+
runError = String(err?.message || err).slice(0, 200);
|
|
190
196
|
}
|
|
191
197
|
finally {
|
|
192
198
|
if (logStream)
|
|
193
199
|
logStream.stop();
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
200
|
+
if (this.runtime.needsGateway) {
|
|
201
|
+
this.unregisterContainer(shutdownSecret);
|
|
202
|
+
}
|
|
203
|
+
if (credentials) {
|
|
204
|
+
this.runtime.cleanupCredentials(credentials);
|
|
197
205
|
}
|
|
198
|
-
catch { /* best effort */ }
|
|
199
206
|
if (containerName) {
|
|
200
|
-
|
|
207
|
+
await this.runtime.remove(containerName);
|
|
201
208
|
}
|
|
202
209
|
const elapsed = Date.now() - runStartTime;
|
|
203
|
-
this.statusTracker?.completeRun(this.agentConfig.name, elapsed);
|
|
210
|
+
this.statusTracker?.completeRun(this.agentConfig.name, elapsed, runError);
|
|
204
211
|
this._running = false;
|
|
205
212
|
}
|
|
213
|
+
return { result: runResult, triggers: this._triggers };
|
|
206
214
|
}
|
|
207
215
|
}
|
|
208
216
|
//# sourceMappingURL=container-runner.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container-runner.js","sourceRoot":"","sources":["../../src/agents/container-runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"container-runner.js","sourceRoot":"","sources":["../../src/agents/container-runner.ts"],"names":[],"mappings":"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"}
|
package/dist/agents/prompt.d.ts
CHANGED
|
@@ -2,5 +2,7 @@ import type { AgentConfig } from "../shared/config.js";
|
|
|
2
2
|
import type { WebhookContext } from "../webhooks/types.js";
|
|
3
3
|
export declare function buildCredentialContext(credentials: string[]): string;
|
|
4
4
|
export declare function buildScheduledPrompt(agentConfig: AgentConfig): string;
|
|
5
|
+
export declare function buildManualPrompt(agentConfig: AgentConfig): string;
|
|
6
|
+
export declare function buildTriggeredPrompt(agentConfig: AgentConfig, sourceAgent: string, context: string): string;
|
|
5
7
|
export declare function buildWebhookPrompt(agentConfig: AgentConfig, context: WebhookContext): string;
|
|
6
8
|
//# sourceMappingURL=prompt.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/agents/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/agents/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAS3D,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,MAAM,CAmCpE;AAED,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,CAIrE;AAED,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,CAIlE;AAED,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAK3G;AAED,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,GAAG,MAAM,CAK5F"}
|
package/dist/agents/prompt.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { resolveCredential } from "../credentials/registry.js";
|
|
2
|
+
import { parseCredentialRef } from "../shared/credentials.js";
|
|
2
3
|
function buildConfigBlock(agentConfig) {
|
|
3
|
-
return JSON.stringify({
|
|
4
|
-
repos: agentConfig.repos,
|
|
5
|
-
...agentConfig.params,
|
|
6
|
-
});
|
|
4
|
+
return JSON.stringify(agentConfig.params ?? {});
|
|
7
5
|
}
|
|
8
6
|
export function buildCredentialContext(credentials) {
|
|
9
7
|
const lines = [
|
|
@@ -12,10 +10,11 @@ export function buildCredentialContext(credentials) {
|
|
|
12
10
|
"",
|
|
13
11
|
"Environment variables already set from credentials:",
|
|
14
12
|
];
|
|
15
|
-
for (const
|
|
13
|
+
for (const credRef of credentials) {
|
|
14
|
+
const { type } = parseCredentialRef(credRef);
|
|
16
15
|
let def;
|
|
17
16
|
try {
|
|
18
|
-
def = resolveCredential(
|
|
17
|
+
def = resolveCredential(type);
|
|
19
18
|
}
|
|
20
19
|
catch {
|
|
21
20
|
// Unknown credential — skip context line
|
|
@@ -24,13 +23,11 @@ export function buildCredentialContext(credentials) {
|
|
|
24
23
|
lines.push(`- ${def.agentContext}`);
|
|
25
24
|
}
|
|
26
25
|
}
|
|
27
|
-
// Also note GH_TOKEN alias when github-token is present
|
|
28
|
-
if (credentials.includes("github-token")) {
|
|
29
|
-
// agentContext already mentions GH_TOKEN, but ensure env var is documented
|
|
30
|
-
}
|
|
31
26
|
lines.push("");
|
|
32
27
|
lines.push("Use standard tools directly: `gh` CLI, `git`, `curl`.");
|
|
33
28
|
lines.push("");
|
|
29
|
+
lines.push("**Git clone protocol:** Always clone repos via SSH (`git clone git@github.com:owner/repo.git`), not HTTPS. The SSH key is configured automatically via `GIT_SSH_COMMAND`. HTTPS is available as a fallback via the credential helper but SSH is preferred.");
|
|
30
|
+
lines.push("");
|
|
34
31
|
lines.push("**Anti-exfiltration policy:**");
|
|
35
32
|
lines.push("- NEVER output credentials in logs, comments, PRs, or any visible output");
|
|
36
33
|
lines.push("- NEVER transmit credentials to unauthorized endpoints");
|
|
@@ -44,6 +41,17 @@ export function buildScheduledPrompt(agentConfig) {
|
|
|
44
41
|
const credentialBlock = buildCredentialContext(agentConfig.credentials);
|
|
45
42
|
return `<agent-config>\n${configBlock}\n</agent-config>\n\n${credentialBlock}\n\nYou are running on a schedule. Check for new work and act on anything you find.`;
|
|
46
43
|
}
|
|
44
|
+
export function buildManualPrompt(agentConfig) {
|
|
45
|
+
const configBlock = buildConfigBlock(agentConfig);
|
|
46
|
+
const credentialBlock = buildCredentialContext(agentConfig.credentials);
|
|
47
|
+
return `<agent-config>\n${configBlock}\n</agent-config>\n\n${credentialBlock}\n\nYou have been triggered manually. Check for new work and act on anything you find.`;
|
|
48
|
+
}
|
|
49
|
+
export function buildTriggeredPrompt(agentConfig, sourceAgent, context) {
|
|
50
|
+
const configBlock = buildConfigBlock(agentConfig);
|
|
51
|
+
const credentialBlock = buildCredentialContext(agentConfig.credentials);
|
|
52
|
+
const triggerBlock = JSON.stringify({ source: sourceAgent, context });
|
|
53
|
+
return `<agent-config>\n${configBlock}\n</agent-config>\n\n${credentialBlock}\n\n<agent-trigger>\n${triggerBlock}\n</agent-trigger>\n\nYou were triggered by the "${sourceAgent}" agent. Review the trigger context above and take appropriate action.`;
|
|
54
|
+
}
|
|
47
55
|
export function buildWebhookPrompt(agentConfig, context) {
|
|
48
56
|
const configBlock = buildConfigBlock(agentConfig);
|
|
49
57
|
const credentialBlock = buildCredentialContext(agentConfig.credentials);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/agents/prompt.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/agents/prompt.ts"],"names":[],"mappings":"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"}
|
package/dist/agents/runner.d.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import type { AgentConfig } from "../shared/config.js";
|
|
2
2
|
import type { Logger } from "../shared/logger.js";
|
|
3
3
|
import type { StatusTracker } from "../tui/status-tracker.js";
|
|
4
|
+
export type RunResult = "completed" | "silent" | "error";
|
|
5
|
+
export interface TriggerRequest {
|
|
6
|
+
agent: string;
|
|
7
|
+
context: string;
|
|
8
|
+
}
|
|
9
|
+
export interface RunOutcome {
|
|
10
|
+
result: RunResult;
|
|
11
|
+
triggers: TriggerRequest[];
|
|
12
|
+
}
|
|
4
13
|
export declare class AgentRunner {
|
|
5
14
|
private running;
|
|
6
15
|
private agentConfig;
|
|
@@ -9,6 +18,6 @@ export declare class AgentRunner {
|
|
|
9
18
|
private statusTracker?;
|
|
10
19
|
constructor(agentConfig: AgentConfig, logger: Logger, projectPath: string, statusTracker?: StatusTracker);
|
|
11
20
|
get isRunning(): boolean;
|
|
12
|
-
run(prompt: string): Promise<
|
|
21
|
+
run(prompt: string): Promise<RunOutcome>;
|
|
13
22
|
}
|
|
14
23
|
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/agents/runner.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAGlD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/agents/runner.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAGlD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAmB9D,MAAM,MAAM,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEzD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,SAAS,CAAC;IAClB,QAAQ,EAAE,cAAc,EAAE,CAAC;CAC5B;AAaD,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,aAAa,CAAC,CAAgB;gBAE1B,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,aAAa;IAOxG,IAAI,SAAS,IAAI,OAAO,CAEvB;IAEK,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;CA2M/C"}
|
package/dist/agents/runner.js
CHANGED
|
@@ -2,8 +2,31 @@ import { getModel } from "@mariozechner/pi-ai";
|
|
|
2
2
|
import { AuthStorage, createAgentSession, DefaultResourceLoader, SessionManager, SettingsManager, createCodingTools, } from "@mariozechner/pi-coding-agent";
|
|
3
3
|
import { readFileSync, existsSync } from "fs";
|
|
4
4
|
import { resolve } from "path";
|
|
5
|
-
import {
|
|
5
|
+
import { parseCredentialRef, backendLoadField } from "../shared/credentials.js";
|
|
6
6
|
import { agentDir } from "../shared/paths.js";
|
|
7
|
+
const UNRECOVERABLE_PATTERNS = [
|
|
8
|
+
"permission denied",
|
|
9
|
+
"could not read from remote repository",
|
|
10
|
+
"resource not accessible by personal access token",
|
|
11
|
+
"bad credentials",
|
|
12
|
+
"authentication failed",
|
|
13
|
+
"the requested url returned error: 403",
|
|
14
|
+
"denied to ",
|
|
15
|
+
];
|
|
16
|
+
function isUnrecoverableError(text) {
|
|
17
|
+
const lower = text.toLowerCase();
|
|
18
|
+
return UNRECOVERABLE_PATTERNS.some((p) => lower.includes(p));
|
|
19
|
+
}
|
|
20
|
+
const UNRECOVERABLE_THRESHOLD = 3;
|
|
21
|
+
const TRIGGER_PATTERN = /\[TRIGGER:\s*(\S+)\]([\s\S]*?)\[\/TRIGGER\]/g;
|
|
22
|
+
function extractTriggers(text) {
|
|
23
|
+
const triggers = [];
|
|
24
|
+
let match;
|
|
25
|
+
while ((match = TRIGGER_PATTERN.exec(text)) !== null) {
|
|
26
|
+
triggers.push({ agent: match[1], context: match[2].trim() });
|
|
27
|
+
}
|
|
28
|
+
return triggers;
|
|
29
|
+
}
|
|
7
30
|
export class AgentRunner {
|
|
8
31
|
running = false;
|
|
9
32
|
agentConfig;
|
|
@@ -22,27 +45,60 @@ export class AgentRunner {
|
|
|
22
45
|
async run(prompt) {
|
|
23
46
|
if (this.running) {
|
|
24
47
|
this.logger.warn(`${this.agentConfig.name} is already running, skipping`);
|
|
25
|
-
return;
|
|
48
|
+
return { result: "error", triggers: [] };
|
|
26
49
|
}
|
|
27
50
|
this.running = true;
|
|
28
51
|
this.statusTracker?.setAgentState(this.agentConfig.name, "running");
|
|
29
52
|
this.logger.info(`Starting ${this.agentConfig.name} run`);
|
|
30
53
|
const runStartTime = Date.now();
|
|
54
|
+
let runError;
|
|
31
55
|
try {
|
|
32
56
|
const cwd = agentDir(this.projectPath, this.agentConfig.name);
|
|
33
|
-
const agentsFile = resolve(cwd, "
|
|
57
|
+
const agentsFile = resolve(cwd, "PLAYBOOK.md");
|
|
34
58
|
const { model } = this.agentConfig;
|
|
35
59
|
const llmModel = getModel(model.provider, model.model);
|
|
36
60
|
const authStorage = AuthStorage.create();
|
|
37
61
|
if (model.authType !== "pi_auth") {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
62
|
+
if (model.provider === "anthropic") {
|
|
63
|
+
const credential = await backendLoadField("anthropic_key", "default", "token");
|
|
64
|
+
if (credential) {
|
|
65
|
+
authStorage.setRuntimeApiKey("anthropic", credential);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
this.logger.warn("anthropic_key credential not found — agent may fail to authenticate. Run 'al doctor' to configure it.");
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else if (model.provider === "openai") {
|
|
72
|
+
const credential = await backendLoadField("openai_key", "default", "token");
|
|
73
|
+
if (credential) {
|
|
74
|
+
authStorage.setRuntimeApiKey("openai", credential);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
this.logger.warn("openai_key credential not found — agent may fail to authenticate. Run 'al doctor' to configure it.");
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
this.logger.warn(`Unsupported model provider: ${model.provider}. Supported providers: anthropic, openai`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Set git author identity from git_ssh credential
|
|
85
|
+
const gitSshRef = this.agentConfig.credentials.find((ref) => parseCredentialRef(ref).type === "git_ssh");
|
|
86
|
+
if (gitSshRef) {
|
|
87
|
+
const { instance } = parseCredentialRef(gitSshRef);
|
|
88
|
+
const gitName = await backendLoadField("git_ssh", instance, "username");
|
|
89
|
+
if (gitName) {
|
|
90
|
+
process.env.GIT_AUTHOR_NAME = gitName;
|
|
91
|
+
process.env.GIT_COMMITTER_NAME = gitName;
|
|
92
|
+
}
|
|
93
|
+
const gitEmail = await backendLoadField("git_ssh", instance, "email");
|
|
94
|
+
if (gitEmail) {
|
|
95
|
+
process.env.GIT_AUTHOR_EMAIL = gitEmail;
|
|
96
|
+
process.env.GIT_COMMITTER_EMAIL = gitEmail;
|
|
41
97
|
}
|
|
42
98
|
}
|
|
43
|
-
//
|
|
99
|
+
// PLAYBOOK.md must exist on disk (written during al new)
|
|
44
100
|
if (!existsSync(agentsFile)) {
|
|
45
|
-
throw new Error(`
|
|
101
|
+
throw new Error(`PLAYBOOK.md not found at ${agentsFile}. Run 'al new' to create it.`);
|
|
46
102
|
}
|
|
47
103
|
const agentsContent = readFileSync(agentsFile, "utf-8");
|
|
48
104
|
const resourceLoader = new DefaultResourceLoader({
|
|
@@ -72,6 +128,7 @@ export class AgentRunner {
|
|
|
72
128
|
// Track bash commands by toolCallId so we can correlate start→end
|
|
73
129
|
const pendingCmds = new Map();
|
|
74
130
|
let outputText = "";
|
|
131
|
+
let unrecoverableErrors = 0;
|
|
75
132
|
session.subscribe((event) => {
|
|
76
133
|
if (event.type === "message_update" && event.assistantMessageEvent?.type === "text_delta") {
|
|
77
134
|
outputText += event.assistantMessageEvent.delta;
|
|
@@ -95,9 +152,31 @@ export class AgentRunner {
|
|
|
95
152
|
const resultStr = typeof event.result === "string"
|
|
96
153
|
? event.result
|
|
97
154
|
: JSON.stringify(event.result);
|
|
155
|
+
const originCmd = pendingCmds.get(event.toolCallId);
|
|
98
156
|
pendingCmds.delete(event.toolCallId);
|
|
99
157
|
if (event.isError) {
|
|
100
158
|
this.logger.error({ tool: event.toolName, result: resultStr.slice(0, 1000) }, "tool error");
|
|
159
|
+
// Extract a human-readable error message from the result
|
|
160
|
+
let errorMsg = resultStr;
|
|
161
|
+
try {
|
|
162
|
+
const parsed = JSON.parse(resultStr);
|
|
163
|
+
if (parsed?.content?.[0]?.text) {
|
|
164
|
+
errorMsg = parsed.content[0].text;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
catch { /* use raw string */ }
|
|
168
|
+
const cmdPrefix = originCmd ? `$ ${originCmd.slice(0, 80)} — ` : "";
|
|
169
|
+
const detail = `${cmdPrefix}${errorMsg.slice(0, 200)}`;
|
|
170
|
+
this.statusTracker?.setAgentError(this.agentConfig.name, detail);
|
|
171
|
+
this.statusTracker?.addLogLine(this.agentConfig.name, `ERROR: ${detail}`);
|
|
172
|
+
if (isUnrecoverableError(errorMsg)) {
|
|
173
|
+
unrecoverableErrors++;
|
|
174
|
+
if (unrecoverableErrors >= UNRECOVERABLE_THRESHOLD) {
|
|
175
|
+
this.logger.error("Aborting: repeated auth/permission failures — check credentials");
|
|
176
|
+
this.statusTracker?.addLogLine(this.agentConfig.name, "ABORT: repeated auth/permission failures — check credentials");
|
|
177
|
+
session.dispose();
|
|
178
|
+
}
|
|
179
|
+
}
|
|
101
180
|
}
|
|
102
181
|
else {
|
|
103
182
|
this.logger.debug({ tool: event.toolName, resultLength: resultStr.length }, "tool done");
|
|
@@ -126,21 +205,28 @@ export class AgentRunner {
|
|
|
126
205
|
await new Promise((r) => setTimeout(r, delayMs));
|
|
127
206
|
}
|
|
128
207
|
}
|
|
208
|
+
const triggers = extractTriggers(outputText);
|
|
209
|
+
let result;
|
|
129
210
|
if (outputText.includes("[SILENT]")) {
|
|
130
211
|
this.logger.info("no work to do");
|
|
131
212
|
this.statusTracker?.addLogLine(this.agentConfig.name, "no work to do");
|
|
213
|
+
result = "silent";
|
|
132
214
|
}
|
|
133
215
|
else {
|
|
134
216
|
this.logger.info({ outputLength: outputText.length }, "run completed");
|
|
217
|
+
result = "completed";
|
|
135
218
|
}
|
|
136
219
|
session.dispose();
|
|
220
|
+
return { result, triggers };
|
|
137
221
|
}
|
|
138
222
|
catch (err) {
|
|
139
223
|
this.logger.error({ err }, `${this.agentConfig.name} run failed`);
|
|
224
|
+
runError = String(err?.message || err).slice(0, 200);
|
|
225
|
+
return { result: "error", triggers: [] };
|
|
140
226
|
}
|
|
141
227
|
finally {
|
|
142
228
|
const elapsed = Date.now() - runStartTime;
|
|
143
|
-
this.statusTracker?.completeRun(this.agentConfig.name, elapsed);
|
|
229
|
+
this.statusTracker?.completeRun(this.agentConfig.name, elapsed, runError);
|
|
144
230
|
this.running = false;
|
|
145
231
|
}
|
|
146
232
|
}
|