@fastagent-sh/fastagent 0.24.3 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -82
- package/dist/agent-api.d.ts +452 -0
- package/dist/agent-api.js +201 -0
- package/dist/answer-text.d.ts +8 -0
- package/dist/answer-text.js +18 -0
- package/dist/atomic-write.d.ts +2 -2
- package/dist/atomic-write.js +2 -2
- package/dist/authoring.d.ts +77 -0
- package/dist/authoring.js +238 -0
- package/dist/channel.d.ts +29 -15
- package/dist/channel.js +4 -1
- package/dist/channels/agentcore-protocol.d.ts +36 -50
- package/dist/channels/agentcore-protocol.js +3 -3
- package/dist/channels/agentcore-service.d.ts +8 -18
- package/dist/channels/agentcore-service.js +108 -127
- package/dist/channels/agentcore.d.ts +8 -24
- package/dist/channels/agentcore.js +32 -65
- package/dist/channels/body.d.ts +0 -16
- package/dist/channels/body.js +0 -25
- package/dist/channels/busy.js +6 -1
- package/dist/channels/context.d.ts +4 -0
- package/dist/channels/context.js +35 -0
- package/dist/channels/discover.d.ts +18 -20
- package/dist/channels/discover.js +41 -99
- package/dist/channels/feishu/feishu-api.d.ts +54 -4
- package/dist/channels/feishu/feishu-api.js +192 -149
- package/dist/channels/feishu/feishu.d.ts +3 -0
- package/dist/channels/feishu/feishu.js +117 -106
- package/dist/channels/feishu/history.d.ts +55 -0
- package/dist/channels/feishu/history.js +199 -0
- package/dist/channels/feishu/invoke-turn.d.ts +13 -11
- package/dist/channels/feishu/invoke-turn.js +9 -10
- package/dist/channels/feishu/model.d.ts +2 -1
- package/dist/channels/feishu/normalize.js +100 -0
- package/dist/channels/feishu/preview.d.ts +2 -2
- package/dist/channels/feishu/register-webhook.d.ts +1 -0
- package/dist/channels/feishu/register-webhook.js +3 -2
- package/dist/channels/feishu/scaffold/channel.ts +65 -46
- package/dist/channels/feishu/scaffold/feishu-send.ts +38 -33
- package/dist/channels/feishu/scaffold/feishu-threads.ts +25 -0
- package/dist/channels/feishu/setup-mode.d.ts +45 -25
- package/dist/channels/feishu/setup-mode.js +74 -23
- package/dist/channels/feishu/shared-api.d.ts +24 -6
- package/dist/channels/feishu/shared-api.js +30 -24
- package/dist/channels/kit/context-buffer.d.ts +11 -2
- package/dist/channels/kit/context-buffer.js +7 -4
- package/dist/channels/kit/delivery.d.ts +19 -3
- package/dist/channels/kit/delivery.js +74 -15
- package/dist/channels/kit/event-stream.js +2 -1
- package/dist/channels/kit/invoke-turn-kit.d.ts +41 -41
- package/dist/channels/kit/invoke-turn-kit.js +62 -71
- package/dist/channels/kit/place-history.d.ts +107 -0
- package/dist/channels/kit/place-history.js +182 -0
- package/dist/channels/kit/preview-kit.d.ts +9 -5
- package/dist/channels/kit/preview-kit.js +36 -15
- package/dist/channels/kit/room-threads.d.ts +46 -0
- package/dist/channels/kit/room-threads.js +81 -0
- package/dist/channels/kit/seen.js +1 -1
- package/dist/channels/kit/stop-command.d.ts +6 -3
- package/dist/channels/kit/stop-command.js +20 -18
- package/dist/channels/kit/thread-fork.d.ts +17 -0
- package/dist/channels/kit/thread-fork.js +43 -0
- package/dist/channels/kit/thread-participants.js +1 -1
- package/dist/channels/kit/transport.d.ts +5 -0
- package/dist/channels/kit/transport.js +5 -0
- package/dist/channels/kit/turn-runner.d.ts +10 -9
- package/dist/channels/kit/turn-runner.js +17 -19
- package/dist/channels/kit/turn-store.d.ts +5 -4
- package/dist/channels/kit/turn-store.js +5 -5
- package/dist/channels/lark/lark.d.ts +3 -0
- package/dist/channels/lark/lark.js +5 -0
- package/dist/channels/lark/onboard.d.ts +5 -3
- package/dist/channels/lark/onboard.js +14 -14
- package/dist/channels/lark/scaffold/channel.ts +67 -44
- package/dist/channels/lark/scaffold/lark-send.ts +38 -33
- package/dist/channels/lark/scaffold/lark-threads.ts +25 -0
- package/dist/channels/respond.d.ts +0 -4
- package/dist/channels/respond.js +1 -1
- package/dist/channels/router.d.ts +18 -0
- package/dist/channels/router.js +68 -0
- package/dist/channels/serve.d.ts +5 -70
- package/dist/channels/serve.js +105 -287
- package/dist/channels/slack/history.d.ts +42 -0
- package/dist/channels/slack/history.js +282 -0
- package/dist/channels/slack/invoke-turn.d.ts +12 -5
- package/dist/channels/slack/invoke-turn.js +7 -5
- package/dist/channels/slack/manifest.d.ts +1 -4
- package/dist/channels/slack/manifest.js +22 -10
- package/dist/channels/slack/model.d.ts +2 -1
- package/dist/channels/slack/onboard.d.ts +0 -2
- package/dist/channels/slack/onboard.js +2 -4
- package/dist/channels/slack/onboarding-state.d.ts +0 -2
- package/dist/channels/slack/onboarding-state.js +0 -1
- package/dist/channels/slack/parse.d.ts +0 -5
- package/dist/channels/slack/parse.js +1 -16
- package/dist/channels/slack/preview.d.ts +2 -3
- package/dist/channels/slack/preview.js +78 -52
- package/dist/channels/slack/register-webhook.d.ts +1 -0
- package/dist/channels/slack/register-webhook.js +6 -5
- package/dist/channels/slack/scaffold/channel.ts +23 -24
- package/dist/channels/slack/scaffold/slack-send.ts +50 -43
- package/dist/channels/slack/scaffold/slack-threads.ts +29 -0
- package/dist/channels/slack/setup-server.d.ts +19 -0
- package/dist/channels/slack/setup-server.js +113 -11
- package/dist/channels/slack/shared-api.d.ts +15 -4
- package/dist/channels/slack/shared-api.js +19 -14
- package/dist/channels/slack/slack-api.d.ts +61 -2
- package/dist/channels/slack/slack-api.js +28 -5
- package/dist/channels/slack/slack.js +97 -52
- package/dist/channels/slack/welcomed.js +1 -1
- package/dist/channels/telegram/context-buffer.d.ts +6 -1
- package/dist/channels/telegram/context-buffer.js +19 -0
- package/dist/channels/telegram/invoke-turn.d.ts +8 -4
- package/dist/channels/telegram/invoke-turn.js +7 -7
- package/dist/channels/telegram/parse.d.ts +7 -2
- package/dist/channels/telegram/parse.js +7 -0
- package/dist/channels/telegram/preview.d.ts +2 -2
- package/dist/channels/telegram/register-webhook.d.ts +1 -0
- package/dist/channels/telegram/register-webhook.js +3 -2
- package/dist/channels/telegram/scaffold/channel.ts +27 -28
- package/dist/channels/telegram/scaffold/telegram-send.ts +61 -108
- package/dist/channels/telegram/shared-api.d.ts +34 -0
- package/dist/channels/telegram/shared-api.js +79 -0
- package/dist/channels/telegram/telegram-api.d.ts +15 -5
- package/dist/channels/telegram/telegram-api.js +10 -6
- package/dist/channels/telegram/telegram.js +27 -21
- package/dist/channels/telegram/turn-store.js +1 -1
- package/dist/channels/{kit/turn-queue.d.ts → turn-queue.d.ts} +2 -2
- package/dist/channels/{kit/turn-queue.js → turn-queue.js} +10 -10
- package/dist/cli/add-feishu.d.ts +42 -12
- package/dist/cli/add-feishu.js +177 -124
- package/dist/cli/add-slack.d.ts +8 -3
- package/dist/cli/add-slack.js +115 -63
- package/dist/cli/auth-view.d.ts +10 -3
- package/dist/cli/auth-view.js +8 -6
- package/dist/cli/box-login.d.ts +17 -7
- package/dist/cli/box-login.js +46 -12
- package/dist/cli/commands/add.d.ts +15 -4
- package/dist/cli/commands/add.js +252 -143
- package/dist/cli/commands/auth.d.ts +6 -0
- package/dist/cli/commands/auth.js +50 -0
- package/dist/cli/commands/content.d.ts +6 -0
- package/dist/cli/commands/content.js +45 -0
- package/dist/cli/commands/deploy/agentcore.js +50 -77
- package/dist/cli/commands/deploy/docker.js +38 -39
- package/dist/cli/commands/deploy/fly.js +21 -18
- package/dist/cli/commands/deploy/host-login.d.ts +26 -0
- package/dist/cli/commands/deploy/host-login.js +90 -0
- package/dist/cli/commands/deploy/railway.js +21 -26
- package/dist/cli/commands/deploy/shared.d.ts +45 -17
- package/dist/cli/commands/deploy/shared.js +34 -15
- package/dist/cli/commands/deploy.d.ts +0 -4
- package/dist/cli/commands/deploy.js +237 -50
- package/dist/cli/commands/destroy.js +8 -6
- package/dist/cli/commands/dev.d.ts +0 -2
- package/dist/cli/commands/dev.js +20 -19
- package/dist/cli/commands/env.d.ts +12 -0
- package/dist/cli/commands/env.js +190 -0
- package/dist/cli/commands/info.js +95 -156
- package/dist/cli/commands/init.d.ts +2 -2
- package/dist/cli/commands/init.js +35 -33
- package/dist/cli/commands/invoke.d.ts +6 -0
- package/dist/cli/commands/invoke.js +131 -16
- package/dist/cli/commands/login.d.ts +31 -2
- package/dist/cli/commands/login.js +413 -64
- package/dist/cli/commands/logout.d.ts +4 -0
- package/dist/cli/commands/logout.js +53 -0
- package/dist/cli/commands/logs.js +8 -6
- package/dist/cli/commands/models.d.ts +2 -1
- package/dist/cli/commands/models.js +39 -37
- package/dist/cli/commands/schedules.d.ts +21 -0
- package/dist/cli/commands/schedules.js +143 -0
- package/dist/cli/commands/start.d.ts +11 -10
- package/dist/cli/commands/start.js +35 -62
- package/dist/cli/content-view.d.ts +9 -0
- package/dist/cli/content-view.js +26 -0
- package/dist/cli/fail.d.ts +9 -12
- package/dist/cli/fail.js +17 -14
- package/dist/cli/invoke-stream.d.ts +12 -3
- package/dist/cli/invoke-stream.js +85 -23
- package/dist/cli/kernel.d.ts +9 -2
- package/dist/cli/kernel.js +15 -6
- package/dist/cli/login-relay.d.ts +3 -2
- package/dist/cli/login-relay.js +18 -6
- package/dist/cli/models-view.d.ts +5 -1
- package/dist/cli/models-view.js +1 -1
- package/dist/cli/person.d.ts +10 -0
- package/dist/cli/person.js +23 -0
- package/dist/cli/program.js +421 -203
- package/dist/cli/serve.d.ts +13 -63
- package/dist/cli/serve.js +31 -121
- package/dist/cli/shared.d.ts +21 -48
- package/dist/cli/shared.js +68 -89
- package/dist/cli/ticket.d.ts +136 -0
- package/dist/cli/ticket.js +476 -0
- package/dist/client.d.ts +7 -0
- package/dist/client.js +2 -0
- package/dist/content/declare.d.ts +70 -0
- package/dist/content/declare.js +163 -0
- package/dist/content/file.d.ts +32 -0
- package/dist/content/file.js +119 -0
- package/dist/content/git.d.ts +41 -0
- package/dist/content/git.js +217 -0
- package/dist/content/mount.d.ts +2 -0
- package/dist/content/mount.js +15 -0
- package/dist/content/resolve.d.ts +52 -0
- package/dist/content/resolve.js +151 -0
- package/dist/content/source.d.ts +27 -0
- package/dist/content/source.js +53 -0
- package/dist/conversation-sessions.d.ts +26 -0
- package/dist/conversation-sessions.js +99 -0
- package/dist/declared-secrets.d.ts +19 -37
- package/dist/declared-secrets.js +16 -58
- package/dist/deploy/agentcore/destroy.d.ts +3 -3
- package/dist/deploy/agentcore/destroy.js +46 -28
- package/dist/deploy/agentcore/forwarder.js +105 -22
- package/dist/deploy/agentcore/logs.js +1 -1
- package/dist/deploy/agentcore/plan.d.ts +10 -24
- package/dist/deploy/agentcore/plan.js +31 -135
- package/dist/deploy/agentcore/run.d.ts +1 -1
- package/dist/deploy/agentcore/run.js +8 -5
- package/dist/deploy/agentcore/shell.d.ts +1 -1
- package/dist/deploy/agentcore/shell.js +5 -5
- package/dist/deploy/api.d.ts +34 -0
- package/dist/deploy/api.js +50 -0
- package/dist/deploy/box-shell.d.ts +6 -0
- package/dist/deploy/box-shell.js +7 -0
- package/dist/deploy/build-context.d.ts +7 -5
- package/dist/deploy/build-context.js +41 -35
- package/dist/deploy/channel-ingress.d.ts +6 -1
- package/dist/deploy/channel-ingress.js +18 -5
- package/dist/deploy/container.d.ts +22 -9
- package/dist/deploy/container.js +96 -55
- package/dist/deploy/docker/plan.d.ts +3 -2
- package/dist/deploy/docker/plan.js +13 -14
- package/dist/deploy/docker/run.d.ts +2 -2
- package/dist/deploy/docker/run.js +8 -4
- package/dist/deploy/fly/plan.d.ts +1 -1
- package/dist/deploy/fly/plan.js +12 -21
- package/dist/deploy/fly/run.d.ts +10 -6
- package/dist/deploy/fly/run.js +11 -6
- package/dist/deploy/hosts.d.ts +2 -1
- package/dist/deploy/hosts.js +2 -1
- package/dist/deploy/preflight.d.ts +21 -23
- package/dist/deploy/preflight.js +222 -201
- package/dist/deploy/railway/plan.d.ts +8 -6
- package/dist/deploy/railway/plan.js +15 -58
- package/dist/deploy/railway/run.d.ts +8 -3
- package/dist/deploy/railway/run.js +12 -8
- package/dist/deploy/residency.d.ts +5 -11
- package/dist/deploy/residency.js +0 -6
- package/dist/deploy/runner.d.ts +1 -1
- package/dist/deploy/runner.js +1 -1
- package/dist/deploy/secrets.d.ts +16 -2
- package/dist/deploy/secrets.js +33 -6
- package/dist/deploy/workspace.d.ts +11 -6
- package/dist/deploy/workspace.js +55 -38
- package/dist/dev-supervisor.d.ts +11 -2
- package/dist/dev-supervisor.js +51 -26
- package/dist/effect-port.d.ts +4 -4
- package/dist/effect-port.js +4 -4
- package/dist/environment/apt.d.ts +4 -0
- package/dist/environment/apt.js +32 -0
- package/dist/environment/declare.d.ts +59 -0
- package/dist/environment/declare.js +210 -0
- package/dist/environment/mise.d.ts +50 -0
- package/dist/environment/mise.js +268 -0
- package/dist/feishu.d.ts +2 -2
- package/dist/feishu.js +2 -2
- package/dist/git.d.ts +13 -0
- package/dist/git.js +55 -0
- package/dist/harnesses/models/catalog.d.ts +20 -0
- package/dist/harnesses/models/catalog.js +254 -0
- package/dist/{engines/pi/auth.d.ts → harnesses/models/credentials.d.ts} +3 -3
- package/dist/{engines/pi/auth.js → harnesses/models/credentials.js} +3 -3
- package/dist/harnesses/models/environment.d.ts +43 -0
- package/dist/harnesses/models/environment.js +82 -0
- package/dist/{engines/pi → harnesses/models}/login.d.ts +57 -26
- package/dist/{engines/pi → harnesses/models}/login.js +187 -79
- package/dist/harnesses/models/models.d.ts +83 -0
- package/dist/harnesses/models/models.js +158 -0
- package/dist/harnesses/pi-durable/agent.d.ts +42 -0
- package/dist/harnesses/pi-durable/agent.js +579 -0
- package/dist/harnesses/pi-durable/defaults.d.ts +28 -0
- package/dist/harnesses/pi-durable/defaults.js +26 -0
- package/dist/harnesses/pi-durable/define.d.ts +77 -0
- package/dist/harnesses/pi-durable/define.js +28 -0
- package/dist/harnesses/pi-durable/entries.d.ts +32 -0
- package/dist/harnesses/pi-durable/entries.js +126 -0
- package/dist/harnesses/pi-durable/events.d.ts +25 -0
- package/dist/harnesses/pi-durable/events.js +238 -0
- package/dist/harnesses/pi-durable/ids.d.ts +16 -0
- package/dist/harnesses/pi-durable/ids.js +55 -0
- package/dist/harnesses/pi-durable/messages.d.ts +41 -0
- package/dist/harnesses/pi-durable/messages.js +116 -0
- package/dist/harnesses/pi-durable/open.d.ts +88 -0
- package/dist/harnesses/pi-durable/open.js +329 -0
- package/dist/harnesses/pi-durable/reads.d.ts +30 -0
- package/dist/harnesses/pi-durable/reads.js +94 -0
- package/dist/harnesses/pi-durable/registry.d.ts +18 -0
- package/dist/harnesses/pi-durable/registry.js +56 -0
- package/dist/harnesses/pi-durable/release.d.ts +13 -0
- package/dist/harnesses/pi-durable/release.js +40 -0
- package/dist/harnesses/pi-durable/serve.d.ts +80 -0
- package/dist/harnesses/pi-durable/serve.js +156 -0
- package/dist/harnesses/pi-durable/sessions.d.ts +27 -0
- package/dist/harnesses/pi-durable/sessions.js +47 -0
- package/dist/harnesses/pi-durable/storage.d.ts +4 -0
- package/dist/harnesses/pi-durable/storage.js +49 -0
- package/dist/harnesses/pi-durable/stream.d.ts +20 -0
- package/dist/harnesses/pi-durable/stream.js +221 -0
- package/dist/harnesses/pi-durable/text.d.ts +30 -0
- package/dist/harnesses/pi-durable/text.js +292 -0
- package/dist/harnesses/pi-durable/wake.d.ts +4 -0
- package/dist/harnesses/pi-durable/wake.js +81 -0
- package/dist/http/client.d.ts +6 -0
- package/dist/http/client.js +256 -0
- package/dist/http/contract.d.ts +541 -0
- package/dist/http/contract.js +179 -0
- package/dist/http/server.d.ts +34 -0
- package/dist/http/server.js +194 -0
- package/dist/index.d.ts +17 -4
- package/dist/index.js +10 -5
- package/dist/lark.d.ts +2 -2
- package/dist/lark.js +2 -2
- package/dist/locked-file.d.ts +17 -0
- package/dist/{engines/pi/locked-file.js → locked-file.js} +16 -10
- package/dist/once.d.ts +6 -0
- package/dist/once.js +23 -0
- package/dist/paths.d.ts +36 -52
- package/dist/paths.js +66 -182
- package/dist/runtime.d.ts +25 -2
- package/dist/runtime.js +27 -0
- package/dist/scaffold/add-channel.d.ts +14 -27
- package/dist/scaffold/add-channel.js +82 -180
- package/dist/scaffold/init.d.ts +17 -18
- package/dist/scaffold/init.js +87 -99
- package/dist/scaffold/templates/SYSTEM.md +12 -0
- package/dist/scaffold/templates/env.example +4 -10
- package/dist/scaffold/templates/fastagent.config.ts +21 -33
- package/dist/scaffold/templates/gitignore +8 -1
- package/dist/scaffold/templates/skills/writing-great-skills/SKILL.md +1 -2
- package/dist/scaffold/templates.d.ts +9 -4
- package/dist/scaffold/templates.js +7 -5
- package/dist/scaffold/vendor-skill.d.ts +1 -4
- package/dist/scaffold/vendor-skill.js +5 -6
- package/dist/schedule/cron.d.ts +13 -0
- package/dist/schedule/cron.js +52 -0
- package/dist/schedule/eventbridge-cron.d.ts +17 -0
- package/dist/schedule/eventbridge-cron.js +88 -0
- package/dist/schedule/schedule.d.ts +23 -0
- package/dist/schedule/schedule.js +34 -0
- package/dist/schedule/scheduler.d.ts +34 -33
- package/dist/schedule/scheduler.js +251 -137
- package/dist/schedule/state.d.ts +4 -14
- package/dist/schedule/state.js +7 -7
- package/dist/schedule/wake-alarm.d.ts +22 -2
- package/dist/schedule/wake-alarm.js +66 -20
- package/dist/schedule/wakeups.d.ts +16 -15
- package/dist/schedule/wakeups.js +47 -45
- package/dist/service.d.ts +56 -169
- package/dist/service.js +91 -187
- package/dist/serving-command.d.ts +10 -0
- package/dist/serving-command.js +16 -0
- package/dist/slack.d.ts +1 -1
- package/dist/slack.js +1 -1
- package/dist/{channels/kit/state.js → state-file.js} +6 -6
- package/dist/telegram.d.ts +1 -0
- package/dist/telegram.js +1 -0
- package/dist/tunnel.d.ts +3 -0
- package/dist/tunnel.js +12 -4
- package/dist/value-file.d.ts +21 -0
- package/dist/value-file.js +108 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.js +14 -1
- package/package.json +18 -28
- package/dist/agent.d.ts +0 -106
- package/dist/agent.js +0 -21
- package/dist/channels/control.d.ts +0 -31
- package/dist/channels/control.js +0 -329
- package/dist/channels/define-channel.d.ts +0 -39
- package/dist/channels/define-channel.js +0 -9
- package/dist/channels/feishu/context-buffer.d.ts +0 -35
- package/dist/channels/feishu/context-buffer.js +0 -65
- package/dist/channels/feishu/scaffold/channel.websocket.ts +0 -31
- package/dist/channels/http.d.ts +0 -23
- package/dist/channels/http.js +0 -57
- package/dist/channels/lark/scaffold/channel.websocket.ts +0 -31
- package/dist/channels/slack/context-buffer.d.ts +0 -23
- package/dist/channels/slack/context-buffer.js +0 -37
- package/dist/channels/sse.d.ts +0 -4
- package/dist/channels/sse.js +0 -66
- package/dist/cli/commands/chat.d.ts +0 -3
- package/dist/cli/commands/chat.js +0 -14
- package/dist/cli/commands/routine-run.d.ts +0 -6
- package/dist/cli/commands/routine-run.js +0 -46
- package/dist/cli/commands/routine.d.ts +0 -25
- package/dist/cli/commands/routine.js +0 -122
- package/dist/cli/commands/tool.d.ts +0 -1
- package/dist/cli/commands/tool.js +0 -57
- package/dist/collect.d.ts +0 -63
- package/dist/collect.js +0 -90
- package/dist/core.d.ts +0 -13
- package/dist/core.js +0 -15
- package/dist/engines/pi/agent-models.d.ts +0 -83
- package/dist/engines/pi/agent-models.js +0 -120
- package/dist/engines/pi/agent-session-factory.d.ts +0 -121
- package/dist/engines/pi/agent-session-factory.js +0 -517
- package/dist/engines/pi/chat.d.ts +0 -3
- package/dist/engines/pi/chat.js +0 -8
- package/dist/engines/pi/config.d.ts +0 -71
- package/dist/engines/pi/config.js +0 -199
- package/dist/engines/pi/create.d.ts +0 -170
- package/dist/engines/pi/create.js +0 -343
- package/dist/engines/pi/definition.d.ts +0 -74
- package/dist/engines/pi/definition.js +0 -236
- package/dist/engines/pi/entry-images.d.ts +0 -14
- package/dist/engines/pi/entry-images.js +0 -23
- package/dist/engines/pi/invoke-session.d.ts +0 -18
- package/dist/engines/pi/invoke-session.js +0 -403
- package/dist/engines/pi/locked-file.d.ts +0 -9
- package/dist/engines/pi/machine.d.ts +0 -53
- package/dist/engines/pi/machine.js +0 -137
- package/dist/engines/pi/models.d.ts +0 -200
- package/dist/engines/pi/models.js +0 -533
- package/dist/engines/pi/open.d.ts +0 -180
- package/dist/engines/pi/open.js +0 -270
- package/dist/engines/pi/openai-account-models.d.ts +0 -35
- package/dist/engines/pi/openai-account-models.js +0 -116
- package/dist/engines/pi/report.d.ts +0 -18
- package/dist/engines/pi/report.js +0 -59
- package/dist/engines/pi/retry-event.d.ts +0 -6
- package/dist/engines/pi/retry-event.js +0 -15
- package/dist/engines/pi/service.d.ts +0 -9
- package/dist/engines/pi/service.js +0 -14
- package/dist/engines/pi/session-builder.d.ts +0 -13
- package/dist/engines/pi/session-builder.js +0 -117
- package/dist/engines/pi/session-control.d.ts +0 -77
- package/dist/engines/pi/session-control.js +0 -908
- package/dist/engines/pi/session-effects.d.ts +0 -14
- package/dist/engines/pi/session-effects.js +0 -30
- package/dist/engines/pi/session-inheritance.d.ts +0 -21
- package/dist/engines/pi/session-inheritance.js +0 -204
- package/dist/engines/pi/session-markers.d.ts +0 -49
- package/dist/engines/pi/session-markers.js +0 -60
- package/dist/engines/pi/session-settings.d.ts +0 -67
- package/dist/engines/pi/session-settings.js +0 -119
- package/dist/engines/pi/session-store.d.ts +0 -69
- package/dist/engines/pi/session-store.js +0 -430
- package/dist/engines/pi/tool-context.d.ts +0 -45
- package/dist/engines/pi/tool-context.js +0 -31
- package/dist/engines/pi/tool.d.ts +0 -99
- package/dist/engines/pi/tool.js +0 -118
- package/dist/engines/pi/turn-kit.d.ts +0 -83
- package/dist/engines/pi/turn-kit.js +0 -275
- package/dist/engines/pi/wake-tool.d.ts +0 -9
- package/dist/engines/pi/wake-tool.js +0 -92
- package/dist/loader.d.ts +0 -41
- package/dist/loader.js +0 -116
- package/dist/node.d.ts +0 -3
- package/dist/node.js +0 -4
- package/dist/observe.d.ts +0 -6
- package/dist/observe.js +0 -47
- package/dist/pi.d.ts +0 -25
- package/dist/pi.js +0 -15
- package/dist/scaffold/templates/APPEND_SYSTEM.md +0 -12
- package/dist/scaffold/templates/tools/fetch-url.ts +0 -25
- package/dist/schedule/discover.d.ts +0 -17
- package/dist/schedule/discover.js +0 -61
- package/dist/schedule/routine.d.ts +0 -43
- package/dist/schedule/routine.js +0 -32
- package/dist/schedule/run.d.ts +0 -55
- package/dist/schedule/run.js +0 -146
- package/dist/secrets-gate.d.ts +0 -32
- package/dist/secrets-gate.js +0 -33
- package/dist/session-remote.d.ts +0 -47
- package/dist/session-remote.js +0 -460
- package/dist/session.d.ts +0 -466
- package/dist/session.js +0 -57
- /package/dist/{channels/kit/state.d.ts → state-file.d.ts} +0 -0
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* on a host with NO resident process.
|
|
2
|
+
* ALARMS for the AgentCore deployment: what makes the agent's self-scheduled wake-ups (`wake`) and its schedules fire
|
|
3
|
+
* on a host with NO resident process. The container mirrors both through the forwarder into EventBridge Scheduler:
|
|
4
|
+
* - each schedule as a RECURRING cron schedule, which EventBridge fires on its own clock, the way AWS runs any
|
|
5
|
+
* recurring job. Mirroring only creates, changes or deletes it; nothing has to happen after a fire for the next
|
|
6
|
+
* one, so a failed mirror delays an edit, never stops a schedule. Because the container sets it, a schedule written
|
|
7
|
+
* or edited while it runs takes effect without a deploy.
|
|
8
|
+
* - each pending wake-up as a one-shot schedule that deletes itself once it has poked the container.
|
|
4
9
|
*/
|
|
5
10
|
import { readFileSync } from "node:fs";
|
|
6
11
|
import * as Clock from "effect/Clock";
|
|
7
12
|
import * as Effect from "effect/Effect";
|
|
8
13
|
import { PortFailure, portError, portJoin, portRequest } from "../effect-port.js";
|
|
9
|
-
import { RESERVED_PATHS } from "../channels/agentcore-protocol.js";
|
|
14
|
+
import { RESERVED_PATHS, } from "../channels/agentcore-protocol.js";
|
|
10
15
|
import { beginWork } from "../channels/busy.js";
|
|
11
16
|
import { log } from "../log.js";
|
|
12
17
|
import { scheduleFile, writeScheduleFile } from "./state.js";
|
|
13
18
|
import { listWakeups } from "./wakeups.js";
|
|
19
|
+
import { toEventBridgeCron } from "./eventbridge-cron.js";
|
|
14
20
|
const URL_FILE = "wake-alarm-url";
|
|
15
21
|
/**
|
|
16
22
|
* Persist the forwarder URL the adapter saw in an envelope (write-if-changed — envelopes arrive on every turn, the
|
|
@@ -41,14 +47,39 @@ export function readWakeAlarmUrl(stateRoot) {
|
|
|
41
47
|
*/
|
|
42
48
|
export const MAX_SYNC_ATTEMPTS = 5;
|
|
43
49
|
const RETRY_BASE_MS = 2_000;
|
|
50
|
+
/**
|
|
51
|
+
* After a whole sync gives up, how long until it is tried again, for as long as this process lives. Outside the busy
|
|
52
|
+
* count, so a container that is only waiting to retry can still be reclaimed; its next start mirrors again.
|
|
53
|
+
*/
|
|
54
|
+
export const HEAL_MS = 5 * 60_000;
|
|
44
55
|
const SYNC_TIMEOUT_MS = 10_000;
|
|
45
56
|
/** Alarms due within this margin are NOT mirrored. */
|
|
46
57
|
const DUE_MARGIN_MS = 5_000;
|
|
47
|
-
/**
|
|
58
|
+
/**
|
|
59
|
+
* Pending wake-ups → the desired one-shot alarms. A wake-up already due is left out (see {@link DUE_MARGIN_MS}): the
|
|
60
|
+
* container is awake for it, and its wake pump fires it.
|
|
61
|
+
*
|
|
62
|
+
* ONE ID PER INSTANT, never per wake-up. An alarm deletes itself once it has fired, and a recurring wake-up's claim
|
|
63
|
+
* mirrors its next instant right after: an id reused for it would update the alarm EventBridge is about to delete,
|
|
64
|
+
* and the next instant would be deleted with it. With one id per instant, mirroring again is idempotent.
|
|
65
|
+
*/
|
|
48
66
|
export function toAlarms(pending, now) {
|
|
67
|
+
const earliest = now.getTime() + DUE_MARGIN_MS;
|
|
49
68
|
return pending
|
|
50
|
-
.filter((w) => Date.parse(w.fireAt) >
|
|
51
|
-
.map((w) => ({ id: w.id
|
|
69
|
+
.filter((w) => Date.parse(w.fireAt) > earliest)
|
|
70
|
+
.map((w) => ({ id: `${w.id}@${w.fireAt}`, at: w.fireAt }));
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Each armed schedule → the recurring EventBridge schedule that fires it. Discovery admits only a cron that
|
|
74
|
+
* translates (schedule/discover.ts), so one that does not here is a defect, and throws.
|
|
75
|
+
*/
|
|
76
|
+
export function toRecurring(schedules) {
|
|
77
|
+
return schedules.map((s) => {
|
|
78
|
+
const translated = toEventBridgeCron(s.cron);
|
|
79
|
+
if ("error" in translated)
|
|
80
|
+
throw new Error(`schedule "${s.name}" has no EventBridge form: ${translated.error}`);
|
|
81
|
+
return { name: s.name, expression: translated.expression, tz: s.tz ?? "UTC" };
|
|
82
|
+
});
|
|
52
83
|
}
|
|
53
84
|
/**
|
|
54
85
|
* Build the wakeups sink for an AgentCore deployment (registered via `setWakeupsSink` by `start` when
|
|
@@ -58,7 +89,7 @@ export function createWakeAlarmSink(options) {
|
|
|
58
89
|
return Effect.gen(function* () {
|
|
59
90
|
const clock = yield* Clock.Clock;
|
|
60
91
|
const fork = Effect.runForkWith(yield* Effect.context());
|
|
61
|
-
const { secret, fetchImpl = fetch, now = () => new Date(clock.currentTimeMillisUnsafe()), delay: pause } = options;
|
|
92
|
+
const { secret, schedules = () => [], fetchImpl = fetch, now = () => new Date(clock.currentTimeMillisUnsafe()), delay: pause, } = options;
|
|
62
93
|
const delay = (ms) => (pause ? portJoin(() => pause(ms)) : Effect.sleep(ms));
|
|
63
94
|
let running = false;
|
|
64
95
|
let dirty = false;
|
|
@@ -68,18 +99,20 @@ export function createWakeAlarmSink(options) {
|
|
|
68
99
|
try: () => toAlarms(listWakeups(stateRoot), now()),
|
|
69
100
|
catch: (cause) => new PortFailure(cause),
|
|
70
101
|
});
|
|
71
|
-
|
|
72
|
-
if (alarms.length === 0)
|
|
73
|
-
return true;
|
|
102
|
+
const recurring = toRecurring(schedules());
|
|
74
103
|
const url = yield* Effect.try({
|
|
75
104
|
try: () => readWakeAlarmUrl(stateRoot),
|
|
76
105
|
catch: (cause) => new PortFailure(cause),
|
|
77
106
|
});
|
|
78
107
|
if (!url) {
|
|
79
|
-
|
|
108
|
+
// Nothing to set, before the forwarder was ever seen: nothing can be pending there either.
|
|
109
|
+
if (alarms.length > 0 || recurring.length > 0) {
|
|
110
|
+
log.warn("[schedule] alarm sync skipped — forwarder URL not seen yet");
|
|
111
|
+
}
|
|
80
112
|
return true;
|
|
81
113
|
}
|
|
82
|
-
|
|
114
|
+
// Sent EMPTY too: the schedules are the whole set, and the forwarder deletes one this set no longer has.
|
|
115
|
+
const body = { secret, alarms, schedules: recurring };
|
|
83
116
|
return yield* portRequest(async (signal) => {
|
|
84
117
|
const res = await fetchImpl(`${url.replace(/\/$/, "")}${RESERVED_PATHS.wakeAlarm}`, {
|
|
85
118
|
method: "POST",
|
|
@@ -121,14 +154,18 @@ export function createWakeAlarmSink(options) {
|
|
|
121
154
|
break;
|
|
122
155
|
}
|
|
123
156
|
}
|
|
124
|
-
if (failures
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
157
|
+
if (failures < MAX_SYNC_ATTEMPTS)
|
|
158
|
+
return true;
|
|
159
|
+
log.error(`[schedule] alarm sync FAILED after ${MAX_SYNC_ATTEMPTS} attempts — new wake-ups have no alarm, and ` +
|
|
160
|
+
`schedule edits since the last sync have not reached EventBridge (schedules it already holds keep ` +
|
|
161
|
+
`firing). It is tried again every ${HEAL_MS / 60_000} minutes while this container runs, and at its next start`);
|
|
162
|
+
return false;
|
|
128
163
|
});
|
|
164
|
+
/** One retry pending at a time, however many syncs gave up meanwhile. */
|
|
165
|
+
let healing = false;
|
|
129
166
|
// Single-flight: a save arriving while the loop runs only marks it dirty, so a burst coalesces into one more pass
|
|
130
167
|
// instead of one concurrent loop each.
|
|
131
|
-
|
|
168
|
+
const sink = (stateRoot) => {
|
|
132
169
|
dirty = true;
|
|
133
170
|
if (running)
|
|
134
171
|
return;
|
|
@@ -136,12 +173,21 @@ export function createWakeAlarmSink(options) {
|
|
|
136
173
|
fork(Effect.acquireUseRelease(Effect.sync(beginWork), () =>
|
|
137
174
|
// Claim notification precedes scheduler admission; retain busy ownership through that handoff.
|
|
138
175
|
Effect.yieldNow.pipe(Effect.andThen(reconcile(stateRoot)), Effect.catchCause((cause) => Effect.sync(() => {
|
|
139
|
-
|
|
140
|
-
|
|
176
|
+
log.error(`[schedule] alarm reconcile failed (tried again in ${HEAL_MS / 60_000} minutes while this ` +
|
|
177
|
+
`container runs): ${String(portError(cause))}`);
|
|
178
|
+
return false;
|
|
141
179
|
}))), (done) => Effect.sync(() => {
|
|
142
180
|
running = false;
|
|
143
181
|
done();
|
|
144
|
-
})))
|
|
182
|
+
})).pipe(Effect.flatMap((converged) => converged || healing
|
|
183
|
+
? Effect.void
|
|
184
|
+
: Effect.sync(() => {
|
|
185
|
+
healing = true;
|
|
186
|
+
}).pipe(Effect.andThen(delay(HEAL_MS)), Effect.andThen(Effect.sync(() => {
|
|
187
|
+
healing = false;
|
|
188
|
+
sink(stateRoot);
|
|
189
|
+
}))))));
|
|
145
190
|
};
|
|
191
|
+
return sink;
|
|
146
192
|
});
|
|
147
193
|
}
|
|
@@ -10,9 +10,12 @@ export interface Wakeup {
|
|
|
10
10
|
cron?: string;
|
|
11
11
|
/** IANA timezone for `cron` (default UTC). */
|
|
12
12
|
tz?: string;
|
|
13
|
-
/** ONE-SHOT ONLY: consecutive busy-defer attempts. */
|
|
14
|
-
attempts?: number;
|
|
15
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Parse a delay to milliseconds: a number is SECONDS; a string MUST carry a unit — `"<n><s|m|h|d>"` ("30m", "2h",
|
|
16
|
+
* "1d").
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseDelayMs(input: string | number): number | undefined;
|
|
16
19
|
/** The minimum delay a wake-up may be scheduled for — rejects a busy-loop (`wake in 1s`, then again…). */
|
|
17
20
|
export declare const MIN_WAKE_MS = 60000;
|
|
18
21
|
/**
|
|
@@ -21,8 +24,6 @@ export declare const MIN_WAKE_MS = 60000;
|
|
|
21
24
|
* deploy is one session per chat).
|
|
22
25
|
*/
|
|
23
26
|
export declare const MAX_PENDING_WAKEUPS = 20;
|
|
24
|
-
/** How many times a busy/transient wake is retried (deferred) before being dropped. */
|
|
25
|
-
export declare const MAX_WAKE_ATTEMPTS = 120;
|
|
26
27
|
export declare function setWakeupsSink(sink: ((stateRoot: string) => void) | undefined): void;
|
|
27
28
|
/** The current pending wake-ups — read by the wake-alarm sink, which mirrors them into an external clock. */
|
|
28
29
|
export declare function listWakeups(stateRoot: string): Wakeup[];
|
|
@@ -43,22 +44,22 @@ export declare function addWakeup(stateRoot: string, input: {
|
|
|
43
44
|
tz?: string;
|
|
44
45
|
}, now?: Date): AddWakeupResult;
|
|
45
46
|
/**
|
|
46
|
-
* Remove ONE pending wake-up, and only from the session that made it.
|
|
47
|
-
*
|
|
48
|
-
* SESSION-SCOPED WITH NO WAY AROUND IT, because `unwake` is the only caller: an agent cancels its own alarm, and
|
|
49
|
-
* cancelling another conversation's silently is a cost with no matching benefit. There is no operator command: a
|
|
50
|
-
* wake-up only fires while a serve is running, and a running serve is one whose
|
|
51
|
-
* session can be spoken to (`POST /invoke`, the control plane's `follow_up`, or the chat thread it lives in), so
|
|
52
|
-
* "the alarm is loose" and "the agent is unreachable" cannot both be true. The last resort is editing
|
|
53
|
-
* `<stateRoot>/schedule/wakeups.json`, which needs no command.
|
|
47
|
+
* Remove ONE pending wake-up, and only from the session that made it: `unwake`, an agent cancelling its own alarm.
|
|
48
|
+
* Cancelling another conversation's silently is a cost with no matching benefit.
|
|
54
49
|
*/
|
|
55
50
|
export declare function removeWakeup(stateRoot: string, id: string, session: string): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Remove ONE pending wake-up whatever session set it: the operator's `fastagent schedules unwake`, the one way out of a
|
|
53
|
+
* wake-up set in a session nobody can message (a schedule's own). Its caller holds the instance, so no serve's poll
|
|
54
|
+
* writes the store between this read and its write.
|
|
55
|
+
*/
|
|
56
|
+
export declare function removeAnyWakeup(stateRoot: string, id: string): Wakeup | undefined;
|
|
56
57
|
/**
|
|
57
58
|
* CLAIM the FIRST due wake-up (at or before `now`) in stored order, remove + return it, or undefined if none is due.
|
|
58
59
|
*/
|
|
59
60
|
export declare function takeFirstDueWakeup(stateRoot: string, now?: Date): Wakeup | undefined;
|
|
60
61
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
62
|
+
* Put back a ONE-SHOT wake-up its session refused for now (the process or the session's queue was full), to fire at
|
|
63
|
+
* `fireAt`. It was taken out of the store to fire, so it does not count against the session's cap again.
|
|
63
64
|
*/
|
|
64
|
-
export declare function
|
|
65
|
+
export declare function requeueWakeup(stateRoot: string, w: Wakeup, fireAt: Date): void;
|
package/dist/schedule/wakeups.js
CHANGED
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The agent's self-scheduled wake-ups — the SECOND producer of scheduled invocations (the first is the author's
|
|
3
|
-
* `
|
|
3
|
+
* `schedules/` files).
|
|
4
4
|
*/
|
|
5
5
|
import { randomUUID } from "node:crypto";
|
|
6
6
|
import { log } from "../log.js";
|
|
7
|
-
import { cronError, nextRun } from "./cron.js";
|
|
7
|
+
import { cronError, nextRun, recurringCronError } from "./cron.js";
|
|
8
8
|
import { readScheduleFile, scheduleFile, writeScheduleFile } from "./state.js";
|
|
9
|
+
/**
|
|
10
|
+
* Parse a delay to milliseconds: a number is SECONDS; a string MUST carry a unit — `"<n><s|m|h|d>"` ("30m", "2h",
|
|
11
|
+
* "1d").
|
|
12
|
+
*/
|
|
13
|
+
export function parseDelayMs(input) {
|
|
14
|
+
if (typeof input === "number")
|
|
15
|
+
return Number.isFinite(input) && input > 0 ? input * 1000 : undefined;
|
|
16
|
+
const m = input.trim().match(/^(\d+(?:\.\d+)?)\s*(s|m|h|d)$/i); // unit REQUIRED on a string
|
|
17
|
+
if (!m)
|
|
18
|
+
return undefined;
|
|
19
|
+
const mult = { s: 1_000, m: 60_000, h: 3_600_000, d: 86_400_000 }[m[2].toLowerCase()];
|
|
20
|
+
return Number(m[1]) * mult;
|
|
21
|
+
}
|
|
9
22
|
/** The minimum delay a wake-up may be scheduled for — rejects a busy-loop (`wake in 1s`, then again…). */
|
|
10
23
|
export const MIN_WAKE_MS = 60_000; // 1 minute
|
|
11
24
|
/**
|
|
@@ -14,10 +27,6 @@ export const MIN_WAKE_MS = 60_000; // 1 minute
|
|
|
14
27
|
* deploy is one session per chat).
|
|
15
28
|
*/
|
|
16
29
|
export const MAX_PENDING_WAKEUPS = 20;
|
|
17
|
-
/** How many times a busy/transient wake is retried (deferred) before being dropped. */
|
|
18
|
-
export const MAX_WAKE_ATTEMPTS = 120;
|
|
19
|
-
/** The minimum gap between two consecutive fires of a RECURRING wake. */
|
|
20
|
-
const MIN_RECURRING_GAP_MS = 10 * 60_000; // 10 minutes
|
|
21
30
|
/** A stored entry is a real Wakeup: the fields are present and `fireAt` is a parseable date. */
|
|
22
31
|
function isWakeup(e) {
|
|
23
32
|
if (!e || typeof e !== "object")
|
|
@@ -28,7 +37,6 @@ function isWakeup(e) {
|
|
|
28
37
|
typeof w.prompt === "string" &&
|
|
29
38
|
typeof w.fireAt === "string" &&
|
|
30
39
|
!Number.isNaN(Date.parse(w.fireAt)) &&
|
|
31
|
-
(w.attempts === undefined || typeof w.attempts === "number") && // a non-number would make deferWakeup's count NaN
|
|
32
40
|
(w.tz === undefined || typeof w.tz === "string") &&
|
|
33
41
|
// A stored cron must PARSE: a bad one would throw inside the claim's nextRun.
|
|
34
42
|
(w.cron === undefined ||
|
|
@@ -74,22 +82,15 @@ export function listWakeups(stateRoot) {
|
|
|
74
82
|
export function addWakeup(stateRoot, input, now = new Date()) {
|
|
75
83
|
let fireAtDate;
|
|
76
84
|
if (input.cron !== undefined) {
|
|
77
|
-
|
|
85
|
+
// A recurring wake runs FOREVER — gated harder than a one-shot, by the rule every recurring producer shares.
|
|
86
|
+
const err = recurringCronError(input.cron, input.tz);
|
|
78
87
|
if (err)
|
|
79
|
-
return { ok: false, error: `
|
|
80
|
-
//
|
|
81
|
-
// instants must be ≥ the recurring floor.
|
|
88
|
+
return { ok: false, error: `${err}${err.startsWith("this cron never") ? " — use `in` for a one-shot" : ""}.` };
|
|
89
|
+
// DERIVED from the cron — a caller-passed fireAt can't disagree with the schedule.
|
|
82
90
|
const first = nextRun(input.cron, input.tz, now);
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (second.getTime() - first.getTime() < MIN_RECURRING_GAP_MS) {
|
|
87
|
-
return {
|
|
88
|
-
ok: false,
|
|
89
|
-
error: `too frequent — a recurring wake must fire at most every ${MIN_RECURRING_GAP_MS / 60_000} minutes.`,
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
fireAtDate = first; // DERIVED from the cron — a caller-passed fireAt can't disagree with the schedule
|
|
91
|
+
if (!first)
|
|
92
|
+
return { ok: false, error: "this cron never fires again — use `in` for a one-shot." };
|
|
93
|
+
fireAtDate = first;
|
|
93
94
|
}
|
|
94
95
|
else {
|
|
95
96
|
if (!input.fireAt)
|
|
@@ -121,22 +122,28 @@ export function addWakeup(stateRoot, input, now = new Date()) {
|
|
|
121
122
|
return { ok: true, id, fireAt };
|
|
122
123
|
}
|
|
123
124
|
/**
|
|
124
|
-
* Remove ONE pending wake-up, and only from the session that made it.
|
|
125
|
-
*
|
|
126
|
-
* SESSION-SCOPED WITH NO WAY AROUND IT, because `unwake` is the only caller: an agent cancels its own alarm, and
|
|
127
|
-
* cancelling another conversation's silently is a cost with no matching benefit. There is no operator command: a
|
|
128
|
-
* wake-up only fires while a serve is running, and a running serve is one whose
|
|
129
|
-
* session can be spoken to (`POST /invoke`, the control plane's `follow_up`, or the chat thread it lives in), so
|
|
130
|
-
* "the alarm is loose" and "the agent is unreachable" cannot both be true. The last resort is editing
|
|
131
|
-
* `<stateRoot>/schedule/wakeups.json`, which needs no command.
|
|
125
|
+
* Remove ONE pending wake-up, and only from the session that made it: `unwake`, an agent cancelling its own alarm.
|
|
126
|
+
* Cancelling another conversation's silently is a cost with no matching benefit.
|
|
132
127
|
*/
|
|
133
128
|
export function removeWakeup(stateRoot, id, session) {
|
|
129
|
+
return removeWhere(stateRoot, (w) => w.id === id && w.session === session) !== undefined;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Remove ONE pending wake-up whatever session set it: the operator's `fastagent schedules unwake`, the one way out of a
|
|
133
|
+
* wake-up set in a session nobody can message (a schedule's own). Its caller holds the instance, so no serve's poll
|
|
134
|
+
* writes the store between this read and its write.
|
|
135
|
+
*/
|
|
136
|
+
export function removeAnyWakeup(stateRoot, id) {
|
|
137
|
+
return removeWhere(stateRoot, (w) => w.id === id);
|
|
138
|
+
}
|
|
139
|
+
function removeWhere(stateRoot, match) {
|
|
134
140
|
const all = load(stateRoot);
|
|
135
|
-
const
|
|
136
|
-
if (
|
|
137
|
-
return
|
|
138
|
-
|
|
139
|
-
|
|
141
|
+
const index = all.findIndex(match);
|
|
142
|
+
if (index === -1)
|
|
143
|
+
return undefined;
|
|
144
|
+
const [removed] = all.splice(index, 1);
|
|
145
|
+
save(stateRoot, all);
|
|
146
|
+
return removed;
|
|
140
147
|
}
|
|
141
148
|
/**
|
|
142
149
|
* CLAIM the FIRST due wake-up (at or before `now`) in stored order, remove + return it, or undefined if none is due.
|
|
@@ -148,11 +155,10 @@ export function takeFirstDueWakeup(stateRoot, now = new Date()) {
|
|
|
148
155
|
return undefined;
|
|
149
156
|
const w = all[idx];
|
|
150
157
|
if (w.cron !== undefined) {
|
|
151
|
-
// RECURRING claim = ADVANCE IN PLACE: the entry STAYS in the store with fireAt pushed to the next cron instant
|
|
152
|
-
// (attempts cleared).
|
|
158
|
+
// RECURRING claim = ADVANCE IN PLACE: the entry STAYS in the store with fireAt pushed to the next cron instant.
|
|
153
159
|
const next = nextRun(w.cron, w.tz, now);
|
|
154
160
|
if (next)
|
|
155
|
-
all[idx] = { ...w, fireAt: next.toISOString()
|
|
161
|
+
all[idx] = { ...w, fireAt: next.toISOString() };
|
|
156
162
|
else
|
|
157
163
|
all.splice(idx, 1); // the cron has no next instant — this is its final occurrence
|
|
158
164
|
save(stateRoot, all);
|
|
@@ -163,13 +169,9 @@ export function takeFirstDueWakeup(stateRoot, now = new Date()) {
|
|
|
163
169
|
return w;
|
|
164
170
|
}
|
|
165
171
|
/**
|
|
166
|
-
*
|
|
167
|
-
*
|
|
172
|
+
* Put back a ONE-SHOT wake-up its session refused for now (the process or the session's queue was full), to fire at
|
|
173
|
+
* `fireAt`. It was taken out of the store to fire, so it does not count against the session's cap again.
|
|
168
174
|
*/
|
|
169
|
-
export function
|
|
170
|
-
|
|
171
|
-
if (attempts > MAX_WAKE_ATTEMPTS)
|
|
172
|
-
return false;
|
|
173
|
-
save(stateRoot, [...load(stateRoot), { ...w, fireAt: fireAt.toISOString(), attempts }]);
|
|
174
|
-
return true;
|
|
175
|
+
export function requeueWakeup(stateRoot, w, fireAt) {
|
|
176
|
+
save(stateRoot, [...load(stateRoot), { ...w, fireAt: fireAt.toISOString() }]);
|
|
175
177
|
}
|
package/dist/service.d.ts
CHANGED
|
@@ -1,194 +1,81 @@
|
|
|
1
|
-
import type { Agent } from "./agent.ts";
|
|
2
|
-
import { type PrefixMount } from "./channels/serve.ts";
|
|
3
|
-
import { type LoadedLongConnectionChannel } from "./channels/discover.ts";
|
|
4
|
-
import type { SessionControl } from "./session.ts";
|
|
1
|
+
import type { Agent } from "./agent-api.ts";
|
|
5
2
|
import type { ChannelHandler, Routes } from "./channel.ts";
|
|
6
|
-
import type
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
unverified: Routes;
|
|
15
|
-
/**
|
|
16
|
-
* What the `channels/` files serve. Exempt from both guards because a channel checks its platform's signature
|
|
17
|
-
* inside itself — an assumption about the author for a CUSTOM channel, not a property we enforce (§14).
|
|
18
|
-
*/
|
|
19
|
-
selfVerifying: Routes;
|
|
20
|
-
/** Prefix-owning handlers mounted beside the routes (the session control plane). */
|
|
21
|
-
mounts?: readonly PrefixMount[];
|
|
3
|
+
import { type AnyChannelModule, type LoadedLongConnectionChannel } from "./channels/discover.ts";
|
|
4
|
+
import { type Scheduler } from "./schedule/scheduler.ts";
|
|
5
|
+
import type { Schedule } from "./schedule/schedule.ts";
|
|
6
|
+
/** The port a serve binds when neither a flag, `PORT` (start only) nor `http.port` names one. */
|
|
7
|
+
export declare const DEFAULT_HTTP_PORT = 8787;
|
|
8
|
+
/** What a serve answers: its channels' routes, and `GET /health` unless a channel serves it. */
|
|
9
|
+
interface ServingSurface {
|
|
10
|
+
routes: Routes;
|
|
22
11
|
longConnections: LoadedLongConnectionChannel[];
|
|
23
|
-
/** Route-channel
|
|
12
|
+
/** Route-channel names; the tunnel registers only this subset. */
|
|
24
13
|
routeChannels: string[];
|
|
25
14
|
/** Flip health between 200 and 503. */
|
|
26
15
|
setReady(value: boolean): void;
|
|
27
16
|
}
|
|
28
|
-
/**
|
|
29
|
-
export declare
|
|
30
|
-
/**
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
*/
|
|
35
|
-
export interface
|
|
36
|
-
/**
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
cors?: readonly string[];
|
|
43
|
-
/**
|
|
44
|
-
* Serve the data plane, `POST /invoke`. On by default: it is the framework's interface, and a deployment that can
|
|
45
|
-
* only be reached through a chat channel is still worth curling. Set it `false` when this port is public and the
|
|
46
|
-
* channels' own signature checks are meant to be the only way in — the route is unauthenticated and runs a turn
|
|
47
|
-
* with the agent's full tool authority.
|
|
48
|
-
*/
|
|
49
|
-
invoke?: boolean;
|
|
17
|
+
/** Mount the channels and the health check. */
|
|
18
|
+
export declare function routesFor(agent: Agent, stateRoot: string, channels: ReadonlyMap<string, AnyChannelModule>): ServingSurface;
|
|
19
|
+
/** Start the clock: the definition's schedules, and the wake-ups the agent sets for itself, on every serve. */
|
|
20
|
+
export declare function startSchedules(agent: Agent, stateRoot: string, schedules: readonly Schedule[], options?: {
|
|
21
|
+
localClock?: boolean;
|
|
22
|
+
}): Pick<Scheduler, "stop">;
|
|
23
|
+
/** What `serve()` answers (SPEC.md §8): the agent's channels, schedules and wake-ups, and `GET /health`. */
|
|
24
|
+
export interface Service {
|
|
25
|
+
/** For an app's own server to route to. */
|
|
26
|
+
fetch(request: Request): Promise<Response>;
|
|
27
|
+
/** Or a server of its own, on this runtime's server: the one way to start one. Answers the port it bound. */
|
|
28
|
+
listen(port: number, host?: string): Promise<number>;
|
|
29
|
+
/** Settles when every long connection is up: immediately when there are none. */
|
|
30
|
+
ready: Promise<void>;
|
|
50
31
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
32
|
+
* Stop the server, giving the requests in flight a moment before ending them, then long connections and schedules.
|
|
33
|
+
* It does NOT drain the agent's messages: one takes seconds to minutes, and the deployment wants the old process gone
|
|
34
|
+
* in under a second. What makes that safe is that they are durable: an accepted message is answered after the
|
|
35
|
+
* restart, and a chat turn's intent is durable before it is accepted (`channels/kit/turn-store.ts`). A schedule
|
|
36
|
+
* fire's claim is written before its message: the next boot writes back the end of a message the agent took, and
|
|
37
|
+
* records one it never took as `interrupted`.
|
|
55
38
|
*/
|
|
56
|
-
|
|
39
|
+
close(): Promise<void>;
|
|
57
40
|
}
|
|
58
|
-
/**
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
* default spelled twice is a default that moves once.
|
|
62
|
-
*/
|
|
63
|
-
export declare function shouldServeRun(http: HttpSurface | undefined): boolean;
|
|
64
|
-
/**
|
|
65
|
-
* What an anonymous caller of a port can do, worst first — the ONE wording the startup report and deploy's pre-flight
|
|
66
|
-
* both print, each from its own facts (what mounted vs what will mount).
|
|
67
|
-
*/
|
|
68
|
-
export declare function describeAnonymousSurface(open: {
|
|
69
|
-
invoke: boolean;
|
|
70
|
-
run: boolean;
|
|
71
|
-
controlPrefix?: string;
|
|
72
|
-
}): string[];
|
|
73
|
-
/**
|
|
74
|
-
* The surface this deployment serves: the DATA plane (`POST /invoke`), `GET /health`, and the discovered channels.
|
|
75
|
-
*
|
|
76
|
-
* `/invoke` is the framework's interface, so it is served whatever channels a definition declares (unless
|
|
77
|
-
* `http.invoke: false`). It is RESERVED for the same reason `/control/*` is: a channel taking that path would silently replace the one route every client,
|
|
78
|
-
* every doc and the startup line all name. `/health` stays overridable — a probe is the deployment's to shape.
|
|
79
|
-
*/
|
|
80
|
-
export declare function routesFor(agentDir: string, agent: Agent, stateRoot: string, control: SessionControl | undefined,
|
|
81
|
-
/**
|
|
82
|
-
* `http.invoke: false` withholds the data plane. Two callers, two reasons: the AgentCore adapter serves the
|
|
83
|
-
* Runtime's `/invocations` contract instead, and an author sets it to leave the channels' signature checks as the
|
|
84
|
-
* only way into a public port.
|
|
85
|
-
*
|
|
86
|
-
* `routines` mounts `POST /run` and `GET /routines` (per {@link shouldServeRun}). Passed in rather than loaded here
|
|
87
|
-
* so the routes and the resident clock cannot disagree about which routines exist (`loadServingRoutines`).
|
|
88
|
-
*/
|
|
89
|
-
options?: {
|
|
90
|
-
http?: HttpSurface;
|
|
91
|
-
routines?: readonly LoadedRoutine[];
|
|
92
|
-
}): Promise<ServingSurface>;
|
|
93
|
-
/** Refuse channel routes the control plane would swallow. */
|
|
94
|
-
export declare function assertNoControlPlaneCollision(channelRoutes: Routes, plane: PrefixMount): void;
|
|
95
|
-
export declare function mountSessionControl(routes: Routes, control: SessionControl | undefined): {
|
|
96
|
-
routes: Routes;
|
|
97
|
-
mounts: PrefixMount[];
|
|
98
|
-
/** The prefix the plane owns, when it is published — what a startup line names. */
|
|
99
|
-
controlPrefix?: string;
|
|
100
|
-
};
|
|
101
|
-
/**
|
|
102
|
-
* Load the agent's `routines/`, gated.
|
|
103
|
-
*
|
|
104
|
-
* Separate from {@link startSchedules} because two things need the SAME list and one of them runs first: the
|
|
105
|
-
* `POST /run` route is built with the routes (so a channel cannot take that path unnoticed), and the resident
|
|
106
|
-
* clock starts later, inside the service's scope. Loading twice would let them disagree about which routines exist.
|
|
107
|
-
*/
|
|
108
|
-
export declare function loadServingRoutines(agentDir: string): Promise<LoadedRoutine[]>;
|
|
109
|
-
/**
|
|
110
|
-
* Start the clock over routines {@link loadServingRoutines} already gated — on every serve, routines or not: the
|
|
111
|
-
* agent's own wake-ups are a default capability, and this is what fires them.
|
|
112
|
-
*/
|
|
113
|
-
export declare function startSchedules(agent: Agent, stateRoot: string, routines: LoadedRoutine[], options?: {
|
|
114
|
-
externalClock?: boolean;
|
|
115
|
-
}): {
|
|
116
|
-
routines: LoadedRoutine[];
|
|
117
|
-
stop: () => void;
|
|
118
|
-
};
|
|
119
|
-
export interface AgentService {
|
|
120
|
-
/** The assembled Fetch handler: channel routes, the control plane, and health. */
|
|
121
|
-
handler: ChannelHandler;
|
|
122
|
-
/** The agent behind it — invoke it directly when you also want a programmatic path. */
|
|
123
|
-
agent: Agent;
|
|
124
|
-
/** The literal routes `handler` was composed from — for a startup line naming what is served. */
|
|
41
|
+
/** A serve as the CLI reports it: what it serves, beside the Service itself. */
|
|
42
|
+
export interface ServedAgent extends Service {
|
|
43
|
+
/** The literal routes the service answers, for a startup line naming them. */
|
|
125
44
|
routes: Routes;
|
|
126
45
|
agentDir: string;
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* What actually mounted, for a startup line: channel files serving routes, and long connections.
|
|
130
|
-
*/
|
|
46
|
+
/** What actually mounted: channels serving routes, and long connections. */
|
|
131
47
|
channels: {
|
|
132
48
|
routes: string[];
|
|
133
49
|
longConnections: string[];
|
|
134
50
|
};
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
*/
|
|
139
|
-
unverifiedRoutes: readonly string[];
|
|
140
|
-
/**
|
|
141
|
-
* The cross-origin allow-list this service was assembled with (`http.cors`), or `undefined` for the `*` default.
|
|
142
|
-
* Read by the startup report for the same reason as {@link AgentService.unverifiedRoutes}: what a caller says
|
|
143
|
-
* about this surface must come from what was actually assembled, not from re-deriving it.
|
|
144
|
-
*/
|
|
145
|
-
corsOrigins?: readonly string[];
|
|
146
|
-
routines: readonly LoadedRoutine[];
|
|
147
|
-
/** Settles when every long connection is up — immediately when there are none. */
|
|
148
|
-
ready: Promise<void>;
|
|
149
|
-
/** The control plane's prefix, when `sessionControl` is on. */
|
|
150
|
-
controlPrefix?: string;
|
|
151
|
-
/**
|
|
152
|
-
* Stop long connections and routines. It does NOT drain agent turns: a turn takes seconds to minutes, and the
|
|
153
|
-
* deployment wants the old process gone in under a second (`SHUTDOWN_GRACE_MS` in `src/cli/serve.ts`). What makes
|
|
154
|
-
* that safe is replay, not waiting — a chat turn's intent is durable before it is accepted and its channel
|
|
155
|
-
* replays it on the next boot (`channels/kit/turn-store.ts`), and an in-flight HTTP/SSE caller sees the stream
|
|
156
|
-
* drop and retries. The one path with neither is a routine fire, whose claim is written before the turn: it
|
|
157
|
-
* stays skipped, and the next boot records it as `interrupted` rather than losing it silently.
|
|
158
|
-
*/
|
|
159
|
-
close(): Promise<void>;
|
|
51
|
+
schedules: readonly Schedule[];
|
|
52
|
+
/** Whether the Agent API is served, under `/v1`: only with a key (SPEC.md §9.1). */
|
|
53
|
+
api: boolean;
|
|
160
54
|
}
|
|
161
|
-
/**
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
55
|
+
/**
|
|
56
|
+
* A Service over `handler`: answered in process, or served on a server of its own. `endStreams` ends what would hold
|
|
57
|
+
* the server's close open (a Caller watching events), and `shutdown` stops the rest once the server has.
|
|
58
|
+
*/
|
|
59
|
+
export declare function serviceOver(handler: ChannelHandler, ready: Promise<void>, shutdown: () => Promise<void>, endStreams?: () => Promise<void>): Service;
|
|
60
|
+
/** What {@link serveAgent} needs beyond an opened agent. */
|
|
61
|
+
export interface ServeOptions {
|
|
167
62
|
/** Called when a long connection ends on its own — a dropped socket-mode channel, say. */
|
|
168
63
|
onChannelClosed?: (name: string, error?: unknown) => void;
|
|
169
64
|
/** How long `close()` waits for a channel to stop before reporting it stuck (default 5s). */
|
|
170
65
|
closeTimeoutMs?: number;
|
|
66
|
+
/** The keys the Agent API takes; without one it is not served (SPEC.md §9.1). */
|
|
67
|
+
apiKeys?: readonly string[];
|
|
171
68
|
}
|
|
172
|
-
/** What the assembly
|
|
173
|
-
export interface
|
|
69
|
+
/** What the assembly serves. */
|
|
70
|
+
export interface ServableAgent {
|
|
174
71
|
agent: Agent;
|
|
175
|
-
/** The definition
|
|
72
|
+
/** The definition's directory: the agent's working directory. */
|
|
176
73
|
agentDir: string;
|
|
177
|
-
/**
|
|
178
|
-
workspace: string;
|
|
179
|
-
/** Where durable state lives (channel state, sessions, routine fires). */
|
|
74
|
+
/** Where durable state lives (channel state, schedule fires, wake-ups). */
|
|
180
75
|
stateRoot: string;
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
sessionControl?: SessionControl;
|
|
184
|
-
/** Whether that hub is ALSO served as `/control/*` (`config.sessionControl`). Required, not defaulted: an
|
|
185
|
-
* embedder assembling this by hand would otherwise lose the plane to a 404 with nothing said anywhere. */
|
|
186
|
-
publishControl: boolean;
|
|
187
|
-
/** What the port publishes, and to which browsers — the config's `http` block ({@link HttpSurface}). */
|
|
188
|
-
http?: HttpSurface;
|
|
76
|
+
channels: ReadonlyMap<string, AnyChannelModule>;
|
|
77
|
+
schedules: readonly Schedule[];
|
|
189
78
|
}
|
|
190
|
-
/**
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
*/
|
|
194
|
-
export declare function mountAgentService(opened: MountableAgent, options?: MountAgentServiceOptions): Promise<AgentService>;
|
|
79
|
+
/** The assembly itself: channels, schedules and long connections, composed into one handler. */
|
|
80
|
+
export declare function serveAgent(opened: ServableAgent, options?: ServeOptions): Promise<ServedAgent>;
|
|
81
|
+
export {};
|