@fastagent-sh/fastagent 0.24.3 → 0.25.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 +53 -82
- package/dist/agent-api.d.ts +452 -0
- package/dist/agent-api.js +201 -0
- package/dist/answer-text.d.ts +8 -0
- package/dist/answer-text.js +18 -0
- package/dist/atomic-write.d.ts +2 -2
- package/dist/atomic-write.js +2 -2
- package/dist/authoring.d.ts +77 -0
- package/dist/authoring.js +238 -0
- package/dist/channel.d.ts +29 -15
- package/dist/channel.js +4 -1
- package/dist/channels/agentcore-protocol.d.ts +36 -50
- package/dist/channels/agentcore-protocol.js +3 -3
- package/dist/channels/agentcore-service.d.ts +8 -18
- package/dist/channels/agentcore-service.js +108 -127
- package/dist/channels/agentcore.d.ts +8 -24
- package/dist/channels/agentcore.js +32 -65
- package/dist/channels/body.d.ts +0 -16
- package/dist/channels/body.js +0 -25
- package/dist/channels/busy.js +6 -1
- package/dist/channels/context.d.ts +4 -0
- package/dist/channels/context.js +35 -0
- package/dist/channels/discover.d.ts +18 -20
- package/dist/channels/discover.js +41 -99
- package/dist/channels/feishu/feishu-api.d.ts +54 -4
- package/dist/channels/feishu/feishu-api.js +192 -149
- package/dist/channels/feishu/feishu.d.ts +3 -0
- package/dist/channels/feishu/feishu.js +117 -106
- package/dist/channels/feishu/history.d.ts +55 -0
- package/dist/channels/feishu/history.js +199 -0
- package/dist/channels/feishu/invoke-turn.d.ts +13 -11
- package/dist/channels/feishu/invoke-turn.js +9 -10
- package/dist/channels/feishu/model.d.ts +2 -1
- package/dist/channels/feishu/normalize.js +100 -0
- package/dist/channels/feishu/preview.d.ts +2 -2
- package/dist/channels/feishu/register-webhook.d.ts +1 -0
- package/dist/channels/feishu/register-webhook.js +3 -2
- package/dist/channels/feishu/scaffold/channel.ts +65 -46
- package/dist/channels/feishu/scaffold/feishu-send.ts +38 -33
- package/dist/channels/feishu/scaffold/feishu-threads.ts +25 -0
- package/dist/channels/feishu/setup-mode.d.ts +45 -25
- package/dist/channels/feishu/setup-mode.js +74 -23
- package/dist/channels/feishu/shared-api.d.ts +24 -6
- package/dist/channels/feishu/shared-api.js +30 -24
- package/dist/channels/kit/context-buffer.d.ts +11 -2
- package/dist/channels/kit/context-buffer.js +7 -4
- package/dist/channels/kit/delivery.d.ts +19 -3
- package/dist/channels/kit/delivery.js +74 -15
- package/dist/channels/kit/event-stream.js +2 -1
- package/dist/channels/kit/invoke-turn-kit.d.ts +41 -41
- package/dist/channels/kit/invoke-turn-kit.js +62 -71
- package/dist/channels/kit/place-history.d.ts +107 -0
- package/dist/channels/kit/place-history.js +182 -0
- package/dist/channels/kit/preview-kit.d.ts +9 -5
- package/dist/channels/kit/preview-kit.js +36 -15
- package/dist/channels/kit/room-threads.d.ts +46 -0
- package/dist/channels/kit/room-threads.js +81 -0
- package/dist/channels/kit/seen.js +1 -1
- package/dist/channels/kit/stop-command.d.ts +6 -3
- package/dist/channels/kit/stop-command.js +20 -18
- package/dist/channels/kit/thread-fork.d.ts +17 -0
- package/dist/channels/kit/thread-fork.js +43 -0
- package/dist/channels/kit/thread-participants.js +1 -1
- package/dist/channels/kit/transport.d.ts +5 -0
- package/dist/channels/kit/transport.js +5 -0
- package/dist/channels/kit/turn-runner.d.ts +10 -9
- package/dist/channels/kit/turn-runner.js +17 -19
- package/dist/channels/kit/turn-store.d.ts +5 -4
- package/dist/channels/kit/turn-store.js +5 -5
- package/dist/channels/lark/lark.d.ts +3 -0
- package/dist/channels/lark/lark.js +5 -0
- package/dist/channels/lark/onboard.d.ts +5 -3
- package/dist/channels/lark/onboard.js +14 -14
- package/dist/channels/lark/scaffold/channel.ts +67 -44
- package/dist/channels/lark/scaffold/lark-send.ts +38 -33
- package/dist/channels/lark/scaffold/lark-threads.ts +25 -0
- package/dist/channels/respond.d.ts +0 -4
- package/dist/channels/respond.js +1 -1
- package/dist/channels/router.d.ts +18 -0
- package/dist/channels/router.js +68 -0
- package/dist/channels/serve.d.ts +5 -70
- package/dist/channels/serve.js +105 -287
- package/dist/channels/slack/history.d.ts +42 -0
- package/dist/channels/slack/history.js +282 -0
- package/dist/channels/slack/invoke-turn.d.ts +12 -5
- package/dist/channels/slack/invoke-turn.js +7 -5
- package/dist/channels/slack/manifest.d.ts +1 -4
- package/dist/channels/slack/manifest.js +22 -10
- package/dist/channels/slack/model.d.ts +2 -1
- package/dist/channels/slack/onboard.d.ts +0 -2
- package/dist/channels/slack/onboard.js +2 -4
- package/dist/channels/slack/onboarding-state.d.ts +0 -2
- package/dist/channels/slack/onboarding-state.js +0 -1
- package/dist/channels/slack/parse.d.ts +0 -5
- package/dist/channels/slack/parse.js +1 -16
- package/dist/channels/slack/preview.d.ts +2 -3
- package/dist/channels/slack/preview.js +78 -52
- package/dist/channels/slack/register-webhook.d.ts +1 -0
- package/dist/channels/slack/register-webhook.js +6 -5
- package/dist/channels/slack/scaffold/channel.ts +23 -24
- package/dist/channels/slack/scaffold/slack-send.ts +50 -43
- package/dist/channels/slack/scaffold/slack-threads.ts +29 -0
- package/dist/channels/slack/setup-server.d.ts +19 -0
- package/dist/channels/slack/setup-server.js +113 -11
- package/dist/channels/slack/shared-api.d.ts +15 -4
- package/dist/channels/slack/shared-api.js +19 -14
- package/dist/channels/slack/slack-api.d.ts +61 -2
- package/dist/channels/slack/slack-api.js +28 -5
- package/dist/channels/slack/slack.js +97 -52
- package/dist/channels/slack/welcomed.js +1 -1
- package/dist/channels/telegram/context-buffer.d.ts +6 -1
- package/dist/channels/telegram/context-buffer.js +19 -0
- package/dist/channels/telegram/invoke-turn.d.ts +8 -4
- package/dist/channels/telegram/invoke-turn.js +7 -7
- package/dist/channels/telegram/parse.d.ts +7 -2
- package/dist/channels/telegram/parse.js +7 -0
- package/dist/channels/telegram/preview.d.ts +2 -2
- package/dist/channels/telegram/register-webhook.d.ts +1 -0
- package/dist/channels/telegram/register-webhook.js +3 -2
- package/dist/channels/telegram/scaffold/channel.ts +27 -28
- package/dist/channels/telegram/scaffold/telegram-send.ts +61 -108
- package/dist/channels/telegram/shared-api.d.ts +34 -0
- package/dist/channels/telegram/shared-api.js +79 -0
- package/dist/channels/telegram/telegram-api.d.ts +15 -5
- package/dist/channels/telegram/telegram-api.js +10 -6
- package/dist/channels/telegram/telegram.js +27 -21
- package/dist/channels/telegram/turn-store.js +1 -1
- package/dist/channels/{kit/turn-queue.d.ts → turn-queue.d.ts} +2 -2
- package/dist/channels/{kit/turn-queue.js → turn-queue.js} +10 -10
- package/dist/cli/add-feishu.d.ts +42 -12
- package/dist/cli/add-feishu.js +177 -124
- package/dist/cli/add-slack.d.ts +8 -3
- package/dist/cli/add-slack.js +115 -63
- package/dist/cli/auth-view.d.ts +10 -3
- package/dist/cli/auth-view.js +8 -6
- package/dist/cli/box-login.d.ts +17 -7
- package/dist/cli/box-login.js +46 -12
- package/dist/cli/commands/add.d.ts +15 -4
- package/dist/cli/commands/add.js +252 -143
- package/dist/cli/commands/auth.d.ts +6 -0
- package/dist/cli/commands/auth.js +50 -0
- package/dist/cli/commands/content.d.ts +6 -0
- package/dist/cli/commands/content.js +45 -0
- package/dist/cli/commands/deploy/agentcore.js +50 -77
- package/dist/cli/commands/deploy/docker.js +38 -39
- package/dist/cli/commands/deploy/fly.js +21 -18
- package/dist/cli/commands/deploy/host-login.d.ts +26 -0
- package/dist/cli/commands/deploy/host-login.js +90 -0
- package/dist/cli/commands/deploy/railway.js +21 -26
- package/dist/cli/commands/deploy/shared.d.ts +45 -17
- package/dist/cli/commands/deploy/shared.js +34 -15
- package/dist/cli/commands/deploy.d.ts +0 -4
- package/dist/cli/commands/deploy.js +237 -50
- package/dist/cli/commands/destroy.js +8 -6
- package/dist/cli/commands/dev.d.ts +0 -2
- package/dist/cli/commands/dev.js +20 -19
- package/dist/cli/commands/env.d.ts +12 -0
- package/dist/cli/commands/env.js +190 -0
- package/dist/cli/commands/info.js +95 -156
- package/dist/cli/commands/init.d.ts +2 -2
- package/dist/cli/commands/init.js +35 -33
- package/dist/cli/commands/invoke.d.ts +6 -0
- package/dist/cli/commands/invoke.js +131 -16
- package/dist/cli/commands/login.d.ts +31 -2
- package/dist/cli/commands/login.js +413 -64
- package/dist/cli/commands/logout.d.ts +4 -0
- package/dist/cli/commands/logout.js +53 -0
- package/dist/cli/commands/logs.js +8 -6
- package/dist/cli/commands/models.d.ts +2 -1
- package/dist/cli/commands/models.js +39 -37
- package/dist/cli/commands/schedules.d.ts +21 -0
- package/dist/cli/commands/schedules.js +143 -0
- package/dist/cli/commands/start.d.ts +11 -10
- package/dist/cli/commands/start.js +35 -62
- package/dist/cli/content-view.d.ts +9 -0
- package/dist/cli/content-view.js +26 -0
- package/dist/cli/fail.d.ts +9 -12
- package/dist/cli/fail.js +17 -14
- package/dist/cli/invoke-stream.d.ts +12 -3
- package/dist/cli/invoke-stream.js +85 -23
- package/dist/cli/kernel.d.ts +9 -2
- package/dist/cli/kernel.js +15 -6
- package/dist/cli/login-relay.d.ts +3 -2
- package/dist/cli/login-relay.js +18 -6
- package/dist/cli/models-view.d.ts +5 -1
- package/dist/cli/models-view.js +1 -1
- package/dist/cli/person.d.ts +10 -0
- package/dist/cli/person.js +23 -0
- package/dist/cli/program.js +421 -203
- package/dist/cli/serve.d.ts +13 -63
- package/dist/cli/serve.js +31 -121
- package/dist/cli/shared.d.ts +21 -48
- package/dist/cli/shared.js +68 -89
- package/dist/cli/ticket.d.ts +136 -0
- package/dist/cli/ticket.js +476 -0
- package/dist/client.d.ts +7 -0
- package/dist/client.js +2 -0
- package/dist/content/declare.d.ts +70 -0
- package/dist/content/declare.js +163 -0
- package/dist/content/file.d.ts +32 -0
- package/dist/content/file.js +119 -0
- package/dist/content/git.d.ts +41 -0
- package/dist/content/git.js +217 -0
- package/dist/content/mount.d.ts +2 -0
- package/dist/content/mount.js +15 -0
- package/dist/content/resolve.d.ts +52 -0
- package/dist/content/resolve.js +151 -0
- package/dist/content/source.d.ts +27 -0
- package/dist/content/source.js +53 -0
- package/dist/conversation-sessions.d.ts +26 -0
- package/dist/conversation-sessions.js +99 -0
- package/dist/declared-secrets.d.ts +19 -37
- package/dist/declared-secrets.js +16 -58
- package/dist/deploy/agentcore/destroy.d.ts +3 -3
- package/dist/deploy/agentcore/destroy.js +46 -28
- package/dist/deploy/agentcore/forwarder.js +105 -22
- package/dist/deploy/agentcore/logs.js +1 -1
- package/dist/deploy/agentcore/plan.d.ts +10 -24
- package/dist/deploy/agentcore/plan.js +31 -135
- package/dist/deploy/agentcore/run.d.ts +1 -1
- package/dist/deploy/agentcore/run.js +8 -5
- package/dist/deploy/agentcore/shell.d.ts +1 -1
- package/dist/deploy/agentcore/shell.js +5 -5
- package/dist/deploy/api.d.ts +34 -0
- package/dist/deploy/api.js +50 -0
- package/dist/deploy/box-shell.d.ts +6 -0
- package/dist/deploy/box-shell.js +7 -0
- package/dist/deploy/build-context.d.ts +7 -5
- package/dist/deploy/build-context.js +41 -35
- package/dist/deploy/channel-ingress.d.ts +6 -1
- package/dist/deploy/channel-ingress.js +18 -5
- package/dist/deploy/container.d.ts +22 -9
- package/dist/deploy/container.js +96 -55
- package/dist/deploy/docker/plan.d.ts +3 -2
- package/dist/deploy/docker/plan.js +13 -14
- package/dist/deploy/docker/run.d.ts +2 -2
- package/dist/deploy/docker/run.js +8 -4
- package/dist/deploy/fly/plan.d.ts +1 -1
- package/dist/deploy/fly/plan.js +12 -21
- package/dist/deploy/fly/run.d.ts +10 -6
- package/dist/deploy/fly/run.js +11 -6
- package/dist/deploy/hosts.d.ts +2 -1
- package/dist/deploy/hosts.js +2 -1
- package/dist/deploy/preflight.d.ts +21 -23
- package/dist/deploy/preflight.js +222 -201
- package/dist/deploy/railway/plan.d.ts +8 -6
- package/dist/deploy/railway/plan.js +15 -58
- package/dist/deploy/railway/run.d.ts +8 -3
- package/dist/deploy/railway/run.js +12 -8
- package/dist/deploy/residency.d.ts +5 -11
- package/dist/deploy/residency.js +0 -6
- package/dist/deploy/runner.d.ts +1 -1
- package/dist/deploy/runner.js +1 -1
- package/dist/deploy/secrets.d.ts +16 -2
- package/dist/deploy/secrets.js +33 -6
- package/dist/deploy/workspace.d.ts +11 -6
- package/dist/deploy/workspace.js +55 -38
- package/dist/dev-supervisor.d.ts +11 -2
- package/dist/dev-supervisor.js +51 -26
- package/dist/effect-port.d.ts +4 -4
- package/dist/effect-port.js +4 -4
- package/dist/environment/apt.d.ts +4 -0
- package/dist/environment/apt.js +32 -0
- package/dist/environment/declare.d.ts +59 -0
- package/dist/environment/declare.js +210 -0
- package/dist/environment/mise.d.ts +50 -0
- package/dist/environment/mise.js +268 -0
- package/dist/feishu.d.ts +2 -2
- package/dist/feishu.js +2 -2
- package/dist/git.d.ts +13 -0
- package/dist/git.js +55 -0
- package/dist/harnesses/models/catalog.d.ts +20 -0
- package/dist/harnesses/models/catalog.js +254 -0
- package/dist/{engines/pi/auth.d.ts → harnesses/models/credentials.d.ts} +3 -3
- package/dist/{engines/pi/auth.js → harnesses/models/credentials.js} +3 -3
- package/dist/harnesses/models/environment.d.ts +43 -0
- package/dist/harnesses/models/environment.js +82 -0
- package/dist/{engines/pi → harnesses/models}/login.d.ts +57 -26
- package/dist/{engines/pi → harnesses/models}/login.js +187 -79
- package/dist/harnesses/models/models.d.ts +83 -0
- package/dist/harnesses/models/models.js +158 -0
- package/dist/harnesses/pi-durable/agent.d.ts +42 -0
- package/dist/harnesses/pi-durable/agent.js +579 -0
- package/dist/harnesses/pi-durable/defaults.d.ts +28 -0
- package/dist/harnesses/pi-durable/defaults.js +26 -0
- package/dist/harnesses/pi-durable/define.d.ts +77 -0
- package/dist/harnesses/pi-durable/define.js +28 -0
- package/dist/harnesses/pi-durable/entries.d.ts +32 -0
- package/dist/harnesses/pi-durable/entries.js +126 -0
- package/dist/harnesses/pi-durable/events.d.ts +25 -0
- package/dist/harnesses/pi-durable/events.js +238 -0
- package/dist/harnesses/pi-durable/ids.d.ts +16 -0
- package/dist/harnesses/pi-durable/ids.js +55 -0
- package/dist/harnesses/pi-durable/messages.d.ts +41 -0
- package/dist/harnesses/pi-durable/messages.js +116 -0
- package/dist/harnesses/pi-durable/open.d.ts +88 -0
- package/dist/harnesses/pi-durable/open.js +329 -0
- package/dist/harnesses/pi-durable/reads.d.ts +30 -0
- package/dist/harnesses/pi-durable/reads.js +94 -0
- package/dist/harnesses/pi-durable/registry.d.ts +18 -0
- package/dist/harnesses/pi-durable/registry.js +56 -0
- package/dist/harnesses/pi-durable/release.d.ts +13 -0
- package/dist/harnesses/pi-durable/release.js +40 -0
- package/dist/harnesses/pi-durable/serve.d.ts +80 -0
- package/dist/harnesses/pi-durable/serve.js +156 -0
- package/dist/harnesses/pi-durable/sessions.d.ts +27 -0
- package/dist/harnesses/pi-durable/sessions.js +47 -0
- package/dist/harnesses/pi-durable/storage.d.ts +4 -0
- package/dist/harnesses/pi-durable/storage.js +49 -0
- package/dist/harnesses/pi-durable/stream.d.ts +20 -0
- package/dist/harnesses/pi-durable/stream.js +221 -0
- package/dist/harnesses/pi-durable/text.d.ts +30 -0
- package/dist/harnesses/pi-durable/text.js +292 -0
- package/dist/harnesses/pi-durable/wake.d.ts +4 -0
- package/dist/harnesses/pi-durable/wake.js +81 -0
- package/dist/http/client.d.ts +6 -0
- package/dist/http/client.js +256 -0
- package/dist/http/contract.d.ts +541 -0
- package/dist/http/contract.js +179 -0
- package/dist/http/server.d.ts +34 -0
- package/dist/http/server.js +194 -0
- package/dist/index.d.ts +17 -4
- package/dist/index.js +10 -5
- package/dist/lark.d.ts +2 -2
- package/dist/lark.js +2 -2
- package/dist/locked-file.d.ts +17 -0
- package/dist/{engines/pi/locked-file.js → locked-file.js} +16 -10
- package/dist/once.d.ts +6 -0
- package/dist/once.js +23 -0
- package/dist/paths.d.ts +36 -52
- package/dist/paths.js +66 -182
- package/dist/runtime.d.ts +25 -2
- package/dist/runtime.js +27 -0
- package/dist/scaffold/add-channel.d.ts +14 -27
- package/dist/scaffold/add-channel.js +82 -180
- package/dist/scaffold/init.d.ts +17 -18
- package/dist/scaffold/init.js +87 -99
- package/dist/scaffold/templates/SYSTEM.md +12 -0
- package/dist/scaffold/templates/env.example +4 -10
- package/dist/scaffold/templates/fastagent.config.ts +21 -33
- package/dist/scaffold/templates/gitignore +8 -1
- package/dist/scaffold/templates/skills/writing-great-skills/SKILL.md +1 -2
- package/dist/scaffold/templates.d.ts +9 -4
- package/dist/scaffold/templates.js +7 -5
- package/dist/scaffold/vendor-skill.d.ts +1 -4
- package/dist/scaffold/vendor-skill.js +5 -6
- package/dist/schedule/cron.d.ts +13 -0
- package/dist/schedule/cron.js +52 -0
- package/dist/schedule/eventbridge-cron.d.ts +17 -0
- package/dist/schedule/eventbridge-cron.js +88 -0
- package/dist/schedule/schedule.d.ts +23 -0
- package/dist/schedule/schedule.js +34 -0
- package/dist/schedule/scheduler.d.ts +34 -33
- package/dist/schedule/scheduler.js +251 -137
- package/dist/schedule/state.d.ts +4 -14
- package/dist/schedule/state.js +7 -7
- package/dist/schedule/wake-alarm.d.ts +22 -2
- package/dist/schedule/wake-alarm.js +66 -20
- package/dist/schedule/wakeups.d.ts +16 -15
- package/dist/schedule/wakeups.js +47 -45
- package/dist/service.d.ts +56 -169
- package/dist/service.js +91 -187
- package/dist/serving-command.d.ts +10 -0
- package/dist/serving-command.js +16 -0
- package/dist/slack.d.ts +1 -1
- package/dist/slack.js +1 -1
- package/dist/{channels/kit/state.js → state-file.js} +6 -6
- package/dist/telegram.d.ts +1 -0
- package/dist/telegram.js +1 -0
- package/dist/tunnel.d.ts +3 -0
- package/dist/tunnel.js +12 -4
- package/dist/value-file.d.ts +21 -0
- package/dist/value-file.js +108 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.js +14 -1
- package/package.json +18 -28
- package/dist/agent.d.ts +0 -106
- package/dist/agent.js +0 -21
- package/dist/channels/control.d.ts +0 -31
- package/dist/channels/control.js +0 -329
- package/dist/channels/define-channel.d.ts +0 -39
- package/dist/channels/define-channel.js +0 -9
- package/dist/channels/feishu/context-buffer.d.ts +0 -35
- package/dist/channels/feishu/context-buffer.js +0 -65
- package/dist/channels/feishu/scaffold/channel.websocket.ts +0 -31
- package/dist/channels/http.d.ts +0 -23
- package/dist/channels/http.js +0 -57
- package/dist/channels/lark/scaffold/channel.websocket.ts +0 -31
- package/dist/channels/slack/context-buffer.d.ts +0 -23
- package/dist/channels/slack/context-buffer.js +0 -37
- package/dist/channels/sse.d.ts +0 -4
- package/dist/channels/sse.js +0 -66
- package/dist/cli/commands/chat.d.ts +0 -3
- package/dist/cli/commands/chat.js +0 -14
- package/dist/cli/commands/routine-run.d.ts +0 -6
- package/dist/cli/commands/routine-run.js +0 -46
- package/dist/cli/commands/routine.d.ts +0 -25
- package/dist/cli/commands/routine.js +0 -122
- package/dist/cli/commands/tool.d.ts +0 -1
- package/dist/cli/commands/tool.js +0 -57
- package/dist/collect.d.ts +0 -63
- package/dist/collect.js +0 -90
- package/dist/core.d.ts +0 -13
- package/dist/core.js +0 -15
- package/dist/engines/pi/agent-models.d.ts +0 -83
- package/dist/engines/pi/agent-models.js +0 -120
- package/dist/engines/pi/agent-session-factory.d.ts +0 -121
- package/dist/engines/pi/agent-session-factory.js +0 -517
- package/dist/engines/pi/chat.d.ts +0 -3
- package/dist/engines/pi/chat.js +0 -8
- package/dist/engines/pi/config.d.ts +0 -71
- package/dist/engines/pi/config.js +0 -199
- package/dist/engines/pi/create.d.ts +0 -170
- package/dist/engines/pi/create.js +0 -343
- package/dist/engines/pi/definition.d.ts +0 -74
- package/dist/engines/pi/definition.js +0 -236
- package/dist/engines/pi/entry-images.d.ts +0 -14
- package/dist/engines/pi/entry-images.js +0 -23
- package/dist/engines/pi/invoke-session.d.ts +0 -18
- package/dist/engines/pi/invoke-session.js +0 -403
- package/dist/engines/pi/locked-file.d.ts +0 -9
- package/dist/engines/pi/machine.d.ts +0 -53
- package/dist/engines/pi/machine.js +0 -137
- package/dist/engines/pi/models.d.ts +0 -200
- package/dist/engines/pi/models.js +0 -533
- package/dist/engines/pi/open.d.ts +0 -180
- package/dist/engines/pi/open.js +0 -270
- package/dist/engines/pi/openai-account-models.d.ts +0 -35
- package/dist/engines/pi/openai-account-models.js +0 -116
- package/dist/engines/pi/report.d.ts +0 -18
- package/dist/engines/pi/report.js +0 -59
- package/dist/engines/pi/retry-event.d.ts +0 -6
- package/dist/engines/pi/retry-event.js +0 -15
- package/dist/engines/pi/service.d.ts +0 -9
- package/dist/engines/pi/service.js +0 -14
- package/dist/engines/pi/session-builder.d.ts +0 -13
- package/dist/engines/pi/session-builder.js +0 -117
- package/dist/engines/pi/session-control.d.ts +0 -77
- package/dist/engines/pi/session-control.js +0 -908
- package/dist/engines/pi/session-effects.d.ts +0 -14
- package/dist/engines/pi/session-effects.js +0 -30
- package/dist/engines/pi/session-inheritance.d.ts +0 -21
- package/dist/engines/pi/session-inheritance.js +0 -204
- package/dist/engines/pi/session-markers.d.ts +0 -49
- package/dist/engines/pi/session-markers.js +0 -60
- package/dist/engines/pi/session-settings.d.ts +0 -67
- package/dist/engines/pi/session-settings.js +0 -119
- package/dist/engines/pi/session-store.d.ts +0 -69
- package/dist/engines/pi/session-store.js +0 -430
- package/dist/engines/pi/tool-context.d.ts +0 -45
- package/dist/engines/pi/tool-context.js +0 -31
- package/dist/engines/pi/tool.d.ts +0 -99
- package/dist/engines/pi/tool.js +0 -118
- package/dist/engines/pi/turn-kit.d.ts +0 -83
- package/dist/engines/pi/turn-kit.js +0 -275
- package/dist/engines/pi/wake-tool.d.ts +0 -9
- package/dist/engines/pi/wake-tool.js +0 -92
- package/dist/loader.d.ts +0 -41
- package/dist/loader.js +0 -116
- package/dist/node.d.ts +0 -3
- package/dist/node.js +0 -4
- package/dist/observe.d.ts +0 -6
- package/dist/observe.js +0 -47
- package/dist/pi.d.ts +0 -25
- package/dist/pi.js +0 -15
- package/dist/scaffold/templates/APPEND_SYSTEM.md +0 -12
- package/dist/scaffold/templates/tools/fetch-url.ts +0 -25
- package/dist/schedule/discover.d.ts +0 -17
- package/dist/schedule/discover.js +0 -61
- package/dist/schedule/routine.d.ts +0 -43
- package/dist/schedule/routine.js +0 -32
- package/dist/schedule/run.d.ts +0 -55
- package/dist/schedule/run.js +0 -146
- package/dist/secrets-gate.d.ts +0 -32
- package/dist/secrets-gate.js +0 -33
- package/dist/session-remote.d.ts +0 -47
- package/dist/session-remote.js +0 -460
- package/dist/session.d.ts +0 -466
- package/dist/session.js +0 -57
- /package/dist/{channels/kit/state.d.ts → state-file.d.ts} +0 -0
package/dist/service.js
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
|
-
/** The product, as one call: an agent
|
|
1
|
+
/** The product, as one call: an opened agent becomes a live service, its channels, schedules and wake-ups. */
|
|
2
2
|
import * as Cause from "effect/Cause";
|
|
3
3
|
import * as Effect from "effect/Effect";
|
|
4
4
|
import * as Exit from "effect/Exit";
|
|
5
5
|
import * as Fiber from "effect/Fiber";
|
|
6
6
|
import * as Scope from "effect/Scope";
|
|
7
|
-
import {
|
|
8
|
-
import { createInvokeHandler } from "./channels/http.js";
|
|
7
|
+
import { mountChannels } from "./channels/discover.js";
|
|
9
8
|
import { text } from "./channels/respond.js";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
9
|
+
import { parseRouteKey, router } from "./channels/router.js";
|
|
10
|
+
import { serveHandler, totalFetch } from "./channels/serve.js";
|
|
11
|
+
import { portCleanup } from "./effect-port.js";
|
|
12
|
+
import { API_PREFIX } from "./http/contract.js";
|
|
13
|
+
import { apiHandler, isApiPath } from "./http/server.js";
|
|
15
14
|
import { log } from "./log.js";
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
15
|
+
import { once } from "./once.js";
|
|
16
|
+
import { createScheduler } from "./schedule/scheduler.js";
|
|
18
17
|
/** Default wait for a channel's `closed` before reporting it stuck. */
|
|
19
18
|
const CLOSE_DEADLINE_MS = 5_000;
|
|
20
19
|
/** One deadline for all connections; a failed close must not hide a sibling that is still running. */
|
|
@@ -42,98 +41,23 @@ function closeWithin(runs, names, deadlineMs) {
|
|
|
42
41
|
}
|
|
43
42
|
/** The port a serve binds when neither a flag, `PORT` (start only) nor `http.port` names one. */
|
|
44
43
|
export const DEFAULT_HTTP_PORT = 8787;
|
|
45
|
-
/**
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* What an anonymous caller of a port can do, worst first — the ONE wording the startup report and deploy's pre-flight
|
|
55
|
-
* both print, each from its own facts (what mounted vs what will mount).
|
|
56
|
-
*/
|
|
57
|
-
export function describeAnonymousSurface(open) {
|
|
58
|
-
return [
|
|
59
|
-
...(open.invoke ? ["POST /invoke (run a turn with this agent's tools)"] : []),
|
|
60
|
-
...(open.run ? ["POST /run (run any routine this agent declares; GET /routines lists them)"] : []),
|
|
61
|
-
...(open.controlPrefix ? [`${open.controlPrefix}/* (read, steer or delete any session)`] : []),
|
|
62
|
-
];
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* The surface this deployment serves: the DATA plane (`POST /invoke`), `GET /health`, and the discovered channels.
|
|
66
|
-
*
|
|
67
|
-
* `/invoke` is the framework's interface, so it is served whatever channels a definition declares (unless
|
|
68
|
-
* `http.invoke: false`). It is RESERVED for the same reason `/control/*` is: a channel taking that path would silently replace the one route every client,
|
|
69
|
-
* every doc and the startup line all name. `/health` stays overridable — a probe is the deployment's to shape.
|
|
70
|
-
*/
|
|
71
|
-
export async function routesFor(agentDir, agent, stateRoot, control,
|
|
72
|
-
/**
|
|
73
|
-
* `http.invoke: false` withholds the data plane. Two callers, two reasons: the AgentCore adapter serves the
|
|
74
|
-
* Runtime's `/invocations` contract instead, and an author sets it to leave the channels' signature checks as the
|
|
75
|
-
* only way into a public port.
|
|
76
|
-
*
|
|
77
|
-
* `routines` mounts `POST /run` and `GET /routines` (per {@link shouldServeRun}). Passed in rather than loaded here
|
|
78
|
-
* so the routes and the resident clock cannot disagree about which routines exist (`loadServingRoutines`).
|
|
79
|
-
*/
|
|
80
|
-
options = {}) {
|
|
81
|
-
const { routes, longConnections, routeChannels, collisions, failures } = await loadChannels(agentDir, {
|
|
82
|
-
agent,
|
|
83
|
-
stateRoot,
|
|
84
|
-
control,
|
|
85
|
-
});
|
|
86
|
-
for (const c of collisions) {
|
|
87
|
-
log.warn(`[fastagent] channel route "${c.route}" (${c.source}) collides with an earlier channel — not mounted`);
|
|
88
|
-
}
|
|
89
|
-
refuseBrokenDeclarations(failures);
|
|
90
|
-
if (collisions.length > 0) {
|
|
91
|
-
throw new Error(`${collisions.length} channel route collision(s) — two channels cannot serve one route`);
|
|
44
|
+
/** Mount the channels and the health check. */
|
|
45
|
+
export function routesFor(agent, stateRoot, channels) {
|
|
46
|
+
const { routes, longConnections, routeChannels } = mountChannels(channels, agent, stateRoot);
|
|
47
|
+
for (const key of Object.keys(routes)) {
|
|
48
|
+
if (isApiPath(parseRouteKey(key).path)) {
|
|
49
|
+
throw new Error(`route "${key}" is under ${API_PREFIX}, which the Agent API serves — move it`);
|
|
50
|
+
}
|
|
92
51
|
}
|
|
93
|
-
/**
|
|
94
|
-
* Which channel key already serves this path for the method a built-in would answer — the CHANNEL's spelling, not
|
|
95
|
-
* ours. A channel may write the method-less `"/invoke"`, and an error naming `"POST /invoke"` sends its author
|
|
96
|
-
* grepping their own file for a string that is not in it.
|
|
97
|
-
*/
|
|
98
|
-
const covered = (path, method) => Object.keys(routes).find((key) => {
|
|
99
|
-
const entry = parseRouteKey(key);
|
|
100
|
-
return entry.path === path && (entry.method === undefined || entry.method === method);
|
|
101
|
-
});
|
|
102
52
|
let ready = longConnections.length === 0;
|
|
103
53
|
const health = () => (ready ? text("ok\n", 200) : text("starting\n", 503));
|
|
104
|
-
|
|
105
|
-
// with no `/invoke` of ours on that surface there is nothing to reserve, which is why the refusal is in here.
|
|
106
|
-
const unverified = { ...(covered("/health", "GET") ? {} : { "GET /health": health }) };
|
|
107
|
-
if (options.http?.invoke !== false)
|
|
108
|
-
unverified["POST /invoke"] = createInvokeHandler(agent);
|
|
109
|
-
// `POST /run` exists only where there is something to run, and `GET /routines` exactly where that route does:
|
|
110
|
-
// it is the catalogue OF that route, so listing names nobody can use would be a catalogue of nothing. Both ride
|
|
111
|
-
// this table for the reason the table exists: they authenticate nobody, so they inherit the JSON body gate, the
|
|
112
|
-
// cross-origin policy, the reserved path and the startup report's account of what is open.
|
|
113
|
-
if (shouldServeRun(options.http)) {
|
|
114
|
-
const routines = options.routines ?? [];
|
|
115
|
-
const run = createRunHandler({ agent, routines });
|
|
116
|
-
if (run)
|
|
117
|
-
unverified["POST /run"] = run;
|
|
118
|
-
const list = createRoutineListHandler({ routines });
|
|
119
|
-
if (list)
|
|
120
|
-
unverified["GET /routines"] = list;
|
|
121
|
-
}
|
|
122
|
-
// ONE rule over the whole table, so the next route we add is reserved by existing here rather than by someone
|
|
123
|
-
// remembering to write a second check for it. `/health` is exempt by construction: it is only in `ours` when no
|
|
124
|
-
// channel already serves it, because a probe is the deployment's to shape.
|
|
125
|
-
const taken = Object.keys(unverified).flatMap((key) => {
|
|
54
|
+
const probed = Object.keys(routes).some((key) => {
|
|
126
55
|
const entry = parseRouteKey(key);
|
|
127
|
-
|
|
128
|
-
return channelKey === undefined ? [] : [{ channelKey, key }];
|
|
56
|
+
return entry.path === "/health" && (entry.method === undefined || entry.method === "GET");
|
|
129
57
|
});
|
|
130
|
-
if (taken.length > 0) {
|
|
131
|
-
throw new Error(`channel route(s) ${taken.map((t) => `"${t.channelKey}"`).join(", ")} take a path this serve answers on ` +
|
|
132
|
-
`itself (${taken.map((t) => `"${t.key}"`).join(", ")}) — rename the channel route`);
|
|
133
|
-
}
|
|
134
58
|
return {
|
|
135
|
-
|
|
136
|
-
|
|
59
|
+
// A probe is the deployment's to shape, so a channel may serve `/health` itself.
|
|
60
|
+
routes: probed ? routes : { ...routes, "GET /health": health },
|
|
137
61
|
longConnections,
|
|
138
62
|
routeChannels,
|
|
139
63
|
setReady(value) {
|
|
@@ -141,78 +65,71 @@ options = {}) {
|
|
|
141
65
|
},
|
|
142
66
|
};
|
|
143
67
|
}
|
|
144
|
-
/**
|
|
145
|
-
export function
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
export function mountSessionControl(routes, control) {
|
|
153
|
-
if (!control)
|
|
154
|
-
return { routes, mounts: [] };
|
|
155
|
-
const plane = createControlPlane(control);
|
|
156
|
-
assertNoControlPlaneCollision(routes, plane);
|
|
157
|
-
return { routes, mounts: [plane], controlPrefix: plane.prefix };
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Load the agent's `routines/`, gated.
|
|
161
|
-
*
|
|
162
|
-
* Separate from {@link startSchedules} because two things need the SAME list and one of them runs first: the
|
|
163
|
-
* `POST /run` route is built with the routes (so a channel cannot take that path unnoticed), and the resident
|
|
164
|
-
* clock starts later, inside the service's scope. Loading twice would let them disagree about which routines exist.
|
|
165
|
-
*/
|
|
166
|
-
export async function loadServingRoutines(agentDir) {
|
|
167
|
-
// Thrown, not exited on: this runs inside an embedder's app as well as the CLI, and a library that calls
|
|
168
|
-
// process.exit takes a decision (degrade? retry? stop?) that belongs to its host.
|
|
169
|
-
const { routines, secrets, failures } = await loadRoutines(agentDir);
|
|
170
|
-
// The routines' half of the serving-path gate (the opener does the tools', loadChannels the
|
|
171
|
-
// channels'): a routine reads its env at IMPORT time, so an unset declared value has already
|
|
172
|
-
// produced a broken prompt — refusing here is the last point where that is a startup failure.
|
|
173
|
-
gateSecrets({ declared: secrets, failures });
|
|
174
|
-
refuseBrokenDeclarations(failures);
|
|
175
|
-
return routines;
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Start the clock over routines {@link loadServingRoutines} already gated — on every serve, routines or not: the
|
|
179
|
-
* agent's own wake-ups are a default capability, and this is what fires them.
|
|
180
|
-
*/
|
|
181
|
-
export function startSchedules(agent, stateRoot, routines, options = {}) {
|
|
182
|
-
const scheduler = Effect.runSync(createScheduler({ agent, stateRoot, routines, externalClock: options.externalClock }));
|
|
68
|
+
/** Start the clock: the definition's schedules, and the wake-ups the agent sets for itself, on every serve. */
|
|
69
|
+
export function startSchedules(agent, stateRoot, schedules, options = {}) {
|
|
70
|
+
const scheduler = Effect.runSync(createScheduler({
|
|
71
|
+
agent,
|
|
72
|
+
stateRoot,
|
|
73
|
+
schedules,
|
|
74
|
+
...(options.localClock === false ? { localClock: false } : {}),
|
|
75
|
+
}));
|
|
183
76
|
scheduler.start();
|
|
184
|
-
if (
|
|
185
|
-
log.info(`[fastagent]
|
|
186
|
-
|
|
187
|
-
return { routines, stop: () => scheduler.stop() };
|
|
77
|
+
if (schedules.length > 0)
|
|
78
|
+
log.info(`[fastagent] schedules: ${schedules.map((s) => s.name).join(", ")}`);
|
|
79
|
+
return scheduler;
|
|
188
80
|
}
|
|
189
81
|
/**
|
|
190
|
-
*
|
|
191
|
-
*
|
|
82
|
+
* A Service over `handler`: answered in process, or served on a server of its own. `endStreams` ends what would hold
|
|
83
|
+
* the server's close open (a Caller watching events), and `shutdown` stops the rest once the server has.
|
|
192
84
|
*/
|
|
193
|
-
export
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
85
|
+
export function serviceOver(handler, ready, shutdown, endStreams = async () => { }) {
|
|
86
|
+
let listener;
|
|
87
|
+
let closing;
|
|
88
|
+
const fetch = totalFetch(handler);
|
|
89
|
+
return {
|
|
90
|
+
fetch,
|
|
91
|
+
listen(port, host) {
|
|
92
|
+
if (closing !== undefined)
|
|
93
|
+
return Promise.reject(new Error("the service is closed"));
|
|
94
|
+
if (listener !== undefined)
|
|
95
|
+
return Promise.reject(new Error("the service is already listening"));
|
|
96
|
+
const current = serveHandler(handler, { port, ...(host === undefined ? {} : { host }) });
|
|
97
|
+
listener = current;
|
|
98
|
+
return current.listening.catch(async (error) => {
|
|
99
|
+
// A bind that failed holds nothing once its scope is closed, so the service may listen again, elsewhere.
|
|
100
|
+
if (listener === current)
|
|
101
|
+
listener = undefined;
|
|
102
|
+
await current.close();
|
|
103
|
+
throw error;
|
|
104
|
+
});
|
|
105
|
+
},
|
|
106
|
+
ready,
|
|
107
|
+
close() {
|
|
108
|
+
closing ??= (async () => {
|
|
109
|
+
// The server first, so nothing new reaches what stops after it; each step runs, and every failure is said.
|
|
110
|
+
const failures = [];
|
|
111
|
+
for (const step of [endStreams, () => listener?.close(), shutdown]) {
|
|
112
|
+
await Promise.resolve()
|
|
113
|
+
.then(step)
|
|
114
|
+
.catch((error) => failures.push(error));
|
|
115
|
+
}
|
|
116
|
+
if (failures.length > 0) {
|
|
117
|
+
throw failures.length === 1 ? failures[0] : new AggregateError(failures, "the service did not close cleanly");
|
|
118
|
+
}
|
|
119
|
+
})();
|
|
120
|
+
return closing;
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/** The assembly itself: channels, schedules and long connections, composed into one handler. */
|
|
125
|
+
export async function serveAgent(opened, options = {}) {
|
|
126
|
+
const { agent, agentDir, stateRoot, schedules } = opened;
|
|
198
127
|
const closeTimeoutMs = options.closeTimeoutMs ?? CLOSE_DEADLINE_MS;
|
|
199
|
-
|
|
200
|
-
// trailing slash would refuse the front end with nothing naming the rule.
|
|
201
|
-
const corsOrigins = opened.http?.cors;
|
|
202
|
-
if (corsOrigins)
|
|
203
|
-
assertCorsOrigins(corsOrigins, "mountAgentService: http.cors");
|
|
204
|
-
// Loaded BEFORE the routes, because `POST /run` is one of them and the resident clock below must run over the
|
|
205
|
-
// same list — two loads would be two answers to "which routines exist".
|
|
206
|
-
const routines = await loadServingRoutines(agentDir);
|
|
207
|
-
const routed = await routesFor(agentDir, agent, stateRoot, sessionControl, { http: opened.http, routines });
|
|
208
|
-
const withControl = mountSessionControl(routed.selfVerifying, opened.publishControl ? sessionControl : undefined);
|
|
128
|
+
const routed = routesFor(agent, stateRoot, opened.channels);
|
|
209
129
|
// Composed BEFORE anything starts.
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
mounts: withControl.mounts,
|
|
214
|
-
...(corsOrigins ? { corsOrigins } : {}),
|
|
215
|
-
});
|
|
130
|
+
const channels = router(routed.routes);
|
|
131
|
+
const api = options.apiKeys?.length ? apiHandler(agent, { keys: options.apiKeys }) : undefined;
|
|
132
|
+
const handler = api === undefined ? channels : (req) => (isApiPath(new URL(req.url).pathname) ? api.fetch(req) : channels(req));
|
|
216
133
|
return Effect.runPromise(Effect.gen(function* () {
|
|
217
134
|
const lifetime = yield* Scope.make();
|
|
218
135
|
const abort = new AbortController();
|
|
@@ -229,21 +146,21 @@ export async function mountAgentService(opened, options = {}) {
|
|
|
229
146
|
routed.setReady(false);
|
|
230
147
|
onClosed(name, error);
|
|
231
148
|
};
|
|
232
|
-
// Scope.close alone does not join concurrent closes or retain their failure.
|
|
233
|
-
|
|
149
|
+
// Scope.close alone does not join concurrent closes or retain their failure. Every later call, the rollback a
|
|
150
|
+
// close itself triggers included, awaits the first one's outcome.
|
|
151
|
+
const shutdown = once(Effect.gen(function* () {
|
|
234
152
|
abort.abort();
|
|
235
153
|
yield* Scope.close(lifetime, Exit.void);
|
|
236
154
|
}));
|
|
237
155
|
const close = () => Effect.runPromise(shutdown);
|
|
238
156
|
const rollback = shutdown.pipe(Effect.catchCause((cause) => Effect.sync(() => log.error(`[fastagent] cleanup after a failed start also failed: ${String(Cause.squash(cause))}`))));
|
|
239
|
-
const onAbort = () => {
|
|
240
|
-
void close().catch((error) => log.error(`[fastagent] service close failed: ${String(error)}`));
|
|
241
|
-
};
|
|
242
157
|
return yield* Effect.gen(function* () {
|
|
158
|
+
if (api !== undefined)
|
|
159
|
+
yield* Effect.addFinalizer(() => portCleanup("closing the Agent API", api.dispose));
|
|
243
160
|
// Registered first, so subscriptions and schedule timers stop before waiting for transports.
|
|
244
161
|
yield* Effect.addFinalizer(() => closeWithin(runs, names, closeTimeoutMs).pipe(Effect.orDie));
|
|
245
|
-
|
|
246
|
-
try: () => startSchedules(agent, stateRoot,
|
|
162
|
+
yield* Effect.acquireRelease(Effect.try({
|
|
163
|
+
try: () => startSchedules(agent, stateRoot, schedules),
|
|
247
164
|
catch: (error) => error,
|
|
248
165
|
}), (scheduled) => Effect.sync(scheduled.stop));
|
|
249
166
|
const readiness = yield* Effect.forEach(routed.longConnections, (connection) => Effect.gen(function* () {
|
|
@@ -269,10 +186,6 @@ export async function mountAgentService(opened, options = {}) {
|
|
|
269
186
|
log.info(`[fastagent] long connection ready: ${connection.name}`);
|
|
270
187
|
})), Effect.forkScoped({ startImmediately: true }));
|
|
271
188
|
}));
|
|
272
|
-
if (options.signal?.aborted)
|
|
273
|
-
yield* shutdown;
|
|
274
|
-
else
|
|
275
|
-
yield* Effect.acquireRelease(Effect.sync(() => options.signal?.addEventListener("abort", onAbort, { once: true })), () => Effect.sync(() => options.signal?.removeEventListener("abort", onAbort)));
|
|
276
189
|
// The public readiness waiter lives outside the scope it may roll back.
|
|
277
190
|
const ready = Effect.runPromise(Effect.gen(function* () {
|
|
278
191
|
yield* Effect.forEach(readiness, Fiber.join, { concurrency: "unbounded", discard: true });
|
|
@@ -287,21 +200,12 @@ export async function mountAgentService(opened, options = {}) {
|
|
|
287
200
|
// The rejection is still delivered to callers that await ready.
|
|
288
201
|
ready.catch(() => { });
|
|
289
202
|
return {
|
|
290
|
-
handler,
|
|
291
|
-
|
|
292
|
-
routes: { ...routed.unverified, ...withControl.routes },
|
|
203
|
+
...serviceOver(handler, ready, close, async () => api?.endStreams()),
|
|
204
|
+
routes: routed.routes,
|
|
293
205
|
agentDir,
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
longConnections: names,
|
|
298
|
-
},
|
|
299
|
-
unverifiedRoutes: Object.keys(routed.unverified),
|
|
300
|
-
...(corsOrigins ? { corsOrigins } : {}),
|
|
301
|
-
routines: scheduled.routines,
|
|
302
|
-
ready,
|
|
303
|
-
...(withControl.controlPrefix ? { controlPrefix: withControl.controlPrefix } : {}),
|
|
304
|
-
close,
|
|
206
|
+
channels: { routes: routed.routeChannels, longConnections: names },
|
|
207
|
+
schedules,
|
|
208
|
+
api: api !== undefined,
|
|
305
209
|
};
|
|
306
210
|
}).pipe(Scope.provide(lifetime), Effect.onError(() => rollback));
|
|
307
211
|
}));
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which command serves this process: `dev` marks it, and everything else (`start`, a deployed box, an embedder) is
|
|
3
|
+
* the default. A channel file reads it at import through the agent's OWN installed copy of this package, which shares
|
|
4
|
+
* nothing with the CLI's copy but the process environment, so the mark lives there.
|
|
5
|
+
*/
|
|
6
|
+
export declare const DEV_SERVE_ENV = "FASTAGENT_DEV";
|
|
7
|
+
export declare function markDevServe(env?: NodeJS.ProcessEnv): void;
|
|
8
|
+
/** For a command that is never `dev` (`start`, `deploy`), run from a shell or a tool that a `dev` process spawned. */
|
|
9
|
+
export declare function unmarkDevServe(env?: NodeJS.ProcessEnv): void;
|
|
10
|
+
export declare function servedByDev(env?: NodeJS.ProcessEnv): boolean;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which command serves this process: `dev` marks it, and everything else (`start`, a deployed box, an embedder) is
|
|
3
|
+
* the default. A channel file reads it at import through the agent's OWN installed copy of this package, which shares
|
|
4
|
+
* nothing with the CLI's copy but the process environment, so the mark lives there.
|
|
5
|
+
*/
|
|
6
|
+
export const DEV_SERVE_ENV = "FASTAGENT_DEV";
|
|
7
|
+
export function markDevServe(env = process.env) {
|
|
8
|
+
env[DEV_SERVE_ENV] = "1";
|
|
9
|
+
}
|
|
10
|
+
/** For a command that is never `dev` (`start`, `deploy`), run from a shell or a tool that a `dev` process spawned. */
|
|
11
|
+
export function unmarkDevServe(env = process.env) {
|
|
12
|
+
delete env[DEV_SERVE_ENV];
|
|
13
|
+
}
|
|
14
|
+
export function servedByDev(env = process.env) {
|
|
15
|
+
return env[DEV_SERVE_ENV] === "1";
|
|
16
|
+
}
|
package/dist/slack.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/** `@fastagent-sh/fastagent/slack` — the first-party Slack Events API bot-channel surface. */
|
|
2
2
|
export { slackChannel, defaultSlackRoute, slackEnvelope, verifySlackSignature, type SlackChannelOptions, type SlackEventEnvelope, type SlackFile, type SlackMessageEvent, type SlackRendering, type SlackRoute, type SlackFailure, } from "./channels/slack/slack.ts";
|
|
3
|
-
export { slackTransport, type SlackTransport } from "./channels/slack/shared-api.ts";
|
|
3
|
+
export { slackThreads, slackTransport, type SlackTransport } from "./channels/slack/shared-api.ts";
|
|
4
4
|
export type { SentSlackMessage, SlackTarget, UploadedSlackFile } from "./channels/slack/slack-api.ts";
|
package/dist/slack.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/** `@fastagent-sh/fastagent/slack` — the first-party Slack Events API bot-channel surface. */
|
|
2
2
|
export { slackChannel, defaultSlackRoute, slackEnvelope, verifySlackSignature, } from "./channels/slack/slack.js";
|
|
3
|
-
export { slackTransport } from "./channels/slack/shared-api.js";
|
|
3
|
+
export { slackThreads, slackTransport } from "./channels/slack/shared-api.js";
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* (`<stateRoot>/channels/<
|
|
4
|
-
* means one ingress credential in two places, and no
|
|
5
|
-
*
|
|
2
|
+
* A Caller's durable state under the state root, with no cross-instance locking: a channel's files are in its own
|
|
3
|
+
* directory (`<stateRoot>/channels/<the channel file's name>/`) and the schedules' in `schedule/`, so what must not
|
|
4
|
+
* happen is two processes serving the SAME channel — which also means one ingress credential in two places, and no
|
|
5
|
+
* local guard can see that (docs/design/core.md §9).
|
|
6
6
|
*/
|
|
7
7
|
import { mkdirSync, readFileSync } from "node:fs";
|
|
8
|
-
import { writeFileAtomic } from "
|
|
9
|
-
import { log } from "
|
|
8
|
+
import { writeFileAtomic } from "./atomic-write.js";
|
|
9
|
+
import { log } from "./log.js";
|
|
10
10
|
/** Create the channel's state home — the one shared spelling of it, so no channel invents its own. */
|
|
11
11
|
export function ensureStateHome(dir) {
|
|
12
12
|
mkdirSync(dir, { recursive: true });
|
package/dist/telegram.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
/** `@fastagent-sh/fastagent/telegram` — the Telegram bot channel subpath export, kept off the root surface. */
|
|
2
2
|
export { telegramChannel, defaultTelegramRoute, telegramEnvelope, telegramStop, type TelegramChannelOptions, type TelegramUpdate, type TelegramMessage, type TelegramRoute, type TelegramFailure, } from "./channels/telegram/telegram.ts";
|
|
3
|
+
export { telegramTransport, type TelegramSendTarget, type TelegramSent, type TelegramTransport, } from "./channels/telegram/shared-api.ts";
|
package/dist/telegram.js
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
/** `@fastagent-sh/fastagent/telegram` — the Telegram bot channel subpath export, kept off the root surface. */
|
|
2
2
|
export { telegramChannel, defaultTelegramRoute, telegramEnvelope, telegramStop, } from "./channels/telegram/telegram.js";
|
|
3
|
+
export { telegramTransport, } from "./channels/telegram/shared-api.js";
|
package/dist/tunnel.d.ts
CHANGED
|
@@ -27,6 +27,9 @@ export declare function startCloudflareTunnel(port: number, spawnFn?: SpawnCloud
|
|
|
27
27
|
export declare function announceWebhooks(dir: string, baseUrl: string, channels: readonly DeclaredChannel[], opts?: {
|
|
28
28
|
openUrl?: (url: string) => void;
|
|
29
29
|
stateRoot?: string;
|
|
30
|
+
env?: NodeJS.ProcessEnv;
|
|
31
|
+
/** {@link Registrars.leave}. */
|
|
32
|
+
leave?: (step: string) => void;
|
|
30
33
|
}): Promise<{
|
|
31
34
|
kind: string;
|
|
32
35
|
outcome: RegistrationOutcome;
|
package/dist/tunnel.js
CHANGED
|
@@ -7,10 +7,10 @@ import { spawn } from "node:child_process";
|
|
|
7
7
|
import { registerFeishuWebhook } from "./channels/feishu/register-webhook.js";
|
|
8
8
|
import { registerSlackWebhook } from "./channels/slack/register-webhook.js";
|
|
9
9
|
import { registerTelegramWebhook } from "./channels/telegram/register-webhook.js";
|
|
10
|
-
import { pointChannelsAt } from "./deploy/channel-ingress.js";
|
|
10
|
+
import { pointChannelsAt, webhookKinds } from "./deploy/channel-ingress.js";
|
|
11
11
|
import { dotEnvPath, loadDotEnv } from "./env.js";
|
|
12
12
|
import { installProxyFetch } from "./proxy.js";
|
|
13
|
-
import { resolveStateRoot } from "./paths.js";
|
|
13
|
+
import { AGENT_ENVIRONMENT_ENV, resolveStateRoot } from "./paths.js";
|
|
14
14
|
import { log } from "./log.js";
|
|
15
15
|
// `(?!api\.)`: cloudflared's ERROR lines mention its request endpoint (`https://api.trycloudflare.com/tunnel`, e.g.
|
|
16
16
|
// "failed to request quick Tunnel: Post ... timeout" under a flaky proxy) — without the exclusion a transient error
|
|
@@ -130,7 +130,8 @@ function lastErrorLine(tail) {
|
|
|
130
130
|
export async function announceWebhooks(dir, baseUrl, channels, opts = {}) {
|
|
131
131
|
log.info(`[fastagent] public URL: ${baseUrl}`);
|
|
132
132
|
try {
|
|
133
|
-
|
|
133
|
+
if (!opts.env)
|
|
134
|
+
loadDotEnv(dir);
|
|
134
135
|
}
|
|
135
136
|
catch (error) {
|
|
136
137
|
// best-effort boundary: an unreadable .env (a MISSING one is already tolerated) still leaves registrars that can
|
|
@@ -141,16 +142,23 @@ export async function announceWebhooks(dir, baseUrl, channels, opts = {}) {
|
|
|
141
142
|
// Readiness is the registrar's job: a fresh quick tunnel returns Cloudflare 530 for ~20-30s before its origin
|
|
142
143
|
// connects, and each registrar absorbs that by retrying the platform call whose own URL verification reports it.
|
|
143
144
|
const feishuOptions = {
|
|
145
|
+
env: opts.env,
|
|
144
146
|
onManualRegistration: ({ consoleUrl }) => opts.openUrl?.(consoleUrl),
|
|
145
147
|
};
|
|
148
|
+
const moving = webhookKinds(channels);
|
|
149
|
+
if (moving.length > 0) {
|
|
150
|
+
log.info(`[fastagent] pointing the selected ${moving.join(", ")} app at ${baseUrl}; only this app's Request URL changes`);
|
|
151
|
+
}
|
|
146
152
|
return pointChannelsAt({
|
|
147
153
|
baseUrl,
|
|
148
154
|
channels,
|
|
149
155
|
log: (message) => log.info(`[fastagent] ${message}`),
|
|
150
156
|
registrars: {
|
|
151
|
-
|
|
157
|
+
...(opts.leave === undefined ? {} : { leave: opts.leave }),
|
|
158
|
+
telegram: (url) => registerTelegramWebhook(url, { env: opts.env }),
|
|
152
159
|
slack: (url) => registerSlackWebhook(url, {
|
|
153
160
|
stateRoot: opts.stateRoot ?? resolveStateRoot(dir),
|
|
161
|
+
environment: process.env[AGENT_ENVIRONMENT_ENV] === "production" ? "production" : "dev",
|
|
154
162
|
log: (message) => log.info(message),
|
|
155
163
|
}),
|
|
156
164
|
feishu: (url, kind) => registerFeishuWebhook(url, kind, feishuOptions),
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** One variable to write: with a `value`, an active line; without one, a placeholder under its `hint`. */
|
|
2
|
+
export interface ValueEntry {
|
|
3
|
+
name: string;
|
|
4
|
+
value?: string;
|
|
5
|
+
hint?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ValueWriteResult {
|
|
8
|
+
/** Generated values written as active `NAME=value` lines. */
|
|
9
|
+
written: string[];
|
|
10
|
+
/** Vars already present with a non-empty active value; left untouched and omitted from next steps. */
|
|
11
|
+
alreadySet: string[];
|
|
12
|
+
/** Set when the secrets dir is an operator-chosen one (`FASTAGENT_SECRETS_DIR`) carrying no `.gitignore`. */
|
|
13
|
+
unprotectedSecretsDir?: string;
|
|
14
|
+
}
|
|
15
|
+
/** What a command says when it wrote a secret into a secrets directory fastagent does not own and git may track. */
|
|
16
|
+
export declare function unprotectedSecretsNote(dir: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Write `entries` into the selected environment's value file, under a `# --- <section> ---` line. A name with a
|
|
19
|
+
* non-empty active value is kept unless `overwrite` names it.
|
|
20
|
+
*/
|
|
21
|
+
export declare function writeValues(dir: string, section: string, entries: readonly ValueEntry[], overwrite?: readonly string[]): Promise<ValueWriteResult>;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Writing the selected environment's value file (`.secrets/.env`, or `.secrets/production/.env` for a deployment):
|
|
3
|
+
* what a command generates (a channel's secret, the Agent API's key) goes in as an active `NAME=value` line, a value
|
|
4
|
+
* already set stays, and the secrets directory fastagent made carries its own `.gitignore`.
|
|
5
|
+
*/
|
|
6
|
+
import { appendFile, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
7
|
+
import { dirname, join } from "node:path";
|
|
8
|
+
import { dotEnvPath, parseEnvContent } from "./env.js";
|
|
9
|
+
import { SECRETS_DIRNAME, SECRET_FILE_MODE, exists } from "./paths.js";
|
|
10
|
+
import { baseTemplate } from "./scaffold/templates.js";
|
|
11
|
+
/** What a command says when it wrote a secret into a secrets directory fastagent does not own and git may track. */
|
|
12
|
+
export function unprotectedSecretsNote(dir) {
|
|
13
|
+
return (`${dir} (FASTAGENT_SECRETS_DIR) now holds a secret and has no .gitignore — that directory is yours, so ` +
|
|
14
|
+
"fastagent will not write one into it. Make sure git does not track what is in there.");
|
|
15
|
+
}
|
|
16
|
+
/** Whether `.env` content carries a non-empty ACTIVE value for `name`. */
|
|
17
|
+
function hasActiveEnvValue(content, name) {
|
|
18
|
+
return (parseEnvContent(content).get(name)?.trim() ?? "") !== "";
|
|
19
|
+
}
|
|
20
|
+
function mentionsEnvName(content, name) {
|
|
21
|
+
return content.split("\n").some((line) => new RegExp(`^\\s*#?\\s*${name}\\s*=`).test(line));
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Write `entries` into the selected environment's value file, under a `# --- <section> ---` line. A name with a
|
|
25
|
+
* non-empty active value is kept unless `overwrite` names it.
|
|
26
|
+
*/
|
|
27
|
+
export async function writeValues(dir, section, entries, overwrite = []) {
|
|
28
|
+
const file = dotEnvPath(dir);
|
|
29
|
+
const secretsDir = dirname(file);
|
|
30
|
+
await mkdir(secretsDir, { recursive: true });
|
|
31
|
+
// THE one exception to "fastagent has no opinion about git": the directory it writes secrets into carries its own
|
|
32
|
+
// `.gitignore`.
|
|
33
|
+
const owned = secretsDir === join(dir, SECRETS_DIRNAME) || secretsDir === join(dir, SECRETS_DIRNAME, "production");
|
|
34
|
+
let unprotectedSecretsDir;
|
|
35
|
+
if (owned) {
|
|
36
|
+
// Only EEXIST is tolerable (already protected, or a concurrent writer).
|
|
37
|
+
await writeFile(join(secretsDir, ".gitignore"), baseTemplate("secrets.gitignore"), { flag: "wx" }).catch((e) => {
|
|
38
|
+
if (e.code !== "EEXIST")
|
|
39
|
+
throw e;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
else if (!(await exists(join(secretsDir, ".gitignore")))) {
|
|
43
|
+
unprotectedSecretsDir = secretsDir;
|
|
44
|
+
}
|
|
45
|
+
let current = "";
|
|
46
|
+
try {
|
|
47
|
+
current = await readFile(file, "utf8");
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
if (e.code !== "ENOENT")
|
|
51
|
+
throw e;
|
|
52
|
+
}
|
|
53
|
+
const alreadySet = entries
|
|
54
|
+
.filter((e) => !overwrite.includes(e.name) && hasActiveEnvValue(current, e.name))
|
|
55
|
+
.map((e) => e.name);
|
|
56
|
+
const lines = [];
|
|
57
|
+
const written = [];
|
|
58
|
+
const contentLines = current.split("\n");
|
|
59
|
+
let replacedInPlace = false;
|
|
60
|
+
for (const e of entries) {
|
|
61
|
+
if (alreadySet.includes(e.name))
|
|
62
|
+
continue;
|
|
63
|
+
if (e.value !== undefined) {
|
|
64
|
+
// An ACTIVE but EMPTY assignment already in the file (an uncommented, unfilled placeholder from `cp
|
|
65
|
+
// .env.example .env`) must be replaced IN PLACE.
|
|
66
|
+
let idx = -1;
|
|
67
|
+
for (let i = contentLines.length - 1; i >= 0; i--) {
|
|
68
|
+
if (parseEnvContent(contentLines[i]).has(e.name)) {
|
|
69
|
+
idx = i;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (idx >= 0) {
|
|
74
|
+
contentLines[idx] = `${e.name}=${e.value}`;
|
|
75
|
+
replacedInPlace = true;
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
lines.push(`${e.name}=${e.value}`);
|
|
79
|
+
}
|
|
80
|
+
written.push(e.name);
|
|
81
|
+
}
|
|
82
|
+
else if (!mentionsEnvName(current, e.name)) {
|
|
83
|
+
// Hint above, never inline after `=` (this IS the file loadDotEnv reads).
|
|
84
|
+
lines.push(...(e.hint === undefined ? [] : [`# ${e.hint}`]), `# ${e.name}=`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// 0600 on the file this call CREATES, and nothing at all about one it did not: a `.env` the operator made with
|
|
88
|
+
// `cp .secrets/.env.example .secrets/.env` carries the mode that command gave it, and re-deciding it would be
|
|
89
|
+
// fastagent changing the permissions of a file it does not own.
|
|
90
|
+
const secret = { mode: SECRET_FILE_MODE };
|
|
91
|
+
if (replacedInPlace) {
|
|
92
|
+
current = contentLines.join("\n");
|
|
93
|
+
await writeFile(file, current, secret);
|
|
94
|
+
}
|
|
95
|
+
if (lines.length > 0) {
|
|
96
|
+
const marker = `# --- ${section} ---`;
|
|
97
|
+
if (current.includes(marker)) {
|
|
98
|
+
// A marker already present (e.g. a .env copied from .env.example) — slot the new lines under it instead of
|
|
99
|
+
// orphaning them at the end of the file.
|
|
100
|
+
await writeFile(file, current.replace(marker, `${marker}\n${lines.join("\n")}`), secret);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
const prefix = current === "" ? "" : current.endsWith("\n") ? "\n" : "\n\n";
|
|
104
|
+
await appendFile(file, `${prefix}${marker}\n${lines.join("\n")}\n`, secret);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return { written, alreadySet, ...(unprotectedSecretsDir === undefined ? {} : { unprotectedSecretsDir }) };
|
|
108
|
+
}
|
package/dist/version.d.ts
CHANGED
|
@@ -3,3 +3,8 @@
|
|
|
3
3
|
* scaffolded dependency range (`^${version}`), so `init` must never fall back and scaffold an uninstallable `^0.0.0`.
|
|
4
4
|
*/
|
|
5
5
|
export declare function fastagentVersion(): Promise<string>;
|
|
6
|
+
/** This build's version, and the exact versions of the harness packages it runs, for a new agent to depend on. */
|
|
7
|
+
export declare function fastagentBuild(): Promise<{
|
|
8
|
+
version: string;
|
|
9
|
+
harness: Record<string, string>;
|
|
10
|
+
}>;
|