@fastagent-sh/fastagent 0.15.0 → 0.16.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/README.md +13 -3
- package/dist/channels/agentcore-limits.d.ts +7 -0
- package/dist/channels/agentcore-limits.js +9 -0
- package/dist/channels/agentcore-state.d.ts +83 -0
- package/dist/channels/agentcore-state.js +258 -0
- package/dist/channels/agentcore.d.ts +98 -0
- package/dist/channels/agentcore.js +260 -0
- package/dist/channels/busy.d.ts +23 -0
- package/dist/channels/busy.js +53 -0
- package/dist/channels/context-buffer.d.ts +5 -0
- package/dist/channels/context-buffer.js +5 -0
- package/dist/channels/feishu/context-buffer.d.ts +13 -8
- package/dist/channels/feishu/context-buffer.js +60 -6
- package/dist/channels/feishu/feishu-api.js +4 -1
- package/dist/channels/feishu/feishu.d.ts +0 -12
- package/dist/channels/feishu/feishu.js +143 -54
- package/dist/channels/feishu/invoke-turn.js +35 -18
- package/dist/channels/feishu/model.d.ts +0 -1
- package/dist/channels/feishu/normalize.js +0 -1
- package/dist/channels/feishu/parse.d.ts +21 -7
- package/dist/channels/feishu/parse.js +24 -7
- package/dist/channels/feishu/preview.js +3 -2
- package/dist/channels/feishu/scaffold/channel.ts +9 -8
- package/dist/channels/feishu/scaffold/feishu-send.ts +6 -4
- package/dist/channels/feishu/setup-mode.d.ts +30 -1
- package/dist/channels/feishu/setup-mode.js +27 -1
- package/dist/channels/github/github.js +8 -1
- package/dist/channels/http.js +1 -1
- package/dist/channels/lark/scaffold/channel.ts +9 -8
- package/dist/channels/lark/scaffold/lark-send.ts +6 -4
- package/dist/channels/preview-kit.d.ts +7 -1
- package/dist/channels/preview-kit.js +3 -2
- package/dist/channels/slack/parse.d.ts +16 -1
- package/dist/channels/slack/parse.js +46 -3
- package/dist/channels/slack/preview.d.ts +1 -2
- package/dist/channels/slack/preview.js +68 -24
- package/dist/channels/slack/scaffold/channel.ts +5 -5
- package/dist/channels/slack/slack-api.d.ts +3 -23
- package/dist/channels/slack/slack-api.js +6 -22
- package/dist/channels/slack/slack.d.ts +13 -20
- package/dist/channels/slack/slack.js +95 -50
- package/dist/channels/state.d.ts +11 -4
- package/dist/channels/state.js +19 -12
- package/dist/channels/tasks.d.ts +0 -6
- package/dist/channels/tasks.js +16 -1
- package/dist/channels/telegram/parse.d.ts +0 -7
- package/dist/channels/telegram/parse.js +4 -2
- package/dist/channels/telegram/scaffold/telegram-send.ts +6 -3
- package/dist/channels/telegram/telegram.js +1 -1
- package/dist/channels/text.d.ts +14 -0
- package/dist/channels/text.js +14 -0
- package/dist/channels/thread-participants.d.ts +21 -0
- package/dist/channels/thread-participants.js +132 -0
- package/dist/channels/turn-queue.js +7 -0
- package/dist/cli/add-feishu.d.ts +7 -4
- package/dist/cli/add-feishu.js +57 -37
- package/dist/cli/add-slack.d.ts +2 -1
- package/dist/cli/add-slack.js +6 -11
- package/dist/cli/commands/add.js +50 -51
- package/dist/cli/commands/attach.js +8 -4
- package/dist/cli/commands/chat.js +8 -8
- package/dist/cli/commands/deploy.d.ts +1 -1
- package/dist/cli/commands/deploy.js +323 -77
- package/dist/cli/commands/dev.js +24 -22
- package/dist/cli/commands/fire.js +15 -16
- package/dist/cli/commands/info.js +36 -29
- package/dist/cli/commands/init.d.ts +1 -1
- package/dist/cli/commands/init.js +65 -53
- package/dist/cli/commands/invoke.js +9 -6
- package/dist/cli/commands/login.js +35 -21
- package/dist/cli/commands/schedule.js +6 -8
- package/dist/cli/commands/start.js +93 -37
- package/dist/cli/commands/tool.js +22 -18
- package/dist/cli/fail.d.ts +17 -0
- package/dist/cli/fail.js +24 -0
- package/dist/cli/program.js +57 -36
- package/dist/cli/serve.d.ts +26 -6
- package/dist/cli/serve.js +62 -15
- package/dist/cli/shared.d.ts +15 -2
- package/dist/cli/shared.js +30 -18
- package/dist/deploy/agentcore/plan.d.ts +117 -0
- package/dist/deploy/agentcore/plan.js +721 -0
- package/dist/deploy/agentcore/run.d.ts +73 -0
- package/dist/deploy/agentcore/run.js +412 -0
- package/dist/deploy/agentcore/zip.d.ts +17 -0
- package/dist/deploy/agentcore/zip.js +68 -0
- package/dist/deploy/container.d.ts +26 -25
- package/dist/deploy/container.js +93 -89
- package/dist/deploy/docker/plan.d.ts +1 -1
- package/dist/deploy/docker/plan.js +12 -17
- package/dist/deploy/fly/plan.d.ts +2 -0
- package/dist/deploy/fly/plan.js +27 -19
- package/dist/deploy/fly/run.d.ts +12 -1
- package/dist/deploy/fly/run.js +36 -2
- package/dist/deploy/preflight.d.ts +11 -5
- package/dist/deploy/preflight.js +217 -65
- package/dist/deploy/railway/plan.d.ts +7 -0
- package/dist/deploy/railway/plan.js +41 -16
- package/dist/deploy/railway/run.d.ts +8 -1
- package/dist/deploy/railway/run.js +7 -2
- package/dist/deploy/runner.d.ts +5 -2
- package/dist/deploy/runner.js +9 -3
- package/dist/dev-supervisor.d.ts +11 -8
- package/dist/dev-supervisor.js +53 -51
- package/dist/engines/pi/auth.d.ts +8 -7
- package/dist/engines/pi/auth.js +12 -10
- package/dist/engines/pi/channel.d.ts +1 -1
- package/dist/engines/pi/channel.js +5 -5
- package/dist/engines/pi/chat.js +2 -2
- package/dist/engines/pi/config.d.ts +6 -46
- package/dist/engines/pi/config.js +21 -108
- package/dist/engines/pi/create.d.ts +8 -8
- package/dist/engines/pi/create.js +13 -12
- package/dist/engines/pi/definition.d.ts +7 -26
- package/dist/engines/pi/definition.js +8 -54
- package/dist/engines/pi/login.d.ts +1 -1
- package/dist/engines/pi/models.d.ts +3 -3
- package/dist/engines/pi/models.js +1 -1
- package/dist/engines/pi/{workspace.d.ts → open.d.ts} +29 -23
- package/dist/engines/pi/{workspace.js → open.js} +27 -29
- package/dist/engines/pi/session-builder.d.ts +2 -2
- package/dist/engines/pi/session-builder.js +11 -11
- package/dist/engines/pi/tool.js +4 -0
- package/dist/env.d.ts +16 -4
- package/dist/env.js +43 -5
- package/dist/host/node.d.ts +2 -2
- package/dist/loader.d.ts +2 -2
- package/dist/loader.js +3 -3
- package/dist/log.d.ts +1 -1
- package/dist/log.js +1 -1
- package/dist/paths.d.ts +138 -0
- package/dist/paths.js +326 -0
- package/dist/pi.d.ts +1 -1
- package/dist/pi.js +2 -2
- package/dist/runtime.d.ts +7 -5
- package/dist/runtime.js +2 -2
- package/dist/scaffold/add-channel.d.ts +7 -3
- package/dist/scaffold/add-channel.js +55 -29
- package/dist/scaffold/init.d.ts +32 -41
- package/dist/scaffold/init.js +161 -185
- package/dist/scaffold/templates/env.example +15 -6
- package/dist/scaffold/templates/fastagent.config.mjs +1 -1
- package/dist/scaffold/templates/gitignore +14 -6
- package/dist/scaffold/templates/persona.md +4 -2
- package/dist/scaffold/templates/secrets.gitignore +5 -0
- package/dist/scaffold/templates.d.ts +1 -7
- package/dist/scaffold/templates.js +3 -25
- package/dist/scaffold/vendor-skill.d.ts +2 -2
- package/dist/scaffold/vendor-skill.js +13 -13
- package/dist/schedule/discover.js +4 -4
- package/dist/schedule/scheduler.d.ts +40 -1
- package/dist/schedule/scheduler.js +89 -56
- package/dist/schedule/state.js +1 -1
- package/dist/schedule/wake-alarm.d.ts +47 -0
- package/dist/schedule/wake-alarm.js +136 -0
- package/dist/schedule/wakeups.d.ts +1 -0
- package/dist/schedule/wakeups.js +18 -0
- package/dist/tunnel.d.ts +3 -3
- package/dist/tunnel.js +7 -7
- package/package.json +4 -1
- package/dist/channels/feishu/owned-threads.d.ts +0 -7
- package/dist/channels/feishu/owned-threads.js +0 -47
- package/dist/channels/slack/owned-threads.d.ts +0 -6
- package/dist/channels/slack/owned-threads.js +0 -43
- package/dist/scaffold/templates/gitignore.agentdir-root +0 -5
- package/dist/scaffold/templates/gitignore.kit +0 -2
- package/dist/workspace.d.ts +0 -9
- package/dist/workspace.js +0 -45
|
@@ -4,77 +4,131 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
6
6
|
import { dirname, resolve } from "node:path";
|
|
7
|
-
import { authSeedBytes } from "../../deploy/fly/run.js";
|
|
7
|
+
import { authSeedBytes, collectAuthSeed } from "../../deploy/fly/run.js";
|
|
8
8
|
import { loadDotEnv } from "../../env.js";
|
|
9
9
|
import { resolveAuthPath, resolveSessionsDirOverride } from "../../engines/pi/config.js";
|
|
10
|
+
import { resolveSecretsDir, workspaceHint } from "../../paths.js";
|
|
10
11
|
import { isUnderDir } from "../../engines/pi/definition.js";
|
|
11
12
|
import { reportDefinitionWarnings, reportModuleLoadFailures, reportToolCollisions } from "../../engines/pi/report.js";
|
|
12
|
-
import {
|
|
13
|
+
import { createPiAgentFromDir } from "../../engines/pi/open.js";
|
|
13
14
|
import { log, setLogLevel } from "../../log.js";
|
|
15
|
+
import { createWakeAlarmSink, reconcileWakeAlarms } from "../../schedule/wake-alarm.js";
|
|
16
|
+
import { setWakeupsSink } from "../../schedule/wakeups.js";
|
|
14
17
|
import { logAgentLoop } from "../../observe.js";
|
|
15
18
|
import { installProxyFetch } from "../../proxy.js";
|
|
16
|
-
import { exists } from "../../
|
|
17
|
-
import { failStartup } from "../fail.js";
|
|
18
|
-
import { maybeTunnel, mountSessionControl, routesFor, serve, startSchedules } from "../serve.js";
|
|
19
|
-
import { parsePort, reportAuth, resolveFirstRunModel } from "../shared.js";
|
|
19
|
+
import { exists } from "../../paths.js";
|
|
20
|
+
import { failStartup, placementOrExit } from "../fail.js";
|
|
21
|
+
import { maybeTunnel, mountAgentcore, mountSessionControl, routesFor, serve, startSchedules } from "../serve.js";
|
|
22
|
+
import { parsePort, reportAuth, reportLine, resolveFirstRunModel, reportWorkspaceHint } from "../shared.js";
|
|
20
23
|
export async function runStart(dirArg, opts) {
|
|
21
24
|
const dir = resolve(dirArg);
|
|
22
|
-
|
|
25
|
+
// Flag validation first: a bad --port is a USAGE error (exit 2), and reporting it must not depend on
|
|
26
|
+
// the directory being an agent (which is a runtime/environment failure, exit 1).
|
|
23
27
|
const portFlag = parsePort(opts.port, "--port", "flag");
|
|
24
|
-
|
|
28
|
+
const placement = placementOrExit(dir);
|
|
29
|
+
setLogLevel("info"); // production posture: info+, the debug turn trace (and its end-user content) gated out
|
|
30
|
+
loadDotEnv(placement.agentDir);
|
|
25
31
|
installProxyFetch();
|
|
26
|
-
await resolveFirstRunModel(
|
|
32
|
+
await resolveFirstRunModel(placement.agentDir, opts);
|
|
27
33
|
// A `deploy --run` may carry the operator's local credential as FASTAGENT_AUTH_SEED —
|
|
28
|
-
// materialize it
|
|
34
|
+
// materialize it into the writable secrets dir BEFORE the opener resolves auth (once, absent-only).
|
|
29
35
|
// Same resolveAuthPath the opener uses — ONE owner of the flag > env > default chain.
|
|
30
|
-
await maybeSeedAuth(resolveAuthPath(
|
|
36
|
+
await maybeSeedAuth(resolveAuthPath(placement.agentDir, opts.authPath));
|
|
31
37
|
// The same opener dev uses (single assembly source), just no watch.
|
|
32
38
|
const sessionsDirOverride = resolveSessionsDirOverride(opts.sessionsDir);
|
|
33
|
-
const { agent, definition, agentDir, config, modelSpec, stateRoot, sessionsDir, authPath, toolNames, deferredToolNames, toolCollisions, toolFailures, sessionControl, } = await
|
|
39
|
+
const { agent, definition, agentDir, workspace, config, modelSpec, stateRoot, sessionsDir, authPath, toolNames, deferredToolNames, toolCollisions, toolFailures, sessionControl, } = await createPiAgentFromDir(dir, {
|
|
34
40
|
model: opts.model,
|
|
35
41
|
sessionsDir: sessionsDirOverride,
|
|
36
42
|
authPath: opts.authPath,
|
|
37
43
|
serving: true, // long-running serve: the scheduler poller runs (wake mounts iff config.selfSchedule)
|
|
38
44
|
}).catch(failStartup);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
reportLine("agent", agentDir);
|
|
46
|
+
reportLine("workspace", workspace);
|
|
47
|
+
reportWorkspaceHint(workspaceHint({ agentDir, workspace }));
|
|
48
|
+
reportLine("model", `${modelSpec}${config.thinkingLevel ? ` (thinking: ${config.thinkingLevel})` : ""}`);
|
|
43
49
|
await reportAuth(modelSpec, authPath);
|
|
44
|
-
|
|
50
|
+
reportLine("context", definition.contextFiles.map((f) => f.path).join(", ") || "(none)");
|
|
45
51
|
if (definition.persona)
|
|
46
|
-
|
|
47
|
-
|
|
52
|
+
reportLine("persona", "persona.md");
|
|
53
|
+
reportLine("skills", definition.skills.map((s) => s.name).join(", ") || "(none)");
|
|
48
54
|
if (toolNames.length > 0)
|
|
49
|
-
|
|
55
|
+
reportLine("tools", toolNames.join(", "));
|
|
50
56
|
if (deferredToolNames.length > 0) {
|
|
51
|
-
|
|
57
|
+
reportLine("deferred", `${deferredToolNames.join(", ")} (activated via search_tools)`);
|
|
52
58
|
}
|
|
53
59
|
reportToolCollisions(toolCollisions);
|
|
54
60
|
reportModuleLoadFailures(toolFailures);
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
// State defaults under the
|
|
58
|
-
// root ACTUALLY resolved (
|
|
59
|
-
// as unset (resolveStateRoot) and still lands in-
|
|
60
|
-
// silence the warning. A sessions
|
|
61
|
-
// telegram turn/context files replay depends on) is still in-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
reportLine("state", stateRoot);
|
|
62
|
+
reportLine("sessions", sessionsDir);
|
|
63
|
+
// State defaults under the agent dir, which a redeploy may replace wholesale. Gate on where the
|
|
64
|
+
// state root ACTUALLY resolved (inside the agent dir?), not on the raw env var: an empty
|
|
65
|
+
// `FASTAGENT_STATE_DIR=""` reads as unset (resolveStateRoot) and still lands in-agent, so a raw
|
|
66
|
+
// `=== undefined` check would wrongly silence the warning. A sessions override to a volume does not
|
|
67
|
+
// help — channel state (the telegram turn/context files replay depends on) is still in-agent.
|
|
68
|
+
// (auth.json is NOT under the state root — it lives in the secrets dir, resolveSecretsDir.)
|
|
69
|
+
if (isUnderDir(stateRoot, agentDir)) {
|
|
70
|
+
log.info(`[fastagent] note: state (sessions, channel state) lives under the definition dir; point ` +
|
|
64
71
|
`FASTAGENT_STATE_DIR at a persistent volume so a redeploy that replaces the dir does not wipe it.`);
|
|
65
72
|
}
|
|
73
|
+
// The secrets dir is the SAME trap on a different lifecycle: auth.json is MACHINE-WRITTEN (OAuth
|
|
74
|
+
// rotation), so the copy under the definition dir is the only valid one — a redeploy that replaces
|
|
75
|
+
// the dir loses a credential no re-seed can restore. An independent check on purpose: moving ONE
|
|
76
|
+
// of the two to a volume must not silence the note about the other.
|
|
77
|
+
if (isUnderDir(resolveSecretsDir(agentDir), agentDir)) {
|
|
78
|
+
log.info(`[fastagent] note: secrets (.env, rotated auth.json) live under the definition dir; point ` +
|
|
79
|
+
`FASTAGENT_SECRETS_DIR at a persistent volume so a redeploy that replaces the dir does not wipe them.`);
|
|
80
|
+
}
|
|
66
81
|
reportDefinitionWarnings(definition.collisions, definition.diagnostics);
|
|
82
|
+
// AgentCore Runtime posture (FASTAGENT_AGENTCORE=1, set by the generated deploy artifacts): the
|
|
83
|
+
// adapter (POST /invocations + GET /ping) is the container's only reachable surface, and cron
|
|
84
|
+
// slots arrive from the external clock through it — so no resident cron timers. In particular,
|
|
85
|
+
// do NOT mount the ordinary unauthenticated POST /invoke fallback: a selfSchedule-only topology
|
|
86
|
+
// needs a public Function URL for wake callbacks, and its forwarder can relay arbitrary paths.
|
|
87
|
+
const agentcore = process.env.FASTAGENT_AGENTCORE === "1";
|
|
67
88
|
// Same debug turn trace as dev; gated out here by the info level (see dev.ts serveOnce).
|
|
68
89
|
const traced = logAgentLoop(agent);
|
|
69
|
-
const routed = await routesFor(agentDir, traced, stateRoot, sessionControl).catch(failStartup);
|
|
90
|
+
const routed = await routesFor(agentDir, traced, stateRoot, sessionControl, { builtinInvoke: !agentcore }).catch(failStartup);
|
|
70
91
|
const withControl = mountSessionControl(routed.routes, sessionControl, stateRoot, {
|
|
71
92
|
tunnel: opts.tunnel ?? false,
|
|
72
93
|
agent: traced,
|
|
73
94
|
});
|
|
74
|
-
|
|
75
|
-
|
|
95
|
+
// AgentCore + selfSchedule: register the wake-ALARM sink BEFORE the scheduler starts — the boot
|
|
96
|
+
// wake pump may advance a recurring entry (a store save) and that save must already re-arm its
|
|
97
|
+
// alarm. The secret arrives via the stack (FASTAGENT_WAKE_SECRET); without it the deployment
|
|
98
|
+
// degrades to awake-only wakes — warned, never silent.
|
|
99
|
+
let onStateReady;
|
|
100
|
+
if (agentcore && config.selfSchedule) {
|
|
101
|
+
const wakeSecret = process.env.FASTAGENT_WAKE_SECRET;
|
|
102
|
+
if (wakeSecret) {
|
|
103
|
+
const sink = createWakeAlarmSink({ secret: wakeSecret });
|
|
104
|
+
setWakeupsSink(sink);
|
|
105
|
+
// NOT here: at boot the state mount is whatever the platform just provisioned — after a runtime
|
|
106
|
+
// version update that is EMPTY, so a reconcile now would see no pending wake-ups and conclude
|
|
107
|
+
// there is nothing to re-arm. It runs once the snapshot has been restored (mountAgentcore).
|
|
108
|
+
onStateReady = () => reconcileWakeAlarms(stateRoot, sink);
|
|
109
|
+
log.info(`[fastagent] wake alarms: EventBridge-backed via the forwarder`);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
log.warn(`[fastagent] FASTAGENT_WAKE_SECRET is not set — wake-ups fire only while a session is awake ` +
|
|
113
|
+
`(redeploy with the current template to fix)`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const schedules = await startSchedules(agentDir, traced, stateRoot, config.selfSchedule ?? false, {
|
|
117
|
+
externalClock: agentcore,
|
|
118
|
+
});
|
|
119
|
+
let routes = withControl.routes;
|
|
120
|
+
if (agentcore) {
|
|
121
|
+
try {
|
|
122
|
+
routes = mountAgentcore(routes, { agent: traced, stateRoot, schedules, onStateReady });
|
|
123
|
+
}
|
|
124
|
+
catch (e) {
|
|
125
|
+
failStartup(e);
|
|
126
|
+
}
|
|
127
|
+
log.info(`[fastagent] agentcore: serving POST /invocations + GET /ping (FASTAGENT_AGENTCORE=1)`);
|
|
128
|
+
}
|
|
129
|
+
serve({ ...routed, routes }, portFlag ?? parsePort(process.env.PORT, "PORT env", "env") ?? config.http?.port ?? 8787, (p) => {
|
|
76
130
|
withControl.announce(p);
|
|
77
|
-
maybeTunnel(
|
|
131
|
+
maybeTunnel(agentDir, routed.routeChannels, p, opts.tunnel ?? false, stateRoot);
|
|
78
132
|
});
|
|
79
133
|
// No graceful drain: webhook turns run fire-and-forget; SIGTERM just exits mid-turn. Whether an
|
|
80
134
|
// in-flight turn is LOST depends on the channel: the Telegram channel persists turn intent pre-ACK
|
|
@@ -82,13 +136,15 @@ export async function runStart(dirArg, opts) {
|
|
|
82
136
|
// channels have no such layer, so their in-flight turns are still lost (the asker re-invokes).
|
|
83
137
|
}
|
|
84
138
|
/**
|
|
85
|
-
* Materialize `FASTAGENT_AUTH_SEED` (base64 of an auth.json, set by `deploy --run`)
|
|
86
|
-
* writable
|
|
139
|
+
* Materialize `FASTAGENT_AUTH_SEED` (base64 of an auth.json, set by `deploy --run`) into the
|
|
140
|
+
* writable secrets dir ONCE — only when the seed is set AND the auth file is absent, so a refreshed
|
|
87
141
|
* volume copy is never clobbered by the stale seed. Lets a deploy carry the operator's local
|
|
88
142
|
* OAuth/API credential so the box runs on the SAME subscription. No-op locally (the seed is unset).
|
|
89
143
|
*/
|
|
90
144
|
async function maybeSeedAuth(authPath) {
|
|
91
|
-
|
|
145
|
+
// collectAuthSeed: the seed may arrive CHUNKED (FASTAGENT_AUTH_SEED + _2…) on hosts with a small
|
|
146
|
+
// env-value max length (AgentCore); single-var hosts are unchanged.
|
|
147
|
+
const bytes = authSeedBytes(collectAuthSeed(process.env), await exists(authPath));
|
|
92
148
|
if (!bytes)
|
|
93
149
|
return;
|
|
94
150
|
await mkdir(dirname(authPath), { recursive: true });
|
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
/** `fastagent tool <name> '<json>' [dir]`: run one tool's body directly with JSON args — no model. */
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { loadDotEnv } from "../../env.js";
|
|
4
|
-
import { loadConfig
|
|
5
|
-
import {
|
|
4
|
+
import { loadConfig } from "../../engines/pi/config.js";
|
|
5
|
+
import { resolveAgentTools } from "../../engines/pi/create.js";
|
|
6
6
|
import { reportModuleLoadFailures } from "../../engines/pi/report.js";
|
|
7
7
|
import { turnContext } from "../../engines/pi/tool-context.js";
|
|
8
|
-
import { failStartup, failUsage } from "../fail.js";
|
|
8
|
+
import { failStartup, failUsage, placementOrExit } from "../fail.js";
|
|
9
9
|
export async function runTool(name, argsJson, dirArg) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
10
|
+
// Argument shape first: malformed JSON is a USAGE error (exit 2), independent of whether the
|
|
11
|
+
// directory is an agent (a runtime failure, exit 1).
|
|
12
|
+
const args = parseToolArgs(argsJson);
|
|
13
|
+
const { agentDir, workspace } = placementOrExit(resolve(dirArg));
|
|
14
|
+
loadDotEnv(agentDir); // a tool may read a key from .env
|
|
15
|
+
const { config } = await loadConfig(agentDir).catch(failStartup);
|
|
13
16
|
// The same tool set dev/start mount (defaults + config.tools + discovered, deduped), so the runner
|
|
14
|
-
// exercises exactly what gets served — a shadowed tool is surfaced, not silently run. Resolve
|
|
15
|
-
// like the openers so `fastagent tool` finds the SAME tools/ as dev/start
|
|
16
|
-
const
|
|
17
|
-
const { tools, toolCollisions, toolFailures } = await resolveWorkspaceTools(config, agentDir, toolDir).catch(failStartup);
|
|
17
|
+
// exercises exactly what gets served — a shadowed tool is surfaced, not silently run. Resolve the
|
|
18
|
+
// placement like the openers, so `fastagent tool` finds the SAME tools/ as dev/start.
|
|
19
|
+
const { tools, toolCollisions, toolFailures } = await resolveAgentTools(config, agentDir, workspace).catch(failStartup);
|
|
18
20
|
for (const c of toolCollisions) {
|
|
19
21
|
console.error(`[fastagent] warn: tool "${c.name}" (${c.source}) is shadowed by a default/config tool — not mounted`);
|
|
20
22
|
}
|
|
@@ -23,16 +25,18 @@ export async function runTool(name, argsJson, dirArg) {
|
|
|
23
25
|
if (!tool) {
|
|
24
26
|
failStartup(new Error(`unknown tool "${name}". available: ${tools.map((t) => t.name).join(", ") || "(none)"}`));
|
|
25
27
|
}
|
|
26
|
-
|
|
27
|
-
try {
|
|
28
|
-
args = JSON.parse(argsJson);
|
|
29
|
-
}
|
|
30
|
-
catch {
|
|
31
|
-
failUsage(`invalid JSON args: ${argsJson}`); // malformed input syntax = usage error, exit 2
|
|
32
|
-
}
|
|
33
|
-
const result = await turnContext.run({ cwd: toolDir }, () => tool.execute(`cli-${name}`, args)).catch(failStartup);
|
|
28
|
+
const result = await turnContext.run({ cwd: workspace }, () => tool.execute(`cli-${name}`, args)).catch(failStartup);
|
|
34
29
|
const out = result?.details !== undefined
|
|
35
30
|
? result.details
|
|
36
31
|
: (result?.content ?? []).map((c) => ("text" in c ? c.text : "")).join("");
|
|
37
32
|
console.log(typeof out === "string" ? out : JSON.stringify(out, null, 2));
|
|
38
33
|
}
|
|
34
|
+
/** Parse the CLI's JSON args blob; malformed input syntax is a usage error (exit 2). */
|
|
35
|
+
function parseToolArgs(argsJson) {
|
|
36
|
+
try {
|
|
37
|
+
return JSON.parse(argsJson);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
failUsage(`invalid JSON args: ${argsJson}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
package/dist/cli/fail.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ResolvedPlacement } from "../paths.ts";
|
|
1
2
|
/**
|
|
2
3
|
* The ONE error prefix every error message carries — bold red when stderr renders color, plain
|
|
3
4
|
* otherwise. Errors are the only place the CLI uses color at all.
|
|
@@ -9,6 +10,22 @@ export declare function errorPrefix(colors?: boolean): string;
|
|
|
9
10
|
* Shared by the kernel and the command modules; exit 1 (runtime failure).
|
|
10
11
|
*/
|
|
11
12
|
export declare function failStartup(error: unknown): never;
|
|
13
|
+
/**
|
|
14
|
+
* THE placement entry point for commands: resolve `dir`, or exit 1 with the one-line refusal. Every
|
|
15
|
+
* command that needs an agent goes through this — the try/catch was hand-repeated at sixteen call
|
|
16
|
+
* sites, which is sixteen chances to forget it (`dev`'s supervisor did, and surfaced a raw stack).
|
|
17
|
+
*
|
|
18
|
+
* The catch is what makes it a function at all: placement resolves SYNCHRONOUSLY, before any promise
|
|
19
|
+
* exists, so it cannot ride the `.catch(failStartup)` every async startup chain carries — and its
|
|
20
|
+
* refusals ("not a fastagent agent", plus the two dead ends with their own exits) are user-fixable,
|
|
21
|
+
* which means a one-line `Error:` and exit 1, never a stack.
|
|
22
|
+
*
|
|
23
|
+
* Not every command calls it — and the exceptions are the useful part of this note. `init` CREATES the
|
|
24
|
+
* agent (it must run where there is none). `models` is directory-independent. `login` needs one only for
|
|
25
|
+
* the project-level credential and falls back to the global one, and `attach --url/--token` reads
|
|
26
|
+
* nothing local. Everything else needs an agent, so it comes through here.
|
|
27
|
+
*/
|
|
28
|
+
export declare function placementOrExit(dir: string): ResolvedPlacement;
|
|
12
29
|
/**
|
|
13
30
|
* A usage error the parser could not catch (a bad value shape, an invalid flag/argument combination
|
|
14
31
|
* discovered in a command body): print the message and exit 2 — the same class as a parse error.
|
package/dist/cli/fail.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolvePlacement } from "../paths.js";
|
|
1
2
|
/** stderr renders color: a color TTY, with Node's `hasColors()` carrying the NO_COLOR/TERM=dumb veto. */
|
|
2
3
|
function stderrHasColors() {
|
|
3
4
|
return process.stderr.isTTY === true && (process.stderr.hasColors?.() ?? false);
|
|
@@ -21,6 +22,29 @@ export function failStartup(error) {
|
|
|
21
22
|
console.error(errorPrefix(), error);
|
|
22
23
|
process.exit(1);
|
|
23
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* THE placement entry point for commands: resolve `dir`, or exit 1 with the one-line refusal. Every
|
|
27
|
+
* command that needs an agent goes through this — the try/catch was hand-repeated at sixteen call
|
|
28
|
+
* sites, which is sixteen chances to forget it (`dev`'s supervisor did, and surfaced a raw stack).
|
|
29
|
+
*
|
|
30
|
+
* The catch is what makes it a function at all: placement resolves SYNCHRONOUSLY, before any promise
|
|
31
|
+
* exists, so it cannot ride the `.catch(failStartup)` every async startup chain carries — and its
|
|
32
|
+
* refusals ("not a fastagent agent", plus the two dead ends with their own exits) are user-fixable,
|
|
33
|
+
* which means a one-line `Error:` and exit 1, never a stack.
|
|
34
|
+
*
|
|
35
|
+
* Not every command calls it — and the exceptions are the useful part of this note. `init` CREATES the
|
|
36
|
+
* agent (it must run where there is none). `models` is directory-independent. `login` needs one only for
|
|
37
|
+
* the project-level credential and falls back to the global one, and `attach --url/--token` reads
|
|
38
|
+
* nothing local. Everything else needs an agent, so it comes through here.
|
|
39
|
+
*/
|
|
40
|
+
export function placementOrExit(dir) {
|
|
41
|
+
try {
|
|
42
|
+
return resolvePlacement(dir);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
failStartup(error);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
24
48
|
/**
|
|
25
49
|
* A usage error the parser could not catch (a bad value shape, an invalid flag/argument combination
|
|
26
50
|
* discovered in a command body): print the message and exit 2 — the same class as a parse error.
|
package/dist/cli/program.js
CHANGED
|
@@ -8,14 +8,18 @@ import { fastagentVersion } from "../version.js";
|
|
|
8
8
|
import { buildProgram } from "./kernel.js";
|
|
9
9
|
// Help groups (clig: most common commands first) — the authoring loop leads, operations close.
|
|
10
10
|
// Shared flags — same name, same meaning, on every command that supports them (clig: consistency).
|
|
11
|
-
const DIR_ARG = {
|
|
11
|
+
const DIR_ARG = {
|
|
12
|
+
name: "[dir]",
|
|
13
|
+
description: "workspace directory (the agent is here, or in a directory inside it)",
|
|
14
|
+
default: ".",
|
|
15
|
+
};
|
|
12
16
|
const MODEL = {
|
|
13
17
|
flags: "--model <provider/modelId>",
|
|
14
18
|
description: "model override (precedence: --model > FASTAGENT_MODEL > config)",
|
|
15
19
|
};
|
|
16
20
|
const AUTH_PATH = {
|
|
17
21
|
flags: "--auth-path <file>",
|
|
18
|
-
description: "credentials file (default: <
|
|
22
|
+
description: "credentials file (default: <agent dir>/.secrets/auth.json; env: FASTAGENT_AUTH_PATH)",
|
|
19
23
|
};
|
|
20
24
|
const JSON_FLAG = { flags: "--json", description: "machine-readable JSON output" };
|
|
21
25
|
const NO_INPUT = {
|
|
@@ -32,31 +36,43 @@ const TUNNEL = {
|
|
|
32
36
|
const init = {
|
|
33
37
|
name: "init",
|
|
34
38
|
summary: "scaffold a runnable agent and install its dependencies",
|
|
35
|
-
description: "Scaffold a runnable agent
|
|
36
|
-
"agent
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
+
description: "Scaffold a runnable agent and run npm install. By default the agent goes into ./fastagent/ in dir " +
|
|
40
|
+
"(default .; --agent-dir names it otherwise) — the rest of the directory gets zero writes, and it is " +
|
|
41
|
+
"the WORKSPACE the agent works ON when you point fastagent there. Default content is a " +
|
|
42
|
+
"self-iterating agent: persona.md (its identity), a writing-great-skills " +
|
|
43
|
+
"example skill, a fetch-url code tool, config, package.json, .gitignore. An existing AGENTS.md is " +
|
|
44
|
+
"kept as project context.",
|
|
39
45
|
args: [DIR_ARG],
|
|
40
46
|
flags: [
|
|
41
47
|
{ flags: "--minimal", description: "persona.md + the example skill + config only (no code tool / package.json)" },
|
|
42
48
|
{ flags: "--no-install", description: "scaffold everything but skip npm install" },
|
|
43
|
-
{ flags: "--
|
|
44
|
-
{
|
|
49
|
+
{ flags: "--agent-dir <name>", description: "name the agent directory (default fastagent; . = dir itself)" },
|
|
50
|
+
{
|
|
51
|
+
flags: "--flat",
|
|
52
|
+
description: "alias for --agent-dir . — the directory IS the agent; keeps existing files",
|
|
53
|
+
// Two spellings of ONE knob: `--flat --agent-dir bot` names the same thing twice with different
|
|
54
|
+
// values, which is a usage error, not a precedence question to settle silently.
|
|
55
|
+
conflicts: ["agentDir"],
|
|
56
|
+
},
|
|
45
57
|
],
|
|
46
58
|
examples: [
|
|
47
|
-
{ cmd: "fastagent init
|
|
48
|
-
{ cmd: "fastagent init", note: "
|
|
59
|
+
{ cmd: "fastagent init", note: "the agent lands in ./fastagent/" },
|
|
60
|
+
{ cmd: "fastagent init my-project", note: "my-project/fastagent/ (created)" },
|
|
61
|
+
{ cmd: "fastagent init . --agent-dir bot", note: "./bot/ — any name works" },
|
|
62
|
+
{ cmd: "fastagent init . --flat", note: "this repo IS the agent" },
|
|
49
63
|
],
|
|
50
|
-
notes:
|
|
51
|
-
"the
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
64
|
+
notes: "An agent is a directory holding a fastagent.config.* — never its NAME, so --agent-dir can call it " +
|
|
65
|
+
"anything (the name decides only which agent answers when a workspace holds several: see " +
|
|
66
|
+
"FASTAGENT_AGENT). What the agent works ON (its cwd, where its AGENTS.md context is read from) is " +
|
|
67
|
+
"whatever directory you later point fastagent at: point at the project and the agent inside it " +
|
|
68
|
+
"serves with the project as its workspace; point at the agent directory (all a deployed box may " +
|
|
69
|
+
"hold) and it works on itself. A directory resolves to ONE agent, at it or one level inside.",
|
|
55
70
|
run: async (args, f) => (await import("./commands/init.js")).runInit(args[0], {
|
|
56
71
|
minimal: f.minimal === true,
|
|
57
72
|
install: f.install !== false,
|
|
58
|
-
|
|
59
|
-
|
|
73
|
+
// `--flat` is the spelling for the common case of the same knob (they conflict, so only one is
|
|
74
|
+
// ever set); both land in ONE value, so the scaffolder never sees two ways to say ".".
|
|
75
|
+
agentDir: f.flat === true ? "." : typeof f.agentDir === "string" ? f.agentDir : undefined,
|
|
60
76
|
}),
|
|
61
77
|
};
|
|
62
78
|
const dev = {
|
|
@@ -64,8 +80,8 @@ const dev = {
|
|
|
64
80
|
summary: "serve the agent locally, restarting on code edits",
|
|
65
81
|
description: "Assemble the agent in dir (default .) and serve a local HTTP channel. persona.md/AGENTS.md/skills " +
|
|
66
82
|
"are re-read every turn (edits go live next turn); edits to code inputs — tools/, channels/, " +
|
|
67
|
-
"fastagent.config.*, package.json, .env — restart the worker. Files the agent writes as
|
|
68
|
-
"product never trigger a restart.",
|
|
83
|
+
"fastagent.config.*, package.json, .secrets/.env — restart the worker. Files the agent writes as " +
|
|
84
|
+
"work product never trigger a restart.",
|
|
69
85
|
args: [DIR_ARG],
|
|
70
86
|
flags: [
|
|
71
87
|
PORT,
|
|
@@ -214,14 +230,14 @@ const start = {
|
|
|
214
230
|
],
|
|
215
231
|
notes: "Precedence chains:\n" +
|
|
216
232
|
" port: --port > PORT env > fastagent.config.ts http.port > 8787\n" +
|
|
217
|
-
" state: FASTAGENT_STATE_DIR > <dir>/.
|
|
218
|
-
"
|
|
219
|
-
"
|
|
220
|
-
"
|
|
233
|
+
" state: FASTAGENT_STATE_DIR > <agent dir>/.state — mutable machine state\n" +
|
|
234
|
+
" (sessions, channel state, schedule state); point it at a mounted\n" +
|
|
235
|
+
" volume so a redeploy that replaces the directory never wipes it\n" +
|
|
236
|
+
" secrets: FASTAGENT_SECRETS_DIR > <agent dir>/.secrets — .env + auth.json\n" +
|
|
221
237
|
" sessions: --sessions-dir > FASTAGENT_SESSIONS_DIR > <state>/sessions\n" +
|
|
222
|
-
" auth: --auth-path > FASTAGENT_AUTH_PATH > <
|
|
223
|
-
" (project-level; point it at ~/.fastagent/auth.json to
|
|
224
|
-
" credential across projects)",
|
|
238
|
+
" auth: --auth-path > FASTAGENT_AUTH_PATH > <secrets>/auth.json\n" +
|
|
239
|
+
" (project-level; point it at ~/.fastagent/.secrets/auth.json to\n" +
|
|
240
|
+
" share one credential across projects)",
|
|
225
241
|
run: async (args, f) => (await import("./commands/start.js")).runStart(args[0], {
|
|
226
242
|
port: f.port,
|
|
227
243
|
model: f.model,
|
|
@@ -286,7 +302,7 @@ const add = {
|
|
|
286
302
|
"message pump, and an optional route() policy."),
|
|
287
303
|
channelSub("slack", "scaffold the Slack Events API channel (files, threads, context, live preview)", "Choose group visibility, scaffold channels/slack.ts plus slack-send.ts, create a single-workspace " +
|
|
288
304
|
"internal Slack app from a manifest, and install it through OAuth. The channel provides signed " +
|
|
289
|
-
"Events API ingress, durable turns, files,
|
|
305
|
+
"Events API ingress, durable turns, files, threads, context, and an edited live preview.", "Automated onboarding requires Slack App Configuration access + refresh tokens and a temporary " +
|
|
290
306
|
"cloudflared tunnel. They stay in owner-readable local state and are never deployed; --no-onboard " +
|
|
291
307
|
"keeps the explicit manual/scaffold-only path."),
|
|
292
308
|
channelSub("feishu", "scaffold the Feishu channel AND create/configure the platform app", "Choose WebSocket or webhook, scaffold channels/feishu.ts, and create/configure the Feishu app " +
|
|
@@ -324,19 +340,22 @@ const add = {
|
|
|
324
340
|
};
|
|
325
341
|
const deploy = {
|
|
326
342
|
name: "deploy",
|
|
327
|
-
summary: "generate deploy artifacts + a runbook for docker, fly, or
|
|
343
|
+
summary: "generate deploy artifacts + a runbook for docker, fly, railway, or agentcore (--run drives it)",
|
|
328
344
|
description: "Generate Dockerfile/.dockerignore plus the target config and print an ordered runbook. " +
|
|
329
345
|
"docker: fastagent.compose.yml, loopback port, persistent state volume. fly: fly.toml " +
|
|
330
346
|
"(autostop=suspend, state→volume). railway: railway.json (healthcheck /health); its " +
|
|
331
|
-
"volume/variables/App-Sleeping are dashboard/CLI steps the runbook states.
|
|
332
|
-
"
|
|
333
|
-
|
|
347
|
+
"volume/variables/App-Sleeping are dashboard/CLI steps the runbook states. agentcore: one " +
|
|
348
|
+
"CloudFormation stack (AWS Bedrock AgentCore Runtime + forwarder Lambda for webhooks + " +
|
|
349
|
+
"EventBridge rules for schedules; linux/arm64 image built locally). Durable ingress " +
|
|
350
|
+
"remains operator-owned (agentcore's forwarder URL is the exception — the stack owns it).",
|
|
351
|
+
args: [{ name: "<host>", description: "deploy target", choices: ["docker", "fly", "railway", "agentcore"] }, DIR_ARG],
|
|
334
352
|
flags: [
|
|
335
353
|
{
|
|
336
354
|
flags: "--run",
|
|
337
355
|
description: "drive the target CLI to completion. Docker runs `docker compose up -d --build`; with a tunnel " +
|
|
338
356
|
"service, reads its URL and registers webhooks. Fly/Railway provision app/service + volume + " +
|
|
339
|
-
"secrets + deploy + webhook setup.
|
|
357
|
+
"secrets + deploy + webhook setup. AgentCore builds/pushes the arm64 image and deploys the " +
|
|
358
|
+
"stack (aws + docker CLIs). Carries your local credential (env key or OAuth auth.json). " +
|
|
340
359
|
"Stops at a gate (missing CLI/daemon/login/secret) with one actionable line. Without it: prints " +
|
|
341
360
|
"the runbook",
|
|
342
361
|
},
|
|
@@ -367,6 +386,7 @@ const deploy = {
|
|
|
367
386
|
{ cmd: "fastagent deploy fly --run", note: "provision + deploy + webhooks" },
|
|
368
387
|
{ cmd: "fastagent deploy docker --tunnel --run", note: "Compose + a public URL" },
|
|
369
388
|
{ cmd: "fastagent deploy railway", note: "print the runbook only" },
|
|
389
|
+
{ cmd: "fastagent deploy agentcore --run", note: "arm64 image + stack + webhooks" },
|
|
370
390
|
],
|
|
371
391
|
notes: "Definition-read-only: the only writes are generated artifacts (never clobbered without " +
|
|
372
392
|
"--force). A routine redeploy of an already-provisioned agent is just the host's own command " +
|
|
@@ -427,10 +447,11 @@ const schedule = {
|
|
|
427
447
|
const login = {
|
|
428
448
|
name: "login",
|
|
429
449
|
summary: "authenticate a model provider (subscription/OAuth or API key)",
|
|
430
|
-
description: "Authenticate a model provider into the project-level <
|
|
431
|
-
"
|
|
432
|
-
"(subscription/OAuth or API
|
|
433
|
-
"
|
|
450
|
+
description: "Authenticate a model provider into the project-level <agent dir>/.secrets/auth.json (outside an " +
|
|
451
|
+
"agent it writes the global ~/.fastagent/.secrets/auth.json, and says so): pick a method " +
|
|
452
|
+
"(subscription/OAuth or API " +
|
|
453
|
+
"key), then a provider that offers it (configured status shown). [provider] takes the method from " +
|
|
454
|
+
"what that provider supports, asked only when both.",
|
|
434
455
|
args: [{ name: "[provider]", description: "provider id (skip the provider menu)" }],
|
|
435
456
|
flags: [AUTH_PATH, NO_INPUT],
|
|
436
457
|
examples: [{ cmd: "fastagent login" }, { cmd: "fastagent login openai" }],
|
package/dist/cli/serve.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Agent } from "../agent.ts";
|
|
2
2
|
import { type LoadedLongConnectionChannel } from "../engines/pi/channel.ts";
|
|
3
3
|
import { type Routes } from "../host/node.ts";
|
|
4
|
+
import type { LoadedSchedule } from "../schedule/schedule.ts";
|
|
4
5
|
import type { SessionControl } from "../session.ts";
|
|
5
6
|
export interface ServingSurface {
|
|
6
7
|
routes: Routes;
|
|
@@ -15,9 +16,11 @@ export interface ServingSurface {
|
|
|
15
16
|
* The surface this deployment serves: default `GET /health` plus discovered channels, or the default
|
|
16
17
|
* POST `/invoke` only when neither a route nor a long-connection channel was declared.
|
|
17
18
|
*/
|
|
18
|
-
export declare function routesFor(
|
|
19
|
+
export declare function routesFor(agentDir: string, agent: Agent, stateRoot: string, control?: SessionControl, options?: {
|
|
20
|
+
builtinInvoke?: boolean;
|
|
21
|
+
}): Promise<ServingSurface>;
|
|
19
22
|
/**
|
|
20
|
-
* Mount the session control plane (`/control/*`) when the
|
|
23
|
+
* Mount the session control plane (`/control/*`) when the agent enabled it
|
|
21
24
|
* (`config.sessionControl`): merge the bearer-authenticated routes and return an announcer that
|
|
22
25
|
* writes `<stateRoot>/control.json` — `{ url, token }`, 0600 — once the port is known. The file is
|
|
23
26
|
* the LOCAL discovery channel (`fastagent attach`, a local desktop app); filesystem permissions are
|
|
@@ -33,6 +36,19 @@ export declare function mountSessionControl(routes: Routes, control: SessionCont
|
|
|
33
36
|
routes: Routes;
|
|
34
37
|
announce: (boundPort: number) => void;
|
|
35
38
|
};
|
|
39
|
+
/**
|
|
40
|
+
* Mount the AgentCore Runtime adapter (`POST /invocations` + `GET /ping`) over the serving routes —
|
|
41
|
+
* the deployed container's ONLY reachable surface (channels/agentcore.ts). Wired by `start` when
|
|
42
|
+
* `FASTAGENT_AGENTCORE=1` (set by the generated deploy artifacts, never by hand). A channel colliding
|
|
43
|
+
* on either path fails startup, same disposition as the control-plane mount: the adapter's paths are
|
|
44
|
+
* the platform's contract, so a channel shadowing them would silently unserve the whole deployment.
|
|
45
|
+
*/
|
|
46
|
+
export declare function mountAgentcore(routes: Routes, options: {
|
|
47
|
+
agent: Agent;
|
|
48
|
+
stateRoot: string;
|
|
49
|
+
schedules: LoadedSchedule[];
|
|
50
|
+
onStateReady?: () => void;
|
|
51
|
+
}): Routes;
|
|
36
52
|
/**
|
|
37
53
|
* Bind HTTP, open long-connection channels, and report ready only when both forms are usable. Each
|
|
38
54
|
* adapter owns reconnects; a terminal close rejects `closed` and fails the process visibly. Abort is
|
|
@@ -40,9 +56,13 @@ export declare function mountSessionControl(routes: Routes, control: SessionCont
|
|
|
40
56
|
*/
|
|
41
57
|
export declare function serve(surface: ServingSurface, port: number, onListening?: (boundPort: number) => void): void;
|
|
42
58
|
/** Start a Cloudflare tunnel for route channels only. */
|
|
43
|
-
export declare function maybeTunnel(
|
|
59
|
+
export declare function maybeTunnel(agentDir: string, routeChannels: string[], boundPort: number, tunnel: boolean, stateRoot?: string): void;
|
|
44
60
|
/**
|
|
45
|
-
* Load and start the
|
|
46
|
-
* there are static schedules OR `selfSchedule` is on. Best-effort stop on process signals.
|
|
61
|
+
* Load and start the agent's `schedules/` — a time-trigger firing the agent on each cron. Starts iff
|
|
62
|
+
* there are static schedules OR `selfSchedule` is on. Best-effort stop on process signals. Returns the
|
|
63
|
+
* loaded schedules so a serving surface that needs them (the AgentCore adapter's fire binding) shares
|
|
64
|
+
* ONE load instead of re-discovering. `externalClock` (AgentCore) arms no resident cron timers.
|
|
47
65
|
*/
|
|
48
|
-
export declare function startSchedules(
|
|
66
|
+
export declare function startSchedules(agentDir: string, agent: Agent, stateRoot: string, selfSchedule: boolean, options?: {
|
|
67
|
+
externalClock?: boolean;
|
|
68
|
+
}): Promise<LoadedSchedule[]>;
|