@fastagent-sh/fastagent 0.24.4 → 0.26.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 +54 -82
- package/dist/agent-api.d.ts +460 -0
- package/dist/agent-api.js +209 -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 +81 -0
- package/dist/authoring.js +245 -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 +116 -64
- package/dist/cli/auth-view.d.ts +10 -3
- package/dist/cli/auth-view.js +8 -6
- package/dist/cli/box-login.d.ts +18 -7
- package/dist/cli/box-login.js +46 -12
- package/dist/cli/commands/add.d.ts +15 -4
- package/dist/cli/commands/add.js +253 -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 +191 -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 +132 -16
- package/dist/cli/commands/login.d.ts +31 -2
- package/dist/cli/commands/login.js +416 -65
- 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 +6 -4
- package/dist/cli/login-relay.js +19 -7
- 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 +70 -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 +220 -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 +223 -202
- 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 +52 -27
- package/dist/effect-port.d.ts +4 -4
- package/dist/effect-port.js +4 -4
- package/dist/env.d.ts +0 -13
- package/dist/env.js +1 -44
- 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 +51 -0
- package/dist/environment/mise.js +272 -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 +48 -0
- package/dist/harnesses/models/environment.js +88 -0
- package/dist/harnesses/models/host.d.ts +30 -0
- package/dist/harnesses/models/host.js +97 -0
- package/dist/{engines/pi → harnesses/models}/login.d.ts +66 -70
- package/dist/harnesses/models/login.js +439 -0
- package/dist/harnesses/models/models.d.ts +84 -0
- package/dist/harnesses/models/models.js +197 -0
- package/dist/harnesses/pi-durable/agent.d.ts +42 -0
- package/dist/harnesses/pi-durable/agent.js +581 -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 +95 -0
- package/dist/harnesses/pi-durable/open.js +330 -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 +90 -0
- package/dist/harnesses/pi-durable/serve.js +186 -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 +11 -0
- package/dist/harnesses/pi-durable/wake.js +90 -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 +19 -4
- package/dist/index.js +13 -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/sign-in-api.d.ts +147 -0
- package/dist/sign-in-api.js +9 -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 +14 -5
- package/dist/value-file.d.ts +40 -0
- package/dist/value-file.js +164 -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 -535
- 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/login.js +0 -331
- 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 -92
- package/dist/engines/pi/turn-kit.js +0 -288
- 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/loader.js
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
-
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
-
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
-
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
-
});
|
|
6
|
-
}
|
|
7
|
-
return path;
|
|
8
|
-
};
|
|
9
|
-
import { readdir } from "node:fs/promises";
|
|
10
|
-
import { basename, extname, join } from "node:path";
|
|
11
|
-
import { pathToFileURL } from "node:url";
|
|
12
|
-
import { log } from "./log.js";
|
|
13
|
-
const MODULE_EXTS = new Set([".ts", ".js", ".mjs"]);
|
|
14
|
-
/** Whether `name` is an importable agent module (a discovery candidate, not a type declaration). */
|
|
15
|
-
function isModuleFile(name) {
|
|
16
|
-
return MODULE_EXTS.has(extname(name)) && !name.endsWith(".d.ts");
|
|
17
|
-
}
|
|
18
|
-
/** The name a module is known by: its basename without the extension. */
|
|
19
|
-
function moduleName(fileName) {
|
|
20
|
-
return basename(fileName, extname(fileName));
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* WHAT A CODE-INPUT DIRECTORY DECLARES — the single answer to "which files here are modules", without importing any of
|
|
24
|
-
* them. Internal: the loading functions below are its only consumers.
|
|
25
|
-
*/
|
|
26
|
-
async function moduleInventory(subDir) {
|
|
27
|
-
let dirents;
|
|
28
|
-
try {
|
|
29
|
-
dirents = await readdir(subDir, { withFileTypes: true });
|
|
30
|
-
}
|
|
31
|
-
catch (error) {
|
|
32
|
-
const code = error.code;
|
|
33
|
-
if (code === "ENOENT" || code === "not_found")
|
|
34
|
-
return [];
|
|
35
|
-
throw new Error(`cannot read ${subDir}: ${error.message}`);
|
|
36
|
-
}
|
|
37
|
-
const sub = basename(subDir);
|
|
38
|
-
const entries = [];
|
|
39
|
-
// Sorted by the NAME a consumer sees, so none of them re-sorts and none can disagree about order.
|
|
40
|
-
const byName = (a, b) => moduleName(a.name).localeCompare(moduleName(b.name)) || a.name.localeCompare(b.name);
|
|
41
|
-
for (const dirent of dirents.sort(byName)) {
|
|
42
|
-
if (!isModuleFile(dirent.name))
|
|
43
|
-
continue;
|
|
44
|
-
const label = `${sub}/${dirent.name}`;
|
|
45
|
-
if (dirent.isFile()) {
|
|
46
|
-
entries.push({ name: moduleName(dirent.name), label, file: join(subDir, dirent.name) });
|
|
47
|
-
}
|
|
48
|
-
else if (dirent.isSymbolicLink()) {
|
|
49
|
-
log.warn(`[fastagent] ${label} is a symlink — code inputs must be real files inside the agent dir — not loaded`);
|
|
50
|
-
}
|
|
51
|
-
else if (dirent.isDirectory()) {
|
|
52
|
-
log.warn(`[fastagent] ${label} is a directory, not a file — not loaded`);
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
log.warn(`[fastagent] ${label} is not a regular file — not loaded`);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
return entries;
|
|
59
|
-
}
|
|
60
|
-
/** A module the loader skipped, said once, the same way for tools, channels and routines. */
|
|
61
|
-
export function reportModuleLoadFailures(failures) {
|
|
62
|
-
for (const f of failures)
|
|
63
|
-
log.warn(`[fastagent] ${f.label} failed to load, skipping it — ${f.message}`);
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* THE REFUSAL every path that is about to RUN the agent shares: an enabled file under `tools/`, `channels/` or
|
|
67
|
-
* `routines/` is a declaration, so one that cannot load means the agent is missing something its author said it
|
|
68
|
-
* has. Starting anyway announces a ready service over an absent capability — a schedule that never fires, a tool the
|
|
69
|
-
* model simply never gets — with nothing but one warning to find it by. Every failure is reported before this
|
|
70
|
-
* throws, so a boot fixes all of them at once rather than one per restart.
|
|
71
|
-
*
|
|
72
|
-
* Inspecting a definition (`info`, `fastagent tool`) is NOT this path: it must survive a broken file in order to
|
|
73
|
-
* report it.
|
|
74
|
-
*/
|
|
75
|
-
export function refuseBrokenDeclarations(failures) {
|
|
76
|
-
if (failures.length === 0)
|
|
77
|
-
return;
|
|
78
|
-
reportModuleLoadFailures(failures);
|
|
79
|
-
// The reasons are repeated from the warnings above because this message is all an embedder catching the rejection
|
|
80
|
-
// has, and all a deployment running at FASTAGENT_LOG_LEVEL=error sees.
|
|
81
|
-
throw new Error(`failed to load: ${failures.map((f) => `${f.label} (${f.message})`).join("; ")} — fix it, or rename an ` +
|
|
82
|
-
`intentionally disabled file to *.disabled`);
|
|
83
|
-
}
|
|
84
|
-
/** Import every module the directory declares ({@link moduleInventory}). */
|
|
85
|
-
export async function loadModuleDir(subDir) {
|
|
86
|
-
const entries = await moduleInventory(subDir);
|
|
87
|
-
const modules = [];
|
|
88
|
-
const failures = [];
|
|
89
|
-
for (const { name, label, file } of entries) {
|
|
90
|
-
try {
|
|
91
|
-
const mod = (await import(__rewriteRelativeImportExtension(pathToFileURL(file).href)));
|
|
92
|
-
modules.push({ name, label, file, mod });
|
|
93
|
-
}
|
|
94
|
-
catch (error) {
|
|
95
|
-
failures.push({
|
|
96
|
-
label,
|
|
97
|
-
file,
|
|
98
|
-
message: `${error.message}${moduleLoadHint(error)}`,
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
return { modules, failures };
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* A hint for the two common dynamic-import failures — an uninstalled dependency or a non-ESM package — and empty
|
|
106
|
-
* otherwise, so an unrelated error is reported on its own.
|
|
107
|
-
*/
|
|
108
|
-
export function moduleLoadHint(error) {
|
|
109
|
-
if (error.code === "ERR_MODULE_NOT_FOUND" || /Cannot find (package|module)/.test(error.message)) {
|
|
110
|
-
return "\n (a dependency is not installed — run `npm install` in the agent dir)";
|
|
111
|
-
}
|
|
112
|
-
if (/import statement outside a module|Unexpected token 'export'|ERR_REQUIRE_ESM/.test(error.message)) {
|
|
113
|
-
return '\n (the agent dir must be ESM — set "type": "module" in package.json)';
|
|
114
|
-
}
|
|
115
|
-
return "";
|
|
116
|
-
}
|
package/dist/node.d.ts
DELETED
package/dist/node.js
DELETED
package/dist/observe.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The turn trace: wrap an Agent to tee each turn's loop — prompt, reasoning, tool calls (name + args) with results,
|
|
3
|
-
* reply, terminal — to the log at DEBUG level.
|
|
4
|
-
*/
|
|
5
|
-
import type { Agent } from "./agent.ts";
|
|
6
|
-
export declare function logAgentLoop(agent: Agent, sink?: (line: string) => void): Agent;
|
package/dist/observe.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { log } from "./log.js";
|
|
2
|
-
const PREVIEW = 200;
|
|
3
|
-
/** One line, whitespace-collapsed, truncated — a log stays scannable. */
|
|
4
|
-
function oneLine(s) {
|
|
5
|
-
const t = s.replace(/\s+/g, " ").trim();
|
|
6
|
-
return t.length > PREVIEW ? `${t.slice(0, PREVIEW - 1)}…` : t;
|
|
7
|
-
}
|
|
8
|
-
const preview = (v) => oneLine(typeof v === "string" ? v : JSON.stringify(v));
|
|
9
|
-
export function logAgentLoop(agent, sink = (line) => log.debug(line)) {
|
|
10
|
-
return {
|
|
11
|
-
async *invoke(scope, prompt) {
|
|
12
|
-
const s = scope.session;
|
|
13
|
-
sink(`[agent] ▶ turn session=${s} ← ${oneLine(prompt.text)}`);
|
|
14
|
-
const toolName = new Map(); // tool_ended carries no name — remember it from tool_started
|
|
15
|
-
let thinking = "";
|
|
16
|
-
let reply = "";
|
|
17
|
-
for await (const e of agent.invoke(scope, prompt)) {
|
|
18
|
-
if (e.type === "text") {
|
|
19
|
-
reply += e.delta;
|
|
20
|
-
}
|
|
21
|
-
else if (e.type === "thinking") {
|
|
22
|
-
thinking += e.delta;
|
|
23
|
-
}
|
|
24
|
-
else if (e.type === "tool_started") {
|
|
25
|
-
toolName.set(e.id, e.name);
|
|
26
|
-
sink(`[agent] tool → ${e.name}(${preview(e.args)})`);
|
|
27
|
-
}
|
|
28
|
-
else if (e.type === "tool_ended") {
|
|
29
|
-
sink(`[agent] tool ${e.isError ? "✗" : "✓"} ${toolName.get(e.id) ?? e.id} → ${preview(e.content)}`);
|
|
30
|
-
}
|
|
31
|
-
else if (e.type === "retrying") {
|
|
32
|
-
sink(`[agent] retrying (${e.attempt}/${e.maxAttempts} in ${e.delayMs}ms): ${oneLine(e.reason)}`);
|
|
33
|
-
}
|
|
34
|
-
else if (e.type === "completed") {
|
|
35
|
-
if (thinking.trim() !== "")
|
|
36
|
-
sink(`[agent] thinking: ${oneLine(thinking)}`);
|
|
37
|
-
sink(`[agent] reply: ${oneLine(reply) || "(empty)"}`);
|
|
38
|
-
sink(`[agent] ■ completed session=${s}`);
|
|
39
|
-
}
|
|
40
|
-
else if (e.type === "failed") {
|
|
41
|
-
sink(`[agent] ■ failed session=${s}: ${e.details} (retryable=${e.retryable})`);
|
|
42
|
-
}
|
|
43
|
-
yield e;
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
}
|
package/dist/pi.d.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
export { createPiAgent, createPiAgentFromDefinition, type CreatePiAgentFromDefinitionOptions, type CreatePiAgentOptions, } from "./engines/pi/create.ts";
|
|
2
|
-
export { defineTool, type DefineToolOptions, type FastagentTool, type MountedTool, type ToolCollision, type ToolContext, } from "./engines/pi/tool.ts";
|
|
3
|
-
export type { ReadonlySessionManager, ToolActivation } from "./engines/pi/tool-context.ts";
|
|
4
|
-
export { z } from "zod";
|
|
5
|
-
export type { AgentTool, ExecutionEnv, Skill, SkillDiagnostic } from "@earendil-works/pi-agent-core";
|
|
6
|
-
/** A conversation record, as the tool runtime and the control plane hold it. */
|
|
7
|
-
export type { SessionManager, SessionEntry as PiSessionEntry } from "@earendil-works/pi-coding-agent";
|
|
8
|
-
export { availableModelsFromDir, createPiAgentFromDir, type CreatePiAgentFromDirOptions, refreshMachineModelCatalog, refreshModelCatalog, } from "./engines/pi/open.ts";
|
|
9
|
-
export type { DefinitionDiagnostic, DefinitionFile, DefinitionPrompt, DefinitionShadow, LoadedDefinition, SkillCollision, } from "./engines/pi/definition.ts";
|
|
10
|
-
export { defineConfig, listModels, resolveModel, type FastagentConfig, } from "./engines/pi/config.ts";
|
|
11
|
-
export type { SessionObserver } from "./engines/pi/turn-kit.ts";
|
|
12
|
-
export { inProcessLease, type Lease, type Release } from "./engines/pi/turn-kit.ts";
|
|
13
|
-
export { createPiSessionControl, type CreatePiSessionControlOptions, } from "./engines/pi/session-control.ts";
|
|
14
|
-
export { piInMemorySessionRecordStore, piSessionRecordStore, type PiSessionRecordStore, } from "./engines/pi/session-store.ts";
|
|
15
|
-
export type { SessionInheritance } from "./engines/pi/session-inheritance.ts";
|
|
16
|
-
export { GLOBAL_AUTH_PATH, fastagentCredentialStore, type FastagentAuthOptions } from "./engines/pi/auth.ts";
|
|
17
|
-
export { createPiModels, type CreatePiModelsOptions } from "./engines/pi/agent-models.ts";
|
|
18
|
-
export { probeAuthSource } from "./engines/pi/models.ts";
|
|
19
|
-
export { login, loginOptions, LoginCancelled, type LoginMethod, type LoginOption, type LoginRequest, type LoginResult, } from "./engines/pi/login.ts";
|
|
20
|
-
/** pi-ai's sign-in types, and the `CredentialStore` a caller supplies as `credentialStore` (with what it holds). */
|
|
21
|
-
export type { AuthEvent, AuthInteraction, AuthPrompt, Credential, CredentialStore } from "@earendil-works/pi-ai";
|
|
22
|
-
export type { Models } from "@earendil-works/pi-ai";
|
|
23
|
-
export type { Provider, ProviderAuth } from "@earendil-works/pi-ai";
|
|
24
|
-
export type { Model } from "@earendil-works/pi-ai";
|
|
25
|
-
export { createAgentService, type CreateAgentServiceOptions } from "./engines/pi/service.ts";
|
package/dist/pi.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
// The pi reference implementation: assembly, agent discovery, tools, config, models, auth, and state ports.
|
|
2
|
-
export { createPiAgent, createPiAgentFromDefinition, } from "./engines/pi/create.js";
|
|
3
|
-
export { defineTool, } from "./engines/pi/tool.js";
|
|
4
|
-
export { z } from "zod";
|
|
5
|
-
export { availableModelsFromDir, createPiAgentFromDir, refreshMachineModelCatalog, refreshModelCatalog, } from "./engines/pi/open.js";
|
|
6
|
-
export { defineConfig, listModels, resolveModel, } from "./engines/pi/config.js";
|
|
7
|
-
export { inProcessLease } from "./engines/pi/turn-kit.js";
|
|
8
|
-
export { createPiSessionControl, } from "./engines/pi/session-control.js";
|
|
9
|
-
export { piInMemorySessionRecordStore, piSessionRecordStore, } from "./engines/pi/session-store.js";
|
|
10
|
-
export { GLOBAL_AUTH_PATH, fastagentCredentialStore } from "./engines/pi/auth.js";
|
|
11
|
-
export { createPiModels } from "./engines/pi/agent-models.js";
|
|
12
|
-
export { probeAuthSource } from "./engines/pi/models.js";
|
|
13
|
-
export { login, loginOptions, LoginCancelled, } from "./engines/pi/login.js";
|
|
14
|
-
// The product's one-call assembly: a directory becomes a live service.
|
|
15
|
-
export { createAgentService } from "./engines/pi/service.js";
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
# Standing instructions
|
|
2
|
-
|
|
3
|
-
These instructions are added to your system prompt on every turn. This file, `APPEND_SYSTEM.md`, is re-read every turn along with the rest of your definition (`skills/` — capabilities you load when a task calls for them; `prompts/` — prompt templates; `tools/` — code tools your author added, in the same directory as this file). An edit to any of them takes effect on your next message, no restart.
|
|
4
|
-
|
|
5
|
-
Your definition is this directory: `APPEND_SYSTEM.md`, `skills/`, `tools/`, and the config beside them. Your WORKSPACE is the directory you were started in — the project you work on. It may be this same directory, or the one containing it; `fastagent info` prints both. Use only the tools actually listed in your system prompt. If the workspace has an `AGENTS.md`, it is project context — follow it without assuming a file tool is available.
|
|
6
|
-
|
|
7
|
-
When your mounted tools allow it, you can improve yourself. When a task reveals something durable — a repeatable process, a standing preference, a hard-won fact — write it into your definition instead of losing it:
|
|
8
|
-
|
|
9
|
-
- A repeatable process or capability → a new skill beside this file: `skills/<name>/SKILL.md`. Read `skills/writing-great-skills/SKILL.md` first; it is the guide to authoring skills well.
|
|
10
|
-
- A standing instruction or fact → edit this file.
|
|
11
|
-
|
|
12
|
-
Keep both lean: include only what changes your behavior, and delete what no longer earns its place.
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { defineTool, z } from "@fastagent-sh/fastagent";
|
|
2
|
-
|
|
3
|
-
// A code tool: filename (fetch-url.ts) is the tool name. tools/ is auto-discovered,
|
|
4
|
-
// so it needs no registration in fastagent.config. Test it without a model:
|
|
5
|
-
// fastagent tool fetch-url '{"url":"https://example.com"}'
|
|
6
|
-
const MAX_TEXT = 20_000; // keep a huge page from flooding the model's context
|
|
7
|
-
|
|
8
|
-
export default defineTool({
|
|
9
|
-
description: "Fetch a web page and return its readable text (HTML stripped, truncated).",
|
|
10
|
-
input: z.object({ url: z.url({ protocol: /^https?$/ }).describe("The http(s) URL to fetch") }),
|
|
11
|
-
async execute({ url }) {
|
|
12
|
-
const res = await fetch(url, { redirect: "follow", signal: AbortSignal.timeout(15_000) });
|
|
13
|
-
if (!res.ok) throw new Error(`GET ${url} failed: ${res.status} ${res.statusText}`);
|
|
14
|
-
const html = await res.text();
|
|
15
|
-
// ponytail: naive tag strip — fine for articles and docs; swap in a readability library if it falls short.
|
|
16
|
-
const entities: Record<string, string> = { amp: "&", lt: "<", gt: ">", quot: '"', "#39": "'", nbsp: " " };
|
|
17
|
-
const text = html
|
|
18
|
-
.replace(/<(script|style)\b[\s\S]*?<\/\1>/gi, " ")
|
|
19
|
-
.replace(/<[^>]+>/g, " ")
|
|
20
|
-
.replace(/&(amp|lt|gt|quot|#39|nbsp);/g, (_, e) => entities[e] ?? " ")
|
|
21
|
-
.replace(/\s+/g, " ")
|
|
22
|
-
.trim();
|
|
23
|
-
return { url: res.url, text: text.slice(0, MAX_TEXT), truncated: text.length > MAX_TEXT };
|
|
24
|
-
},
|
|
25
|
-
});
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { type ModuleLoadFailure } from "../loader.ts";
|
|
2
|
-
import { type DeclaredSecret } from "../declared-secrets.ts";
|
|
3
|
-
import type { LoadedRoutine } from "./routine.ts";
|
|
4
|
-
/**
|
|
5
|
-
* Discover routines in `<dir>/routines/`: each file default-exports a `defineRoutine({...})`, named from its
|
|
6
|
-
* filename.
|
|
7
|
-
*/
|
|
8
|
-
export declare function loadRoutines(dir: string): Promise<{
|
|
9
|
-
routines: LoadedRoutine[];
|
|
10
|
-
/** What each loaded routine declared it needs, BY ROUTINE NAME and attributed to its file. Per
|
|
11
|
-
* routine because a caller that runs exactly ONE of them (`fastagent routine run`) must not be stopped
|
|
12
|
-
* by a sibling's credential, and because two routines declaring the same variable would
|
|
13
|
-
* otherwise blame whichever file was read first. The clock flattens it (it runs all of them).
|
|
14
|
-
* Data, not a check — only a serving path asserts it (src/declared-secrets.ts). */
|
|
15
|
-
secrets: Map<string, DeclaredSecret[]>;
|
|
16
|
-
failures: ModuleLoadFailure[];
|
|
17
|
-
}>;
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Routine discovery: an agent declares its named units of work by dropping files in `routines/`, mirroring
|
|
3
|
-
* `tools/` and `channels/`.
|
|
4
|
-
*/
|
|
5
|
-
import { join } from "node:path";
|
|
6
|
-
import { loadModuleDir } from "../loader.js";
|
|
7
|
-
import { readSecretDeclaration } from "../declared-secrets.js";
|
|
8
|
-
import { assertInsideAgentDir } from "../paths.js";
|
|
9
|
-
import { cronError } from "./cron.js";
|
|
10
|
-
import { isSafeScheduleName } from "./state.js";
|
|
11
|
-
/**
|
|
12
|
-
* Discover routines in `<dir>/routines/`: each file default-exports a `defineRoutine({...})`, named from its
|
|
13
|
-
* filename.
|
|
14
|
-
*/
|
|
15
|
-
export async function loadRoutines(dir) {
|
|
16
|
-
await assertInsideAgentDir(dir, "routines");
|
|
17
|
-
const { modules, failures } = await loadModuleDir(join(dir, "routines"));
|
|
18
|
-
const byName = new Map();
|
|
19
|
-
const secrets = new Map();
|
|
20
|
-
for (const { name, label, file, mod } of modules) {
|
|
21
|
-
try {
|
|
22
|
-
const r = mod.default;
|
|
23
|
-
if (!r || typeof r.prompt !== "string") {
|
|
24
|
-
throw new Error(`${label} must default-export defineRoutine({ prompt, cron? })`);
|
|
25
|
-
}
|
|
26
|
-
const declaration = readSecretDeclaration(r, label);
|
|
27
|
-
if (declaration.error !== undefined)
|
|
28
|
-
throw new Error(declaration.error);
|
|
29
|
-
// NO CRON IS NOT AN ERROR: the routine is then reachable by name only (`POST /run`, the CLI, a scheduler
|
|
30
|
-
// that calls the route). A `tz` without one is, though — it would read as a time this routine does not have.
|
|
31
|
-
if (r.cron !== undefined && typeof r.cron !== "string")
|
|
32
|
-
throw new Error(`${label}: "cron" must be a string`);
|
|
33
|
-
if (r.cron === undefined && r.tz !== undefined) {
|
|
34
|
-
throw new Error(`${label}: "tz" means nothing without "cron" — remove it, or give this routine a cron`);
|
|
35
|
-
}
|
|
36
|
-
if (r.cron !== undefined) {
|
|
37
|
-
const err = cronError(r.cron, r.tz);
|
|
38
|
-
if (err)
|
|
39
|
-
throw new Error(`${label}: invalid cron/tz — ${err}`);
|
|
40
|
-
}
|
|
41
|
-
// The name becomes a path segment (the fired-slot claims live under `claims/<name>/`), so anything that could
|
|
42
|
-
// leave that directory is refused here — where the author sees which file is wrong — rather than deeper.
|
|
43
|
-
if (!isSafeScheduleName(name)) {
|
|
44
|
-
throw new Error(`${label}: a routine name cannot be ".", ".." or contain a path separator`);
|
|
45
|
-
}
|
|
46
|
-
if (byName.has(name))
|
|
47
|
-
throw new Error(`${label}: duplicate routine name "${name}" — kept the first`);
|
|
48
|
-
byName.set(name, {
|
|
49
|
-
name,
|
|
50
|
-
prompt: r.prompt,
|
|
51
|
-
...(r.cron !== undefined ? { cron: r.cron } : {}),
|
|
52
|
-
...(r.tz !== undefined ? { tz: r.tz } : {}),
|
|
53
|
-
});
|
|
54
|
-
secrets.set(name, declaration.secrets);
|
|
55
|
-
}
|
|
56
|
-
catch (error) {
|
|
57
|
-
failures.push({ label, file, message: error.message });
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return { routines: [...byName.values()], secrets, failures };
|
|
61
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WHICH conversation a routine's turns belong to: all of them, so a routine shares one continuing conversation —
|
|
3
|
-
* and without depending on engine session storage. The ONE spelling of it: the clock invokes through it,
|
|
4
|
-
* `fastagent routine run` reproduces a run with it, `POST /run` reports it as where to look, and
|
|
5
|
-
* `routine history` prints the command that opens it.
|
|
6
|
-
*/
|
|
7
|
-
export declare function routineSession(name: string): string;
|
|
8
|
-
/** A named unit of work the definition owns. With a `cron`, a clock fires it; without one, only its name reaches it. */
|
|
9
|
-
export interface Routine {
|
|
10
|
-
/**
|
|
11
|
-
* 5-field cron expression (`minute hour day-of-month month day-of-week`), or absent.
|
|
12
|
-
*
|
|
13
|
-
* ABSENT IS A REAL CHOICE, not an omission: the routine is then reachable only by name — `POST /run`, the CLI, a
|
|
14
|
-
* platform scheduler that calls the route. A time is one way to ask for work, not what the work is.
|
|
15
|
-
*/
|
|
16
|
-
cron?: string;
|
|
17
|
-
/** IANA timezone for the cron (default "UTC"). Meaningless without `cron`. */
|
|
18
|
-
tz?: string;
|
|
19
|
-
/** The turn's text = the routine's instruction. */
|
|
20
|
-
prompt: string;
|
|
21
|
-
/** Env vars this routine declared — carried by `deploy`, asserted before the clock starts. */
|
|
22
|
-
secrets?: readonly string[];
|
|
23
|
-
}
|
|
24
|
-
/** What an author writes. `prompt` may be built FROM the declared secrets, which is the only reason a
|
|
25
|
-
* routine file ever read the environment (a channel id, a target inbox). */
|
|
26
|
-
export interface DefineRoutineOptions<S extends readonly string[]> {
|
|
27
|
-
cron?: string;
|
|
28
|
-
tz?: string;
|
|
29
|
-
prompt: string | ((secrets: Record<S[number], string>) => string);
|
|
30
|
-
/**
|
|
31
|
-
* Env vars this routine needs (`["SLACK_DIGEST_CHANNEL"]`), typed into the `prompt` builder.
|
|
32
|
-
* `deploy` carries them and the clock refuses to start while one is unset, naming this file
|
|
33
|
-
* (see src/declared-secrets.ts) — the guarantees a bare `process.env` read cannot have.
|
|
34
|
-
*/
|
|
35
|
-
secrets?: S;
|
|
36
|
-
}
|
|
37
|
-
/** Type + completion for a routine file, and the ONE place a prompt builder is resolved (at load:
|
|
38
|
-
* what the loader stores is always a string, so every consumer sees one shape). */
|
|
39
|
-
export declare function defineRoutine<const S extends readonly string[] = readonly []>(routine: DefineRoutineOptions<S>): Routine;
|
|
40
|
-
/** A loaded routine: its authored fields plus the name derived from its filename (authoritative). */
|
|
41
|
-
export interface LoadedRoutine extends Routine {
|
|
42
|
-
name: string;
|
|
43
|
-
}
|
package/dist/schedule/routine.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Routine authoring: `defineRoutine`.
|
|
3
|
-
*
|
|
4
|
-
* A ROUTINE IS THE UNIT OF WORK, and the only named one in the system: a prompt the definition owns, addressed by
|
|
5
|
-
* name. `cron` is a FIELD of it, not a second concept — with one, a clock fires it; without one, it is reached by
|
|
6
|
-
* name alone (`POST /run`).
|
|
7
|
-
*
|
|
8
|
-
* WHAT IT IS NOT: a wake-up. The agent can schedule work for itself too (the `wake` tool, schedule/wakeups.ts), and
|
|
9
|
-
* conceptually that is the same idea — work to be done later. Every operational difference between them follows
|
|
10
|
-
* from ONE root: a routine is written in the DEFINITION (versioned, reviewed, shipped with the image, addressable
|
|
11
|
-
* by name) and a wake-up is written into the STATE by a running agent (minted id, cancellable, aimed back at the
|
|
12
|
-
* conversation it came from, erased by the next release if it were a definition file). Code and data.
|
|
13
|
-
*
|
|
14
|
-
* A `prompt` may be a function of the file's declared `secrets` — the only reason such a file ever read the
|
|
15
|
-
* environment (src/declared-secrets.ts).
|
|
16
|
-
*/
|
|
17
|
-
import { secretValues } from "../declared-secrets.js";
|
|
18
|
-
/**
|
|
19
|
-
* WHICH conversation a routine's turns belong to: all of them, so a routine shares one continuing conversation —
|
|
20
|
-
* and without depending on engine session storage. The ONE spelling of it: the clock invokes through it,
|
|
21
|
-
* `fastagent routine run` reproduces a run with it, `POST /run` reports it as where to look, and
|
|
22
|
-
* `routine history` prints the command that opens it.
|
|
23
|
-
*/
|
|
24
|
-
export function routineSession(name) {
|
|
25
|
-
return `routine:${name}`;
|
|
26
|
-
}
|
|
27
|
-
/** Type + completion for a routine file, and the ONE place a prompt builder is resolved (at load:
|
|
28
|
-
* what the loader stores is always a string, so every consumer sees one shape). */
|
|
29
|
-
export function defineRoutine(routine) {
|
|
30
|
-
const { prompt, ...rest } = routine;
|
|
31
|
-
return { ...rest, prompt: typeof prompt === "function" ? prompt(secretValues(routine.secrets)) : prompt };
|
|
32
|
-
}
|
package/dist/schedule/run.d.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import type { Agent } from "../agent.ts";
|
|
2
|
-
import { type LoadedRoutine } from "./routine.ts";
|
|
3
|
-
/**
|
|
4
|
-
* The 404 for a name this deployment does not declare — drift: a caller outliving the thing it calls. The names are
|
|
5
|
-
* listed so an operator can see whether it is a typo or a stale job without shelling in. The caller's name is CLIPPED
|
|
6
|
-
* before it goes back out: listing this deployment's own names is deliberate, quoting an unauthenticated caller's
|
|
7
|
-
* 4 KiB of body is not (`refuseNonJsonBody` states the same rule for the same table).
|
|
8
|
-
*/
|
|
9
|
-
export declare function unknownRoutine(name: string, routines: readonly LoadedRoutine[]): Response;
|
|
10
|
-
/** The reply shape both doors answer with — one for the route, one for a host that has no route (AgentCore). */
|
|
11
|
-
export interface RoutineRunReply {
|
|
12
|
-
name: string;
|
|
13
|
-
/** WHERE TO LOOK: the turn's output lives in this session's journal (`fastagent routine history`, `/control/*`). */
|
|
14
|
-
session: string;
|
|
15
|
-
ran: boolean;
|
|
16
|
-
/** Present when `ran: false` — today, the previous turn still holding this routine's one session. */
|
|
17
|
-
reason?: string;
|
|
18
|
-
/** Present when the turn RAN and did not finish. */
|
|
19
|
-
failed?: string;
|
|
20
|
-
ms: number;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Run one routine and say what happened. THE one implementation, because there are two doors and only one
|
|
24
|
-
* contract: `POST /run` on any host that publishes routes, and AgentCore's IAM-gated `routine-run` envelope on the
|
|
25
|
-
* host that publishes none. A second copy is how the two would come to answer differently.
|
|
26
|
-
*/
|
|
27
|
-
export declare function runRoutineByName(agent: Agent, routine: LoadedRoutine): Promise<RoutineRunReply>;
|
|
28
|
-
/**
|
|
29
|
-
* Build the handler for `GET /routines` — what a caller may ask for by name.
|
|
30
|
-
*
|
|
31
|
-
* DISCOVERY, because the alternative was a 404. The names were already public: `POST /run` lists them when a caller
|
|
32
|
-
* gets one wrong, which is deliberate (an operator has to tell a typo from a stale caller) — so the only thing this
|
|
33
|
-
* adds is not having to guess wrong first. "Expose a declared prompt as an API" is half a sentence without it.
|
|
34
|
-
*
|
|
35
|
-
* NAMES AND SCHEDULES, NEVER PROMPTS. What a routine SAYS is the definition's content; handing it to an
|
|
36
|
-
* unauthenticated caller would publish the agent's behaviour, which is the one thing keeping the prompt out of the
|
|
37
|
-
* request body was for. `cron` is here because it answers "will this run on its own, or is my clock the only one?",
|
|
38
|
-
* which is a caller's question, not the definition's secret.
|
|
39
|
-
*
|
|
40
|
-
* Mounted exactly where `POST /run` is: it describes that route, so listing names a caller cannot use would be a
|
|
41
|
-
* catalogue of nothing.
|
|
42
|
-
*/
|
|
43
|
-
export declare function createRoutineListHandler(options: {
|
|
44
|
-
routines: readonly LoadedRoutine[];
|
|
45
|
-
}): ((req: Request) => Promise<Response>) | undefined;
|
|
46
|
-
/**
|
|
47
|
-
* Build the handler for `POST /run`, bound to what this serve loaded.
|
|
48
|
-
*
|
|
49
|
-
* `undefined` when the definition declares nothing runnable: a route that can only ever answer 404 is not a route,
|
|
50
|
-
* and the startup report names what is actually mounted.
|
|
51
|
-
*/
|
|
52
|
-
export declare function createRunHandler(options: {
|
|
53
|
-
agent: Agent;
|
|
54
|
-
routines: readonly LoadedRoutine[];
|
|
55
|
-
}): ((req: Request) => Promise<Response>) | undefined;
|
package/dist/schedule/run.js
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `POST /run` — **an API**: run a unit of work this definition declares, by name.
|
|
3
|
-
*
|
|
4
|
-
* NOT A TIME TRIGGER, and the difference is the whole design. Occurrence semantics — a slot, a claim, a fire
|
|
5
|
-
* history, an overlap policy — exist exactly where fastagent OWNS the clock: the resident loop in `dev`/`start`,
|
|
6
|
-
* and AgentCore, where `deploy` writes the EventBridge rule, injects the instant and relays it through an ingress
|
|
7
|
-
* secret (channels/agentcore.ts). Both of those know which occurrence a run is for because they produced it.
|
|
8
|
-
*
|
|
9
|
-
* This route is the other case: somebody else's clock, CI job, button or script. It cannot be told which occurrence
|
|
10
|
-
* it means, and pretending otherwise was measurably worse than admitting it. The attempt cost four rounds — an
|
|
11
|
-
* instant dated ahead poisoned the claim gate permanently, one off the grid minted a claim no occurrence would ever
|
|
12
|
-
* match, an old one replayed history a turn at a time, and the grid arithmetic all three needed was ~6ms of
|
|
13
|
-
* synchronous CPU per request on an anonymous route. A platform cron drifting a few minutes then lost an occurrence
|
|
14
|
-
* outright (Railway documents "a few minutes" of variance; measured: 3 fires, 2 turns).
|
|
15
|
-
*
|
|
16
|
-
* So the contract is the one an API has:
|
|
17
|
-
*
|
|
18
|
-
* - the body names WHAT to run and nothing else — the prompt stays in the definition, which is the whole reason
|
|
19
|
-
* this exists beside `POST /invoke`, whose caller brings its own text and therefore its own behaviour
|
|
20
|
-
* - the reply says what happened and WHERE TO LOOK (the session the turn ran in). Retry policy is the caller's,
|
|
21
|
-
* because only the caller knows whether its work tolerates running twice
|
|
22
|
-
* - it is exactly as exposed as `POST /invoke`: unauthenticated, full tool authority, `http.invoke: false` and a
|
|
23
|
-
* gateway in front are the answers. The framework authenticates nothing (docs/design/session-control.md §14)
|
|
24
|
-
*
|
|
25
|
-
* AND NO IDEMPOTENCY KEY. A key would deduplicate the CALL, not the WORK: a turn that sent one message and then died
|
|
26
|
-
* would answer a keyed retry with "already ran" — safety exactly where it is absent, which is the same reason a failed
|
|
27
|
-
* fire is not retried (schedule/scheduler.ts). What makes a retry safe is idempotent WORK, which only the author can
|
|
28
|
-
* arrange.
|
|
29
|
-
*
|
|
30
|
-
* NAME IN THE BODY, not the path. A declared name is a filename (`每日简报`, `my schedule` are both legal), and a
|
|
31
|
-
* path segment would mean percent-encoding it — the cost the control plane pays for session ids and this route has
|
|
32
|
-
* no reason to. It also keeps the shape of `POST /invoke`, whose scope rides in the body for the same reason.
|
|
33
|
-
*/
|
|
34
|
-
import * as Effect from "effect/Effect";
|
|
35
|
-
import { readBodyCapped, refuseNonJsonBody } from "../channels/body.js";
|
|
36
|
-
import { text } from "../channels/respond.js";
|
|
37
|
-
import { routineSession } from "./routine.js";
|
|
38
|
-
import { runTurn } from "./scheduler.js";
|
|
39
|
-
/** A trigger body is a name; the cap only has to admit that. */
|
|
40
|
-
const MAX_RUN_BODY_BYTES = 4 * 1024;
|
|
41
|
-
/**
|
|
42
|
-
* How much of a caller's `name` a 404 will quote back — the ONE thing this route echoes, because telling a typo
|
|
43
|
-
* from a stale caller needs the name and nothing else does. Long enough to recognise one, short enough not to be a
|
|
44
|
-
* page.
|
|
45
|
-
*/
|
|
46
|
-
const MAX_ECHOED_NAME = 64;
|
|
47
|
-
/**
|
|
48
|
-
* The 404 for a name this deployment does not declare — drift: a caller outliving the thing it calls. The names are
|
|
49
|
-
* listed so an operator can see whether it is a typo or a stale job without shelling in. The caller's name is CLIPPED
|
|
50
|
-
* before it goes back out: listing this deployment's own names is deliberate, quoting an unauthenticated caller's
|
|
51
|
-
* 4 KiB of body is not (`refuseNonJsonBody` states the same rule for the same table).
|
|
52
|
-
*/
|
|
53
|
-
export function unknownRoutine(name, routines) {
|
|
54
|
-
return text(`no declared work named "${name.slice(0, MAX_ECHOED_NAME)}" (this deployment has: ${routines
|
|
55
|
-
.map((r) => r.name)
|
|
56
|
-
.join(", ")})\n`, 404);
|
|
57
|
-
}
|
|
58
|
-
/** The Effect boundary, in one place: the turn runs, and its outcome is what the caller reads. */
|
|
59
|
-
const runOnce = (agent, routine) => Effect.runPromise(runTurn(agent, routine.name, routineSession(routine.name), routine.prompt));
|
|
60
|
-
/**
|
|
61
|
-
* Run one routine and say what happened. THE one implementation, because there are two doors and only one
|
|
62
|
-
* contract: `POST /run` on any host that publishes routes, and AgentCore's IAM-gated `routine-run` envelope on the
|
|
63
|
-
* host that publishes none. A second copy is how the two would come to answer differently.
|
|
64
|
-
*/
|
|
65
|
-
export async function runRoutineByName(agent, routine) {
|
|
66
|
-
const session = routineSession(routine.name);
|
|
67
|
-
const { busy, failed, ms } = await runOnce(agent, routine);
|
|
68
|
-
// BUSY IS NOT A FAILURE and it is the one "did not run" this has: a declared unit of work has ONE session, so a
|
|
69
|
-
// call arriving while the previous turn holds it is refused by that session. Reported as itself, with what the
|
|
70
|
-
// caller needs in order to decide — try later — rather than as an error it would retry blindly.
|
|
71
|
-
if (busy) {
|
|
72
|
-
return {
|
|
73
|
-
name: routine.name,
|
|
74
|
-
session,
|
|
75
|
-
ran: false,
|
|
76
|
-
reason: `the previous turn of "${routine.name}" is still running`,
|
|
77
|
-
ms,
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
return { name: routine.name, session, ran: true, ...(failed !== undefined ? { failed } : {}), ms };
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Build the handler for `GET /routines` — what a caller may ask for by name.
|
|
84
|
-
*
|
|
85
|
-
* DISCOVERY, because the alternative was a 404. The names were already public: `POST /run` lists them when a caller
|
|
86
|
-
* gets one wrong, which is deliberate (an operator has to tell a typo from a stale caller) — so the only thing this
|
|
87
|
-
* adds is not having to guess wrong first. "Expose a declared prompt as an API" is half a sentence without it.
|
|
88
|
-
*
|
|
89
|
-
* NAMES AND SCHEDULES, NEVER PROMPTS. What a routine SAYS is the definition's content; handing it to an
|
|
90
|
-
* unauthenticated caller would publish the agent's behaviour, which is the one thing keeping the prompt out of the
|
|
91
|
-
* request body was for. `cron` is here because it answers "will this run on its own, or is my clock the only one?",
|
|
92
|
-
* which is a caller's question, not the definition's secret.
|
|
93
|
-
*
|
|
94
|
-
* Mounted exactly where `POST /run` is: it describes that route, so listing names a caller cannot use would be a
|
|
95
|
-
* catalogue of nothing.
|
|
96
|
-
*/
|
|
97
|
-
export function createRoutineListHandler(options) {
|
|
98
|
-
const { routines } = options;
|
|
99
|
-
if (routines.length === 0)
|
|
100
|
-
return undefined;
|
|
101
|
-
const body = routines.map((r) => ({
|
|
102
|
-
name: r.name,
|
|
103
|
-
...(r.cron !== undefined ? { cron: r.cron } : {}),
|
|
104
|
-
...(r.tz !== undefined ? { tz: r.tz } : {}),
|
|
105
|
-
}));
|
|
106
|
-
// NO METHOD CHECK. The router dispatches `GET /routines` here and nothing else, so the only thing such a check
|
|
107
|
-
// could reach is HEAD — which `channels/serve.ts` deliberately answers with the GET route, the same way
|
|
108
|
-
// `GET /health` is HEAD-probeable. Checking would break that and buy nothing.
|
|
109
|
-
return async () => Response.json(body);
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Build the handler for `POST /run`, bound to what this serve loaded.
|
|
113
|
-
*
|
|
114
|
-
* `undefined` when the definition declares nothing runnable: a route that can only ever answer 404 is not a route,
|
|
115
|
-
* and the startup report names what is actually mounted.
|
|
116
|
-
*/
|
|
117
|
-
export function createRunHandler(options) {
|
|
118
|
-
const { agent, routines } = options;
|
|
119
|
-
if (routines.length === 0)
|
|
120
|
-
return undefined;
|
|
121
|
-
return async (req) => {
|
|
122
|
-
if (req.method !== "POST")
|
|
123
|
-
return text("POST only\n", 405);
|
|
124
|
-
const wrongType = refuseNonJsonBody(req);
|
|
125
|
-
if (wrongType)
|
|
126
|
-
return wrongType;
|
|
127
|
-
const body = await readBodyCapped(req, MAX_RUN_BODY_BYTES);
|
|
128
|
-
if ("tooLarge" in body)
|
|
129
|
-
return text("body too large\n", 413);
|
|
130
|
-
let payload;
|
|
131
|
-
try {
|
|
132
|
-
payload = JSON.parse(body.text);
|
|
133
|
-
}
|
|
134
|
-
catch {
|
|
135
|
-
return text("invalid json\n", 400);
|
|
136
|
-
}
|
|
137
|
-
const { name } = (payload ?? {});
|
|
138
|
-
if (typeof name !== "string" || name === "") {
|
|
139
|
-
return text('need { "name": string } — e.g. {"name":"daily"}\n', 400);
|
|
140
|
-
}
|
|
141
|
-
const routine = routines.find((r) => r.name === name);
|
|
142
|
-
if (!routine)
|
|
143
|
-
return unknownRoutine(name, routines);
|
|
144
|
-
return Response.json(await runRoutineByName(agent, routine));
|
|
145
|
-
};
|
|
146
|
-
}
|