@fastagent-sh/fastagent 0.18.0 → 0.19.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 +25 -7
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +1 -1
- package/dist/atomic-write.d.ts +19 -0
- package/dist/atomic-write.js +48 -0
- package/dist/{host/node.d.ts → channel.d.ts} +24 -28
- package/dist/channel.js +1 -0
- package/dist/channels/agentcore-service.d.ts +54 -0
- package/dist/channels/agentcore-service.js +111 -0
- package/dist/channels/agentcore.d.ts +12 -2
- package/dist/channels/agentcore.js +6 -4
- package/dist/channels/busy.d.ts +1 -1
- package/dist/channels/busy.js +1 -1
- package/dist/channels/control.d.ts +16 -6
- package/dist/channels/control.js +106 -4
- package/dist/{engines/pi/channel.d.ts → channels/discover.d.ts} +2 -2
- package/dist/{engines/pi/channel.js → channels/discover.js} +8 -12
- package/dist/channels/feishu/card.js +1 -1
- package/dist/channels/feishu/context-buffer.d.ts +1 -1
- package/dist/channels/feishu/context-buffer.js +4 -4
- package/dist/channels/feishu/feishu-api.js +1 -1
- package/dist/channels/feishu/feishu.d.ts +1 -1
- package/dist/channels/feishu/feishu.js +7 -7
- package/dist/channels/feishu/invoke-turn.d.ts +1 -1
- package/dist/channels/feishu/invoke-turn.js +3 -4
- package/dist/channels/feishu/preview.d.ts +1 -1
- package/dist/channels/feishu/preview.js +7 -3
- package/dist/channels/feishu/ws-ingress.d.ts +1 -1
- package/dist/channels/github/github.d.ts +1 -1
- package/dist/channels/http.d.ts +11 -7
- package/dist/channels/http.js +1 -109
- package/dist/channels/{context-buffer.js → kit/context-buffer.js} +2 -2
- package/dist/channels/{invoke-turn-kit.d.ts → kit/invoke-turn-kit.d.ts} +14 -3
- package/dist/channels/{invoke-turn-kit.js → kit/invoke-turn-kit.js} +17 -6
- package/dist/channels/{preview-kit.d.ts → kit/preview-kit.d.ts} +3 -1
- package/dist/channels/{seen.js → kit/seen.js} +1 -1
- package/dist/channels/{state.js → kit/state.js} +4 -7
- package/dist/channels/{stop-command.d.ts → kit/stop-command.d.ts} +1 -1
- package/dist/channels/{stop-command.js → kit/stop-command.js} +2 -2
- package/dist/channels/{tasks.js → kit/tasks.js} +1 -1
- package/dist/channels/{thread-participants.js → kit/thread-participants.js} +1 -1
- package/dist/channels/{turn-queue.js → kit/turn-queue.js} +2 -2
- package/dist/channels/{turn-store.js → kit/turn-store.js} +1 -1
- package/dist/channels/lark/lark.d.ts +1 -1
- package/dist/channels/serve.d.ts +73 -0
- package/dist/channels/serve.js +243 -0
- package/dist/channels/slack/bot-auth.js +3 -14
- package/dist/channels/slack/context-buffer.d.ts +2 -2
- package/dist/channels/slack/context-buffer.js +2 -2
- package/dist/channels/slack/invoke-turn.d.ts +1 -1
- package/dist/channels/slack/invoke-turn.js +8 -5
- package/dist/channels/slack/parse.js +2 -2
- package/dist/channels/slack/preview.d.ts +1 -1
- package/dist/channels/slack/preview.js +11 -3
- package/dist/channels/slack/slack-api.js +1 -1
- package/dist/channels/slack/slack.d.ts +1 -1
- package/dist/channels/slack/slack.js +8 -8
- package/dist/channels/slack/welcomed.js +1 -1
- package/dist/channels/telegram/context-buffer.d.ts +2 -2
- package/dist/channels/telegram/context-buffer.js +2 -2
- package/dist/channels/telegram/invoke-turn.d.ts +1 -1
- package/dist/channels/telegram/invoke-turn.js +1 -1
- package/dist/channels/telegram/parse.js +2 -2
- package/dist/channels/telegram/preview.d.ts +1 -1
- package/dist/channels/telegram/preview.js +6 -2
- package/dist/channels/telegram/telegram.d.ts +1 -1
- package/dist/channels/telegram/telegram.js +3 -3
- package/dist/channels/telegram/turn-store.d.ts +2 -2
- package/dist/channels/telegram/turn-store.js +2 -2
- package/dist/cli/commands/add.js +1 -1
- package/dist/cli/commands/dev.js +25 -13
- package/dist/cli/commands/fire.js +1 -1
- package/dist/cli/commands/info.js +7 -4
- package/dist/cli/commands/schedule.js +1 -1
- package/dist/cli/commands/start.js +63 -94
- package/dist/cli/commands/tool.js +5 -7
- package/dist/cli/program.js +1 -1
- package/dist/cli/serve.d.ts +18 -57
- package/dist/cli/serve.js +57 -243
- package/dist/cli/shared.d.ts +1 -1
- package/dist/cli/shared.js +2 -2
- package/dist/core.d.ts +3 -5
- package/dist/core.js +7 -5
- package/dist/deploy/preflight.js +1 -1
- package/dist/dev-supervisor.js +9 -3
- package/dist/engines/pi/agent-session-factory.d.ts +104 -0
- package/dist/engines/pi/agent-session-factory.js +314 -0
- package/dist/engines/pi/config.d.ts +4 -4
- package/dist/engines/pi/config.js +1 -1
- package/dist/engines/pi/create.d.ts +56 -43
- package/dist/engines/pi/create.js +141 -71
- package/dist/engines/pi/definition.d.ts +41 -7
- package/dist/engines/pi/definition.js +115 -11
- package/dist/engines/pi/invoke-session.d.ts +22 -19
- package/dist/engines/pi/invoke-session.js +286 -100
- package/dist/engines/pi/login.js +7 -4
- package/dist/engines/pi/models.d.ts +14 -0
- package/dist/engines/pi/models.js +9 -1
- package/dist/engines/pi/open.d.ts +9 -6
- package/dist/engines/pi/open.js +20 -10
- package/dist/engines/pi/report.d.ts +0 -4
- package/dist/engines/pi/report.js +0 -7
- package/dist/engines/pi/service.d.ts +23 -0
- package/dist/engines/pi/service.js +19 -0
- package/dist/engines/pi/session-builder.js +84 -88
- package/dist/engines/pi/session-control.d.ts +10 -9
- package/dist/engines/pi/session-control.js +114 -77
- package/dist/engines/pi/session-inheritance.d.ts +44 -0
- package/dist/engines/pi/session-inheritance.js +242 -0
- package/dist/engines/pi/session-settings.d.ts +14 -2
- package/dist/engines/pi/session-settings.js +18 -0
- package/dist/engines/pi/session-store.d.ts +70 -0
- package/dist/engines/pi/session-store.js +313 -0
- package/dist/engines/pi/tool-context.d.ts +18 -8
- package/dist/engines/pi/tool-context.js +23 -1
- package/dist/engines/pi/tool.d.ts +5 -5
- package/dist/engines/pi/tool.js +1 -1
- package/dist/engines/pi/turn-kit.d.ts +32 -6
- package/dist/engines/pi/turn-kit.js +28 -1
- package/dist/engines/pi/wake-tool.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/log.d.ts +3 -0
- package/dist/log.js +5 -1
- package/dist/node.d.ts +16 -0
- package/dist/node.js +20 -0
- package/dist/paths.d.ts +7 -0
- package/dist/paths.js +10 -0
- package/dist/pi.d.ts +14 -8
- package/dist/pi.js +6 -5
- package/dist/scaffold/templates/persona.md +2 -2
- package/dist/schedule/state.js +4 -9
- package/dist/schedule/wakeups.d.ts +1 -1
- package/dist/schedule/wakeups.js +1 -1
- package/dist/service.d.ts +158 -0
- package/dist/service.js +354 -0
- package/dist/session-remote.d.ts +1 -1
- package/dist/session.d.ts +4 -2
- package/dist/session.js +1 -1
- package/package.json +14 -5
- package/dist/engines/pi/harness.d.ts +0 -115
- package/dist/engines/pi/harness.js +0 -154
- package/dist/engines/pi/invoke.d.ts +0 -60
- package/dist/engines/pi/invoke.js +0 -459
- package/dist/engines/pi/read-image.d.ts +0 -4
- package/dist/engines/pi/read-image.js +0 -62
- package/dist/engines/pi/sessions.d.ts +0 -60
- package/dist/engines/pi/sessions.js +0 -464
- package/dist/host/node.js +0 -52
- /package/dist/channels/{context-buffer.d.ts → kit/context-buffer.d.ts} +0 -0
- /package/dist/channels/{preview-kit.js → kit/preview-kit.js} +0 -0
- /package/dist/channels/{seen.d.ts → kit/seen.d.ts} +0 -0
- /package/dist/channels/{state.d.ts → kit/state.d.ts} +0 -0
- /package/dist/channels/{tasks.d.ts → kit/tasks.d.ts} +0 -0
- /package/dist/channels/{text.d.ts → kit/text.d.ts} +0 -0
- /package/dist/channels/{text.js → kit/text.js} +0 -0
- /package/dist/channels/{thread-participants.d.ts → kit/thread-participants.d.ts} +0 -0
- /package/dist/channels/{turn-queue.d.ts → kit/turn-queue.d.ts} +0 -0
- /package/dist/channels/{turn-store.d.ts → kit/turn-store.d.ts} +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The telegram-shaped turn store: the channel's persisted record (what its runner needs to re-execute a
|
|
3
3
|
* turn), its IO-boundary shape validator, and its arrival ordering, over the generic L1 turn store
|
|
4
|
-
* (../turn-store.ts — the semantics live there: pre-ACK persist, replay on the next start, the poison-
|
|
4
|
+
* (../kit/turn-store.ts — the semantics live there: pre-ACK persist, replay on the next start, the poison-
|
|
5
5
|
* turn execution ceiling, the fail-closed attempt bump).
|
|
6
6
|
*/
|
|
7
|
-
import { type TurnStore } from "../turn-store.ts";
|
|
7
|
+
import { type TurnStore } from "../kit/turn-store.ts";
|
|
8
8
|
/** An accepted turn's persisted intent — the SOURCE for the fields a runner needs to re-execute it
|
|
9
9
|
* (telegram.ts's PendingTurn derives from this, so a new execution field added here propagates and
|
|
10
10
|
* cannot silently drop from the persisted record). Minus the live `previewId` (a restart's queue
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The telegram-shaped turn store: the channel's persisted record (what its runner needs to re-execute a
|
|
3
3
|
* turn), its IO-boundary shape validator, and its arrival ordering, over the generic L1 turn store
|
|
4
|
-
* (../turn-store.ts — the semantics live there: pre-ACK persist, replay on the next start, the poison-
|
|
4
|
+
* (../kit/turn-store.ts — the semantics live there: pre-ACK persist, replay on the next start, the poison-
|
|
5
5
|
* turn execution ceiling, the fail-closed attempt bump).
|
|
6
6
|
*/
|
|
7
|
-
import { createTurnStore as createGenericTurnStore } from "../turn-store.js";
|
|
7
|
+
import { createTurnStore as createGenericTurnStore } from "../kit/turn-store.js";
|
|
8
8
|
/** State files are an IO boundary: valid JSON of the WRONG SHAPE must degrade like a corrupt file
|
|
9
9
|
* (warn + empty), not flow in as trusted data (mirrors context-buffer's isBufferEntry). */
|
|
10
10
|
function isStoredTurn(t) {
|
package/dist/cli/commands/add.js
CHANGED
|
@@ -11,7 +11,7 @@ import { dotEnvPath, loadDotEnv } from "../../env.js";
|
|
|
11
11
|
import { resolveStateRoot } from "../../paths.js";
|
|
12
12
|
import { SECRETS_DIRNAME } from "../../paths.js";
|
|
13
13
|
import { detectRuntime, readPackageJson } from "../../runtime.js";
|
|
14
|
-
import { isUnderDir } from "../../
|
|
14
|
+
import { isUnderDir } from "../../paths.js";
|
|
15
15
|
import { displayPath } from "../../paths.js";
|
|
16
16
|
import { appendChannelDotEnv, appendChannelEnv, assertChannelReady, channelExists, channelSetup, scaffoldChannel, } from "../../scaffold/add-channel.js";
|
|
17
17
|
import { exists } from "../../paths.js";
|
package/dist/cli/commands/dev.js
CHANGED
|
@@ -6,15 +6,18 @@
|
|
|
6
6
|
import { resolve } from "node:path";
|
|
7
7
|
import { runDevSupervisor } from "../../dev-supervisor.js";
|
|
8
8
|
import { loadDotEnv } from "../../env.js";
|
|
9
|
-
import { reportFindingsIfChanged,
|
|
9
|
+
import { reportFindingsIfChanged, reportToolCollisions } from "../../engines/pi/report.js";
|
|
10
|
+
import { reportModuleLoadFailures } from "../../log.js";
|
|
11
|
+
import { CODING_TOOL_NAMES } from "../../engines/pi/create.js";
|
|
10
12
|
import { createPiAgentFromDir } from "../../engines/pi/open.js";
|
|
13
|
+
import { mountAgentService } from "../../service.js";
|
|
11
14
|
import { setLogLevel } from "../../log.js";
|
|
12
15
|
import { logAgentLoop } from "../../observe.js";
|
|
13
16
|
import { installProxyFetch } from "../../proxy.js";
|
|
14
17
|
import { workspaceHint } from "../../paths.js";
|
|
15
18
|
import { bindAddress } from "../../bind.js";
|
|
16
19
|
import { failStartup, placementOrExit } from "../fail.js";
|
|
17
|
-
import { assertTunnelBindable, maybeTunnel,
|
|
20
|
+
import { SHUTDOWN_GRACE_MS, assertTunnelBindable, maybeTunnel, reportServing, serve } from "../serve.js";
|
|
18
21
|
import { parseBind, parsePort, reportAuth, reportLine, resolveFirstRunModel, reportWorkspaceHint } from "../shared.js";
|
|
19
22
|
export async function runDev(dirArg, opts) {
|
|
20
23
|
const dir = resolve(dirArg);
|
|
@@ -60,22 +63,30 @@ async function serveOnce(dir, opts) {
|
|
|
60
63
|
reportAgentsSkillsTools(a);
|
|
61
64
|
// Trace each turn's agent loop (tool calls + reply) to the log at debug level — shown in dev, gated
|
|
62
65
|
// out in start (level info), keeping end-user content out of production logs. Wired in both postures.
|
|
63
|
-
const traced = logAgentLoop(a.agent);
|
|
64
|
-
const routed = await routesFor(a.agentDir, traced, a.stateRoot, a.sessionControl).catch(failStartup);
|
|
65
66
|
// `http.host` enters here the way the flag enters `parseBind` — through `bindAddress`, so a
|
|
66
67
|
// configured `localhost` is an ADDRESS by the time anything binds, renders or dials it.
|
|
67
68
|
const configured = a.config.http?.host;
|
|
68
69
|
const host = bindFlag ?? (configured === undefined ? undefined : bindAddress(configured));
|
|
69
70
|
assertTunnelBindable(host, opts.tunnel ?? false, bindFlag ? "flag" : "config");
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
71
|
+
// The SAME assembly an embedder gets from `createAgentService` — channels, control plane,
|
|
72
|
+
// schedules, long connections. `dev` opens the directory itself only because its startup report
|
|
73
|
+
// prints the opened values before anything mounts.
|
|
74
|
+
const service = await mountAgentService(a, {
|
|
75
|
+
// Trace each turn's agent loop (tool calls + reply) to the log at debug level — shown in dev,
|
|
76
|
+
// gated out in start (level info), keeping end-user content out of production logs.
|
|
77
|
+
wrapAgent: logAgentLoop,
|
|
78
|
+
closeTimeoutMs: SHUTDOWN_GRACE_MS,
|
|
79
|
+
control: { tunnel: opts.tunnel ?? false, ...(host !== undefined ? { host } : {}) },
|
|
80
|
+
onChannelClosed: (name, error) => failStartup(new Error(`${name} ${error === undefined ? "closed unexpectedly" : `failed: ${String(error)}`}`)),
|
|
81
|
+
}).catch(failStartup);
|
|
82
|
+
serve(service.handler, { port: portFlag ?? a.config.http?.port ?? 8787, host }, {
|
|
83
|
+
ready: service.ready,
|
|
84
|
+
onListening: (p) => {
|
|
85
|
+
reportServing(service, host, p);
|
|
86
|
+
service.announce(p);
|
|
87
|
+
maybeTunnel(a.agentDir, service.channels.routes, p, opts.tunnel ?? false, a.stateRoot);
|
|
88
|
+
},
|
|
89
|
+
onShutdown: () => service.close(),
|
|
79
90
|
});
|
|
80
91
|
}
|
|
81
92
|
/** The agents/skills/tools/collisions report lines. */
|
|
@@ -84,6 +95,7 @@ function reportAgentsSkillsTools(a) {
|
|
|
84
95
|
if (a.definition.persona)
|
|
85
96
|
reportLine("persona", "persona.md");
|
|
86
97
|
reportLine("skills", a.definition.skills.map((s) => s.name).join(", ") || "(none)");
|
|
98
|
+
reportLine("codingTools", CODING_TOOL_NAMES.join(", "));
|
|
87
99
|
if (a.toolNames.length > 0)
|
|
88
100
|
reportLine("tools", a.toolNames.join(", "));
|
|
89
101
|
if (a.deferredToolNames.length > 0) {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { join, resolve } from "node:path";
|
|
8
8
|
import { loadDotEnv } from "../../env.js";
|
|
9
9
|
import { displayPath } from "../../paths.js";
|
|
10
|
-
import { reportModuleLoadFailures } from "../../
|
|
10
|
+
import { reportModuleLoadFailures } from "../../log.js";
|
|
11
11
|
import { createPiAgentFromDir } from "../../engines/pi/open.js";
|
|
12
12
|
import { runInvokeStream } from "../invoke-stream.js";
|
|
13
13
|
import { installProxyFetch } from "../../proxy.js";
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
/** `fastagent info [dir] [--json]`: print what the directory ASSEMBLES into, WITHOUT booting a server. Read-only. */
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { loadDotEnv } from "../../env.js";
|
|
4
|
-
import { discoverChannelFiles } from "../../
|
|
4
|
+
import { discoverChannelFiles } from "../../channels/discover.js";
|
|
5
5
|
import { defaultSessionsDir, loadConfig, resolveAuthPath, resolveModel, resolveModelSpec, resolveSessionsDirOverride, } from "../../engines/pi/config.js";
|
|
6
6
|
import { createPiModelRuntime } from "../../engines/pi/models.js";
|
|
7
7
|
import { resolveStateRoot, workspaceHint } from "../../paths.js";
|
|
8
|
-
import { resolveAgentTools } from "../../engines/pi/create.js";
|
|
8
|
+
import { CODING_TOOL_NAMES, resolveAgentTools } from "../../engines/pi/create.js";
|
|
9
9
|
import { loadAgentDefinition } from "../../engines/pi/definition.js";
|
|
10
|
-
import { reportFindingsIfChanged,
|
|
10
|
+
import { reportFindingsIfChanged, reportToolCollisions } from "../../engines/pi/report.js";
|
|
11
|
+
import { reportModuleLoadFailures } from "../../log.js";
|
|
11
12
|
import { log } from "../../log.js";
|
|
12
13
|
import { nextRun } from "../../schedule/cron.js";
|
|
13
14
|
import { loadSchedules } from "../../schedule/discover.js";
|
|
@@ -25,7 +26,7 @@ export async function runInfo(dirArg, opts) {
|
|
|
25
26
|
// tool), is isolated the same way everywhere (G2): info, dev, AND start report it and keep going with
|
|
26
27
|
// the tools that loaded. The `error`/`.catch` below only fires for a whole-load fault (an unreadable
|
|
27
28
|
// tools/ dir), not a single bad file.
|
|
28
|
-
const tools = await resolveAgentTools(config, agentDir)
|
|
29
|
+
const tools = await resolveAgentTools(config, agentDir, workspace)
|
|
29
30
|
.then((r) => ({
|
|
30
31
|
names: r.toolNames,
|
|
31
32
|
deferred: r.deferredToolNames,
|
|
@@ -78,6 +79,7 @@ export async function runInfo(dirArg, opts) {
|
|
|
78
79
|
model: modelSpec ?? null,
|
|
79
80
|
modelError: modelError ?? null,
|
|
80
81
|
thinkingLevel: config.thinkingLevel ?? null,
|
|
82
|
+
codingTools: [...CODING_TOOL_NAMES],
|
|
81
83
|
context: definition.contextFiles.map((f) => f.path),
|
|
82
84
|
persona: definition.persona !== undefined,
|
|
83
85
|
skills: definition.skills.map((skill) => ({ name: skill.name, description: skill.description })),
|
|
@@ -114,6 +116,7 @@ export async function runInfo(dirArg, opts) {
|
|
|
114
116
|
cont(`⚠ does not resolve: ${modelError}`);
|
|
115
117
|
if (config.thinkingLevel)
|
|
116
118
|
line("thinking", config.thinkingLevel);
|
|
119
|
+
line("codingTools", CODING_TOOL_NAMES.join(", "));
|
|
117
120
|
line("context", definition.contextFiles.map((f) => f.path).join(", ") || "(none)");
|
|
118
121
|
line("persona", definition.persona ? "persona.md" : "(none)");
|
|
119
122
|
line("skills", definition.skills.map((skill) => skill.name).join(", ") || "(none)");
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { resolve } from "node:path";
|
|
7
7
|
import { loadDotEnv } from "../../env.js";
|
|
8
8
|
import { resolveStateRoot } from "../../paths.js";
|
|
9
|
-
import { reportModuleLoadFailures } from "../../
|
|
9
|
+
import { reportModuleLoadFailures } from "../../log.js";
|
|
10
10
|
import { readRuns } from "../../schedule/audit.js";
|
|
11
11
|
import { nextRun } from "../../schedule/cron.js";
|
|
12
12
|
import { loadSchedules } from "../../schedule/discover.js";
|
|
@@ -8,19 +8,22 @@ 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
10
|
import { resolveSecretsDir, workspaceHint } from "../../paths.js";
|
|
11
|
-
import { isUnderDir } from "../../
|
|
12
|
-
import { reportFindingsIfChanged,
|
|
11
|
+
import { isUnderDir } from "../../paths.js";
|
|
12
|
+
import { reportFindingsIfChanged, reportToolCollisions } from "../../engines/pi/report.js";
|
|
13
|
+
import { reportModuleLoadFailures } from "../../log.js";
|
|
14
|
+
import { CODING_TOOL_NAMES } from "../../engines/pi/create.js";
|
|
13
15
|
import { createPiAgentFromDir } from "../../engines/pi/open.js";
|
|
16
|
+
import { mountAgentService } from "../../service.js";
|
|
14
17
|
import { log, setLogLevel } from "../../log.js";
|
|
15
|
-
import { createWakeAlarmSink, reconcileWakeAlarms } from "../../schedule/wake-alarm.js";
|
|
16
|
-
import { setWakeupsSink } from "../../schedule/wakeups.js";
|
|
17
18
|
import { logAgentLoop } from "../../observe.js";
|
|
18
19
|
import { installProxyFetch } from "../../proxy.js";
|
|
19
20
|
import { exists } from "../../paths.js";
|
|
20
21
|
import { bindAddress } from "../../bind.js";
|
|
21
|
-
import {
|
|
22
|
+
import { isAgentcoreRuntime, mountAgentcoreService } from "../../channels/agentcore-service.js";
|
|
23
|
+
import { createWakeAlarmSink, reconcileWakeAlarms } from "../../schedule/wake-alarm.js";
|
|
24
|
+
import { setWakeupsSink } from "../../schedule/wakeups.js";
|
|
22
25
|
import { failStartup, placementOrExit } from "../fail.js";
|
|
23
|
-
import { assertTunnelBindable, maybeTunnel,
|
|
26
|
+
import { SHUTDOWN_GRACE_MS, assertTunnelBindable, maybeTunnel, reportServing, serve } from "../serve.js";
|
|
24
27
|
import { parseBind, parsePort, reportAuth, reportLine, resolveFirstRunModel, reportWorkspaceHint } from "../shared.js";
|
|
25
28
|
export async function runStart(dirArg, opts) {
|
|
26
29
|
const dir = resolve(dirArg);
|
|
@@ -39,12 +42,8 @@ export async function runStart(dirArg, opts) {
|
|
|
39
42
|
await maybeSeedAuth(resolveAuthPath(placement.agentDir, opts.authPath));
|
|
40
43
|
// The same opener dev uses (single assembly source), just no watch.
|
|
41
44
|
const sessionsDirOverride = resolveSessionsDirOverride(opts.sessionsDir);
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
sessionsDir: sessionsDirOverride,
|
|
45
|
-
authPath: opts.authPath,
|
|
46
|
-
serving: true, // long-running serve: the scheduler poller runs (wake mounts iff config.selfSchedule)
|
|
47
|
-
}).catch(failStartup);
|
|
45
|
+
const opened = await openStartDir(dir, opts, sessionsDirOverride);
|
|
46
|
+
const { agent, definition, agentDir, workspace, config, modelSpec, stateRoot, sessionsDir, authPath, toolNames, deferredToolNames, toolCollisions, toolFailures, } = opened;
|
|
48
47
|
reportLine("agent", agentDir);
|
|
49
48
|
reportLine("workspace", workspace);
|
|
50
49
|
reportWorkspaceHint(workspaceHint({ agentDir, workspace }));
|
|
@@ -54,6 +53,7 @@ export async function runStart(dirArg, opts) {
|
|
|
54
53
|
if (definition.persona)
|
|
55
54
|
reportLine("persona", "persona.md");
|
|
56
55
|
reportLine("skills", definition.skills.map((s) => s.name).join(", ") || "(none)");
|
|
56
|
+
reportLine("codingTools", CODING_TOOL_NAMES.join(", "));
|
|
57
57
|
if (toolNames.length > 0)
|
|
58
58
|
reportLine("tools", toolNames.join(", "));
|
|
59
59
|
if (deferredToolNames.length > 0) {
|
|
@@ -82,95 +82,37 @@ export async function runStart(dirArg, opts) {
|
|
|
82
82
|
`FASTAGENT_SECRETS_DIR at a persistent volume so a redeploy that replaces the dir does not wipe them.`);
|
|
83
83
|
}
|
|
84
84
|
reportFindingsIfChanged(definition.dir, definition);
|
|
85
|
-
// AgentCore Runtime posture (FASTAGENT_AGENTCORE=1, set by the generated deploy artifacts): the
|
|
86
|
-
// adapter (POST /invocations + GET /ping) is the container's only reachable surface, and cron
|
|
87
|
-
// slots arrive from the external clock through it — so no resident cron timers. In particular,
|
|
88
|
-
// do NOT mount the ordinary unauthenticated POST /invoke fallback: a selfSchedule-only topology
|
|
89
|
-
// needs a public Function URL for wake callbacks, and its forwarder can relay arbitrary paths.
|
|
90
|
-
const agentcore = process.env.FASTAGENT_AGENTCORE === "1";
|
|
91
85
|
// Same debug turn trace as dev; gated out here by the info level (see dev.ts serveOnce).
|
|
92
86
|
const traced = logAgentLoop(agent);
|
|
93
|
-
// On AgentCore the channels are constructed LAZILY (mountAgentcore's lazyChannels, resolved on the
|
|
94
|
-
// first envelope after the state-snapshot restore): construction loads channel state and replays
|
|
95
|
-
// turn intent, and at boot the state mount is PRE-RESTORE — empty after every version update — so
|
|
96
|
-
// an eager build would cache that emptiness (thread participation, delivery dedup, pending turns)
|
|
97
|
-
// and then clobber the restored files with it. Everywhere else the state root is durable at boot,
|
|
98
|
-
// so channels mount eagerly and a broken channel fails startup.
|
|
99
|
-
const routed = agentcore
|
|
100
|
-
? undefined
|
|
101
|
-
: await routesFor(agentDir, traced, stateRoot, sessionControl, { builtinInvoke: true }).catch(failStartup);
|
|
102
87
|
// `http.host` enters here the way the flag enters `parseBind` — through `bindAddress`, so a
|
|
103
88
|
// configured `localhost` is an ADDRESS by the time anything binds, renders or dials it.
|
|
104
89
|
const configured = config.http?.host;
|
|
105
90
|
const host = bindFlag ?? (configured === undefined ? undefined : bindAddress(configured));
|
|
106
91
|
assertTunnelBindable(host, opts.tunnel ?? false, bindFlag ? "flag" : "config");
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
//
|
|
113
|
-
//
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
const schedules = await startSchedules(agentDir, traced, stateRoot, config.selfSchedule ?? false, {
|
|
134
|
-
externalClock: agentcore,
|
|
135
|
-
});
|
|
136
|
-
let routes = withControl.routes;
|
|
137
|
-
if (agentcore) {
|
|
138
|
-
// The lazy channel surface the adapter resolves post-restore. Control routes ride along so a
|
|
139
|
-
// forwarder-relayed /control/* request dispatches the same as on a direct host. Long-connection
|
|
140
|
-
// channels cannot serve here — scale-to-zero severs a resident connection and nothing
|
|
141
|
-
// re-establishes it — so their presence is a configuration error, surfaced per envelope and by
|
|
142
|
-
// the deploy driver's health probe (there is no boot to fail on this host).
|
|
143
|
-
const lazyChannels = async () => {
|
|
144
|
-
const surface = await routesFor(agentDir, traced, stateRoot, sessionControl, { builtinInvoke: false });
|
|
145
|
-
if (surface.longConnections.length > 0) {
|
|
146
|
-
throw new Error(`long-connection channel(s) ${surface.longConnections.map((c) => c.name).join(", ")} cannot serve on ` +
|
|
147
|
-
`AgentCore (scale-to-zero severs resident connections) — use the channel's webhook form`);
|
|
148
|
-
}
|
|
149
|
-
// mountSessionControl's PATH-level collision rule, re-asserted here: with no channels at boot
|
|
150
|
-
// its own check ran against an empty base, and a spread merge would silently let control win —
|
|
151
|
-
// but a channel on /control/* is the same configuration error it is on every other host.
|
|
152
|
-
const controlPaths = new Set(Object.keys(withControl.routes).map((key) => parseRouteKey(key).path));
|
|
153
|
-
const collisions = Object.keys(surface.routes).filter((key) => controlPaths.has(parseRouteKey(key).path));
|
|
154
|
-
if (collisions.length > 0) {
|
|
155
|
-
throw new Error(`channel route(s) ${collisions.map((key) => `"${key}"`).join(", ")} collide with the session control ` +
|
|
156
|
-
`plane — rename the channel route or disable sessionControl in fastagent.config`);
|
|
157
|
-
}
|
|
158
|
-
return { ...surface.routes, ...withControl.routes };
|
|
159
|
-
};
|
|
160
|
-
try {
|
|
161
|
-
routes = mountAgentcore(routes, { agent: traced, stateRoot, schedules, onStateReady, lazyChannels });
|
|
162
|
-
}
|
|
163
|
-
catch (e) {
|
|
164
|
-
failStartup(e);
|
|
165
|
-
}
|
|
166
|
-
log.info(`[fastagent] agentcore: serving POST /invocations + GET /ping (FASTAGENT_AGENTCORE=1)`);
|
|
167
|
-
}
|
|
168
|
-
serve({
|
|
169
|
-
...(routed ?? { longConnections: [], routeChannels: [], builtinInvoke: false, markReady() { } }),
|
|
170
|
-
routes,
|
|
171
|
-
}, { port: portFlag ?? parsePort(process.env.PORT, "PORT env", "env") ?? config.http?.port ?? 8787, host }, (p) => {
|
|
172
|
-
withControl.announce(p);
|
|
173
|
-
maybeTunnel(agentDir, routed?.routeChannels ?? [], p, opts.tunnel ?? false, stateRoot);
|
|
92
|
+
const control = { tunnel: opts.tunnel ?? false, ...(host !== undefined ? { host } : {}) };
|
|
93
|
+
// ONE branch for the whole posture. AgentCore assembles differently — lazy channels over a
|
|
94
|
+
// pre-restore state mount, an external clock, no resident connections — but it yields the same
|
|
95
|
+
// AgentService, so everything below this point is common.
|
|
96
|
+
// The wake-alarm sink is a PROCESS-global (schedule/wakeups.ts) — this process IS the AgentCore
|
|
97
|
+
// deployment, so the process entry installs it. A service can be closed; a global cannot be
|
|
98
|
+
// handed to something that can, without inventing an ownership the singleton does not have.
|
|
99
|
+
const onStateReady = isAgentcoreRuntime() && config.selfSchedule ? armWakeAlarms(stateRoot) : undefined;
|
|
100
|
+
const service = await (isAgentcoreRuntime()
|
|
101
|
+
? mountAgentcoreService(opened, { wrapAgent: () => traced, control, onStateReady })
|
|
102
|
+
: mountAgentService(opened, {
|
|
103
|
+
wrapAgent: () => traced,
|
|
104
|
+
closeTimeoutMs: SHUTDOWN_GRACE_MS,
|
|
105
|
+
control,
|
|
106
|
+
onChannelClosed: (name, error) => failStartup(new Error(`${name} ${error === undefined ? "closed unexpectedly" : `failed: ${String(error)}`}`)),
|
|
107
|
+
})).catch(failStartup);
|
|
108
|
+
serve(service.handler, { port: portFlag ?? parsePort(process.env.PORT, "PORT env", "env") ?? config.http?.port ?? 8787, host }, {
|
|
109
|
+
ready: service.ready,
|
|
110
|
+
onListening: (p) => {
|
|
111
|
+
reportServing(service, host, p);
|
|
112
|
+
service.announce(p);
|
|
113
|
+
maybeTunnel(agentDir, service.channels.routes, p, opts.tunnel ?? false, stateRoot);
|
|
114
|
+
},
|
|
115
|
+
onShutdown: () => service.close(),
|
|
174
116
|
});
|
|
175
117
|
// No graceful drain: webhook turns run fire-and-forget; SIGTERM just exits mid-turn. Whether an
|
|
176
118
|
// in-flight turn is LOST depends on the channel: the Telegram channel persists turn intent pre-ACK
|
|
@@ -183,6 +125,15 @@ export async function runStart(dirArg, opts) {
|
|
|
183
125
|
* volume copy is never clobbered by the stale seed. Lets a deploy carry the operator's local
|
|
184
126
|
* OAuth/API credential so the box runs on the SAME subscription. No-op locally (the seed is unset).
|
|
185
127
|
*/
|
|
128
|
+
/** The opener, kept as its own call so `opened` can also feed the shared assembly below. */
|
|
129
|
+
function openStartDir(dir, opts, sessionsDir) {
|
|
130
|
+
return createPiAgentFromDir(dir, {
|
|
131
|
+
model: opts.model,
|
|
132
|
+
sessionsDir,
|
|
133
|
+
authPath: opts.authPath,
|
|
134
|
+
serving: true, // long-running serve: the scheduler poller runs (wake mounts iff config.selfSchedule)
|
|
135
|
+
}).catch(failStartup);
|
|
136
|
+
}
|
|
186
137
|
async function maybeSeedAuth(authPath) {
|
|
187
138
|
// collectAuthSeed: the seed may arrive CHUNKED (FASTAGENT_AUTH_SEED + _2…) on hosts with a small
|
|
188
139
|
// env-value max length (AgentCore); single-var hosts are unchanged.
|
|
@@ -193,3 +144,21 @@ async function maybeSeedAuth(authPath) {
|
|
|
193
144
|
await writeFile(authPath, bytes);
|
|
194
145
|
log.info(`[fastagent] seeded ${authPath} from FASTAGENT_AUTH_SEED (first boot)`);
|
|
195
146
|
}
|
|
147
|
+
/**
|
|
148
|
+
* Install the wake-ALARM sink before the scheduler starts — the boot wake pump may advance a
|
|
149
|
+
* recurring entry, and that save must already re-arm its alarm. Returns the post-restore reconcile:
|
|
150
|
+
* running it at boot would read the pre-restore state mount, see no pending wake-ups, and conclude
|
|
151
|
+
* there is nothing to re-arm.
|
|
152
|
+
*/
|
|
153
|
+
function armWakeAlarms(stateRoot) {
|
|
154
|
+
const secret = process.env.FASTAGENT_WAKE_SECRET;
|
|
155
|
+
if (!secret) {
|
|
156
|
+
log.warn(`[fastagent] FASTAGENT_WAKE_SECRET is not set — wake-ups fire only while a session is awake ` +
|
|
157
|
+
`(redeploy with the current template to fix)`);
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
const sink = createWakeAlarmSink({ secret });
|
|
161
|
+
setWakeupsSink(sink);
|
|
162
|
+
log.info(`[fastagent] wake alarms: EventBridge-backed via the forwarder`);
|
|
163
|
+
return () => reconcileWakeAlarms(stateRoot, sink);
|
|
164
|
+
}
|
|
@@ -4,7 +4,7 @@ import { NodeExecutionEnv } from "@earendil-works/pi-agent-core/node";
|
|
|
4
4
|
import { loadDotEnv } from "../../env.js";
|
|
5
5
|
import { loadConfig } from "../../engines/pi/config.js";
|
|
6
6
|
import { resolveAgentTools } from "../../engines/pi/create.js";
|
|
7
|
-
import { reportModuleLoadFailures } from "../../
|
|
7
|
+
import { reportModuleLoadFailures } from "../../log.js";
|
|
8
8
|
import { turnContext } from "../../engines/pi/tool-context.js";
|
|
9
9
|
import { failStartup, failUsage, placementOrExit } from "../fail.js";
|
|
10
10
|
export async function runTool(name, argsJson, dirArg) {
|
|
@@ -14,10 +14,10 @@ export async function runTool(name, argsJson, dirArg) {
|
|
|
14
14
|
const { agentDir, workspace } = placementOrExit(resolve(dirArg));
|
|
15
15
|
loadDotEnv(agentDir); // a tool may read a key from .env
|
|
16
16
|
const { config } = await loadConfig(agentDir).catch(failStartup);
|
|
17
|
-
// The same tool set dev/start mount (
|
|
17
|
+
// The same tool set dev/start mount (all coding tools + config.tools + discovered, deduped), so the runner
|
|
18
18
|
// exercises exactly what gets served — a shadowed tool is surfaced, not silently run. Resolve the
|
|
19
19
|
// placement like the openers, so `fastagent tool` finds the SAME tools/ as dev/start.
|
|
20
|
-
const { tools, toolCollisions, toolFailures } = await resolveAgentTools(config, agentDir).catch(failStartup);
|
|
20
|
+
const { tools, toolCollisions, toolFailures } = await resolveAgentTools(config, agentDir, workspace).catch(failStartup);
|
|
21
21
|
for (const c of toolCollisions) {
|
|
22
22
|
console.error(`[fastagent] warn: tool "${c.name}" (${c.source}) is shadowed by a default/config tool — not mounted`);
|
|
23
23
|
}
|
|
@@ -26,10 +26,8 @@ export async function runTool(name, argsJson, dirArg) {
|
|
|
26
26
|
if (!tool) {
|
|
27
27
|
failStartup(new Error(`unknown tool "${name}". available: ${tools.map((t) => t.name).join(", ") || "(none)"}`));
|
|
28
28
|
}
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
// (AsyncLocalStorage), and pi's default coding tools take the ExecutionEnv from the harness's TOOL
|
|
32
|
-
// context — which no harness supplies here, so this stands in for it, rooted at the same workspace.
|
|
29
|
+
// Authored tools read cwd from turnContext; coding tools are already rooted at the workspace. Keep
|
|
30
|
+
// the fifth-argument env for lower-level MountedTools that explicitly consume it.
|
|
33
31
|
const env = new NodeExecutionEnv({ cwd: workspace });
|
|
34
32
|
const result = await turnContext
|
|
35
33
|
.run({ cwd: workspace }, () => tool.execute(`cli-${name}`, args, undefined, undefined, { env }))
|
package/dist/cli/program.js
CHANGED
|
@@ -171,7 +171,7 @@ const tool = {
|
|
|
171
171
|
DIR_ARG,
|
|
172
172
|
],
|
|
173
173
|
examples: [{ cmd: `fastagent tool add '{"a":2,"b":3}'` }],
|
|
174
|
-
notes: "Mounts the same tool set dev/start serve (
|
|
174
|
+
notes: "Mounts the same tool set dev/start serve (all coding tools + config.tools + discovered tools/, " +
|
|
175
175
|
"deduped), so a shadowed or broken tool is surfaced here exactly as it would be when serving.",
|
|
176
176
|
run: async (args) => (await import("./commands/tool.js")).runTool(args[0], args[1], args[2]),
|
|
177
177
|
};
|
package/dist/cli/serve.d.ts
CHANGED
|
@@ -1,24 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
3
|
-
import { type Routes } from "../host/node.ts";
|
|
4
|
-
import type { LoadedSchedule } from "../schedule/schedule.ts";
|
|
5
|
-
import type { SessionControl } from "../session.ts";
|
|
6
|
-
export interface ServingSurface {
|
|
7
|
-
routes: Routes;
|
|
8
|
-
longConnections: LoadedLongConnectionChannel[];
|
|
9
|
-
/** Route-channel basenames; the tunnel registers only this subset. */
|
|
10
|
-
routeChannels: string[];
|
|
11
|
-
builtinInvoke: boolean;
|
|
12
|
-
/** Marks the built-in health route ready after every long-connection channel first connects. */
|
|
13
|
-
markReady(): void;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* The surface this deployment serves: default `GET /health` plus discovered channels, or the default
|
|
17
|
-
* POST `/invoke` only when neither a route nor a long-connection channel was declared.
|
|
18
|
-
*/
|
|
19
|
-
export declare function routesFor(agentDir: string, agent: Agent, stateRoot: string, control?: SessionControl, options?: {
|
|
20
|
-
builtinInvoke?: boolean;
|
|
21
|
-
}): Promise<ServingSurface>;
|
|
1
|
+
import type { ChannelHandler } from "../channel.ts";
|
|
2
|
+
import type { AgentService } from "../service.ts";
|
|
22
3
|
/**
|
|
23
4
|
* Mount the session control plane (`/control/*`) when the agent enabled it
|
|
24
5
|
* (`config.sessionControl`): merge the bearer-authenticated routes and return an announcer that
|
|
@@ -29,31 +10,6 @@ export declare function routesFor(agentDir: string, agent: Agent, stateRoot: str
|
|
|
29
10
|
* (routesFor): `sessionControl` is an explicit opt-in, so declaring both is a configuration error,
|
|
30
11
|
* and silently shadowing either side would serve a surface the author didn't write.
|
|
31
12
|
*/
|
|
32
|
-
export declare function mountSessionControl(routes: Routes, control: SessionControl | undefined, stateRoot: string, options?: {
|
|
33
|
-
tunnel?: boolean;
|
|
34
|
-
agent?: Agent;
|
|
35
|
-
host?: string;
|
|
36
|
-
}): {
|
|
37
|
-
routes: Routes;
|
|
38
|
-
announce: (boundPort: number) => void;
|
|
39
|
-
};
|
|
40
|
-
/**
|
|
41
|
-
* Mount the AgentCore Runtime adapter (`POST /invocations` + `GET /ping`) over the serving routes —
|
|
42
|
-
* the deployed container's ONLY reachable surface (channels/agentcore.ts). Wired by `start` when
|
|
43
|
-
* `FASTAGENT_AGENTCORE=1` (set by the generated deploy artifacts, never by hand). A channel colliding
|
|
44
|
-
* on either path fails startup, same disposition as the control-plane mount: the adapter's paths are
|
|
45
|
-
* the platform's contract, so a channel shadowing them would silently unserve the whole deployment.
|
|
46
|
-
*/
|
|
47
|
-
export declare function mountAgentcore(routes: Routes, options: {
|
|
48
|
-
agent: Agent;
|
|
49
|
-
stateRoot: string;
|
|
50
|
-
schedules: LoadedSchedule[];
|
|
51
|
-
onStateReady?: () => void;
|
|
52
|
-
/** The serving path's LAZY channel surface: constructed by the adapter on the first envelope
|
|
53
|
-
* AFTER the state-snapshot restore, never at boot (channels/agentcore.ts). When absent,
|
|
54
|
-
* `routes` is the dispatch target — for wirings whose state root is already authoritative. */
|
|
55
|
-
lazyChannels?: () => Promise<Routes>;
|
|
56
|
-
}): Routes;
|
|
57
13
|
/**
|
|
58
14
|
* Refuse `--tunnel` with a bind that cloudflared cannot reach: it dials the NAME `localhost:<port>`
|
|
59
15
|
* (the dev supervisor's tunnel too), so anything outside `127.0.0.1`/`::1`/wildcard — including a
|
|
@@ -73,24 +29,29 @@ export declare function assertTunnelBindable(host: string | undefined, tunnel: b
|
|
|
73
29
|
* A wildcard bind is every interface, and naming one address there would understate it — but the curl
|
|
74
30
|
* still needs one to dial, which is what `clientHost` gives (loopback for a wildcard, itself otherwise).
|
|
75
31
|
*/
|
|
32
|
+
/**
|
|
33
|
+
* The "we are serving" report: the supervisor message `dev`'s watcher waits for, the addresses, and
|
|
34
|
+
* what mounted. One function because both commands must say the same thing at the same moment —
|
|
35
|
+
* after readiness, never at socket bind.
|
|
36
|
+
*/
|
|
37
|
+
export declare function reportServing(service: AgentService, host: string | undefined, boundPort: number): void;
|
|
76
38
|
export declare function readyAddressLines(host: string | undefined, boundPort: number, builtinInvoke: boolean): string[];
|
|
77
39
|
/**
|
|
78
40
|
* Bind HTTP, open long-connection channels, and report ready only when both forms are usable. Each
|
|
79
41
|
* adapter owns reconnects; a terminal close rejects `closed` and fails the process visibly. Abort is
|
|
80
42
|
* the sole clean-shutdown command. `host` unset binds all interfaces.
|
|
81
43
|
*/
|
|
82
|
-
|
|
44
|
+
/** What the CLI gives a service to stop in, and the hard exit that follows it. The order matters:
|
|
45
|
+
* a forced exit before the service answers would report a clean shutdown over a stuck channel. */
|
|
46
|
+
export declare const SHUTDOWN_GRACE_MS = 800;
|
|
47
|
+
export declare function serve(handler: ChannelHandler, bind: {
|
|
83
48
|
port: number;
|
|
84
49
|
host?: string;
|
|
85
|
-
},
|
|
50
|
+
}, hooks?: {
|
|
51
|
+
/** Awaited before anything is reported ready — see the listening handler. */
|
|
52
|
+
ready?: Promise<void>;
|
|
53
|
+
onListening?: (boundPort: number) => void;
|
|
54
|
+
onShutdown?: () => Promise<void> | void;
|
|
55
|
+
}): void;
|
|
86
56
|
/** Start a Cloudflare tunnel for route channels only. */
|
|
87
57
|
export declare function maybeTunnel(agentDir: string, routeChannels: string[], boundPort: number, tunnel: boolean, stateRoot?: string): void;
|
|
88
|
-
/**
|
|
89
|
-
* Load and start the agent's `schedules/` — a time-trigger firing the agent on each cron. Starts iff
|
|
90
|
-
* there are static schedules OR `selfSchedule` is on. Best-effort stop on process signals. Returns the
|
|
91
|
-
* loaded schedules so a serving surface that needs them (the AgentCore adapter's fire binding) shares
|
|
92
|
-
* ONE load instead of re-discovering. `externalClock` (AgentCore) arms no resident cron timers.
|
|
93
|
-
*/
|
|
94
|
-
export declare function startSchedules(agentDir: string, agent: Agent, stateRoot: string, selfSchedule: boolean, options?: {
|
|
95
|
-
externalClock?: boolean;
|
|
96
|
-
}): Promise<LoadedSchedule[]>;
|