@fastagent-sh/fastagent 0.24.4 → 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 -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/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
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Standing instructions
|
|
2
|
+
|
|
3
|
+
This file, `SYSTEM.md`, is your system prompt. It is read for every message along with the rest of your definition: `AGENTS.md` if there is one, `skills/` (capabilities you load when a task calls for them) and `prompts/` (prompt templates). An edit to any of them takes effect on your next message, no restart. Code in `src/` (tools, extensions, channels, schedules) loads when you start.
|
|
4
|
+
|
|
5
|
+
Your definition is this directory: this file, `skills/`, `src/` and the config beside them. It is also your working directory, so a file you create lands here unless you put it elsewhere. Use only the tools actually listed in your system prompt.
|
|
6
|
+
|
|
7
|
+
When your 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 the `writing-great-skills` skill 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.
|
|
@@ -2,30 +2,24 @@
|
|
|
2
2
|
# fastagent) and uncomment what you need. Everything here is OPTIONAL — the defaults work without a .env.
|
|
3
3
|
|
|
4
4
|
# --- Model auth ---
|
|
5
|
-
# Pick auth once: `fastagent login` (
|
|
5
|
+
# Pick auth once: `fastagent login` (an account such as ChatGPT for openai, or an API key),
|
|
6
6
|
# or set a provider API key here — the variable name is provider-specific (e.g. OPENAI_API_KEY,
|
|
7
7
|
# ANTHROPIC_API_KEY). `fastagent dev` then lets you choose a model from whatever you're logged into.
|
|
8
8
|
# OPENAI_API_KEY=
|
|
9
9
|
# ANTHROPIC_API_KEY=
|
|
10
10
|
|
|
11
|
-
# --- Which agent (only when a workspace holds several) ---
|
|
12
|
-
# FASTAGENT_AGENT names the agent directory to serve. It CANNOT be set here: placement resolves before
|
|
13
|
-
# this file is read (it is what decides whose .env this is). Put it in your shell, an .envrc, or the
|
|
14
|
-
# command: `FASTAGENT_AGENT=pm fastagent dev`.
|
|
15
|
-
|
|
16
11
|
# --- Model selection (overrides fastagent.config) ---
|
|
17
12
|
# Precedence: --model flag > FASTAGENT_MODEL > config — one chain, evaluated in whichever environment
|
|
18
|
-
# is running. `fastagent
|
|
19
|
-
# it. THIS FILE also declares the environment `fastagent deploy` resolves in, so a value here rides the
|
|
13
|
+
# is running. THIS FILE also declares the environment `fastagent deploy` resolves in, so a value here rides the
|
|
20
14
|
# release manifest into the deployment and a deployment can run a model the committed config does not
|
|
21
15
|
# name. That recorded value outranks the deployed box's own .env, so switching models there means
|
|
22
16
|
# editing this line and redeploying.
|
|
23
|
-
# FASTAGENT_MODEL=openai
|
|
17
|
+
# FASTAGENT_MODEL=openai/gpt-5.5
|
|
24
18
|
|
|
25
19
|
# --- Serving (fastagent start) ---
|
|
26
20
|
# Port precedence: --port > PORT > config.http.port > 8787
|
|
27
21
|
# PORT=8787
|
|
28
|
-
# Machine-state root:
|
|
22
|
+
# Machine-state root: the agent's storage, schedule state, and channel state live under it.
|
|
29
23
|
# Default: <agent dir>/.state. Point it at a mounted volume so a redeploy that replaces the
|
|
30
24
|
# directory keeps conversations.
|
|
31
25
|
# FASTAGENT_STATE_DIR=/data/.state
|
|
@@ -1,36 +1,24 @@
|
|
|
1
|
-
// fastagent.config.ts —
|
|
2
|
-
//
|
|
3
|
-
// An AGENTS.md in the WORKSPACE (the directory the agent is started in) is read as project context.
|
|
4
|
-
// Model precedence: `--model` flag > FASTAGENT_MODEL env > this default.
|
|
5
|
-
// No model is preset: `fastagent dev` shows the full model catalog (models you already have
|
|
6
|
-
// credentials for come first; picking one that needs auth logs you in inline) and writes your choice
|
|
7
|
-
// below. Or set it by hand to a "provider/modelId" (`fastagent models` lists them).
|
|
8
|
-
// Self-hosted model (vLLM/Ollama/…) or your own gateway? Declare it in a models.json next to this
|
|
9
|
-
// file and select it like any other spec — see docs/configuration.md "Custom model endpoints".
|
|
1
|
+
// fastagent.config.ts — the agent's configuration: its default model and how it is served. Its prompt lives in
|
|
2
|
+
// SYSTEM.md, its capabilities in skills/ and src/ (tools, extensions, channels, schedules) — never here.
|
|
10
3
|
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
|
|
4
|
+
// Model precedence: `--model` flag > FASTAGENT_MODEL env > this default. No model is preset: `fastagent dev` shows
|
|
5
|
+
// the model catalog (models you already have credentials for come first; picking one that needs auth logs you in
|
|
6
|
+
// inline) and runs with your choice; set it below to keep it. `fastagent models` lists every "provider/modelId".
|
|
7
|
+
// A self-hosted model (vLLM, Ollama, …) or your own gateway is a provider in code: `providers: [...]`, built with
|
|
8
|
+
// pi-ai's `createProvider`.
|
|
9
|
+
//
|
|
10
|
+
// Every key is optional; the commented lines carry an example. `satisfies` is what makes your editor complete these
|
|
11
|
+
// keys and turns a typo into an error you see while writing. The import is TYPE-only: nothing is loaded at runtime,
|
|
12
|
+
// so the agent opens before `npm install` has run.
|
|
13
|
+
import type { AgentConfig } from "@fastagent-sh/fastagent";
|
|
16
14
|
|
|
17
15
|
export default {
|
|
18
|
-
// model: "openai
|
|
19
|
-
// thinkingLevel: "high", // reasoning effort (off|minimal|low|medium|high|xhigh|max)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
// sessionControl: true, // serve /control/* for remote observation + steering (a Web panel, a desktop app)
|
|
28
|
-
// tools: [], // programmatically defined tools, appended after the coding ones — tools/ is the usual way
|
|
29
|
-
// deploy: what the agent needs on the box (so `fastagent deploy` doesn't need a hand-written Dockerfile
|
|
30
|
-
// or hand-set host variables). Uncomment as needed:
|
|
31
|
-
// deploy: {
|
|
32
|
-
// secrets: ["GH_TOKEN"], // extra secret env vars your tools use — deploy reads their values from .secrets/.env
|
|
33
|
-
// apt: ["git"], // extra apt packages baked into the image (git, ripgrep, …; default repos only)
|
|
34
|
-
// agentcore: { idleTimeoutSeconds: 180 }, // `deploy agentcore` only: idle microVM tail, 60–1209600s
|
|
35
|
-
// },
|
|
36
|
-
} satisfies FastagentConfig;
|
|
16
|
+
// model: "openai/gpt-5.5",
|
|
17
|
+
// thinkingLevel: "high", // reasoning effort (off|minimal|low|medium|high|xhigh|max)
|
|
18
|
+
http: {
|
|
19
|
+
port: 8787, // the port a serve listens on, for its channels' webhooks and its health check
|
|
20
|
+
// api: false, // serve no Agent API under /v1, whatever key the environment holds; deploy gives none a key
|
|
21
|
+
},
|
|
22
|
+
// The commands the agent needs (CLIs, runtimes, apt packages) live in context.json: `fastagent env add gh`.
|
|
23
|
+
// deploy: { agentcore: { idleTimeoutSeconds: 180 } }, // `deploy agentcore` only: idle microVM tail, 60–1209600s
|
|
24
|
+
} satisfies AgentConfig;
|
|
@@ -5,8 +5,15 @@
|
|
|
5
5
|
# DIRECTORY, so a symlinked one (pnpm, a shared store) would show up as untracked.
|
|
6
6
|
node_modules
|
|
7
7
|
|
|
8
|
-
#
|
|
8
|
+
# generated from src/ every time the agent opens
|
|
9
|
+
.fastagent
|
|
10
|
+
# machine state: the agent's storage, channel state, schedule state
|
|
9
11
|
.state
|
|
12
|
+
# where fastagent clones the agent's content (each clone is its repository's, not this one's). No trailing
|
|
13
|
+
# slash: on a deployed host it is a link itself.
|
|
14
|
+
/content
|
|
15
|
+
# the directories of this machine the agent is bound to: this machine's, never the agent's
|
|
16
|
+
/context.local.json
|
|
10
17
|
.cache
|
|
11
18
|
|
|
12
19
|
# fastagent reads the agent's env from .secrets/.env (which un-ignores its own .env.example). A bare
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: writing-great-skills
|
|
3
|
-
description: Reference for writing and editing skills well — the vocabulary and principles that make a skill predictable.
|
|
4
|
-
disable-model-invocation: true
|
|
3
|
+
description: Reference for writing and editing skills well — the vocabulary and principles that make a skill predictable. Read it before writing or changing a skill.
|
|
5
4
|
---
|
|
6
5
|
|
|
7
6
|
A skill exists to wrangle determinism out of a stochastic system. **Predictability** — the agent taking the same _process_ every run, not producing the same output — is the root virtue; every lever below serves it.
|
|
@@ -2,10 +2,15 @@
|
|
|
2
2
|
export declare const baseTemplate: (name: string) => string;
|
|
3
3
|
/** Read one file from a channel's scaffold bundle (src/channels/<kind>/scaffold/<name>). */
|
|
4
4
|
export declare const channelTemplate: (kind: string, name: string) => string;
|
|
5
|
-
/** The .ts files in a channel's bundle: `channel
|
|
6
|
-
* `channel.ts`, `channel.websocket.ts`); the rest are companion tools. */
|
|
5
|
+
/** The .ts files in a channel's bundle: `channel.ts` is the channel template; the rest are companion tools. */
|
|
7
6
|
export declare const channelBundleFiles: (kind: string) => string[];
|
|
8
|
-
/**
|
|
9
|
-
|
|
7
|
+
/**
|
|
8
|
+
* package.json for the complete agent: fastagent at this build's version, and the packages an agent's code is written
|
|
9
|
+
* against (its tools and extensions are pi-durable code, its providers pi-ai's) at the versions this build runs.
|
|
10
|
+
*/
|
|
11
|
+
export declare function packageJson(name: string, build: {
|
|
12
|
+
version: string;
|
|
13
|
+
harness: Record<string, string>;
|
|
14
|
+
}): string;
|
|
10
15
|
/** Sanitize a directory basename into a valid npm package name (lowercase, safe chars). */
|
|
11
16
|
export declare function toPackageName(dir: string): string;
|
|
@@ -9,16 +9,18 @@ export const baseTemplate = (name) => readFileSync(new URL(`./templates/${name}`
|
|
|
9
9
|
const channelScaffoldDir = (kind) => new URL(`../channels/${kind}/scaffold/`, import.meta.url);
|
|
10
10
|
/** Read one file from a channel's scaffold bundle (src/channels/<kind>/scaffold/<name>). */
|
|
11
11
|
export const channelTemplate = (kind, name) => readFileSync(new URL(name, channelScaffoldDir(kind)), "utf8");
|
|
12
|
-
/** The .ts files in a channel's bundle: `channel
|
|
13
|
-
* `channel.ts`, `channel.websocket.ts`); the rest are companion tools. */
|
|
12
|
+
/** The .ts files in a channel's bundle: `channel.ts` is the channel template; the rest are companion tools. */
|
|
14
13
|
export const channelBundleFiles = (kind) => readdirSync(channelScaffoldDir(kind)).filter((f) => f.endsWith(".ts"));
|
|
15
|
-
/**
|
|
16
|
-
|
|
14
|
+
/**
|
|
15
|
+
* package.json for the complete agent: fastagent at this build's version, and the packages an agent's code is written
|
|
16
|
+
* against (its tools and extensions are pi-durable code, its providers pi-ai's) at the versions this build runs.
|
|
17
|
+
*/
|
|
18
|
+
export function packageJson(name, build) {
|
|
17
19
|
return `${JSON.stringify({
|
|
18
20
|
name,
|
|
19
21
|
private: true,
|
|
20
22
|
type: "module",
|
|
21
|
-
dependencies: { "@fastagent-sh/fastagent": `^${version}
|
|
23
|
+
dependencies: { "@fastagent-sh/fastagent": `^${build.version}`, ...build.harness },
|
|
22
24
|
}, null, 2)}\n`;
|
|
23
25
|
}
|
|
24
26
|
/** Sanitize a directory basename into a valid npm package name (lowercase, safe chars). */
|
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
import { type LoadedDefinition } from "../engines/pi/definition.ts";
|
|
2
1
|
export interface VendoredSkill {
|
|
3
2
|
/** The skill's real name (from SKILL.md frontmatter, per the Agent Skills spec). */
|
|
4
3
|
name: string;
|
|
5
4
|
description?: string;
|
|
6
|
-
/**
|
|
5
|
+
/** Agent-dir-relative destination (e.g. `skills/pdf`). */
|
|
7
6
|
dest: string;
|
|
8
7
|
/** The skill ships a `scripts/` dir (executable code) — a trust signal for the caller. */
|
|
9
8
|
hasScripts: boolean;
|
|
10
|
-
/** Spec diagnostics for THIS skill from the runtime loader (e.g. name ≠ dir). */
|
|
11
|
-
diagnostics: LoadedDefinition["diagnostics"];
|
|
12
9
|
/** True when an existing skill was overwritten (--update); false for a fresh vendor. */
|
|
13
10
|
overwritten: boolean;
|
|
14
11
|
}
|
|
@@ -7,7 +7,7 @@ import { existsSync } from "node:fs";
|
|
|
7
7
|
import { randomUUID } from "node:crypto";
|
|
8
8
|
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
9
9
|
import { homedir } from "node:os";
|
|
10
|
-
import {
|
|
10
|
+
import { readSkills } from "../harnesses/pi-durable/text.js";
|
|
11
11
|
import { assertInsideAgentDir } from "../paths.js";
|
|
12
12
|
/** Derive the destination skill name from a source ref: the last path segment, sans `#ref`. */
|
|
13
13
|
function skillNameFromSource(source) {
|
|
@@ -131,17 +131,16 @@ export async function vendorSkill(agentDir, source, options = {}) {
|
|
|
131
131
|
}
|
|
132
132
|
if (overwritten)
|
|
133
133
|
await rm(previous, { recursive: true, force: true });
|
|
134
|
-
// Report via the
|
|
135
|
-
// sibling `<name>-x` and break on Windows path separators).
|
|
136
|
-
|
|
134
|
+
// Report via the loader the agent reads skills with, matching THIS skill by EXACT directory (a substring match
|
|
135
|
+
// would prefix-pollute a sibling `<name>-x` and break on Windows path separators). A skill it refuses is said by
|
|
136
|
+
// that loader, and is missing here.
|
|
137
137
|
const rel = join("skills", name);
|
|
138
|
-
const skill =
|
|
138
|
+
const skill = readSkills(agentDir).find((sk) => relative(agentDir, dirname(sk.filePath)) === rel);
|
|
139
139
|
return {
|
|
140
140
|
name: skill?.name ?? name,
|
|
141
141
|
description: skill?.description,
|
|
142
142
|
dest: rel,
|
|
143
143
|
hasScripts: existsSync(join(dest, "scripts")),
|
|
144
|
-
diagnostics: def.diagnostics.filter((d) => d.path !== undefined && relative(agentDir, dirname(d.path)) === rel),
|
|
145
144
|
overwritten,
|
|
146
145
|
};
|
|
147
146
|
}
|
package/dist/schedule/cron.d.ts
CHANGED
|
@@ -9,3 +9,16 @@ export declare function nextRun(cron: string, tz: string | undefined, from: Date
|
|
|
9
9
|
* constructing the Cron.
|
|
10
10
|
*/
|
|
11
11
|
export declare function cronError(cron: string, tz: string | undefined): string | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Why `cron`/`tz` cannot be something that recurs here, or undefined if it can: THE guard every recurring producer
|
|
14
|
+
* shares (a `schedules/` file, a recurring `wake`), because the agent can write both, and one written wrong must not
|
|
15
|
+
* run turns back to back. Two consecutive instants must be at least {@link MIN_RECURRING_GAP_MS} apart, which also
|
|
16
|
+
* refuses croner's six-field, per-second form.
|
|
17
|
+
*
|
|
18
|
+
* A function of the expression alone, so a file's verdict never flips with the time it is read. Two consecutive
|
|
19
|
+
* instants under 10 minutes apart are on one day or across one midnight, and the time-of-day fields repeat every day,
|
|
20
|
+
* so two days of the time-of-day form (the day fields made `*`, in UTC) hold every such gap. That is conservative:
|
|
21
|
+
* `0,55 0,23 * * 1` is refused for the 23:55 → 00:00 pair, though Tuesday never fires. A DST change only lengthens a
|
|
22
|
+
* gap (croner fires a repeated hour once). A year field is refused, since what repeats every year does not need one.
|
|
23
|
+
*/
|
|
24
|
+
export declare function recurringCronError(cron: string, tz: string | undefined): string | undefined;
|
package/dist/schedule/cron.js
CHANGED
|
@@ -29,3 +29,55 @@ export function cronError(cron, tz) {
|
|
|
29
29
|
return e.message;
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
+
/** The minimum gap between two consecutive fires of anything recurring: a schedule, or a recurring wake-up. */
|
|
33
|
+
const MIN_RECURRING_GAP_MS = 10 * 60_000; // 10 minutes
|
|
34
|
+
/** Where the check below starts: fixed, so its verdict is the cron's and never the hour it was asked in. */
|
|
35
|
+
const ANCHOR = new Date("2024-01-01T00:00:00Z");
|
|
36
|
+
const TWO_DAYS_MS = 2 * 24 * 60 * 60_000;
|
|
37
|
+
/** One verdict per expression: the check walks up to ~300 instants, and every re-read of `schedules/` asks again. */
|
|
38
|
+
const verdicts = new Map();
|
|
39
|
+
/**
|
|
40
|
+
* Why `cron`/`tz` cannot be something that recurs here, or undefined if it can: THE guard every recurring producer
|
|
41
|
+
* shares (a `schedules/` file, a recurring `wake`), because the agent can write both, and one written wrong must not
|
|
42
|
+
* run turns back to back. Two consecutive instants must be at least {@link MIN_RECURRING_GAP_MS} apart, which also
|
|
43
|
+
* refuses croner's six-field, per-second form.
|
|
44
|
+
*
|
|
45
|
+
* A function of the expression alone, so a file's verdict never flips with the time it is read. Two consecutive
|
|
46
|
+
* instants under 10 minutes apart are on one day or across one midnight, and the time-of-day fields repeat every day,
|
|
47
|
+
* so two days of the time-of-day form (the day fields made `*`, in UTC) hold every such gap. That is conservative:
|
|
48
|
+
* `0,55 0,23 * * 1` is refused for the 23:55 → 00:00 pair, though Tuesday never fires. A DST change only lengthens a
|
|
49
|
+
* gap (croner fires a repeated hour once). A year field is refused, since what repeats every year does not need one.
|
|
50
|
+
*/
|
|
51
|
+
export function recurringCronError(cron, tz) {
|
|
52
|
+
const key = `${cron}\u0000${tz ?? ""}`;
|
|
53
|
+
if (!verdicts.has(key))
|
|
54
|
+
verdicts.set(key, judge(cron, tz));
|
|
55
|
+
return verdicts.get(key);
|
|
56
|
+
}
|
|
57
|
+
function judge(cron, tz) {
|
|
58
|
+
const invalid = cronError(cron, tz);
|
|
59
|
+
if (invalid)
|
|
60
|
+
return `invalid cron/tz: ${invalid}`;
|
|
61
|
+
const fields = cron.trim().split(/\s+/);
|
|
62
|
+
if (fields.length === 7)
|
|
63
|
+
return "a year field is not allowed: a recurring cron repeats every year";
|
|
64
|
+
const first = nextRun(cron, tz, ANCHOR);
|
|
65
|
+
if (!first || !nextRun(cron, tz, first))
|
|
66
|
+
return "this cron never fires, or fires only once";
|
|
67
|
+
// A nickname (`@hourly`) has no fields to separate, and is walked as it is.
|
|
68
|
+
const timeOfDay = fields.length === 5
|
|
69
|
+
? `${fields[0]} ${fields[1]} * * *`
|
|
70
|
+
: fields.length === 6
|
|
71
|
+
? `${fields[0]} ${fields[1]} ${fields[2]} * * *`
|
|
72
|
+
: cron;
|
|
73
|
+
const clock = new Cron(timeOfDay, { timezone: "UTC" });
|
|
74
|
+
const end = ANCHOR.getTime() + TWO_DAYS_MS;
|
|
75
|
+
for (let at = clock.nextRun(ANCHOR); at && at.getTime() < end;) {
|
|
76
|
+
const next = clock.nextRun(at);
|
|
77
|
+
if (next && next.getTime() - at.getTime() < MIN_RECURRING_GAP_MS) {
|
|
78
|
+
return `too frequent — it must fire at most every ${MIN_RECURRING_GAP_MS / 60_000} minutes`;
|
|
79
|
+
}
|
|
80
|
+
at = next;
|
|
81
|
+
}
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A schedule's cron in EventBridge Scheduler's dialect: `cron(m h dom mon dow year)`, Quartz-flavoured, with exactly
|
|
3
|
+
* one of the two day fields `?` and 1 = Sunday. AgentCore fires each schedule from a recurring EventBridge schedule
|
|
4
|
+
* the container sets (schedule/wake-alarm.ts), so a schedule must translate to be one at all: discovery refuses one
|
|
5
|
+
* that does not, on every host, so that what runs locally also runs there.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Translate a 5-field cron into EventBridge Scheduler's `cron(m h dom mon dow *)`, or say why it can't be. The two
|
|
9
|
+
* fire on the same instants in the same zone, with one exception at a DST change: a local time the spring change
|
|
10
|
+
* removes (02:30 in most of the US on that day) is skipped by EventBridge and run an hour later by croner, so such a
|
|
11
|
+
* schedule runs once more a year on a resident host. A time the autumn change repeats runs once in both.
|
|
12
|
+
*/
|
|
13
|
+
export declare function toEventBridgeCron(cron: string): {
|
|
14
|
+
expression: string;
|
|
15
|
+
} | {
|
|
16
|
+
error: string;
|
|
17
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A schedule's cron in EventBridge Scheduler's dialect: `cron(m h dom mon dow year)`, Quartz-flavoured, with exactly
|
|
3
|
+
* one of the two day fields `?` and 1 = Sunday. AgentCore fires each schedule from a recurring EventBridge schedule
|
|
4
|
+
* the container sets (schedule/wake-alarm.ts), so a schedule must translate to be one at all: discovery refuses one
|
|
5
|
+
* that does not, on every host, so that what runs locally also runs there.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Remap ONE day-of-week field from standard cron numbering (0–7, 0 and 7 = Sunday) to EventBridge's (1–7,
|
|
9
|
+
* 1 = Sunday). Numeric items are EXPANDED to the days they select and written back as a list: endpoint-wise remapping
|
|
10
|
+
* cannot be right, since Sunday sits at both ends of one numbering and at the start of the other (`0-7` is every day,
|
|
11
|
+
* and remapping its endpoints gives `1-1`, Sundays only; `5-7` would wrap). Names mean the same day in both dialects
|
|
12
|
+
* and pass through.
|
|
13
|
+
*/
|
|
14
|
+
function mapDowField(dow) {
|
|
15
|
+
const days = new Set();
|
|
16
|
+
const named = [];
|
|
17
|
+
for (const item of dow.split(",")) {
|
|
18
|
+
const slash = item.split("/");
|
|
19
|
+
if (slash.length > 2 || slash.some((part) => part === "")) {
|
|
20
|
+
return { error: `malformed day-of-week token "${item}"` };
|
|
21
|
+
}
|
|
22
|
+
const [body, stepText] = slash;
|
|
23
|
+
if (stepText !== undefined && !/^\d+$/.test(stepText))
|
|
24
|
+
return { error: `malformed day-of-week step "${item}"` };
|
|
25
|
+
const endpoints = body === "*" ? ["0", "6"] : body.split("-");
|
|
26
|
+
if (endpoints.length > 2 || endpoints.some((part) => part === "")) {
|
|
27
|
+
return { error: `malformed day-of-week token "${item}"` };
|
|
28
|
+
}
|
|
29
|
+
if (endpoints.every((part) => !/^\d+$/.test(part))) {
|
|
30
|
+
named.push(item);
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (!endpoints.every((part) => /^\d+$/.test(part))) {
|
|
34
|
+
return { error: `day-of-week "${item}" mixes a name and a number` };
|
|
35
|
+
}
|
|
36
|
+
const from = Number(endpoints[0]);
|
|
37
|
+
// A single value with a step (`1/2`) runs to the end of the week, as in croner.
|
|
38
|
+
const to = endpoints.length === 2 ? Number(endpoints[1]) : stepText !== undefined ? 7 : from;
|
|
39
|
+
const step = stepText !== undefined ? Number(stepText) : 1;
|
|
40
|
+
if (from > 7 || to > 7 || from > to || step === 0)
|
|
41
|
+
return { error: `malformed day-of-week token "${item}"` };
|
|
42
|
+
for (let day = from; day <= to; day += step)
|
|
43
|
+
days.add(day % 7);
|
|
44
|
+
}
|
|
45
|
+
const numbers = [...days].map((day) => day + 1).sort((x, y) => x - y);
|
|
46
|
+
// Consecutive days back into ranges, for a readable expression.
|
|
47
|
+
const runs = [];
|
|
48
|
+
for (let i = 0; i < numbers.length;) {
|
|
49
|
+
let j = i;
|
|
50
|
+
while (j + 1 < numbers.length && numbers[j + 1] === numbers[j] + 1)
|
|
51
|
+
j++;
|
|
52
|
+
runs.push(j > i ? `${numbers[i]}-${numbers[j]}` : `${numbers[i]}`);
|
|
53
|
+
i = j + 1;
|
|
54
|
+
}
|
|
55
|
+
return { value: [...runs, ...named].join(",") };
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Translate a 5-field cron into EventBridge Scheduler's `cron(m h dom mon dow *)`, or say why it can't be. The two
|
|
59
|
+
* fire on the same instants in the same zone, with one exception at a DST change: a local time the spring change
|
|
60
|
+
* removes (02:30 in most of the US on that day) is skipped by EventBridge and run an hour later by croner, so such a
|
|
61
|
+
* schedule runs once more a year on a resident host. A time the autumn change repeats runs once in both.
|
|
62
|
+
*/
|
|
63
|
+
export function toEventBridgeCron(cron) {
|
|
64
|
+
const fields = cron.trim().split(/\s+/);
|
|
65
|
+
if (fields.length !== 5) {
|
|
66
|
+
return { error: `EventBridge supports 5-field cron only (got ${fields.length} fields)` };
|
|
67
|
+
}
|
|
68
|
+
const [min, hour, dom, mon, dow] = fields;
|
|
69
|
+
if (/[L#]/i.test(dow) || /[L#]/i.test(dom)) {
|
|
70
|
+
return { error: "L/# day forms don't translate to EventBridge numbering — set this schedule up manually" };
|
|
71
|
+
}
|
|
72
|
+
// `?` FIRST, and not as a synonym for `*`.
|
|
73
|
+
if (dom === "?" || dow === "?") {
|
|
74
|
+
return { expression: `cron(${min} ${hour} * ${mon} ? *)` };
|
|
75
|
+
}
|
|
76
|
+
if (dom !== "*" && dow !== "*") {
|
|
77
|
+
return {
|
|
78
|
+
error: "restricting BOTH day-of-month and day-of-week (cron OR semantics) is not expressible in EventBridge",
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
if (dow === "*") {
|
|
82
|
+
return { expression: `cron(${min} ${hour} ${dom} ${mon} ? *)` };
|
|
83
|
+
}
|
|
84
|
+
const mapped = mapDowField(dow);
|
|
85
|
+
if ("error" in mapped)
|
|
86
|
+
return mapped;
|
|
87
|
+
return { expression: `cron(${min} ${hour} ? ${mon} ${mapped.value} *)` };
|
|
88
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** As many schedules as one conversation may have pending wake-ups: the same bound on what the agent can set going. */
|
|
2
|
+
export declare const MAX_SCHEDULES = 20;
|
|
3
|
+
/** What an author writes. */
|
|
4
|
+
export interface ScheduleConfig {
|
|
5
|
+
/** Five fields, minute first; checked when the definition is built. */
|
|
6
|
+
cron: string;
|
|
7
|
+
/** IANA timezone. Default: UTC. */
|
|
8
|
+
tz?: string;
|
|
9
|
+
/** What the agent is told when it fires: a text, or one made for the instant it fires for. */
|
|
10
|
+
prompt: string | ((fire: {
|
|
11
|
+
at: Date;
|
|
12
|
+
}) => string | Promise<string>);
|
|
13
|
+
}
|
|
14
|
+
/** A schedule as built: its name is its file's name. */
|
|
15
|
+
export interface Schedule extends ScheduleConfig {
|
|
16
|
+
name: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Why `config` is not a schedule this agent can run, or undefined: the one rule the build applies. Its cron passes the
|
|
20
|
+
* guard a recurring wake-up passes, and is one AgentCore's clock (EventBridge) can express, so a schedule that runs
|
|
21
|
+
* locally also runs there.
|
|
22
|
+
*/
|
|
23
|
+
export declare function scheduleConfigProblem(config: ScheduleConfig): string | undefined;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A schedule: a prompt the definition runs on a cron, written in TypeScript as `defineSchedule` in `src/schedules/`
|
|
3
|
+
* (architecture.md §2), its name its file's. It is code, so it changes with a build and a deployment; the clock that
|
|
4
|
+
* fires it is scheduler.ts, or on AgentCore the recurring EventBridge schedule the container sets (wake-alarm.ts).
|
|
5
|
+
*
|
|
6
|
+
* WHAT IT IS NOT: a wake-up. The agent can schedule work for itself too (the `wake` tool, schedule/wakeups.ts). A
|
|
7
|
+
* schedule is written in the DEFINITION and a wake-up into the STATE by a running agent (minted id, cancellable, aimed
|
|
8
|
+
* back at the conversation it came from).
|
|
9
|
+
*/
|
|
10
|
+
import { recurringCronError } from "./cron.js";
|
|
11
|
+
import { toEventBridgeCron } from "./eventbridge-cron.js";
|
|
12
|
+
import { MAX_PENDING_WAKEUPS } from "./wakeups.js";
|
|
13
|
+
/** As many schedules as one conversation may have pending wake-ups: the same bound on what the agent can set going. */
|
|
14
|
+
export const MAX_SCHEDULES = MAX_PENDING_WAKEUPS;
|
|
15
|
+
/**
|
|
16
|
+
* Why `config` is not a schedule this agent can run, or undefined: the one rule the build applies. Its cron passes the
|
|
17
|
+
* guard a recurring wake-up passes, and is one AgentCore's clock (EventBridge) can express, so a schedule that runs
|
|
18
|
+
* locally also runs there.
|
|
19
|
+
*/
|
|
20
|
+
export function scheduleConfigProblem(config) {
|
|
21
|
+
if (typeof config.prompt !== "string" && typeof config.prompt !== "function")
|
|
22
|
+
return "its prompt is a text or a function";
|
|
23
|
+
if (config.prompt === "")
|
|
24
|
+
return "its prompt is empty";
|
|
25
|
+
if (typeof config.cron !== "string")
|
|
26
|
+
return "its cron is a text";
|
|
27
|
+
const invalid = recurringCronError(config.cron, config.tz);
|
|
28
|
+
if (invalid !== undefined)
|
|
29
|
+
return invalid;
|
|
30
|
+
const translated = toEventBridgeCron(config.cron);
|
|
31
|
+
return "error" in translated
|
|
32
|
+
? `AgentCore's clock (EventBridge) cannot express this cron: ${translated.error}`
|
|
33
|
+
: undefined;
|
|
34
|
+
}
|
|
@@ -1,44 +1,32 @@
|
|
|
1
1
|
import * as Effect from "effect/Effect";
|
|
2
|
-
import { type Agent } from "../agent.ts";
|
|
2
|
+
import { type Agent } from "../agent-api.ts";
|
|
3
3
|
import { PortFailure } from "../effect-port.ts";
|
|
4
|
-
import {
|
|
4
|
+
import type { Schedule } from "./schedule.ts";
|
|
5
5
|
export interface Scheduler {
|
|
6
|
-
/** Arm
|
|
6
|
+
/** Arm schedules, account for a fire the previous run was killed in, and catch up overdue work once. */
|
|
7
7
|
start(): void;
|
|
8
8
|
/** Cancel pending waits. */
|
|
9
9
|
stop(): void;
|
|
10
10
|
}
|
|
11
|
+
/** All the scheduler asks of the agent. */
|
|
12
|
+
export type ScheduledAgent = {
|
|
13
|
+
sessions: Pick<Agent["sessions"], "get" | "create">;
|
|
14
|
+
messages: Pick<Agent["messages"], "send" | "get">;
|
|
15
|
+
};
|
|
11
16
|
export interface SchedulerOptions {
|
|
12
|
-
agent:
|
|
17
|
+
agent: ScheduledAgent;
|
|
13
18
|
stateRoot: string;
|
|
14
|
-
/**
|
|
15
|
-
|
|
19
|
+
/** The definition's schedules. */
|
|
20
|
+
schedules: readonly Schedule[];
|
|
21
|
+
/**
|
|
22
|
+
* Run a resident timer per schedule (default). Off where something outside the process delivers each instant as
|
|
23
|
+
* its own fire (AgentCore's recurring EventBridge schedules): one path per instant, so its delivery's reply says
|
|
24
|
+
* whether it ran.
|
|
25
|
+
*/
|
|
26
|
+
localClock?: boolean;
|
|
16
27
|
/** Override wall-clock dates; elapsed time and waits use the Effect clock. */
|
|
17
28
|
now?: () => Date;
|
|
18
|
-
/** External slot delivery owns cron timers and catch-up; local wake polling still runs. */
|
|
19
|
-
externalClock?: boolean;
|
|
20
29
|
}
|
|
21
|
-
/**
|
|
22
|
-
* The iterator is a Promise port inside an uninterruptible claimed occurrence, including its cleanup.
|
|
23
|
-
*
|
|
24
|
-
* WHAT THE TURN SAID IS NOT LOGGED. It is already durable: every fire runs in the session named in the line below
|
|
25
|
-
* (`routine:<name>` for a cron, the asking conversation for a wake-up), and a session is persisted under
|
|
26
|
-
* EXPORTED for the API path (`POST /run`), which runs the same turn without a claim: it has no occurrence to
|
|
27
|
-
* claim, because nobody's grid produced it (schedule/run.ts). The resident clock's own claim/run/settle is
|
|
28
|
-
* {@link fireRoutineOnce}.
|
|
29
|
-
*
|
|
30
|
-
* `<stateRoot>/sessions/` like any other. Copying the reply into the log would be a second store of the same text,
|
|
31
|
-
* unstructured, in a stream with a wider audience and a bound that differs per host.
|
|
32
|
-
*/
|
|
33
|
-
export declare function runTurn(agent: Agent, label: string, session: string, prompt: string): Effect.Effect<{
|
|
34
|
-
busy: boolean;
|
|
35
|
-
failed: string | undefined;
|
|
36
|
-
ms: number;
|
|
37
|
-
} | {
|
|
38
|
-
busy: boolean;
|
|
39
|
-
failed: string;
|
|
40
|
-
ms: number;
|
|
41
|
-
}, never, never>;
|
|
42
30
|
export interface ScheduleFireOutcome {
|
|
43
31
|
fired: boolean;
|
|
44
32
|
/** A delivery whose slot was already claimed, or which is older than the newest claim (a stale replay). */
|
|
@@ -47,18 +35,31 @@ export interface ScheduleFireOutcome {
|
|
|
47
35
|
/**
|
|
48
36
|
* The occurrence was claimed but the turn was refused because the previous one is still running — the overlap
|
|
49
37
|
* policy, not a fault. Reported apart from `failed` because an operator reacts to the two differently, and a
|
|
50
|
-
* clock that reads `failed`
|
|
38
|
+
* clock that reads `failed` would be reading an error that is not one.
|
|
51
39
|
*/
|
|
52
40
|
skipped?: true;
|
|
53
41
|
ms: number;
|
|
54
42
|
}
|
|
55
43
|
/** Shared resident/external claim → run → settle. */
|
|
56
|
-
export declare function
|
|
57
|
-
agent:
|
|
44
|
+
export declare function fireScheduleOnce(opts: {
|
|
45
|
+
agent: ScheduledAgent;
|
|
58
46
|
stateRoot: string;
|
|
59
|
-
|
|
47
|
+
schedule: Schedule;
|
|
60
48
|
/** The instant this fire is FOR. Two schedulers agree on it, which is what makes the claim exclude. */
|
|
61
49
|
slot: Date;
|
|
62
50
|
now?: () => Date;
|
|
63
51
|
}): Effect.Effect<ScheduleFireOutcome, PortFailure>;
|
|
52
|
+
/**
|
|
53
|
+
* Fire `schedule` once, now, outside its clock (`fastagent schedules run`), the way its clock would: a newest claim no
|
|
54
|
+
* fire reported is accounted for first, as a boot does, then this instant is the slot, claimed and settled as any.
|
|
55
|
+
*/
|
|
56
|
+
export declare function fireScheduleNow(opts: {
|
|
57
|
+
agent: ScheduledAgent;
|
|
58
|
+
stateRoot: string;
|
|
59
|
+
schedule: Schedule;
|
|
60
|
+
}): Effect.Effect<ScheduleFireOutcome & {
|
|
61
|
+
slot: Date;
|
|
62
|
+
}, PortFailure>;
|
|
63
|
+
/** Which session each schedule continues: one per schedule, so the agent sees what its earlier runs did. */
|
|
64
|
+
export declare function scheduleSessions(stateRoot: string): import("../conversation-sessions.ts").ConversationSessions;
|
|
64
65
|
export declare function createScheduler(options: SchedulerOptions): Effect.Effect<Scheduler>;
|