@fastagent-sh/fastagent 0.21.0 → 0.22.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 +9 -12
- package/dist/agent.d.ts +24 -37
- package/dist/agent.js +7 -15
- package/dist/atomic-write.d.ts +13 -17
- package/dist/atomic-write.js +18 -29
- package/dist/bind.d.ts +12 -22
- package/dist/bind.js +18 -27
- package/dist/channel.d.ts +11 -33
- package/dist/channels/agentcore-limits.d.ts +2 -13
- package/dist/channels/agentcore-limits.js +2 -13
- package/dist/channels/agentcore-protocol.d.ts +67 -58
- package/dist/channels/agentcore-protocol.js +23 -15
- package/dist/channels/agentcore-service.d.ts +19 -33
- package/dist/channels/agentcore-service.js +176 -59
- package/dist/channels/agentcore.d.ts +39 -33
- package/dist/channels/agentcore.js +90 -224
- package/dist/channels/body.d.ts +15 -2
- package/dist/channels/body.js +24 -2
- package/dist/channels/busy.d.ts +1 -21
- package/dist/channels/busy.js +2 -39
- package/dist/channels/control.d.ts +17 -62
- package/dist/channels/control.js +74 -182
- package/dist/channels/define-channel.d.ts +39 -0
- package/dist/channels/define-channel.js +9 -0
- package/dist/channels/discover.d.ts +10 -31
- package/dist/channels/discover.js +37 -31
- package/dist/channels/feishu/bootstrap-token.d.ts +1 -8
- package/dist/channels/feishu/bootstrap-token.js +7 -23
- package/dist/channels/feishu/card.d.ts +14 -28
- package/dist/channels/feishu/card.js +16 -30
- package/dist/channels/feishu/cloud.d.ts +1 -5
- package/dist/channels/feishu/context-buffer.d.ts +4 -23
- package/dist/channels/feishu/context-buffer.js +8 -31
- package/dist/channels/feishu/crypto.d.ts +10 -5
- package/dist/channels/feishu/crypto.js +12 -19
- package/dist/channels/feishu/feishu-api.d.ts +2 -1
- package/dist/channels/feishu/feishu-api.js +5 -4
- package/dist/channels/feishu/feishu.d.ts +4 -10
- package/dist/channels/feishu/feishu.js +113 -227
- package/dist/channels/feishu/invoke-turn.d.ts +5 -4
- package/dist/channels/feishu/invoke-turn.js +36 -54
- package/dist/channels/feishu/model.d.ts +4 -21
- package/dist/channels/feishu/model.js +1 -8
- package/dist/channels/feishu/normalize.d.ts +2 -10
- package/dist/channels/feishu/normalize.js +7 -42
- package/dist/channels/feishu/parse.d.ts +9 -29
- package/dist/channels/feishu/parse.js +8 -26
- package/dist/channels/feishu/preview.d.ts +12 -14
- package/dist/channels/feishu/preview.js +108 -207
- package/dist/channels/feishu/register-app.d.ts +8 -23
- package/dist/channels/feishu/register-app.js +7 -20
- package/dist/channels/feishu/register-webhook.d.ts +2 -9
- package/dist/channels/feishu/register-webhook.js +9 -33
- package/dist/channels/feishu/scaffold/channel.ts +27 -19
- package/dist/channels/feishu/scaffold/channel.websocket.ts +31 -0
- package/dist/channels/feishu/setup-mode.d.ts +11 -36
- package/dist/channels/feishu/setup-mode.js +7 -26
- package/dist/channels/feishu/ws-ingress.d.ts +1 -2
- package/dist/channels/feishu/ws-ingress.js +6 -8
- package/dist/channels/http.d.ts +15 -15
- package/dist/channels/http.js +19 -9
- package/dist/channels/kit/attachment-path.d.ts +4 -5
- package/dist/channels/kit/attachment-path.js +10 -34
- package/dist/channels/kit/context-buffer.d.ts +14 -21
- package/dist/channels/kit/context-buffer.js +25 -38
- package/dist/channels/kit/delivery.d.ts +35 -0
- package/dist/channels/kit/delivery.js +129 -0
- package/dist/channels/kit/event-stream.d.ts +5 -0
- package/dist/channels/kit/event-stream.js +29 -0
- package/dist/channels/kit/invoke-turn-kit.d.ts +53 -26
- package/dist/channels/kit/invoke-turn-kit.js +89 -32
- package/dist/channels/kit/preview-kit.d.ts +18 -72
- package/dist/channels/kit/preview-kit.js +22 -88
- package/dist/channels/kit/signature.d.ts +3 -9
- package/dist/channels/kit/signature.js +3 -9
- package/dist/channels/kit/state.d.ts +1 -2
- package/dist/channels/kit/state.js +5 -14
- package/dist/channels/kit/stop-command.d.ts +1 -2
- package/dist/channels/kit/stop-command.js +6 -9
- package/dist/channels/kit/tasks.d.ts +1 -1
- package/dist/channels/kit/tasks.js +8 -21
- package/dist/channels/kit/text.d.ts +2 -16
- package/dist/channels/kit/text.js +23 -31
- package/dist/channels/kit/thread-participants.d.ts +4 -17
- package/dist/channels/kit/thread-participants.js +8 -55
- package/dist/channels/kit/transport.d.ts +26 -0
- package/dist/channels/kit/transport.js +20 -0
- package/dist/channels/kit/turn-queue.d.ts +7 -11
- package/dist/channels/kit/turn-queue.js +21 -39
- package/dist/channels/kit/turn-runner.d.ts +32 -18
- package/dist/channels/kit/turn-runner.js +98 -53
- package/dist/channels/kit/turn-store.d.ts +32 -32
- package/dist/channels/kit/turn-store.js +45 -88
- package/dist/channels/lark/lark.d.ts +1 -5
- package/dist/channels/lark/onboard.d.ts +3 -12
- package/dist/channels/lark/onboard.js +3 -13
- package/dist/channels/lark/scaffold/channel.ts +27 -19
- package/dist/channels/lark/scaffold/channel.websocket.ts +31 -0
- package/dist/channels/registration.d.ts +9 -35
- package/dist/channels/registration.js +6 -37
- package/dist/channels/secret.js +2 -5
- package/dist/channels/serve.d.ts +47 -44
- package/dist/channels/serve.js +165 -101
- package/dist/channels/slack/config-api.d.ts +4 -27
- package/dist/channels/slack/config-api.js +5 -34
- package/dist/channels/slack/context-buffer.d.ts +2 -3
- package/dist/channels/slack/context-buffer.js +5 -5
- package/dist/channels/slack/invoke-turn.d.ts +3 -1
- package/dist/channels/slack/invoke-turn.js +25 -34
- package/dist/channels/slack/manifest.js +1 -3
- package/dist/channels/slack/model.d.ts +1 -2
- package/dist/channels/slack/model.js +1 -1
- package/dist/channels/slack/onboard.d.ts +4 -3
- package/dist/channels/slack/onboard.js +8 -11
- package/dist/channels/slack/onboarding-state.d.ts +3 -5
- package/dist/channels/slack/onboarding-state.js +9 -6
- package/dist/channels/slack/parse.d.ts +4 -13
- package/dist/channels/slack/parse.js +7 -28
- package/dist/channels/slack/preview.d.ts +12 -2
- package/dist/channels/slack/preview.js +292 -269
- package/dist/channels/slack/reaction.d.ts +11 -3
- package/dist/channels/slack/reaction.js +19 -8
- package/dist/channels/slack/register-webhook.js +4 -7
- package/dist/channels/slack/scaffold/channel.ts +20 -13
- package/dist/channels/slack/scaffold/slack-send.ts +2 -2
- package/dist/channels/slack/setup-server.d.ts +1 -5
- package/dist/channels/slack/setup-server.js +1 -5
- package/dist/channels/slack/shared-api.d.ts +1 -4
- package/dist/channels/slack/shared-api.js +2 -13
- package/dist/channels/slack/slack-api.d.ts +2 -1
- package/dist/channels/slack/slack-api.js +6 -4
- package/dist/channels/slack/slack.d.ts +11 -14
- package/dist/channels/slack/slack.js +121 -122
- package/dist/channels/sse.d.ts +1 -1
- package/dist/channels/sse.js +1 -1
- package/dist/channels/telegram/context-buffer.d.ts +7 -22
- package/dist/channels/telegram/context-buffer.js +6 -23
- package/dist/channels/telegram/invoke-turn.d.ts +7 -7
- package/dist/channels/telegram/invoke-turn.js +24 -43
- package/dist/channels/telegram/parse.d.ts +24 -51
- package/dist/channels/telegram/parse.js +32 -84
- package/dist/channels/telegram/preview.d.ts +10 -1
- package/dist/channels/telegram/preview.js +79 -100
- package/dist/channels/telegram/register-webhook.js +5 -23
- package/dist/channels/telegram/scaffold/channel.ts +25 -18
- package/dist/channels/telegram/scaffold/telegram-send.ts +6 -4
- package/dist/channels/telegram/telegram-api.d.ts +4 -3
- package/dist/channels/telegram/telegram-api.js +9 -7
- package/dist/channels/telegram/telegram.d.ts +4 -18
- package/dist/channels/telegram/telegram.js +38 -94
- package/dist/channels/telegram/turn-store.d.ts +11 -14
- package/dist/channels/telegram/turn-store.js +8 -6
- package/dist/channels/wait-health.d.ts +4 -6
- package/dist/channels/wait-health.js +10 -14
- package/dist/cli/add-feishu.d.ts +2 -12
- package/dist/cli/add-feishu.js +24 -71
- package/dist/cli/add-slack.d.ts +5 -3
- package/dist/cli/add-slack.js +53 -76
- package/dist/cli/auth-view.d.ts +2 -16
- package/dist/cli/auth-view.js +2 -16
- package/dist/cli/commands/add.js +25 -43
- package/dist/cli/commands/chat.d.ts +0 -1
- package/dist/cli/commands/chat.js +5 -6
- package/dist/cli/commands/deploy/agentcore.js +60 -65
- package/dist/cli/commands/deploy/docker.js +50 -23
- package/dist/cli/commands/deploy/fly.js +23 -61
- package/dist/cli/commands/deploy/railway.js +23 -18
- package/dist/cli/commands/deploy/shared.d.ts +38 -57
- package/dist/cli/commands/deploy/shared.js +40 -59
- package/dist/cli/commands/deploy.d.ts +10 -27
- package/dist/cli/commands/deploy.js +38 -60
- package/dist/cli/commands/destroy.d.ts +4 -0
- package/dist/cli/commands/destroy.js +56 -0
- package/dist/cli/commands/dev.d.ts +2 -1
- package/dist/cli/commands/dev.js +20 -23
- package/dist/cli/commands/info.d.ts +0 -2
- package/dist/cli/commands/info.js +83 -49
- package/dist/cli/commands/init.d.ts +1 -2
- package/dist/cli/commands/init.js +16 -55
- package/dist/cli/commands/invoke.d.ts +0 -1
- package/dist/cli/commands/invoke.js +5 -7
- package/dist/cli/commands/login.d.ts +2 -1
- package/dist/cli/commands/login.js +33 -38
- package/dist/cli/commands/logs.js +3 -4
- package/dist/cli/commands/models.js +1 -5
- package/dist/cli/commands/routine-run.d.ts +6 -0
- package/dist/cli/commands/routine-run.js +47 -0
- package/dist/cli/commands/routine.d.ts +25 -0
- package/dist/cli/commands/routine.js +122 -0
- package/dist/cli/commands/start.d.ts +31 -3
- package/dist/cli/commands/start.js +131 -81
- package/dist/cli/commands/tool.js +26 -12
- package/dist/cli/fail.d.ts +13 -23
- package/dist/cli/fail.js +20 -23
- package/dist/cli/invoke-stream.d.ts +1 -8
- package/dist/cli/kernel.d.ts +6 -38
- package/dist/cli/kernel.js +14 -77
- package/dist/cli/models-view.d.ts +1 -9
- package/dist/cli/models-view.js +11 -22
- package/dist/cli/program.d.ts +5 -6
- package/dist/cli/program.js +120 -157
- package/dist/cli/serve.d.ts +57 -41
- package/dist/cli/serve.js +94 -121
- package/dist/cli/shared.d.ts +15 -61
- package/dist/cli/shared.js +55 -181
- package/dist/cli.js +1 -8
- package/dist/collect.d.ts +6 -0
- package/dist/collect.js +6 -0
- package/dist/core.d.ts +4 -1
- package/dist/core.js +9 -7
- package/dist/declared-secrets.d.ts +55 -0
- package/dist/declared-secrets.js +88 -0
- package/dist/deploy/agentcore/aws-cli.d.ts +91 -0
- package/dist/deploy/agentcore/aws-cli.js +64 -0
- package/dist/deploy/agentcore/destroy.d.ts +51 -0
- package/dist/deploy/agentcore/destroy.js +273 -0
- package/dist/deploy/agentcore/forwarder.js +28 -79
- package/dist/deploy/agentcore/logs.d.ts +2 -18
- package/dist/deploy/agentcore/logs.js +27 -51
- package/dist/deploy/agentcore/plan.d.ts +85 -105
- package/dist/deploy/agentcore/plan.js +152 -314
- package/dist/deploy/agentcore/run.d.ts +28 -28
- package/dist/deploy/agentcore/run.js +227 -306
- package/dist/deploy/agentcore/zip.d.ts +2 -15
- package/dist/deploy/agentcore/zip.js +3 -17
- package/dist/deploy/build-context.d.ts +21 -0
- package/dist/deploy/build-context.js +137 -0
- package/dist/deploy/channel-ingress.d.ts +26 -39
- package/dist/deploy/channel-ingress.js +57 -28
- package/dist/deploy/container.d.ts +20 -34
- package/dist/deploy/container.js +49 -100
- package/dist/deploy/docker/plan.d.ts +12 -11
- package/dist/deploy/docker/plan.js +43 -24
- package/dist/deploy/docker/run.d.ts +22 -25
- package/dist/deploy/docker/run.js +39 -37
- package/dist/deploy/fly/plan.d.ts +15 -44
- package/dist/deploy/fly/plan.js +41 -73
- package/dist/deploy/fly/run.d.ts +16 -51
- package/dist/deploy/fly/run.js +42 -95
- package/dist/deploy/hosts.d.ts +24 -3
- package/dist/deploy/hosts.js +24 -3
- package/dist/deploy/preflight.d.ts +47 -41
- package/dist/deploy/preflight.js +282 -383
- package/dist/deploy/railway/plan.d.ts +16 -42
- package/dist/deploy/railway/plan.js +42 -60
- package/dist/deploy/railway/run.d.ts +30 -68
- package/dist/deploy/railway/run.js +86 -100
- package/dist/deploy/registration-gate.d.ts +6 -13
- package/dist/deploy/residency.d.ts +37 -0
- package/dist/deploy/residency.js +24 -0
- package/dist/deploy/runner.d.ts +10 -9
- package/dist/deploy/runner.js +7 -18
- package/dist/deploy/secrets.d.ts +40 -41
- package/dist/deploy/secrets.js +117 -103
- package/dist/deploy/workspace.d.ts +50 -0
- package/dist/deploy/workspace.js +197 -0
- package/dist/dev-supervisor.d.ts +1 -9
- package/dist/dev-supervisor.js +21 -64
- package/dist/effect-port.d.ts +50 -0
- package/dist/effect-port.js +77 -0
- package/dist/engines/pi/agent-session-factory.d.ts +50 -69
- package/dist/engines/pi/agent-session-factory.js +249 -146
- package/dist/engines/pi/auth.d.ts +15 -11
- package/dist/engines/pi/auth.js +96 -99
- package/dist/engines/pi/chat.d.ts +1 -5
- package/dist/engines/pi/chat.js +2 -14
- package/dist/engines/pi/config.d.ts +53 -51
- package/dist/engines/pi/config.js +83 -92
- package/dist/engines/pi/create.d.ts +60 -75
- package/dist/engines/pi/create.js +108 -141
- package/dist/engines/pi/definition.d.ts +14 -58
- package/dist/engines/pi/definition.js +21 -85
- package/dist/engines/pi/invoke-session.d.ts +5 -25
- package/dist/engines/pi/invoke-session.js +209 -244
- package/dist/engines/pi/login.d.ts +95 -35
- package/dist/engines/pi/login.js +259 -107
- package/dist/engines/pi/machine.d.ts +31 -0
- package/dist/engines/pi/machine.js +106 -0
- package/dist/engines/pi/models.d.ts +70 -89
- package/dist/engines/pi/models.js +188 -81
- package/dist/engines/pi/open.d.ts +65 -53
- package/dist/engines/pi/open.js +129 -69
- package/dist/engines/pi/report.d.ts +3 -12
- package/dist/engines/pi/report.js +2 -16
- package/dist/engines/pi/search-tools.d.ts +1 -9
- package/dist/engines/pi/search-tools.js +26 -57
- package/dist/engines/pi/service.d.ts +2 -16
- package/dist/engines/pi/service.js +2 -16
- package/dist/engines/pi/session-builder.d.ts +5 -9
- package/dist/engines/pi/session-builder.js +44 -82
- package/dist/engines/pi/session-control.js +286 -269
- package/dist/engines/pi/session-effects.d.ts +14 -0
- package/dist/engines/pi/session-effects.js +30 -0
- package/dist/engines/pi/session-inheritance.d.ts +9 -18
- package/dist/engines/pi/session-inheritance.js +103 -160
- package/dist/engines/pi/session-markers.d.ts +31 -30
- package/dist/engines/pi/session-markers.js +26 -25
- package/dist/engines/pi/session-settings.d.ts +6 -22
- package/dist/engines/pi/session-settings.js +10 -21
- package/dist/engines/pi/session-store.d.ts +26 -92
- package/dist/engines/pi/session-store.js +96 -310
- package/dist/engines/pi/tool-context.d.ts +17 -45
- package/dist/engines/pi/tool-context.js +7 -26
- package/dist/engines/pi/tool.d.ts +45 -36
- package/dist/engines/pi/tool.js +43 -57
- package/dist/engines/pi/turn-kit.d.ts +14 -52
- package/dist/engines/pi/turn-kit.js +18 -67
- package/dist/engines/pi/wake-tool.d.ts +2 -10
- package/dist/engines/pi/wake-tool.js +7 -27
- package/dist/env.d.ts +27 -28
- package/dist/env.js +45 -50
- package/dist/index.js +0 -2
- package/dist/lark.d.ts +1 -2
- package/dist/lark.js +1 -2
- package/dist/loader.d.ts +14 -55
- package/dist/loader.js +24 -43
- package/dist/log.d.ts +2 -12
- package/dist/log.js +3 -24
- package/dist/node.d.ts +2 -15
- package/dist/node.js +2 -18
- package/dist/observe.d.ts +2 -8
- package/dist/open-url.d.ts +1 -1
- package/dist/open-url.js +1 -1
- package/dist/paths.d.ts +70 -134
- package/dist/paths.js +165 -232
- package/dist/pi.d.ts +4 -6
- package/dist/pi.js +3 -3
- package/dist/proxy.d.ts +16 -6
- package/dist/proxy.js +52 -16
- package/dist/runtime.d.ts +18 -12
- package/dist/runtime.js +18 -11
- package/dist/scaffold/add-channel.d.ts +14 -31
- package/dist/scaffold/add-channel.js +48 -112
- package/dist/scaffold/init.d.ts +9 -31
- package/dist/scaffold/init.js +45 -138
- package/dist/scaffold/templates/env.example +6 -4
- package/dist/scaffold/templates/fastagent.config.ts +36 -0
- package/dist/scaffold/templates.d.ts +3 -3
- package/dist/scaffold/templates.js +5 -8
- package/dist/scaffold/vendor-skill.d.ts +2 -5
- package/dist/scaffold/vendor-skill.js +19 -29
- package/dist/schedule/cron.d.ts +9 -5
- package/dist/schedule/cron.js +9 -11
- package/dist/schedule/discover.d.ts +12 -12
- package/dist/schedule/discover.js +43 -34
- package/dist/schedule/routine.d.ts +43 -0
- package/dist/schedule/routine.js +32 -0
- package/dist/schedule/run.d.ts +55 -0
- package/dist/schedule/run.js +146 -0
- package/dist/schedule/scheduler.d.ts +44 -55
- package/dist/schedule/scheduler.js +291 -265
- package/dist/schedule/state.d.ts +105 -10
- package/dist/schedule/state.js +293 -19
- package/dist/schedule/wake-alarm.d.ts +10 -23
- package/dist/schedule/wake-alarm.js +91 -121
- package/dist/schedule/wakeups.d.ts +23 -39
- package/dist/schedule/wakeups.js +33 -75
- package/dist/secrets-gate.d.ts +32 -0
- package/dist/secrets-gate.js +33 -0
- package/dist/service.d.ts +137 -98
- package/dist/service.js +250 -252
- package/dist/session-remote.d.ts +33 -44
- package/dist/session-remote.js +203 -192
- package/dist/session.d.ts +153 -228
- package/dist/session.js +33 -55
- package/dist/tunnel.d.ts +8 -36
- package/dist/tunnel.js +24 -65
- package/dist/version.d.ts +2 -2
- package/dist/version.js +2 -2
- package/package.json +10 -16
- package/dist/channels/agentcore-state.d.ts +0 -77
- package/dist/channels/agentcore-state.js +0 -276
- package/dist/channels/github/github.d.ts +0 -31
- package/dist/channels/github/github.js +0 -89
- package/dist/channels/github/scaffold/channel.ts +0 -25
- package/dist/cli/commands/attach.d.ts +0 -108
- package/dist/cli/commands/attach.js +0 -637
- package/dist/cli/commands/fire.d.ts +0 -7
- package/dist/cli/commands/fire.js +0 -38
- package/dist/cli/commands/schedule.d.ts +0 -12
- package/dist/cli/commands/schedule.js +0 -87
- package/dist/github.d.ts +0 -3
- package/dist/github.js +0 -2
- package/dist/scaffold/templates/fastagent.config.mjs +0 -23
- package/dist/schedule/audit.d.ts +0 -18
- package/dist/schedule/audit.js +0 -57
- package/dist/schedule/schedule.d.ts +0 -35
- package/dist/schedule/schedule.js +0 -23
package/README.md
CHANGED
|
@@ -16,12 +16,12 @@
|
|
|
16
16
|
<sub>— the agent harness & multi-provider LLM API under the hood</sub>
|
|
17
17
|
</p>
|
|
18
18
|
|
|
19
|
-
A file-defined agent directory can become a live service. FastAgent takes it out of the terminal and serves it in your Next/Astro app, Telegram,
|
|
19
|
+
A file-defined agent directory can become a live service. FastAgent takes it out of the terminal and serves it in your Next/Astro app, Telegram, Slack, Feishu, an API endpoint, or your own channel.
|
|
20
20
|
|
|
21
21
|
Leave the terminal. Become a live service.
|
|
22
22
|
|
|
23
23
|
- **Add it to your app** — one route, your auth, your database, your host.
|
|
24
|
-
- **Run it as a live service** — Telegram
|
|
24
|
+
- **Run it as a live service** — Telegram, Slack or Feishu bot, webhook handler, API endpoint, or custom channel.
|
|
25
25
|
|
|
26
26
|
FastAgent is not a new agent-authoring DSL. You bring the existing definition and project layout; FastAgent provides the serving runtime and adapters around it.
|
|
27
27
|
|
|
@@ -37,8 +37,8 @@ FastAgent is the missing bridge from local agent directory to live service.
|
|
|
37
37
|
|
|
38
38
|
## Features
|
|
39
39
|
|
|
40
|
-
- **Vibe first — a
|
|
41
|
-
- **Channels.** Serve the same agent as a
|
|
40
|
+
- **Vibe first — add a `fastagent/` folder to any project.** The agent is that folder; the project around it is what it works on, and the project's `AGENTS.md` is its context. Markdown instructions, reusable skills, and TypeScript tools stay as files you inspect, edit, and commit — no new DSL, no framework rewrite.
|
|
41
|
+
- **Channels.** Serve the same agent as a Telegram bot, a Slack app, a Feishu or Lark bot, an HTTP/SSE endpoint, or your own adapter: verified webhooks, streaming replies, group-aware.
|
|
42
42
|
- **Models, tools & skills.** Any model provider (OpenAI, Anthropic, Google, …) via OAuth or API key; typed tools discovered from `tools/` (the filename is the name, Zod-validated); Agent Skills loaded on demand. Built on the open-source [pi](https://github.com/earendil-works/pi) harness.
|
|
43
43
|
- **App embedding — your stack, we plug in.** Mount the agent in your Next / Astro / Hono / Bun / Node route with one handler, or call `invoke` like any function from your own code — your auth, your database, your infra. FastAgent composes with your app, never owns it.
|
|
44
44
|
- **Deploy anywhere.** No application build step — the directory is the deployable unit. `fastagent deploy docker|fly|railway|agentcore` generates the container + target config and a runbook (`--run` drives it to completion). Local Docker gets user-owned Compose + durable state; optional `--tunnel` adds an ephemeral Quick Tunnel service for webhook channels; AWS Bedrock AgentCore gets a one-stack CloudFormation topology (webhooks via a forwarder Lambda, schedules via EventBridge). Durable ingress remains yours.
|
|
@@ -102,7 +102,7 @@ For production-style local serving:
|
|
|
102
102
|
fastagent start
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
-
There is no FastAgent build step: the
|
|
105
|
+
There is no FastAgent build step: the agent folder is the deployable unit.
|
|
106
106
|
|
|
107
107
|
## Embed in an app
|
|
108
108
|
|
|
@@ -150,7 +150,7 @@ const agent = createPiAgent({
|
|
|
150
150
|
| [Embedding](https://fastagent.sh/docs/embedding/) | Use FastAgent as a library inside your own app |
|
|
151
151
|
| [Channels](https://fastagent.sh/docs/channels/) | Add webhook/bot channels |
|
|
152
152
|
| [Deploy](https://fastagent.sh/docs/deploy/) | Ship the directory to Fly, Railway, or any Docker host |
|
|
153
|
-
| [
|
|
153
|
+
| [Telegram](https://fastagent.sh/docs/telegram/) / [Slack](https://fastagent.sh/docs/slack/) / [Feishu and Lark](https://fastagent.sh/docs/feishu/) | First-party channel guides |
|
|
154
154
|
| [Channel development](https://fastagent.sh/docs/channel-development/) | Build custom channel adapters |
|
|
155
155
|
| [API reference](https://fastagent.sh/docs/api-reference/) | Public TypeScript API reference |
|
|
156
156
|
| [Troubleshooting](https://fastagent.sh/docs/troubleshooting/) | Common setup/runtime issues |
|
|
@@ -181,9 +181,9 @@ you register a custom provider.
|
|
|
181
181
|
| Mounting | `createInvokeHandler`, `Routes`, `ChannelHandler` | Reference implementation, pre-1.0 |
|
|
182
182
|
| Node binding | `nodeListener`, `serveNode` (from `/node`) | The one runtime-specific piece; see below |
|
|
183
183
|
| pi assembly | `createPiAgentFromDir`, `createPiAgentFromDefinition`, `createPiAgent` | Usable now, may tighten before 1.0 |
|
|
184
|
-
| Tool/channel authoring | `defineTool`, `z`, `
|
|
184
|
+
| Tool/channel authoring | `defineTool`, `z`, `defineRoutine`, `ChannelModule` | Usable now, may tighten before 1.0 |
|
|
185
185
|
| Injection ports | `PiSessionRecordStore`, `piSessionRecordStore`, `piInMemorySessionRecordStore`, `Lease`, `Provider` | Public because options reference them |
|
|
186
|
-
| Not exported | The assembly's parts — `router`, `createControlPlane`, `loadTools`/`loadChannels`/`
|
|
186
|
+
| Not exported | The assembly's parts — `router`, `createControlPlane`, `loadTools`/`loadChannels`/`loadRoutines`, `createScheduler` — and prompt/config internals | `createAgentService` does this; no compatibility promise |
|
|
187
187
|
|
|
188
188
|
Subpath entry points (`./package.json` is also exported, for tools that read the version):
|
|
189
189
|
|
|
@@ -191,7 +191,6 @@ Subpath entry points (`./package.json` is also exported, for tools that read the
|
|
|
191
191
|
- `@fastagent-sh/fastagent/node` — the engine-neutral pieces that need a Node runtime: `mountAgentService` (the assembly), `serveNode` / `nodeListener` (the `node:http` ↔ Fetch binding);
|
|
192
192
|
- `@fastagent-sh/fastagent/session` — the engine-neutral session-control contract (types and error codes);
|
|
193
193
|
- `@fastagent-sh/fastagent/pi` — the pi reference implementation;
|
|
194
|
-
- `@fastagent-sh/fastagent/github` — GitHub webhook channel;
|
|
195
194
|
- `@fastagent-sh/fastagent/telegram` — Telegram bot channel;
|
|
196
195
|
- `@fastagent-sh/fastagent/slack` — Slack Events API bot channel;
|
|
197
196
|
- `@fastagent-sh/fastagent/feishu` — canonical Feishu bot channel (飞书, open.feishu.cn);
|
|
@@ -205,9 +204,7 @@ test/ vitest suite (faux models by default) + reusable SPEC conformance
|
|
|
205
204
|
docs/ user docs, SPEC, and maintainer design notes
|
|
206
205
|
```
|
|
207
206
|
|
|
208
|
-
|
|
209
|
-
A `packages/` workspace split is deliberately deferred until a second published artifact with
|
|
210
|
-
independent dependencies/versioning actually exists.
|
|
207
|
+
One package; subpath exports are the module boundary.
|
|
211
208
|
|
|
212
209
|
## Status
|
|
213
210
|
|
package/dist/agent.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Agent Handler protocol v0.1 — the engine-neutral contract (docs/SPEC.md). Pure types
|
|
3
|
-
*
|
|
4
|
-
* only appear under engines/).
|
|
2
|
+
* Agent Handler protocol v0.1 — the engine-neutral contract (docs/SPEC.md). Pure types: importing an engine here is
|
|
3
|
+
* forbidden (`@earendil-works/pi-*` may only appear under engines/).
|
|
5
4
|
*/
|
|
6
5
|
export type Json = null | boolean | number | string | Json[] | {
|
|
7
6
|
[k: string]: Json;
|
|
@@ -15,27 +14,25 @@ export interface Prompt {
|
|
|
15
14
|
text: string;
|
|
16
15
|
images?: ImageRef[];
|
|
17
16
|
}
|
|
18
|
-
/** Invocation scope. Core keeps only the `session` anchor; other fields are extensions (SPEC §8). */
|
|
19
17
|
export interface Scope {
|
|
20
18
|
/** Opaque session anchor: turns of the same logical conversation MUST reuse the same value. */
|
|
21
19
|
session: string;
|
|
22
|
-
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
|
|
26
|
-
* understand it ignores it entirely (the session starts empty, yesterday's behavior). */
|
|
20
|
+
/**
|
|
21
|
+
* EXTENSION (SPEC §8): the session this one branched from — a channel sets it when the place it is invoking for was
|
|
22
|
+
* born out of another place (a thread opened in a room).
|
|
23
|
+
*/
|
|
27
24
|
parentSession?: string;
|
|
28
|
-
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
|
|
25
|
+
/**
|
|
26
|
+
* EXTENSION (SPEC §8): opaque markers that MAY locate the branch point inside `parentSession` — e.g. platform
|
|
27
|
+
* message ids its transcript embeds.
|
|
28
|
+
*/
|
|
32
29
|
branchHints?: string[];
|
|
33
30
|
}
|
|
34
31
|
export type AgentEvent = {
|
|
35
32
|
type: "text";
|
|
36
33
|
delta: string;
|
|
37
34
|
}
|
|
38
|
-
/** Model reasoning, streamed live.
|
|
35
|
+
/** Model reasoning, streamed live. */
|
|
39
36
|
| {
|
|
40
37
|
type: "thinking";
|
|
41
38
|
delta: string;
|
|
@@ -50,10 +47,10 @@ export type AgentEvent = {
|
|
|
50
47
|
isError: boolean;
|
|
51
48
|
content: Json;
|
|
52
49
|
}
|
|
53
|
-
/**
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
|
|
50
|
+
/**
|
|
51
|
+
* Advisory, non-terminal (engines MAY emit it): a transient internal failure scheduled a retry with backoff — the
|
|
52
|
+
* turn is still alive.
|
|
53
|
+
*/
|
|
57
54
|
| {
|
|
58
55
|
type: "retrying";
|
|
59
56
|
attempt: number;
|
|
@@ -61,14 +58,12 @@ export type AgentEvent = {
|
|
|
61
58
|
delayMs: number;
|
|
62
59
|
reason: string;
|
|
63
60
|
}
|
|
64
|
-
/** Terminal: success.
|
|
61
|
+
/** Terminal: success. */
|
|
65
62
|
| {
|
|
66
63
|
type: "completed";
|
|
67
64
|
data?: Json;
|
|
68
65
|
}
|
|
69
|
-
/** Terminal: failure.
|
|
70
|
-
* optional machine-readable failure subdivision (SPEC §8) — a stable discriminator a consumer can branch
|
|
71
|
-
* on without parsing `details` (human-facing prose). */
|
|
66
|
+
/** Terminal: failure. */
|
|
72
67
|
| {
|
|
73
68
|
type: "failed";
|
|
74
69
|
details: string;
|
|
@@ -76,27 +71,19 @@ export type AgentEvent = {
|
|
|
76
71
|
code?: string;
|
|
77
72
|
};
|
|
78
73
|
/**
|
|
79
|
-
* The `failed.code` (SPEC §8 failure subdivision) the reference engine sets when a turn is rejected because
|
|
80
|
-
*
|
|
81
|
-
* It lives in the contract (a code VALUE, not an engine import) so a neutral consumer — the scheduler,
|
|
82
|
-
* which re-fires a busy wake-up but not one whose turn may have run side effects — branches on it without
|
|
83
|
-
* text-matching `details` or reaching into the engine. An internal fastagent seam (engine ↔ scheduler),
|
|
84
|
-
* not a public cross-engine mandate.
|
|
74
|
+
* The `failed.code` (SPEC §8 failure subdivision) the reference engine sets when a turn is rejected because the
|
|
75
|
+
* session is BUSY.
|
|
85
76
|
*/
|
|
86
77
|
export declare const SESSION_BUSY_CODE = "session_busy";
|
|
87
78
|
/**
|
|
88
|
-
* The `failed.code` set when a run was DELIBERATELY stopped
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
* outcome — durable turn-intent cleanup included — so a deliberate stop is never replayed as a
|
|
92
|
-
* fresh turn on restart. Exported as a constant for the same reason as {@link SESSION_BUSY_CODE}:
|
|
93
|
-
* a consumer that must branch on it should not string-match.
|
|
79
|
+
* The `failed.code` set when a run was DELIBERATELY stopped. A channel MAY render cancellation distinctly from an
|
|
80
|
+
* error, and MUST treat it as a settled outcome — durable turn-intent cleanup included — so a deliberate stop is
|
|
81
|
+
* never replayed as a fresh turn on restart.
|
|
94
82
|
*/
|
|
95
83
|
export declare const ABORTED_CODE = "aborted";
|
|
96
84
|
/**
|
|
97
|
-
* One turn = one invoke, returning a single async event stream. The stream MUST terminate with
|
|
98
|
-
*
|
|
99
|
-
* AsyncIterable producer that implements this conforms (interface, not base class).
|
|
85
|
+
* One turn = one invoke, returning a single async event stream. The stream MUST terminate with exactly one of
|
|
86
|
+
* `completed` / `failed`, or be cancelled by the caller (no terminal event).
|
|
100
87
|
*/
|
|
101
88
|
export interface Agent {
|
|
102
89
|
invoke(scope: Scope, prompt: Prompt): AsyncIterable<AgentEvent>;
|
package/dist/agent.js
CHANGED
|
@@ -1,23 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Agent Handler protocol v0.1 — the engine-neutral contract (docs/SPEC.md). Pure types
|
|
3
|
-
*
|
|
4
|
-
* only appear under engines/).
|
|
2
|
+
* Agent Handler protocol v0.1 — the engine-neutral contract (docs/SPEC.md). Pure types: importing an engine here is
|
|
3
|
+
* forbidden (`@earendil-works/pi-*` may only appear under engines/).
|
|
5
4
|
*/
|
|
6
5
|
/**
|
|
7
|
-
* The `failed.code` (SPEC §8 failure subdivision) the reference engine sets when a turn is rejected because
|
|
8
|
-
*
|
|
9
|
-
* It lives in the contract (a code VALUE, not an engine import) so a neutral consumer — the scheduler,
|
|
10
|
-
* which re-fires a busy wake-up but not one whose turn may have run side effects — branches on it without
|
|
11
|
-
* text-matching `details` or reaching into the engine. An internal fastagent seam (engine ↔ scheduler),
|
|
12
|
-
* not a public cross-engine mandate.
|
|
6
|
+
* The `failed.code` (SPEC §8 failure subdivision) the reference engine sets when a turn is rejected because the
|
|
7
|
+
* session is BUSY.
|
|
13
8
|
*/
|
|
14
9
|
export const SESSION_BUSY_CODE = "session_busy";
|
|
15
10
|
/**
|
|
16
|
-
* The `failed.code` set when a run was DELIBERATELY stopped
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* outcome — durable turn-intent cleanup included — so a deliberate stop is never replayed as a
|
|
20
|
-
* fresh turn on restart. Exported as a constant for the same reason as {@link SESSION_BUSY_CODE}:
|
|
21
|
-
* a consumer that must branch on it should not string-match.
|
|
11
|
+
* The `failed.code` set when a run was DELIBERATELY stopped. A channel MAY render cancellation distinctly from an
|
|
12
|
+
* error, and MUST treat it as a settled outcome — durable turn-intent cleanup included — so a deliberate stop is
|
|
13
|
+
* never replayed as a fresh turn on restart.
|
|
22
14
|
*/
|
|
23
15
|
export const ABORTED_CODE = "aborted";
|
package/dist/atomic-write.d.ts
CHANGED
|
@@ -1,23 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Write a file so a reader sees the whole thing or nothing: same-directory temp, then rename.
|
|
3
3
|
*
|
|
4
|
-
* The temp name is
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* `add slack --replace-config` can overlap a live `dev --tunnel`. Kept fixed anyway: that window is
|
|
10
|
-
* a single write at tunnel startup, its repair is the `add slack --replace-config` the registration
|
|
11
|
-
* failure already prints, and the fixed name is the seam several channel tests use to inject a write
|
|
12
|
-
* failure by occupying that path with a directory. Revisit for a writer that is neither rare nor
|
|
13
|
-
* self-repairing.
|
|
4
|
+
* The temp name is FIXED (`<path>.tmp`), which rests on one process writing one state root: a deployment runs one
|
|
5
|
+
* container, `dev`'s supervisor respawns its worker only after the old one has exited, and these writes are
|
|
6
|
+
* synchronous. Slack's onboarding state is the documented exception (`add slack` plus the config-token rotation at
|
|
7
|
+
* `--tunnel` startup); it stays fixed because that window is one rare, self-repairing write, and because the fixed
|
|
8
|
+
* name is the seam channel tests use to inject a write failure. Revisit before adding a writer that is neither.
|
|
14
9
|
*
|
|
15
|
-
* `mode` is applied to the temp first, so the content is never briefly world-readable
|
|
10
|
+
* `mode` is applied to the temp first, so the content is never briefly world-readable, and the `chmod` is not
|
|
11
|
+
* redundant with it: `writeFileSync` honours `mode` only when it CREATES the file, so a temp left behind by a crashed
|
|
12
|
+
* writer would keep its old, possibly looser permissions.
|
|
16
13
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* permissions, which a chmod after the rename cannot promise.
|
|
14
|
+
* `sharedWriters` is for a file SEVERAL processes may write at once (the merged models file, content-addressed, so
|
|
15
|
+
* every writer writes the same bytes): each writes its own temp, and the last rename wins. A fixed temp there would
|
|
16
|
+
* let one writer's rename take the other's file and fail it with ENOENT. No test exercises that race: it needs two
|
|
17
|
+
* processes renaming within the same moment, which a test cannot arrange without being flaky.
|
|
22
18
|
*/
|
|
23
|
-
export declare function writeFileAtomic(path: string, data: string | Buffer, mode?: number): void;
|
|
19
|
+
export declare function writeFileAtomic(path: string, data: string | Buffer, mode?: number, sharedWriters?: boolean): void;
|
package/dist/atomic-write.js
CHANGED
|
@@ -1,39 +1,28 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* One spelling of "a reader sees the whole file or none of it", after five copies of it drifted
|
|
3
|
-
* apart: two identical, three with different temp names and different permission handling.
|
|
4
|
-
*
|
|
5
|
-
* Synchronous, and there is no async sibling: every caller either sits on a path where a KB-sized
|
|
6
|
-
* write must complete BEFORE a transport ACK (channel state — an ACKed delivery is not redelivered)
|
|
7
|
-
* or on a CLI/startup path where the cost is not observable. An async spelling would buy one of them
|
|
8
|
-
* nothing and cost this module a second set of rules to keep true.
|
|
9
|
-
*/
|
|
1
|
+
/** One spelling of "a reader sees the whole file or none of it", for every state writer. */
|
|
10
2
|
import { chmodSync, mkdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
11
4
|
import { dirname } from "node:path";
|
|
12
5
|
/**
|
|
13
6
|
* Write a file so a reader sees the whole thing or nothing: same-directory temp, then rename.
|
|
14
7
|
*
|
|
15
|
-
* The temp name is
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* `add slack --replace-config` can overlap a live `dev --tunnel`. Kept fixed anyway: that window is
|
|
21
|
-
* a single write at tunnel startup, its repair is the `add slack --replace-config` the registration
|
|
22
|
-
* failure already prints, and the fixed name is the seam several channel tests use to inject a write
|
|
23
|
-
* failure by occupying that path with a directory. Revisit for a writer that is neither rare nor
|
|
24
|
-
* self-repairing.
|
|
8
|
+
* The temp name is FIXED (`<path>.tmp`), which rests on one process writing one state root: a deployment runs one
|
|
9
|
+
* container, `dev`'s supervisor respawns its worker only after the old one has exited, and these writes are
|
|
10
|
+
* synchronous. Slack's onboarding state is the documented exception (`add slack` plus the config-token rotation at
|
|
11
|
+
* `--tunnel` startup); it stays fixed because that window is one rare, self-repairing write, and because the fixed
|
|
12
|
+
* name is the seam channel tests use to inject a write failure. Revisit before adding a writer that is neither.
|
|
25
13
|
*
|
|
26
|
-
* `mode` is applied to the temp first, so the content is never briefly world-readable
|
|
14
|
+
* `mode` is applied to the temp first, so the content is never briefly world-readable, and the `chmod` is not
|
|
15
|
+
* redundant with it: `writeFileSync` honours `mode` only when it CREATES the file, so a temp left behind by a crashed
|
|
16
|
+
* writer would keep its old, possibly looser permissions.
|
|
27
17
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* permissions, which a chmod after the rename cannot promise.
|
|
18
|
+
* `sharedWriters` is for a file SEVERAL processes may write at once (the merged models file, content-addressed, so
|
|
19
|
+
* every writer writes the same bytes): each writes its own temp, and the last rename wins. A fixed temp there would
|
|
20
|
+
* let one writer's rename take the other's file and fail it with ENOENT. No test exercises that race: it needs two
|
|
21
|
+
* processes renaming within the same moment, which a test cannot arrange without being flaky.
|
|
33
22
|
*/
|
|
34
|
-
export function writeFileAtomic(path, data, mode) {
|
|
23
|
+
export function writeFileAtomic(path, data, mode, sharedWriters = false) {
|
|
35
24
|
mkdirSync(dirname(path), { recursive: true });
|
|
36
|
-
const tmp = `${path}.tmp`;
|
|
25
|
+
const tmp = sharedWriters ? `${path}.${process.pid}.${randomUUID()}.tmp` : `${path}.tmp`;
|
|
37
26
|
try {
|
|
38
27
|
writeFileSync(tmp, data, mode === undefined ? undefined : { mode });
|
|
39
28
|
if (mode !== undefined)
|
|
@@ -45,8 +34,8 @@ export function writeFileAtomic(path, data, mode) {
|
|
|
45
34
|
rmSync(tmp, { force: true });
|
|
46
35
|
}
|
|
47
36
|
catch {
|
|
48
|
-
// `force` only forgives ENOENT: if the temp is a directory, rmSync throws its own error and
|
|
49
|
-
//
|
|
37
|
+
// `force` only forgives ENOENT: if the temp is a directory, rmSync throws its own error and would replace the
|
|
38
|
+
// write failure that actually explains what went wrong.
|
|
50
39
|
}
|
|
51
40
|
throw error;
|
|
52
41
|
}
|
package/dist/bind.d.ts
CHANGED
|
@@ -1,34 +1,24 @@
|
|
|
1
|
-
/** A bindable host: an IP literal (v4/v6, brackets optional) or "localhost".
|
|
2
|
-
* bind address must be an address of THIS machine, and resolving one is not this module's job. */
|
|
1
|
+
/** A bindable host: an IP literal (v4/v6, brackets optional) or "localhost". */
|
|
3
2
|
export declare function isBindAddress(host: string): boolean;
|
|
4
3
|
/**
|
|
5
|
-
* The ADDRESS form of an accepted bind value: `localhost` becomes `127.0.0.1`, everything else is
|
|
6
|
-
* already an address. Applied where a value ENTERS (the flag, `http.host`), so nothing downstream ever
|
|
7
|
-
* holds a name — not deferring the resolution but removing it, which is the module's whole point.
|
|
8
|
-
*
|
|
9
|
-
* Two things go wrong otherwise, and both are silent. `server.listen` hands the name to `dns.lookup`,
|
|
10
|
-
* which picks ONE of 127.0.0.1/::1 by rules we do not control — so what got bound is unknown here. And
|
|
11
|
-
* `clientHost` would then write that NAME into control.json and the copyable curl, where a consumer
|
|
12
|
-
* resolves it again, possibly to the other one.
|
|
4
|
+
* The ADDRESS form of an accepted bind value: `localhost` becomes `127.0.0.1`, everything else is already an address.
|
|
13
5
|
*/
|
|
14
6
|
export declare function bindAddress(host: string): string;
|
|
15
7
|
/**
|
|
16
|
-
* How far a bind address reaches: `wildcard` (unset or all-interfaces) reaches every interface and
|
|
17
|
-
*
|
|
18
|
-
* only as itself. Loopback covers the whole reserved range (127/8, ::1) — a `127.0.0.2` bind is no
|
|
19
|
-
* more LAN-reachable than `127.0.0.1`.
|
|
8
|
+
* How far a bind address reaches: `wildcard` (unset or all-interfaces) reaches every interface and answers on
|
|
9
|
+
* loopback too; `loopback` is this machine only; `specific` is one interface, reachable only as itself.
|
|
20
10
|
*/
|
|
21
11
|
export declare function classifyBind(host: string | undefined): "wildcard" | "loopback" | "specific";
|
|
22
12
|
/**
|
|
23
|
-
* Does a serve bound to `host` answer a dial of the NAME `localhost`? Only the addresses that name
|
|
24
|
-
*
|
|
25
|
-
*
|
|
13
|
+
* Does a serve bound to `host` answer a dial of the NAME `localhost`? Only the addresses that name resolves to
|
|
14
|
+
* (127.0.0.1 / ::1) and a wildcard bind do — `127.0.0.2` is loopback yet unreachable that way. That is why this is not
|
|
15
|
+
* {@link classifyBind}'s reach question: cloudflared dials by name, so `--tunnel` needs this one.
|
|
26
16
|
*/
|
|
27
17
|
export declare function answersLocalhost(host: string | undefined): boolean;
|
|
28
|
-
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
|
|
18
|
+
/**
|
|
19
|
+
* How to NAME a bind in a message: the wildcard is every interface, so calling it one address would understate it;
|
|
20
|
+
* anything else is dialable as itself.
|
|
21
|
+
*/
|
|
32
22
|
export declare function bindLabel(host: string | undefined, port: number): string;
|
|
33
|
-
/** The address a local client should dial for a serve bound to `host` (
|
|
23
|
+
/** The address a local client should dial for a serve bound to `host` (the ready log's curl). */
|
|
34
24
|
export declare function clientHost(host: string | undefined): string;
|
package/dist/bind.js
CHANGED
|
@@ -1,41 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The ONE reading of a bind address, shared by everything that parses, binds, warns about, or ships
|
|
3
|
-
*
|
|
4
|
-
* host-neutral on purpose: a bind address is a plain value, and two parsers of it would disagree.
|
|
2
|
+
* The ONE reading of a bind address, shared by everything that parses, binds, warns about, or ships one (the CLI flag, the
|
|
3
|
+
* Node host, the startup report).
|
|
5
4
|
*/
|
|
6
5
|
import { isIP } from "node:net";
|
|
7
|
-
/**
|
|
8
|
-
*
|
|
6
|
+
/**
|
|
7
|
+
* Lowercase, unbracketed, IPv4-mapped IPv6 reduced to its IPv4 form — the form the checks below read. Brackets come
|
|
8
|
+
* off only as a PAIR: a half-bracketed `[::1` must stay invalid, not become an address.
|
|
9
|
+
*/
|
|
9
10
|
function normalize(host) {
|
|
10
11
|
return host
|
|
11
12
|
.toLowerCase()
|
|
12
13
|
.replace(/^\[(.+)]$/, "$1")
|
|
13
14
|
.replace(/^::ffff:/, "");
|
|
14
15
|
}
|
|
15
|
-
/** A bindable host: an IP literal (v4/v6, brackets optional) or "localhost".
|
|
16
|
-
* bind address must be an address of THIS machine, and resolving one is not this module's job. */
|
|
16
|
+
/** A bindable host: an IP literal (v4/v6, brackets optional) or "localhost". */
|
|
17
17
|
export function isBindAddress(host) {
|
|
18
18
|
const h = normalize(host);
|
|
19
19
|
return h === "localhost" || isIP(h) !== 0;
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
|
-
* The ADDRESS form of an accepted bind value: `localhost` becomes `127.0.0.1`, everything else is
|
|
23
|
-
* already an address. Applied where a value ENTERS (the flag, `http.host`), so nothing downstream ever
|
|
24
|
-
* holds a name — not deferring the resolution but removing it, which is the module's whole point.
|
|
25
|
-
*
|
|
26
|
-
* Two things go wrong otherwise, and both are silent. `server.listen` hands the name to `dns.lookup`,
|
|
27
|
-
* which picks ONE of 127.0.0.1/::1 by rules we do not control — so what got bound is unknown here. And
|
|
28
|
-
* `clientHost` would then write that NAME into control.json and the copyable curl, where a consumer
|
|
29
|
-
* resolves it again, possibly to the other one.
|
|
22
|
+
* The ADDRESS form of an accepted bind value: `localhost` becomes `127.0.0.1`, everything else is already an address.
|
|
30
23
|
*/
|
|
31
24
|
export function bindAddress(host) {
|
|
32
25
|
return normalize(host) === "localhost" ? "127.0.0.1" : host;
|
|
33
26
|
}
|
|
34
27
|
/**
|
|
35
|
-
* How far a bind address reaches: `wildcard` (unset or all-interfaces) reaches every interface and
|
|
36
|
-
*
|
|
37
|
-
* only as itself. Loopback covers the whole reserved range (127/8, ::1) — a `127.0.0.2` bind is no
|
|
38
|
-
* more LAN-reachable than `127.0.0.1`.
|
|
28
|
+
* How far a bind address reaches: `wildcard` (unset or all-interfaces) reaches every interface and answers on
|
|
29
|
+
* loopback too; `loopback` is this machine only; `specific` is one interface, reachable only as itself.
|
|
39
30
|
*/
|
|
40
31
|
export function classifyBind(host) {
|
|
41
32
|
if (host === undefined)
|
|
@@ -48,9 +39,9 @@ export function classifyBind(host) {
|
|
|
48
39
|
return "specific";
|
|
49
40
|
}
|
|
50
41
|
/**
|
|
51
|
-
* Does a serve bound to `host` answer a dial of the NAME `localhost`? Only the addresses that name
|
|
52
|
-
*
|
|
53
|
-
*
|
|
42
|
+
* Does a serve bound to `host` answer a dial of the NAME `localhost`? Only the addresses that name resolves to
|
|
43
|
+
* (127.0.0.1 / ::1) and a wildcard bind do — `127.0.0.2` is loopback yet unreachable that way. That is why this is not
|
|
44
|
+
* {@link classifyBind}'s reach question: cloudflared dials by name, so `--tunnel` needs this one.
|
|
54
45
|
*/
|
|
55
46
|
export function answersLocalhost(host) {
|
|
56
47
|
if (classifyBind(host) === "wildcard")
|
|
@@ -58,14 +49,14 @@ export function answersLocalhost(host) {
|
|
|
58
49
|
const h = normalize(host);
|
|
59
50
|
return h === "localhost" || h === "127.0.0.1" || h === "::1";
|
|
60
51
|
}
|
|
61
|
-
/**
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
|
|
52
|
+
/**
|
|
53
|
+
* How to NAME a bind in a message: the wildcard is every interface, so calling it one address would understate it;
|
|
54
|
+
* anything else is dialable as itself.
|
|
55
|
+
*/
|
|
65
56
|
export function bindLabel(host, port) {
|
|
66
57
|
return classifyBind(host) === "wildcard" ? `port ${port}` : `${clientHost(host)}:${port}`;
|
|
67
58
|
}
|
|
68
|
-
/** The address a local client should dial for a serve bound to `host` (
|
|
59
|
+
/** The address a local client should dial for a serve bound to `host` (the ready log's curl). */
|
|
69
60
|
export function clientHost(host) {
|
|
70
61
|
if (classifyBind(host) === "wildcard")
|
|
71
62
|
return "127.0.0.1";
|
package/dist/channel.d.ts
CHANGED
|
@@ -1,55 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The Channel contract — the trigger side of the product boundary (core.md §1), beside `agent.ts`
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* §7 fixes two module forms: a function is a route channel, an object with `connect` is a long
|
|
7
|
-
* connection. An agent directory ships hand-written `channels/*.ts` against them, which is why they
|
|
8
|
-
* live away from the code that serves them — a WebSocket ingress needs `LongConnection` and has no
|
|
9
|
-
* HTTP in it, and a `ChannelModule` import must not drag `node:http` in behind it.
|
|
10
|
-
*
|
|
11
|
-
* How a route table becomes a running server: `channels/serve.ts`.
|
|
2
|
+
* The Channel contract — the trigger side of the product boundary (core.md §1), beside `agent.ts` (what an engine
|
|
3
|
+
* implements) and `session.ts` (the serving control plane). Pure types: importing a host, a framework, or an engine
|
|
4
|
+
* here is forbidden, as in those two.
|
|
12
5
|
*/
|
|
13
6
|
import type { Agent } from "./agent.ts";
|
|
14
7
|
import type { SessionControl } from "./session.ts";
|
|
15
|
-
/** A mounted request handler (a channel's fetch, or a plain route like health).
|
|
16
|
-
* contract (SPEC §11): the one signature every runtime and embedding app already speaks. */
|
|
8
|
+
/** A mounted request handler (a channel's fetch, or a plain route like health). */
|
|
17
9
|
export type ChannelHandler = (req: Request) => Response | Promise<Response>;
|
|
18
|
-
/**
|
|
19
|
-
* This deployment's HTTP surface: route key → handler.
|
|
20
|
-
*
|
|
21
|
-
* A key is `"/path"` (any method) or `"METHOD /path"`, with a LITERAL path — small on purpose, so
|
|
22
|
-
* that "would these two fight over a request?" is string equality rather than a prediction about a
|
|
23
|
-
* matcher, and no channel silently shadows another. `assertRouteKey` in `channels/serve.ts`
|
|
24
|
-
* enforces it; a handler owning a prefix is a `PrefixMount`, never a key.
|
|
25
|
-
*/
|
|
10
|
+
/** This deployment's HTTP surface: route key → handler. */
|
|
26
11
|
export type Routes = Record<string, ChannelHandler>;
|
|
27
12
|
/**
|
|
28
|
-
* What the framework hands a channel at mount time: the assembled agent plus the resolved state ROOT
|
|
29
|
-
*
|
|
30
|
-
* it (`<stateRoot>/channels/<kind>/`) — they never anchor on `process.cwd()`. env is the OPERATOR
|
|
31
|
-
* input plane; this context is how the resolved result reaches code (embedders without the agent
|
|
32
|
-
* opener construct it explicitly).
|
|
13
|
+
* What the framework hands a channel at mount time: the assembled agent plus the resolved state ROOT (absolute;
|
|
14
|
+
* `FASTAGENT_STATE_DIR` > `<root>/.state`).
|
|
33
15
|
*/
|
|
34
16
|
export interface ChannelContext {
|
|
35
17
|
agent: Agent;
|
|
36
18
|
stateRoot: string;
|
|
37
|
-
/** The serving session-control hub,
|
|
38
|
-
*
|
|
19
|
+
/** The serving session-control hub: every serve has it, so a stop command reaches the live run through it.
|
|
20
|
+
* `config.sessionControl` decides only whether the SAME hub is also published as `/control/*` (and wires its
|
|
21
|
+
* write side). Absent only when an embedder mounts a service without one. */
|
|
39
22
|
control?: SessionControl;
|
|
40
23
|
}
|
|
41
24
|
/** A `channels/<name>.ts` route channel: receives mount context and returns its HTTP routes. */
|
|
42
25
|
export type ChannelModule = (ctx: ChannelContext) => Routes;
|
|
43
|
-
/** One logical long connection's lifecycle. `ready` settles after its first usable connection — and
|
|
44
|
-
* when `signal` aborts before one exists it must still settle: resolution then means cancellation, not
|
|
45
|
-
* readiness (the server skips ready-side effects once the signal is aborted; it must never hang).
|
|
46
|
-
* `closed` resolves after abort-driven shutdown and rejects on a terminal connection failure. */
|
|
47
26
|
export interface LongConnection {
|
|
48
27
|
ready: Promise<void>;
|
|
49
28
|
closed: Promise<void>;
|
|
50
29
|
}
|
|
51
|
-
/** A long-connection channel is an explicit module object rather than an HTTP-route factory.
|
|
52
|
-
* The adapter owns reconnects and treats `signal` as its sole shutdown command. */
|
|
30
|
+
/** A long-connection channel is an explicit module object rather than an HTTP-route factory. */
|
|
53
31
|
export interface LongConnectionChannelModule {
|
|
54
32
|
name: string;
|
|
55
33
|
connect(ctx: ChannelContext, signal: AbortSignal): LongConnection;
|
|
@@ -1,16 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* Lambda Function URLs cap a request at 6 MB, so the forwarder cannot deliver more than that no
|
|
5
|
-
* matter what the adapter accepts; the body arrives base64-encoded (×4/3) inside a JSON envelope, so
|
|
6
|
-
* the ORIGINAL body ceiling is smaller still. This is a real capability difference from a resident
|
|
7
|
-
* host — the GitHub channel's own contract is 25 MiB — which is why `deploy agentcore` states it at
|
|
8
|
-
* plan time rather than letting an oversized payload surface as an opaque 502.
|
|
9
|
-
*/
|
|
10
|
-
/**
|
|
11
|
-
* Maximum original webhook body after reserving JSON-envelope overhead and base64 expansion.
|
|
12
|
-
* Enforced by both the public forwarder and the runtime adapter.
|
|
13
|
-
*/
|
|
1
|
+
/** The HOST's body ceilings, and the one place they are computed. */
|
|
2
|
+
/** Maximum original webhook body after reserving JSON-envelope overhead and base64 expansion. */
|
|
14
3
|
export declare const MAX_WEBHOOK_BODY_BYTES: number;
|
|
15
4
|
/** Largest complete AgentCore envelope accepted by the runtime adapter. */
|
|
16
5
|
export declare const MAX_ENVELOPE_BYTES: number;
|
|
@@ -1,18 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The HOST's body ceilings, and the one place they are computed.
|
|
3
|
-
*
|
|
4
|
-
* Lambda Function URLs cap a request at 6 MB, so the forwarder cannot deliver more than that no
|
|
5
|
-
* matter what the adapter accepts; the body arrives base64-encoded (×4/3) inside a JSON envelope, so
|
|
6
|
-
* the ORIGINAL body ceiling is smaller still. This is a real capability difference from a resident
|
|
7
|
-
* host — the GitHub channel's own contract is 25 MiB — which is why `deploy agentcore` states it at
|
|
8
|
-
* plan time rather than letting an oversized payload surface as an opaque 502.
|
|
9
|
-
*/
|
|
1
|
+
/** The HOST's body ceilings, and the one place they are computed. */
|
|
10
2
|
/** AWS Lambda Function URLs accept request payloads up to 6 MB. */
|
|
11
3
|
const FUNCTION_URL_REQUEST_LIMIT = 6 * 1000 * 1000;
|
|
12
|
-
/**
|
|
13
|
-
* Maximum original webhook body after reserving JSON-envelope overhead and base64 expansion.
|
|
14
|
-
* Enforced by both the public forwarder and the runtime adapter.
|
|
15
|
-
*/
|
|
4
|
+
/** Maximum original webhook body after reserving JSON-envelope overhead and base64 expansion. */
|
|
16
5
|
export const MAX_WEBHOOK_BODY_BYTES = Math.floor((FUNCTION_URL_REQUEST_LIMIT * 3) / 4) - (64 << 10);
|
|
17
6
|
/** Largest complete AgentCore envelope accepted by the runtime adapter. */
|
|
18
7
|
export const MAX_ENVELOPE_BYTES = FUNCTION_URL_REQUEST_LIMIT;
|