@action-llama/action-llama 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +43 -102
- package/dist/agents/container-entry.js +123 -17
- package/dist/agents/container-entry.js.map +1 -1
- package/dist/agents/container-runner.d.ts +10 -4
- package/dist/agents/container-runner.d.ts.map +1 -1
- package/dist/agents/container-runner.js +83 -105
- 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 +12 -4
- 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 +60 -8
- package/dist/agents/runner.js.map +1 -1
- package/dist/cli/commands/{setup.d.ts → cloud-setup.d.ts} +1 -1
- 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/console.d.ts.map +1 -1
- package/dist/cli/commands/console.js +108 -8
- package/dist/cli/commands/console.js.map +1 -1
- 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 +9 -2
- 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 +3 -1
- package/dist/cli/commands/start.d.ts.map +1 -1
- package/dist/cli/commands/start.js +52 -16
- 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 +58 -16
- package/dist/cli/main.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-webhook-secret.d.ts.map +1 -1
- package/dist/credentials/builtins/github-webhook-secret.js +2 -1
- package/dist/credentials/builtins/github-webhook-secret.js.map +1 -1
- package/dist/credentials/builtins/index.d.ts.map +1 -1
- package/dist/credentials/builtins/index.js +10 -0
- 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/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.map +1 -1
- package/dist/credentials/prompter.js +8 -5
- package/dist/credentials/prompter.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.map +1 -1
- package/dist/docker/image.js +3 -2
- 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 +286 -67
- package/dist/scheduler/index.js.map +1 -1
- package/dist/setup/scaffold.d.ts.map +1 -1
- package/dist/setup/scaffold.js +110 -50
- 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 +42 -4
- package/dist/shared/credentials.d.ts.map +1 -1
- package/dist/shared/credentials.js +83 -6
- 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/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 +13 -4
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/plain-logger.d.ts +5 -0
- package/dist/tui/plain-logger.d.ts.map +1 -0
- package/dist/tui/plain-logger.js +80 -0
- package/dist/tui/plain-logger.js.map +1 -0
- package/dist/tui/status-tracker.d.ts +3 -2
- package/dist/tui/status-tracker.d.ts.map +1 -1
- package/dist/tui/status-tracker.js.map +1 -1
- package/dist/webhooks/definitions/github.js +1 -1
- package/dist/webhooks/definitions/github.js.map +1 -1
- package/dist/webhooks/definitions/sentry.js +1 -1
- package/dist/webhooks/definitions/sentry.js.map +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 -1
- package/package.json +10 -1
- package/dist/cli/commands/setup.d.ts.map +0 -1
- package/dist/cli/commands/setup.js +0 -50
- 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,5 +1,6 @@
|
|
|
1
1
|
import type { Router } from "../router.js";
|
|
2
2
|
import type { WebhookRegistry } from "../../webhooks/registry.js";
|
|
3
3
|
import type { Logger } from "../../shared/logger.js";
|
|
4
|
-
|
|
4
|
+
import type { StatusTracker } from "../../tui/status-tracker.js";
|
|
5
|
+
export declare function registerWebhookRoutes(router: Router, registry: WebhookRegistry, webhookSecrets: Record<string, Record<string, string>>, logger: Logger, statusTracker?: StatusTracker): void;
|
|
5
6
|
//# sourceMappingURL=webhooks.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../../src/gateway/routes/webhooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../../src/gateway/routes/webhooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAEjE,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,eAAe,EACzB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EACtD,MAAM,EAAE,MAAM,EACd,aAAa,CAAC,EAAE,aAAa,GAC5B,IAAI,CAsEN"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { readBody, sendJson, sendError } from "../router.js";
|
|
2
|
-
export function registerWebhookRoutes(router, registry, webhookSecrets, logger) {
|
|
2
|
+
export function registerWebhookRoutes(router, registry, webhookSecrets, logger, statusTracker) {
|
|
3
3
|
router.post("/webhooks/:source", async (req, res, params) => {
|
|
4
4
|
const source = params.source;
|
|
5
5
|
logger.debug({ source }, "webhook request received");
|
|
6
6
|
const provider = registry.getProvider(source);
|
|
7
7
|
if (!provider) {
|
|
8
8
|
logger.warn({ source }, "webhook rejected: unknown source");
|
|
9
|
+
statusTracker?.addLogLine("webhook", `Rejected: unknown source "${source}"`);
|
|
9
10
|
sendError(res, 404, `unknown webhook source: ${source}`);
|
|
10
11
|
return;
|
|
11
12
|
}
|
|
@@ -15,6 +16,7 @@ export function registerWebhookRoutes(router, registry, webhookSecrets, logger)
|
|
|
15
16
|
}
|
|
16
17
|
catch (err) {
|
|
17
18
|
logger.error({ err, source }, "webhook body read failed");
|
|
19
|
+
statusTracker?.addLogLine("webhook", `Failed to read body from ${source}: ${err.message}`);
|
|
18
20
|
sendError(res, 400, "failed to read request body");
|
|
19
21
|
return;
|
|
20
22
|
}
|
|
@@ -31,15 +33,20 @@ export function registerWebhookRoutes(router, registry, webhookSecrets, logger)
|
|
|
31
33
|
delivery: headers["x-github-delivery"],
|
|
32
34
|
hasSignature: !!headers["x-hub-signature-256"],
|
|
33
35
|
}, "webhook headers");
|
|
34
|
-
const
|
|
35
|
-
const result = registry.dispatch(source, headers, rawBody,
|
|
36
|
+
const secrets = webhookSecrets[source];
|
|
37
|
+
const result = registry.dispatch(source, headers, rawBody, secrets);
|
|
36
38
|
if (!result.ok) {
|
|
37
39
|
const status = result.errors?.includes("signature validation failed") ? 401 : 400;
|
|
40
|
+
const errorMsg = result.errors?.[0] || "dispatch failed";
|
|
38
41
|
logger.warn({ source, status, errors: result.errors }, "webhook dispatch failed");
|
|
39
|
-
|
|
42
|
+
statusTracker?.addLogLine("webhook", `${source}: ${errorMsg}`);
|
|
43
|
+
sendError(res, status, errorMsg);
|
|
40
44
|
return;
|
|
41
45
|
}
|
|
42
46
|
logger.info({ source, matched: result.matched, skipped: result.skipped }, "webhook dispatched");
|
|
47
|
+
if (result.matched > 0) {
|
|
48
|
+
statusTracker?.addLogLine("webhook", `${source}: dispatched to ${result.matched} agent${result.matched !== 1 ? "s" : ""}`);
|
|
49
|
+
}
|
|
43
50
|
sendJson(res, 200, {
|
|
44
51
|
ok: true,
|
|
45
52
|
matched: result.matched,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../../src/gateway/routes/webhooks.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../../src/gateway/routes/webhooks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/gateway/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IACrE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/gateway/types.ts"],"names":[],"mappings":""}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { Cron } from "croner";
|
|
2
2
|
import type { GlobalConfig } from "../shared/config.js";
|
|
3
|
+
import { type RunOutcome } from "../agents/runner.js";
|
|
3
4
|
import type { StatusTracker } from "../tui/status-tracker.js";
|
|
4
5
|
import { WebhookRegistry } from "../webhooks/registry.js";
|
|
5
6
|
import type { GatewayServer } from "../gateway/index.js";
|
|
6
7
|
interface RunnerLike {
|
|
7
8
|
isRunning: boolean;
|
|
8
|
-
run(prompt: string): Promise<
|
|
9
|
+
run(prompt: string): Promise<RunOutcome>;
|
|
9
10
|
}
|
|
10
|
-
export declare function startScheduler(projectPath: string, globalConfigOverride?: GlobalConfig, statusTracker?: StatusTracker): Promise<{
|
|
11
|
+
export declare function startScheduler(projectPath: string, globalConfigOverride?: GlobalConfig, statusTracker?: StatusTracker, cloudMode?: boolean): Promise<{
|
|
11
12
|
cronJobs: Cron<undefined>[];
|
|
12
13
|
runners: Record<string, RunnerLike>;
|
|
13
14
|
gateway: GatewayServer | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scheduler/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAG9B,OAAO,KAAK,EAAE,YAAY,EAAe,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scheduler/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAG9B,OAAO,KAAK,EAAE,YAAY,EAAe,MAAM,qBAAqB,CAAC;AAIrE,OAAO,EAAe,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAG1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAKzD,UAAU,UAAU;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CAC1C;AAmHD,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,oBAAoB,CAAC,EAAE,YAAY,EAAE,aAAa,CAAC,EAAE,aAAa,EAAE,SAAS,CAAC,EAAE,OAAO;;;;;;;GAqZhJ"}
|
package/dist/scheduler/index.js
CHANGED
|
@@ -1,15 +1,106 @@
|
|
|
1
1
|
import { Cron } from "croner";
|
|
2
2
|
import { mkdirSync } from "fs";
|
|
3
3
|
import { loadGlobalConfig, loadAgentConfig, discoverAgents, validateAgentConfig } from "../shared/config.js";
|
|
4
|
-
import {
|
|
4
|
+
import { backendRequireCredentialRef, backendLoadField, backendListInstances } from "../shared/credentials.js";
|
|
5
5
|
import { createLogger, createFileOnlyLogger } from "../shared/logger.js";
|
|
6
6
|
import { agentDir } from "../shared/paths.js";
|
|
7
7
|
import { AgentRunner } from "../agents/runner.js";
|
|
8
|
-
import { buildScheduledPrompt, buildWebhookPrompt } from "../agents/prompt.js";
|
|
8
|
+
import { buildScheduledPrompt, buildWebhookPrompt, buildTriggeredPrompt } from "../agents/prompt.js";
|
|
9
9
|
import { WebhookRegistry } from "../webhooks/registry.js";
|
|
10
10
|
import { GitHubWebhookProvider } from "../webhooks/providers/github.js";
|
|
11
11
|
import { SentryWebhookProvider } from "../webhooks/providers/sentry.js";
|
|
12
|
-
|
|
12
|
+
import { AWS_CONSTANTS } from "../shared/aws-constants.js";
|
|
13
|
+
// Provider type → credential type for loading secrets
|
|
14
|
+
const PROVIDER_TO_CREDENTIAL = {
|
|
15
|
+
github: "github_webhook_secret",
|
|
16
|
+
sentry: "sentry_client_secret",
|
|
17
|
+
};
|
|
18
|
+
function buildFilterFromTrigger(trigger) {
|
|
19
|
+
const providerType = trigger.type;
|
|
20
|
+
if (providerType === "github") {
|
|
21
|
+
const f = {};
|
|
22
|
+
if (trigger.events)
|
|
23
|
+
f.events = trigger.events;
|
|
24
|
+
if (trigger.actions)
|
|
25
|
+
f.actions = trigger.actions;
|
|
26
|
+
if (trigger.repos)
|
|
27
|
+
f.repos = trigger.repos;
|
|
28
|
+
if (trigger.labels)
|
|
29
|
+
f.labels = trigger.labels;
|
|
30
|
+
if (trigger.assignee)
|
|
31
|
+
f.assignee = trigger.assignee;
|
|
32
|
+
if (trigger.author)
|
|
33
|
+
f.author = trigger.author;
|
|
34
|
+
if (trigger.branches)
|
|
35
|
+
f.branches = trigger.branches;
|
|
36
|
+
return Object.keys(f).length > 0 ? f : undefined;
|
|
37
|
+
}
|
|
38
|
+
if (providerType === "sentry") {
|
|
39
|
+
const f = {};
|
|
40
|
+
if (trigger.resources)
|
|
41
|
+
f.resources = trigger.resources;
|
|
42
|
+
return Object.keys(f).length > 0 ? f : undefined;
|
|
43
|
+
}
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
const DEFAULT_MAX_RERUNS = 10;
|
|
47
|
+
const DEFAULT_MAX_TRIGGER_DEPTH = 3;
|
|
48
|
+
function dispatchTriggers(triggers, sourceAgent, depth, ctx) {
|
|
49
|
+
for (const { agent, context } of triggers) {
|
|
50
|
+
if (agent === sourceAgent) {
|
|
51
|
+
ctx.logger.warn({ source: sourceAgent }, "agent cannot trigger itself, skipping");
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (depth >= ctx.maxTriggerDepth) {
|
|
55
|
+
ctx.logger.warn({ source: sourceAgent, target: agent, depth, maxTriggerDepth: ctx.maxTriggerDepth }, "trigger depth limit reached, skipping");
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const targetConfig = ctx.agentConfigs.find((a) => a.name === agent);
|
|
59
|
+
if (!targetConfig) {
|
|
60
|
+
ctx.logger.warn({ source: sourceAgent, target: agent }, "trigger target agent not found, skipping");
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const runner = ctx.runners[agent];
|
|
64
|
+
if (runner.isRunning) {
|
|
65
|
+
ctx.logger.warn({ source: sourceAgent, target: agent }, "trigger target agent is busy, skipping");
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
ctx.logger.info({ source: sourceAgent, target: agent, depth }, "agent trigger firing");
|
|
69
|
+
const prompt = buildTriggeredPrompt(targetConfig, sourceAgent, context);
|
|
70
|
+
runTriggered(runner, targetConfig, prompt, sourceAgent, depth + 1, ctx).catch((err) => {
|
|
71
|
+
ctx.logger.error({ err, target: agent }, "triggered run failed");
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async function runTriggered(runner, agentConfig, prompt, sourceAgent, depth, ctx) {
|
|
76
|
+
const { result, triggers } = await runner.run(prompt);
|
|
77
|
+
if (triggers.length > 0) {
|
|
78
|
+
dispatchTriggers(triggers, agentConfig.name, depth, ctx);
|
|
79
|
+
}
|
|
80
|
+
// No reruns for triggered runs — they respond to a specific event
|
|
81
|
+
if (result === "completed") {
|
|
82
|
+
ctx.logger.info(`${agentConfig.name} triggered run completed`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async function runWithReruns(runner, agentConfig, depth, ctx) {
|
|
86
|
+
let { result, triggers } = await runner.run(buildScheduledPrompt(agentConfig));
|
|
87
|
+
if (triggers.length > 0) {
|
|
88
|
+
dispatchTriggers(triggers, agentConfig.name, depth, ctx);
|
|
89
|
+
}
|
|
90
|
+
let reruns = 0;
|
|
91
|
+
while (result === "completed" && reruns < ctx.maxReruns) {
|
|
92
|
+
reruns++;
|
|
93
|
+
ctx.logger.info({ rerun: reruns, maxReruns: ctx.maxReruns }, `${agentConfig.name} did work, re-running immediately`);
|
|
94
|
+
({ result, triggers } = await runner.run(buildScheduledPrompt(agentConfig)));
|
|
95
|
+
if (triggers.length > 0) {
|
|
96
|
+
dispatchTriggers(triggers, agentConfig.name, depth, ctx);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (result === "completed" && reruns >= ctx.maxReruns) {
|
|
100
|
+
ctx.logger.warn({ maxReruns: ctx.maxReruns }, `${agentConfig.name} hit max reruns limit`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
export async function startScheduler(projectPath, globalConfigOverride, statusTracker, cloudMode) {
|
|
13
104
|
const mkLogger = statusTracker ? createFileOnlyLogger : createLogger;
|
|
14
105
|
const logger = mkLogger(projectPath, "scheduler");
|
|
15
106
|
logger.info("Starting scheduler...");
|
|
@@ -27,17 +118,19 @@ export async function startScheduler(projectPath, globalConfigOverride, statusTr
|
|
|
27
118
|
// Validate credentials exist for each agent
|
|
28
119
|
const allCredentials = new Set(agentConfigs.flatMap((a) => a.credentials));
|
|
29
120
|
for (const credRef of allCredentials) {
|
|
30
|
-
|
|
121
|
+
await backendRequireCredentialRef(credRef);
|
|
31
122
|
}
|
|
123
|
+
const maxReruns = globalConfig.maxReruns ?? DEFAULT_MAX_RERUNS;
|
|
124
|
+
const maxTriggerDepth = globalConfig.maxTriggerDepth ?? DEFAULT_MAX_TRIGGER_DEPTH;
|
|
32
125
|
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
33
|
-
const dockerEnabled = globalConfig.
|
|
34
|
-
const anyWebhooks = agentConfigs.some((a) => a.webhooks?.
|
|
126
|
+
const dockerEnabled = globalConfig.local?.enabled === true;
|
|
127
|
+
const anyWebhooks = agentConfigs.some((a) => a.webhooks?.length);
|
|
35
128
|
// Validate pi_auth is not used with Docker (containers can't access host auth storage)
|
|
36
129
|
if (dockerEnabled) {
|
|
37
130
|
for (const config of agentConfigs) {
|
|
38
131
|
if (config.model.authType === "pi_auth") {
|
|
39
132
|
throw new Error(`Agent "${config.name}" uses pi_auth which is not supported in Docker mode. ` +
|
|
40
|
-
`Either switch to api_key/oauth_token (run 'al
|
|
133
|
+
`Either switch to api_key/oauth_token (run 'al doctor') or use --no-docker.`);
|
|
41
134
|
}
|
|
42
135
|
}
|
|
43
136
|
}
|
|
@@ -49,64 +142,176 @@ export async function startScheduler(projectPath, globalConfigOverride, statusTr
|
|
|
49
142
|
// Register providers
|
|
50
143
|
webhookRegistry.registerProvider(new GitHubWebhookProvider());
|
|
51
144
|
webhookRegistry.registerProvider(new SentryWebhookProvider());
|
|
52
|
-
// Load GitHub webhook
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
145
|
+
// Load all GitHub webhook secrets (instanceName → secret value)
|
|
146
|
+
const ghInstances = await backendListInstances("github_webhook_secret");
|
|
147
|
+
const ghSecrets = {};
|
|
148
|
+
for (const inst of ghInstances) {
|
|
149
|
+
const secret = await backendLoadField("github_webhook_secret", inst, "secret");
|
|
150
|
+
if (secret)
|
|
151
|
+
ghSecrets[inst] = secret;
|
|
152
|
+
}
|
|
153
|
+
if (Object.keys(ghSecrets).length > 0) {
|
|
154
|
+
webhookSecrets.github = ghSecrets;
|
|
155
|
+
logger.info({ count: Object.keys(ghSecrets).length }, "loaded GitHub webhook secrets");
|
|
156
|
+
}
|
|
157
|
+
// Load all Sentry webhook secrets (instanceName → secret value)
|
|
158
|
+
const sentryInstances = await backendListInstances("sentry_client_secret");
|
|
159
|
+
const sentrySecrets = {};
|
|
160
|
+
for (const inst of sentryInstances) {
|
|
161
|
+
const secret = await backendLoadField("sentry_client_secret", inst, "secret");
|
|
162
|
+
if (secret)
|
|
163
|
+
sentrySecrets[inst] = secret;
|
|
164
|
+
}
|
|
165
|
+
if (Object.keys(sentrySecrets).length > 0) {
|
|
166
|
+
webhookSecrets.sentry = sentrySecrets;
|
|
167
|
+
logger.info({ count: Object.keys(sentrySecrets).length }, "loaded Sentry webhook secrets");
|
|
67
168
|
}
|
|
68
169
|
}
|
|
69
170
|
let gateway;
|
|
70
|
-
let
|
|
171
|
+
let runtime;
|
|
172
|
+
let baseImage = AWS_CONSTANTS.DEFAULT_IMAGE;
|
|
71
173
|
const agentImages = {};
|
|
174
|
+
// Determine runtime type from cloud mode or local
|
|
175
|
+
const useCloudRuntime = cloudMode && globalConfig.cloud;
|
|
176
|
+
const runtimeType = useCloudRuntime ? globalConfig.cloud.provider : "local";
|
|
177
|
+
// Register agents early so the TUI shows them during image builds
|
|
178
|
+
for (const agentConfig of agentConfigs) {
|
|
179
|
+
statusTracker?.registerAgent(agentConfig.name);
|
|
180
|
+
}
|
|
72
181
|
if (dockerEnabled) {
|
|
73
|
-
logger.info("Docker mode enabled — initializing
|
|
74
|
-
// 1.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
182
|
+
logger.info({ runtime: runtimeType }, "Docker mode enabled — initializing infrastructure");
|
|
183
|
+
// 1. Create the container runtime
|
|
184
|
+
if (useCloudRuntime && globalConfig.cloud.provider === "cloud-run") {
|
|
185
|
+
const { CloudRunJobRuntime } = await import("../docker/cloud-run-runtime.js");
|
|
186
|
+
const { gcpProject, region, artifactRegistry, serviceAccount, secretPrefix } = globalConfig.cloud;
|
|
187
|
+
if (!gcpProject || !region || !artifactRegistry || !serviceAccount) {
|
|
188
|
+
throw new Error("Cloud Run runtime requires cloud.gcpProject, cloud.region, " +
|
|
189
|
+
"cloud.artifactRegistry, and cloud.serviceAccount in config.toml");
|
|
190
|
+
}
|
|
191
|
+
runtime = new CloudRunJobRuntime({ gcpProject, region, artifactRegistry, serviceAccount, secretPrefix });
|
|
192
|
+
logger.info({ gcpProject, region }, "Using Cloud Run Jobs runtime");
|
|
193
|
+
}
|
|
194
|
+
else if (useCloudRuntime && globalConfig.cloud.provider === "ecs") {
|
|
195
|
+
const { ECSFargateRuntime } = await import("../docker/ecs-runtime.js");
|
|
196
|
+
const cc = globalConfig.cloud;
|
|
197
|
+
if (!cc.awsRegion || !cc.ecsCluster || !cc.ecrRepository || !cc.executionRoleArn || !cc.taskRoleArn || !cc.subnets?.length) {
|
|
198
|
+
throw new Error("ECS runtime requires cloud.awsRegion, cloud.ecsCluster, cloud.ecrRepository, " +
|
|
199
|
+
"cloud.executionRoleArn, cloud.taskRoleArn, and cloud.subnets in config.toml");
|
|
200
|
+
}
|
|
201
|
+
runtime = new ECSFargateRuntime({
|
|
202
|
+
awsRegion: cc.awsRegion,
|
|
203
|
+
ecsCluster: cc.ecsCluster,
|
|
204
|
+
ecrRepository: cc.ecrRepository,
|
|
205
|
+
executionRoleArn: cc.executionRoleArn,
|
|
206
|
+
taskRoleArn: cc.taskRoleArn,
|
|
207
|
+
subnets: cc.subnets,
|
|
208
|
+
securityGroups: cc.securityGroups,
|
|
209
|
+
secretPrefix: cc.awsSecretPrefix,
|
|
210
|
+
});
|
|
211
|
+
logger.info({ region: cc.awsRegion, cluster: cc.ecsCluster }, "Using ECS Fargate runtime");
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
// Local runtime needs Docker running
|
|
215
|
+
const { execFileSync } = await import("child_process");
|
|
216
|
+
try {
|
|
217
|
+
execFileSync("docker", ["info"], { stdio: "pipe", timeout: 10000 });
|
|
218
|
+
}
|
|
219
|
+
catch {
|
|
220
|
+
throw new Error("Docker is not running. Start Docker Desktop (or the Docker daemon) and try again, " +
|
|
221
|
+
"or use --no-docker to run without container isolation.");
|
|
222
|
+
}
|
|
223
|
+
const { LocalDockerRuntime } = await import("../docker/local-runtime.js");
|
|
224
|
+
runtime = new LocalDockerRuntime();
|
|
225
|
+
// Local-only: ensure Docker network
|
|
226
|
+
logger.info("Ensuring Docker network...");
|
|
227
|
+
const { ensureNetwork } = await import("../docker/network.js");
|
|
228
|
+
ensureNetwork();
|
|
229
|
+
}
|
|
230
|
+
// 2. Build base image via the runtime
|
|
231
|
+
const { resolve: resolvePath, dirname } = await import("path");
|
|
232
|
+
const { fileURLToPath } = await import("url");
|
|
233
|
+
const packageRoot = resolvePath(dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
234
|
+
baseImage = globalConfig.local?.image || AWS_CONSTANTS.DEFAULT_IMAGE;
|
|
235
|
+
logger.info({ image: baseImage }, "Building base image (this may take a few minutes on first run)...");
|
|
236
|
+
// Show all agents as "building" during the base image build
|
|
237
|
+
const setBuildProgress = (message) => {
|
|
238
|
+
for (const ac of agentConfigs) {
|
|
239
|
+
statusTracker?.setAgentStatusText(ac.name, message);
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
for (const ac of agentConfigs) {
|
|
243
|
+
statusTracker?.setAgentState(ac.name, "building");
|
|
244
|
+
}
|
|
245
|
+
if (runtimeType === "local") {
|
|
246
|
+
// Local: only build if image doesn't exist yet
|
|
247
|
+
const { imageExists } = await import("../docker/image.js");
|
|
248
|
+
if (!imageExists(baseImage)) {
|
|
249
|
+
setBuildProgress("Building base image");
|
|
250
|
+
await runtime.buildImage({
|
|
251
|
+
tag: baseImage, dockerfile: "docker/Dockerfile", contextDir: packageRoot,
|
|
252
|
+
onProgress: setBuildProgress,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
// Cloud: always build (Cloud Build handles caching)
|
|
258
|
+
baseImage = await runtime.buildImage({
|
|
259
|
+
tag: baseImage, dockerfile: "docker/Dockerfile", contextDir: packageRoot,
|
|
260
|
+
onProgress: setBuildProgress,
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
// 3. Build per-agent images for agents with a custom Dockerfile
|
|
264
|
+
const { existsSync } = await import("fs");
|
|
93
265
|
for (const agentConfig of agentConfigs) {
|
|
94
|
-
const
|
|
266
|
+
const agentDockerfile = resolvePath(projectPath, agentConfig.name, "Dockerfile");
|
|
267
|
+
if (!existsSync(agentDockerfile)) {
|
|
268
|
+
agentImages[agentConfig.name] = baseImage;
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
statusTracker?.setAgentState(agentConfig.name, "building");
|
|
272
|
+
statusTracker?.setAgentStatusText(agentConfig.name, "Building custom image");
|
|
273
|
+
const agentImageTag = AWS_CONSTANTS.agentImage(agentConfig.name);
|
|
274
|
+
const image = await runtime.buildImage({
|
|
275
|
+
tag: agentImageTag,
|
|
276
|
+
dockerfile: agentDockerfile,
|
|
277
|
+
contextDir: packageRoot,
|
|
278
|
+
baseImage,
|
|
279
|
+
onProgress: (msg) => statusTracker?.setAgentStatusText(agentConfig.name, msg),
|
|
280
|
+
});
|
|
95
281
|
agentImages[agentConfig.name] = image;
|
|
96
|
-
|
|
97
|
-
|
|
282
|
+
logger.info({ agent: agentConfig.name, image }, "Built custom agent image");
|
|
283
|
+
}
|
|
284
|
+
// 4. Push images to remote registry if needed (no-op for local, tags+pushes for cloud)
|
|
285
|
+
if (runtimeType !== "local") {
|
|
286
|
+
for (const agentConfig of agentConfigs) {
|
|
287
|
+
const currentImage = agentImages[agentConfig.name] || baseImage;
|
|
288
|
+
if (!currentImage.includes("/")) {
|
|
289
|
+
// Looks like a local tag — needs pushing
|
|
290
|
+
statusTracker?.setAgentStatusText(agentConfig.name, "Pushing image to registry");
|
|
291
|
+
const remoteImage = await runtime.pushImage(currentImage);
|
|
292
|
+
agentImages[agentConfig.name] = remoteImage;
|
|
293
|
+
logger.info({ agent: agentConfig.name, image: remoteImage }, "Pushed image to registry");
|
|
294
|
+
}
|
|
98
295
|
}
|
|
99
296
|
}
|
|
297
|
+
// Reset all agents back to idle after builds complete
|
|
298
|
+
for (const ac of agentConfigs) {
|
|
299
|
+
statusTracker?.setAgentState(ac.name, "idle");
|
|
300
|
+
}
|
|
100
301
|
logger.info("Docker infrastructure ready");
|
|
101
|
-
//
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
302
|
+
// 6. Start gateway if the runtime needs it or webhooks are configured
|
|
303
|
+
if (runtime.needsGateway || anyWebhooks) {
|
|
304
|
+
const { startGateway } = await import("../gateway/index.js");
|
|
305
|
+
const gatewayPort = globalConfig.gateway?.port || 8080;
|
|
306
|
+
gateway = await startGateway({
|
|
307
|
+
port: gatewayPort,
|
|
308
|
+
logger: mkLogger(projectPath, "gateway"),
|
|
309
|
+
killContainer: (name) => runtime.kill(name),
|
|
310
|
+
webhookRegistry,
|
|
311
|
+
webhookSecrets,
|
|
312
|
+
statusTracker,
|
|
313
|
+
});
|
|
314
|
+
}
|
|
110
315
|
}
|
|
111
316
|
else if (anyWebhooks) {
|
|
112
317
|
// Start gateway even without docker when webhooks are configured
|
|
@@ -118,35 +323,45 @@ export async function startScheduler(projectPath, globalConfigOverride, statusTr
|
|
|
118
323
|
logger: mkLogger(projectPath, "gateway"),
|
|
119
324
|
webhookRegistry,
|
|
120
325
|
webhookSecrets,
|
|
326
|
+
statusTracker,
|
|
121
327
|
});
|
|
122
328
|
}
|
|
123
329
|
// Create runners for each agent
|
|
124
330
|
const runners = {};
|
|
125
|
-
if (dockerEnabled &&
|
|
331
|
+
if (dockerEnabled && runtime) {
|
|
126
332
|
const { ContainerAgentRunner } = await import("../agents/container-runner.js");
|
|
127
333
|
const gatewayPort = globalConfig.gateway?.port || 8080;
|
|
128
334
|
const gatewayUrl = `http://host.docker.internal:${gatewayPort}`;
|
|
335
|
+
// Gateway callbacks — no-ops if gateway isn't running (remote runtimes)
|
|
336
|
+
const registerContainer = gateway
|
|
337
|
+
? gateway.registerContainer
|
|
338
|
+
: (_secret, _reg) => { };
|
|
339
|
+
const unregisterContainer = gateway
|
|
340
|
+
? gateway.unregisterContainer
|
|
341
|
+
: (_secret) => { };
|
|
129
342
|
for (const agentConfig of agentConfigs) {
|
|
130
|
-
|
|
131
|
-
runners[agentConfig.name] = new ContainerAgentRunner(globalConfig, agentConfig, mkLogger(projectPath, agentConfig.name), gateway.registerContainer, gatewayUrl, projectPath, agentImages[agentConfig.name] || baseImage, statusTracker);
|
|
343
|
+
runners[agentConfig.name] = new ContainerAgentRunner(runtime, globalConfig, agentConfig, mkLogger(projectPath, agentConfig.name), registerContainer, unregisterContainer, gatewayUrl, projectPath, agentImages[agentConfig.name] || baseImage, statusTracker);
|
|
132
344
|
}
|
|
133
345
|
}
|
|
134
346
|
else {
|
|
135
347
|
for (const agentConfig of agentConfigs) {
|
|
136
348
|
mkdirSync(agentDir(projectPath, agentConfig.name), { recursive: true });
|
|
137
|
-
statusTracker?.registerAgent(agentConfig.name);
|
|
138
349
|
runners[agentConfig.name] = new AgentRunner(agentConfig, mkLogger(projectPath, agentConfig.name), projectPath, statusTracker);
|
|
139
350
|
}
|
|
140
351
|
}
|
|
352
|
+
const schedulerCtx = { runners, agentConfigs, maxReruns, maxTriggerDepth, logger };
|
|
141
353
|
// Set up webhook bindings
|
|
142
354
|
if (webhookRegistry) {
|
|
143
355
|
for (const agentConfig of agentConfigs) {
|
|
144
|
-
if (!agentConfig.webhooks?.
|
|
356
|
+
if (!agentConfig.webhooks?.length)
|
|
145
357
|
continue;
|
|
146
358
|
const runner = runners[agentConfig.name];
|
|
147
|
-
for (const
|
|
359
|
+
for (const trigger of agentConfig.webhooks) {
|
|
360
|
+
const filter = buildFilterFromTrigger(trigger);
|
|
148
361
|
webhookRegistry.addBinding({
|
|
149
362
|
agentName: agentConfig.name,
|
|
363
|
+
source: trigger.source,
|
|
364
|
+
type: trigger.type,
|
|
150
365
|
filter,
|
|
151
366
|
trigger: (context) => {
|
|
152
367
|
if (runner.isRunning) {
|
|
@@ -155,7 +370,11 @@ export async function startScheduler(projectPath, globalConfigOverride, statusTr
|
|
|
155
370
|
}
|
|
156
371
|
logger.info({ agent: agentConfig.name, event: context.event, action: context.action }, "webhook triggering agent");
|
|
157
372
|
const prompt = buildWebhookPrompt(agentConfig, context);
|
|
158
|
-
runner.run(prompt).
|
|
373
|
+
runner.run(prompt).then(({ triggers }) => {
|
|
374
|
+
if (triggers.length > 0) {
|
|
375
|
+
dispatchTriggers(triggers, agentConfig.name, 0, schedulerCtx);
|
|
376
|
+
}
|
|
377
|
+
}).catch((err) => {
|
|
159
378
|
logger.error({ err }, `${agentConfig.name} webhook run failed`);
|
|
160
379
|
});
|
|
161
380
|
},
|
|
@@ -175,7 +394,7 @@ export async function startScheduler(projectPath, globalConfigOverride, statusTr
|
|
|
175
394
|
return;
|
|
176
395
|
}
|
|
177
396
|
logger.info(`Triggering ${agentConfig.name} (scheduled)`);
|
|
178
|
-
await runner
|
|
397
|
+
await runWithReruns(runner, agentConfig, 0, schedulerCtx);
|
|
179
398
|
});
|
|
180
399
|
cronJobs.push(job);
|
|
181
400
|
const nextRun = job.nextRun();
|
|
@@ -187,9 +406,9 @@ export async function startScheduler(projectPath, globalConfigOverride, statusTr
|
|
|
187
406
|
const webhookUrls = [];
|
|
188
407
|
if (anyWebhooks && gateway) {
|
|
189
408
|
const gatewayPort = globalConfig.gateway?.port || 8080;
|
|
190
|
-
const
|
|
191
|
-
for (const
|
|
192
|
-
webhookUrls.push(`http://localhost:${gatewayPort}/webhooks/${
|
|
409
|
+
const providerTypes = new Set(agentConfigs.flatMap((a) => a.webhooks?.map((t) => t.type) || []));
|
|
410
|
+
for (const pt of providerTypes) {
|
|
411
|
+
webhookUrls.push(`http://localhost:${gatewayPort}/webhooks/${pt}`);
|
|
193
412
|
}
|
|
194
413
|
}
|
|
195
414
|
logger.info(`Scheduler running with ${cronJobs.length} scheduled jobs`);
|
|
@@ -199,7 +418,7 @@ export async function startScheduler(projectPath, globalConfigOverride, statusTr
|
|
|
199
418
|
continue;
|
|
200
419
|
const runner = runners[agentConfig.name];
|
|
201
420
|
logger.info(`Initial run for ${agentConfig.name}`);
|
|
202
|
-
runner
|
|
421
|
+
runWithReruns(runner, agentConfig, 0, schedulerCtx).catch((err) => {
|
|
203
422
|
logger.error({ err }, `Initial ${agentConfig.name} run failed`);
|
|
204
423
|
});
|
|
205
424
|
}
|