@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
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Feed it a message's stream; it answers the text each event adds. */
|
|
2
|
+
export function answerText() {
|
|
3
|
+
let streamed = "";
|
|
4
|
+
return (event) => {
|
|
5
|
+
if (event.type === "delta") {
|
|
6
|
+
if (event.channel !== "text")
|
|
7
|
+
return "";
|
|
8
|
+
streamed += event.text;
|
|
9
|
+
return event.text;
|
|
10
|
+
}
|
|
11
|
+
if (event.type !== "entry" || event.entry.kind !== "assistant")
|
|
12
|
+
return "";
|
|
13
|
+
const text = String(event.entry.data.text ?? "");
|
|
14
|
+
const missing = text.startsWith(streamed) ? text.slice(streamed.length) : "";
|
|
15
|
+
streamed = "";
|
|
16
|
+
return missing;
|
|
17
|
+
};
|
|
18
|
+
}
|
package/dist/atomic-write.d.ts
CHANGED
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
* redundant with it: `writeFileSync` honours `mode` only when it CREATES the file, so a temp left behind by a crashed
|
|
12
12
|
* writer would keep its old, possibly looser permissions.
|
|
13
13
|
*
|
|
14
|
-
* `sharedWriters` is for a file SEVERAL processes may write at once (the
|
|
15
|
-
*
|
|
14
|
+
* `sharedWriters` is for a file SEVERAL processes may write at once (the generated `.fastagent/` files, which every
|
|
15
|
+
* command that reads the definition writes with the same bytes): each writes its own temp, and the last rename wins. A fixed temp there would
|
|
16
16
|
* let one writer's rename take the other's file and fail it with ENOENT. No test exercises that race: it needs two
|
|
17
17
|
* processes renaming within the same moment, which a test cannot arrange without being flaky.
|
|
18
18
|
*/
|
package/dist/atomic-write.js
CHANGED
|
@@ -15,8 +15,8 @@ import { dirname } from "node:path";
|
|
|
15
15
|
* redundant with it: `writeFileSync` honours `mode` only when it CREATES the file, so a temp left behind by a crashed
|
|
16
16
|
* writer would keep its old, possibly looser permissions.
|
|
17
17
|
*
|
|
18
|
-
* `sharedWriters` is for a file SEVERAL processes may write at once (the
|
|
19
|
-
*
|
|
18
|
+
* `sharedWriters` is for a file SEVERAL processes may write at once (the generated `.fastagent/` files, which every
|
|
19
|
+
* command that reads the definition writes with the same bytes): each writes its own temp, and the last rename wins. A fixed temp there would
|
|
20
20
|
* let one writer's rename take the other's file and fail it with ENOENT. No test exercises that race: it needs two
|
|
21
21
|
* processes renaming within the same moment, which a test cannot arrange without being flaky.
|
|
22
22
|
*/
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { type BoundContent } from "./content/declare.ts";
|
|
2
|
+
import type { DeclaredEnvironment } from "./environment/declare.ts";
|
|
3
|
+
import { type ResolvedContent } from "./content/resolve.ts";
|
|
4
|
+
import type { ContentAddition } from "./content/source.ts";
|
|
5
|
+
/**
|
|
6
|
+
* A refusal about a content entry's NAME: one that cannot name an entry, one the agent already has, one it does not
|
|
7
|
+
* have. The caller can fix it by naming another (the CLI exits 2 and asks for `--name`).
|
|
8
|
+
*/
|
|
9
|
+
export declare class ContentNameError extends Error {
|
|
10
|
+
name: string;
|
|
11
|
+
}
|
|
12
|
+
export interface CreateAgentOptions {
|
|
13
|
+
/** What the agent works on and knows: repositories into `context.json`, this machine's directories into
|
|
14
|
+
* `context.local.json`. */
|
|
15
|
+
content?: ContentAddition[];
|
|
16
|
+
/**
|
|
17
|
+
* Install the agent's dependencies, after the scaffold and before its first commit, so the lockfile is in that
|
|
18
|
+
* commit; the agent's code imports them. A rejection is a failed create: the scaffold is removed again and the error
|
|
19
|
+
* thrown, as when writing the content fails, so the directory is empty for a retry. One that reports its failure
|
|
20
|
+
* some other way (the CLI's resolves, and says the install failed) leaves the agent created.
|
|
21
|
+
*/
|
|
22
|
+
install?: (dir: string) => Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
export interface CreatedAgent {
|
|
25
|
+
/** The agent directory, absolute. */
|
|
26
|
+
dir: string;
|
|
27
|
+
/** The files written, relative to `dir`. */
|
|
28
|
+
created: string[];
|
|
29
|
+
/** The content, resolved for this instance. */
|
|
30
|
+
content: ResolvedContent[];
|
|
31
|
+
/**
|
|
32
|
+
* What became of the agent's git repository, as a sentence to show: created with the scaffold as its first commit,
|
|
33
|
+
* or why not (inside a repository that tracks it, git missing, no commit identity).
|
|
34
|
+
*/
|
|
35
|
+
repository: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Create an agent in `dir`, which must be new or empty. Every content entry is checked before anything is written, and
|
|
39
|
+
* the scaffold is removed again when writing the content fails. The agent is then a git repository whose first commit
|
|
40
|
+
* is what was written:
|
|
41
|
+
* it changes itself, and version control is how its author goes back to a version that worked.
|
|
42
|
+
*/
|
|
43
|
+
export declare function createAgent(dir: string, options?: CreateAgentOptions): Promise<CreatedAgent>;
|
|
44
|
+
/**
|
|
45
|
+
* The agent's content, resolved for this instance (what `fastagent content list` shows), and the directories this
|
|
46
|
+
* machine binds that are not here: the agent is not told of those.
|
|
47
|
+
*/
|
|
48
|
+
export declare function listContent(agentDir: string): Promise<{
|
|
49
|
+
content: ResolvedContent[];
|
|
50
|
+
absent: BoundContent[];
|
|
51
|
+
}>;
|
|
52
|
+
/**
|
|
53
|
+
* What an edit leaves: the entry it added or removed, by name, the agent's content after it, and what to tell the
|
|
54
|
+
* user about what was left on this machine.
|
|
55
|
+
*/
|
|
56
|
+
export interface ContentEdit {
|
|
57
|
+
name: string;
|
|
58
|
+
content: ResolvedContent[];
|
|
59
|
+
notes: string[];
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Add a content entry to the agent in `agentDir`: its repository to `context.json`, its directory on this machine to
|
|
63
|
+
* `context.local.json`, or both. A name that cannot be one, or that the agent already has (ignoring case), is a
|
|
64
|
+
* {@link ContentNameError}.
|
|
65
|
+
*/
|
|
66
|
+
export declare function addContent(agentDir: string, addition: ContentAddition): Promise<ContentEdit>;
|
|
67
|
+
/**
|
|
68
|
+
* Remove the agent's content entry named `name` (ignoring case), from `context.json` and from this machine's
|
|
69
|
+
* `context.local.json`. A clone at `content/<name>` is left as it is, and said: it may hold the agent's work, and
|
|
70
|
+
* fastagent never deletes a directory in `content/`. A name the agent does not have is a {@link ContentNameError}.
|
|
71
|
+
*/
|
|
72
|
+
export declare function removeContent(agentDir: string, name: string): Promise<ContentEdit>;
|
|
73
|
+
/**
|
|
74
|
+
* Replace the environment `context.json` declares with what `change` makes of it as it is now, under the lock content
|
|
75
|
+
* edits take, keeping the rest of the file as it is; and return what was written.
|
|
76
|
+
*/
|
|
77
|
+
export declare function writeEnvironment(agentDir: string, change: (current: DeclaredEnvironment | undefined) => DeclaredEnvironment): Promise<DeclaredEnvironment>;
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creating an agent and editing its content: `fastagent init` and `fastagent content` are thin wrappers over these (and
|
|
3
|
+
* `fastagent env` writes its declaration through {@link writeEnvironment}), so the rules live here, not in a command.
|
|
4
|
+
* Nothing here prints or exits; every refusal is thrown with the message the CLI shows. Not exported from the package
|
|
5
|
+
* (#847 decides how a client reaches them).
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, lstatSync, readFileSync, statSync } from "node:fs";
|
|
8
|
+
import { rm } from "node:fs/promises";
|
|
9
|
+
import { join, resolve } from "node:path";
|
|
10
|
+
import { writeFileAtomic } from "./atomic-write.js";
|
|
11
|
+
import { GitNotInstalled, gitFor } from "./git.js";
|
|
12
|
+
import { CONTEXT_FILE, LOCAL_CONTEXT_FILE, contentEntryPath, resolveAgentDir } from "./paths.js";
|
|
13
|
+
import { initRepository, scaffoldAgent } from "./scaffold/init.js";
|
|
14
|
+
import { canonicalBinding, canonicalEntry, declareBindings, declareContent, isContentName, } from "./content/declare.js";
|
|
15
|
+
import { contextFileText, loadContent, localContextFileText, parseContextFile, parseLocalContextFile, } from "./content/file.js";
|
|
16
|
+
import { checkBinding, contentAbsentHere, resolveContent } from "./content/resolve.js";
|
|
17
|
+
import { withLockedFile } from "./locked-file.js";
|
|
18
|
+
/** `context.json` is part of the definition, read by whoever reads the agent. */
|
|
19
|
+
const CONTEXT_FILE_MODE = 0o644;
|
|
20
|
+
/**
|
|
21
|
+
* A refusal about a content entry's NAME: one that cannot name an entry, one the agent already has, one it does not
|
|
22
|
+
* have. The caller can fix it by naming another (the CLI exits 2 and asks for `--name`).
|
|
23
|
+
*/
|
|
24
|
+
export class ContentNameError extends Error {
|
|
25
|
+
name = "ContentNameError";
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Create an agent in `dir`, which must be new or empty. Every content entry is checked before anything is written, and
|
|
29
|
+
* the scaffold is removed again when writing the content fails. The agent is then a git repository whose first commit
|
|
30
|
+
* is what was written:
|
|
31
|
+
* it changes itself, and version control is how its author goes back to a version that worked.
|
|
32
|
+
*/
|
|
33
|
+
export async function createAgent(dir, options = {}) {
|
|
34
|
+
const agentDir = resolve(dir);
|
|
35
|
+
const additions = options.content ?? [];
|
|
36
|
+
let maps = { content: {}, bindings: {} };
|
|
37
|
+
for (const addition of additions)
|
|
38
|
+
maps = withAddition(agentDir, maps, addition).maps;
|
|
39
|
+
const { created, undo } = await scaffoldAgent(agentDir);
|
|
40
|
+
const removeAll = async (error) => {
|
|
41
|
+
await rm(join(agentDir, CONTEXT_FILE), { force: true });
|
|
42
|
+
await rm(join(agentDir, LOCAL_CONTEXT_FILE), { force: true });
|
|
43
|
+
await undo();
|
|
44
|
+
throw error;
|
|
45
|
+
};
|
|
46
|
+
// The content was checked above, so a refusal here is one that check could not foresee (the disk changed in
|
|
47
|
+
// between); the scaffold goes with it, or a retry would find "already an agent" declaring no content.
|
|
48
|
+
try {
|
|
49
|
+
if (Object.keys(maps.content).length > 0) {
|
|
50
|
+
writeFileAtomic(join(agentDir, CONTEXT_FILE), contextFileText({ content: maps.content }), CONTEXT_FILE_MODE);
|
|
51
|
+
}
|
|
52
|
+
if (Object.keys(maps.bindings).length > 0) {
|
|
53
|
+
writeFileAtomic(join(agentDir, LOCAL_CONTEXT_FILE), localContextFileText(maps.bindings), CONTEXT_FILE_MODE);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
await removeAll(error);
|
|
58
|
+
}
|
|
59
|
+
if (options.install)
|
|
60
|
+
await options.install(agentDir).catch(removeAll);
|
|
61
|
+
const content = resolveContent(agentDir, declarationOf(agentDir, maps));
|
|
62
|
+
return { dir: agentDir, created, content, repository: await initRepository(agentDir) };
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The agent's content, resolved for this instance (what `fastagent content list` shows), and the directories this
|
|
66
|
+
* machine binds that are not here: the agent is not told of those.
|
|
67
|
+
*/
|
|
68
|
+
export async function listContent(agentDir) {
|
|
69
|
+
const dir = resolveAgentDir(agentDir);
|
|
70
|
+
const declaration = loadContent(dir);
|
|
71
|
+
return { content: resolveContent(dir, declaration), absent: contentAbsentHere(declaration) };
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Add a content entry to the agent in `agentDir`: its repository to `context.json`, its directory on this machine to
|
|
75
|
+
* `context.local.json`, or both. A name that cannot be one, or that the agent already has (ignoring case), is a
|
|
76
|
+
* {@link ContentNameError}.
|
|
77
|
+
*/
|
|
78
|
+
export async function addContent(agentDir, addition) {
|
|
79
|
+
const dir = resolveAgentDir(agentDir);
|
|
80
|
+
const declaration = await editContext(dir, (shared, local) => {
|
|
81
|
+
const { maps } = withAddition(dir, mapsOf(shared, local), addition);
|
|
82
|
+
return {
|
|
83
|
+
result: declarationOf(dir, maps),
|
|
84
|
+
...(addition.entry !== undefined ? { shared: contextFileText({ ...shared, content: maps.content }) } : {}),
|
|
85
|
+
...(addition.binding !== undefined ? { local: localContextFileText(maps.bindings) } : {}),
|
|
86
|
+
};
|
|
87
|
+
});
|
|
88
|
+
const notes = addition.binding !== undefined ? unignoredLocalFile(dir) : [];
|
|
89
|
+
return { name: addition.name, content: resolveContent(dir, declaration), notes };
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Remove the agent's content entry named `name` (ignoring case), from `context.json` and from this machine's
|
|
93
|
+
* `context.local.json`. A clone at `content/<name>` is left as it is, and said: it may hold the agent's work, and
|
|
94
|
+
* fastagent never deletes a directory in `content/`. A name the agent does not have is a {@link ContentNameError}.
|
|
95
|
+
*/
|
|
96
|
+
export async function removeContent(agentDir, name) {
|
|
97
|
+
const dir = resolveAgentDir(agentDir);
|
|
98
|
+
const { removed, wasDeclared, declaration } = await editContext(dir, (shared, local) => {
|
|
99
|
+
const found = entryNamed(mapsOf(shared, local), name);
|
|
100
|
+
const maps = {
|
|
101
|
+
content: without(shared.content, found.name),
|
|
102
|
+
bindings: without(local.content, found.name),
|
|
103
|
+
};
|
|
104
|
+
const declaration = declarationOf(dir, maps);
|
|
105
|
+
// What is left is resolved before it is written, so an entry that cannot be refuses the edit rather than failing
|
|
106
|
+
// it once it is made. The removed one is not asked: removing a broken entry is how it is mended.
|
|
107
|
+
resolveContent(dir, declaration);
|
|
108
|
+
return {
|
|
109
|
+
result: { removed: found.name, wasDeclared: found.shared, declaration },
|
|
110
|
+
...(found.shared ? { shared: contextFileText({ ...shared, content: maps.content }) } : {}),
|
|
111
|
+
...(found.local ? { local: localContextFileText(maps.bindings) } : {}),
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
const notes = [];
|
|
115
|
+
if (wasDeclared && lstatSync(contentEntryPath(dir, removed), { throwIfNoEntry: false })) {
|
|
116
|
+
notes.push(`content/${removed} is left as it is: it may hold the agent's work — delete it once nothing in it is needed`);
|
|
117
|
+
}
|
|
118
|
+
return { name: removed, content: resolveContent(dir, declaration), notes };
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* `maps` with `addition` among them, checked as a whole before anything is written: its name can name an entry and is
|
|
122
|
+
* not taken (ignoring case), the entry is valid, a repository to clone has nothing at `content/<name>` yet, a
|
|
123
|
+
* directory to bind can be bound, and every other entry still resolves (one that does not refuses the edit, not fails
|
|
124
|
+
* it once made).
|
|
125
|
+
*/
|
|
126
|
+
function withAddition(agentDir, maps, addition) {
|
|
127
|
+
const { name, entry, binding } = addition;
|
|
128
|
+
if (entry === undefined && binding === undefined)
|
|
129
|
+
throw new Error(`content "${name}": nothing to add`);
|
|
130
|
+
if (!isContentName(name)) {
|
|
131
|
+
throw new ContentNameError(`"${name}" cannot name content (one path segment of letters, digits, "-" and "_")`);
|
|
132
|
+
}
|
|
133
|
+
const taken = [...Object.keys(maps.content), ...Object.keys(maps.bindings)].find((key) => key.toLowerCase() === name.toLowerCase());
|
|
134
|
+
if (taken)
|
|
135
|
+
throw new ContentNameError(`this agent already has content named "${taken}"`);
|
|
136
|
+
const next = {
|
|
137
|
+
content: entry !== undefined ? { ...maps.content, [name]: canonicalEntry(entry) } : maps.content,
|
|
138
|
+
bindings: binding !== undefined ? { ...maps.bindings, [name]: canonicalBinding(binding) } : maps.bindings,
|
|
139
|
+
};
|
|
140
|
+
const declaration = declarationOf(agentDir, next);
|
|
141
|
+
if (binding === undefined) {
|
|
142
|
+
if (lstatSync(contentEntryPath(agentDir, name), { throwIfNoEntry: false })) {
|
|
143
|
+
throw new Error(`content/${name} already exists in ${agentDir}: move it away first`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
const bound = declaration.bound.find((b) => b.name === name);
|
|
148
|
+
const repository = declaration.declared.find((d) => d.name === name);
|
|
149
|
+
checkBinding(agentDir, name, bound.path, repository);
|
|
150
|
+
}
|
|
151
|
+
resolveContent(agentDir, declaration);
|
|
152
|
+
return { maps: next };
|
|
153
|
+
}
|
|
154
|
+
/** `maps` declared: what every reader of the files would read from them. */
|
|
155
|
+
function declarationOf(agentDir, maps) {
|
|
156
|
+
const declared = declareContent(maps.content);
|
|
157
|
+
return { declared, bound: declareBindings(maps.bindings, declared, agentDir) };
|
|
158
|
+
}
|
|
159
|
+
function mapsOf(shared, local) {
|
|
160
|
+
return { content: shared.content, bindings: local.content };
|
|
161
|
+
}
|
|
162
|
+
function without(map, name) {
|
|
163
|
+
return Object.fromEntries(Object.entries(map).filter(([key]) => key !== name));
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Where the entry `name` matches ignoring case is written: its name, and which of the two files hold it. One the agent
|
|
167
|
+
* does not have is a {@link ContentNameError}.
|
|
168
|
+
*/
|
|
169
|
+
function entryNamed(maps, name) {
|
|
170
|
+
const matches = (key) => key.toLowerCase() === name.toLowerCase();
|
|
171
|
+
const shared = Object.keys(maps.content).find(matches);
|
|
172
|
+
const local = Object.keys(maps.bindings).find(matches);
|
|
173
|
+
const found = shared ?? local;
|
|
174
|
+
if (found !== undefined)
|
|
175
|
+
return { name: found, shared: shared !== undefined, local: local !== undefined };
|
|
176
|
+
const names = [...new Set([...Object.keys(maps.content), ...Object.keys(maps.bindings)])];
|
|
177
|
+
throw new ContentNameError(`no content named "${name}" (this agent has: ${names.join(", ") || "none"})`);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Run `edit` over both context files under ONE lock, `context.json`'s, which env edits take too: whether a name is
|
|
181
|
+
* taken is asked of both files, so two edits that write different files must still queue behind each other. The lock
|
|
182
|
+
* creates neither file; what `edit` returns for a file is written under it, `context.local.json` first.
|
|
183
|
+
*/
|
|
184
|
+
async function editContext(dir, edit) {
|
|
185
|
+
const sharedPath = join(dir, CONTEXT_FILE);
|
|
186
|
+
const localPath = join(dir, LOCAL_CONTEXT_FILE);
|
|
187
|
+
return withLockedFile(sharedPath, async (sharedText) => {
|
|
188
|
+
const shared = sharedText === undefined ? { content: {}, declared: [] } : parseContextFile(sharedText, sharedPath);
|
|
189
|
+
const localText = textIfExists(localPath);
|
|
190
|
+
const local = localText === undefined
|
|
191
|
+
? { content: {}, bound: [] }
|
|
192
|
+
: parseLocalContextFile(localText, localPath, shared.declared, dir);
|
|
193
|
+
const out = edit(shared, local);
|
|
194
|
+
if (out.local !== undefined)
|
|
195
|
+
writeFileAtomic(localPath, out.local, fileMode(localPath));
|
|
196
|
+
return { result: out.result, next: out.shared };
|
|
197
|
+
}, { mode: fileMode(sharedPath), create: false });
|
|
198
|
+
}
|
|
199
|
+
function textIfExists(path) {
|
|
200
|
+
return existsSync(path) ? readFileSync(path, "utf8") : undefined;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* What to say when git would commit `context.local.json`: it names directories of this machine, so committed it would
|
|
204
|
+
* point every other checkout of the agent at paths it does not have. `init` ignores it; an agent made before that may
|
|
205
|
+
* not. Asked only of an agent in a git repository, and never failing an edit that has already been made.
|
|
206
|
+
*/
|
|
207
|
+
function unignoredLocalFile(dir) {
|
|
208
|
+
const git = gitFor("to check that context.local.json stays out of git");
|
|
209
|
+
try {
|
|
210
|
+
if (git.answer(["rev-parse", "--is-inside-work-tree"], dir) !== "true")
|
|
211
|
+
return [];
|
|
212
|
+
if (git.answer(["check-ignore", "-q", LOCAL_CONTEXT_FILE], dir) !== undefined)
|
|
213
|
+
return [];
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
if (error instanceof GitNotInstalled)
|
|
217
|
+
return [];
|
|
218
|
+
throw error;
|
|
219
|
+
}
|
|
220
|
+
return [`${LOCAL_CONTEXT_FILE} holds directories of this machine and git does not ignore it: add it to .gitignore`];
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Replace the environment `context.json` declares with what `change` makes of it as it is now, under the lock content
|
|
224
|
+
* edits take, keeping the rest of the file as it is; and return what was written.
|
|
225
|
+
*/
|
|
226
|
+
export async function writeEnvironment(agentDir, change) {
|
|
227
|
+
const path = join(resolveAgentDir(agentDir), CONTEXT_FILE);
|
|
228
|
+
return withLockedFile(path, async (src) => {
|
|
229
|
+
const file = parseContextFile(src ?? "{}", path);
|
|
230
|
+
const environment = change(file.environment);
|
|
231
|
+
return { result: environment, next: contextFileText({ ...file, environment }) };
|
|
232
|
+
}, { mode: fileMode(path) });
|
|
233
|
+
}
|
|
234
|
+
/** The mode a rewrite of `path` keeps: its own, or the definition's default for a new one. */
|
|
235
|
+
function fileMode(path) {
|
|
236
|
+
const stat = statSync(path, { throwIfNoEntry: false });
|
|
237
|
+
return stat === undefined ? CONTEXT_FILE_MODE : stat.mode & 0o777;
|
|
238
|
+
}
|
package/dist/channel.d.ts
CHANGED
|
@@ -1,27 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The Channel contract
|
|
3
|
-
*
|
|
4
|
-
* here is forbidden, as in those two.
|
|
2
|
+
* The Channel contract: how a channel is mounted beside the Agent it talks to (agent-api.ts, SPEC.md §8.1), and
|
|
3
|
+
* `defineChannel`, which types a channel file's export. Importing a host, a framework, or a harness here is forbidden.
|
|
5
4
|
*/
|
|
6
|
-
import type { Agent } from "./agent.ts";
|
|
7
|
-
import type { SessionControl } from "./session.ts";
|
|
5
|
+
import type { Agent, CreateSessionOptions } from "./agent-api.ts";
|
|
8
6
|
/** A mounted request handler (a channel's fetch, or a plain route like health). */
|
|
9
7
|
export type ChannelHandler = (req: Request) => Response | Promise<Response>;
|
|
10
8
|
/** This deployment's HTTP surface: route key → handler. */
|
|
11
9
|
export type Routes = Record<string, ChannelHandler>;
|
|
12
|
-
/**
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
*/
|
|
10
|
+
/** The session a new conversation forks from, as `sessions.create` takes it; `undefined` starts it empty. */
|
|
11
|
+
export type ForkSource = CreateSessionOptions["forkFrom"];
|
|
12
|
+
/** What a channel is handed when it is mounted, and all it is handed. */
|
|
16
13
|
export interface ChannelContext {
|
|
14
|
+
/** The Agent, in process. */
|
|
17
15
|
agent: Agent;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
|
|
16
|
+
/**
|
|
17
|
+
* The session the conversation `key` talks in: the one this channel recorded for it, or a new one created and
|
|
18
|
+
* recorded before it is returned, so a message is sent only into a recorded session. With `forkFrom`, a new one is
|
|
19
|
+
* a fork of what it answers, asked only when `key` has no session yet. Calls for one key are taken one at a time,
|
|
20
|
+
* so two first messages of a new conversation get one session.
|
|
21
|
+
*/
|
|
22
|
+
sessionFor(key: string, options?: {
|
|
23
|
+
forkFrom?: () => Promise<ForkSource>;
|
|
24
|
+
}): Promise<string>;
|
|
25
|
+
/** The session recorded for `key`, without creating one: what a stop command asks of a place nothing was said in. */
|
|
26
|
+
recordedSession(key: string): string | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Run `work` after the route has answered, one at a time per `place` (a chat, a thread) in the order they arrived,
|
|
29
|
+
* counted as work in flight, which `dev`'s restart and AgentCore's `/ping` wait for. It keeps no record: a turn the
|
|
30
|
+
* process stops before it runs is lost unless the platform delivers its event again. A failure goes to the log.
|
|
31
|
+
*/
|
|
32
|
+
turn(place: string, work: () => Promise<void>): void;
|
|
33
|
+
/** The channel's own directory, `<state root>/channels/<the channel file's name>`, for the records it must keep. */
|
|
34
|
+
stateDir: string;
|
|
23
35
|
}
|
|
24
|
-
/** A `channels/<name>.ts` route channel: receives
|
|
36
|
+
/** A `channels/<name>.ts` route channel: receives its context and returns its HTTP routes. */
|
|
25
37
|
export type ChannelModule = (ctx: ChannelContext) => Routes;
|
|
26
38
|
export interface LongConnection {
|
|
27
39
|
ready: Promise<void>;
|
|
@@ -32,3 +44,5 @@ export interface LongConnectionChannelModule {
|
|
|
32
44
|
name: string;
|
|
33
45
|
connect(ctx: ChannelContext, signal: AbortSignal): LongConnection;
|
|
34
46
|
}
|
|
47
|
+
/** What a channel file default-exports, typed: its routes for a context, or a long connection. */
|
|
48
|
+
export declare function defineChannel<T extends ChannelModule | LongConnectionChannelModule>(channel: T): T;
|
package/dist/channel.js
CHANGED
|
@@ -6,7 +6,7 @@ export declare const RESERVED_PATHS: {
|
|
|
6
6
|
readonly wakeAlarm: "/__fastagent/wake-alarm";
|
|
7
7
|
};
|
|
8
8
|
/** Every kind the container's `POST /invocations` dispatches on. */
|
|
9
|
-
export declare const ENVELOPE_KINDS: readonly ["webhook", "
|
|
9
|
+
export declare const ENVELOPE_KINDS: readonly ["webhook", "schedule-fire", "wake-poke", "probe"];
|
|
10
10
|
/**
|
|
11
11
|
* Did this envelope come from the FORWARDER, rather than from some other principal holding
|
|
12
12
|
* `bedrock-agentcore:InvokeAgentRuntime`?
|
|
@@ -15,8 +15,8 @@ export declare const ENVELOPE_KINDS: readonly ["webhook", "routine-fire", "routi
|
|
|
15
15
|
* (`envelope.wake.url`) is where the container later POSTs its wake alarms, carrying `FASTAGENT_WAKE_SECRET` — so a
|
|
16
16
|
* principal who could set it would redirect that callback and collect the secret along with every pending wake-up.
|
|
17
17
|
*
|
|
18
|
-
* The other thing it gates — the
|
|
19
|
-
* the `
|
|
18
|
+
* The other thing it gates — the kinds other than `api` — is DEPTH, not a boundary. Every one of them is weaker than
|
|
19
|
+
* the `api` the same caller may already send: `schedule-fire` runs a prompt the definition wrote down,
|
|
20
20
|
* `webhook` reaches only channel routes that verify their own platform's signature, `wake-poke` wakes, `probe`
|
|
21
21
|
* reports. IAM is what decides who gets to ask at all.
|
|
22
22
|
*
|
|
@@ -26,6 +26,16 @@ export declare const ENVELOPE_KINDS: readonly ["webhook", "routine-fire", "routi
|
|
|
26
26
|
export declare function fromForwarder(envelope: {
|
|
27
27
|
auth?: unknown;
|
|
28
28
|
} | undefined, expected: string | undefined): boolean;
|
|
29
|
+
/** An HTTP request carried inside an envelope, byte-exact. */
|
|
30
|
+
export interface CarriedRequest {
|
|
31
|
+
method: string;
|
|
32
|
+
path: string;
|
|
33
|
+
/** Raw query string, no leading `?`. */
|
|
34
|
+
query?: string;
|
|
35
|
+
headers?: Record<string, string>;
|
|
36
|
+
/** The body, base64 (byte-exact). */
|
|
37
|
+
bodyB64?: string;
|
|
38
|
+
}
|
|
29
39
|
/** What the forwarder Lambda / EventBridge deliver in the `/invocations` payload. */
|
|
30
40
|
export type AgentcoreEnvelope = {
|
|
31
41
|
/** Shared secret proving this envelope came from the forwarder (FASTAGENT_INGRESS_SECRET). */
|
|
@@ -33,22 +43,10 @@ export type AgentcoreEnvelope = {
|
|
|
33
43
|
wake?: {
|
|
34
44
|
url: string;
|
|
35
45
|
};
|
|
36
|
-
} & ({
|
|
46
|
+
} /** A platform's webhook, verbatim: its headers carry the signature material its channel checks. */ & (({
|
|
37
47
|
kind: "webhook";
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
path: string;
|
|
41
|
-
/**
|
|
42
|
-
* Original raw query string (no leading `?`) — "verbatim" includes it; a channel reading
|
|
43
|
-
* `request.url.searchParams` must see what the webhook sender sent.
|
|
44
|
-
*/
|
|
45
|
-
query?: string;
|
|
46
|
-
/** Original headers — signature material (secret tokens, Feishu signatures) rides here. */
|
|
47
|
-
headers?: Record<string, string>;
|
|
48
|
-
/** Original body, base64 (webhook bodies are JSON but the tunnel must be byte-exact). */
|
|
49
|
-
bodyB64?: string;
|
|
50
|
-
} | {
|
|
51
|
-
kind: "routine-fire";
|
|
48
|
+
} & CarriedRequest) | {
|
|
49
|
+
kind: "schedule-fire";
|
|
52
50
|
name: string;
|
|
53
51
|
/**
|
|
54
52
|
* The instant EventBridge scheduled this fire for — the clock's NAME for the occurrence, stable across its
|
|
@@ -56,24 +54,6 @@ export type AgentcoreEnvelope = {
|
|
|
56
54
|
* never recomputes it.
|
|
57
55
|
*/
|
|
58
56
|
occurrence: string;
|
|
59
|
-
} | {
|
|
60
|
-
/**
|
|
61
|
-
* Run a declared routine BY NAME — the `POST /run` contract on the host that publishes no routes.
|
|
62
|
-
*
|
|
63
|
-
* On the IAM door, like `invoke`, and for the same reason: the forwarder never emits this, so it can only
|
|
64
|
-
* come from a direct `InvokeAgentRuntime` call, where AWS has already said who the caller is. That makes
|
|
65
|
-
* by-name running STRICTER here than on a host with a public URL, where the same route is anonymous.
|
|
66
|
-
*
|
|
67
|
-
* Separate from `routine-fire` because they are different contracts, not two spellings: a fire names an
|
|
68
|
-
* OCCURRENCE our own clock produced and claims it (dedup across redeliveries, a fire history, the overlap
|
|
69
|
-
* policy); this names only the work (schedule/run.ts).
|
|
70
|
-
*/
|
|
71
|
-
kind: "routine-run";
|
|
72
|
-
name: string;
|
|
73
|
-
} | {
|
|
74
|
-
kind: "invoke";
|
|
75
|
-
session: string;
|
|
76
|
-
text: string;
|
|
77
57
|
}
|
|
78
58
|
/**
|
|
79
59
|
* An EventBridge wake-up poke: the invocation ITSELF is the payload — it wakes the container, whose boot drain / 30s
|
|
@@ -85,7 +65,7 @@ export type AgentcoreEnvelope = {
|
|
|
85
65
|
/**
|
|
86
66
|
* The deploy driver's post-deploy verification (relayed by the forwarder's reserved probe path, which answers on
|
|
87
67
|
* EVERY forwarder topology — schedule-only URLs refuse ordinary public traffic). Also accepted from the IAM door,
|
|
88
|
-
* where it only opens the
|
|
68
|
+
* where it only opens the deployed definition (`login --deployment` needs one) and does not construct the channels.
|
|
89
69
|
*/
|
|
90
70
|
| {
|
|
91
71
|
kind: "probe";
|
|
@@ -99,24 +79,30 @@ export interface WebhookReply {
|
|
|
99
79
|
headers: Record<string, string>;
|
|
100
80
|
bodyB64: string;
|
|
101
81
|
}
|
|
102
|
-
/** One desired alarm:
|
|
82
|
+
/** One desired one-shot alarm: a pending wake-up's next instant, which pokes the container. */
|
|
103
83
|
export interface WakeAlarm {
|
|
84
|
+
/** One per INSTANT (`<wake id>@<instant>`), so mirroring again never rewrites a spent alarm. */
|
|
104
85
|
id: string;
|
|
105
86
|
at: string;
|
|
106
87
|
}
|
|
107
|
-
/**
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
88
|
+
/**
|
|
89
|
+
* One desired RECURRING schedule: a `schedules/` file as an EventBridge cron schedule, which EventBridge fires on its
|
|
90
|
+
* own clock. Each fire delivers `{scheduleFire: {name, occurrence: <aws.scheduler.scheduled-time>}}`, the instant it
|
|
91
|
+
* was scheduled for, repeated byte-identical on every redelivery, which is what lets the container claim it once.
|
|
92
|
+
*/
|
|
93
|
+
export interface RecurringSchedule {
|
|
94
|
+
name: string;
|
|
95
|
+
/** EventBridge's `cron(...)` (schedule/eventbridge-cron.ts). */
|
|
96
|
+
expression: string;
|
|
97
|
+
/** IANA zone the expression is evaluated in. */
|
|
98
|
+
tz: string;
|
|
111
99
|
}
|
|
112
100
|
/**
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
* survives a retry (schedule/run.ts).
|
|
101
|
+
* The wire shape the wake sink POSTs to {@link RESERVED_PATHS.wakeAlarm} (the forwarder validates `secret`). The
|
|
102
|
+
* schedules are the WHOLE desired set: the forwarder deletes a recurring schedule it holds that is not in it.
|
|
116
103
|
*/
|
|
117
|
-
export interface
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
};
|
|
104
|
+
export interface WakeAlarmRequest {
|
|
105
|
+
secret: string;
|
|
106
|
+
alarms: WakeAlarm[];
|
|
107
|
+
schedules: RecurringSchedule[];
|
|
122
108
|
}
|
|
@@ -8,7 +8,7 @@ export const RESERVED_PATHS = {
|
|
|
8
8
|
wakeAlarm: "/__fastagent/wake-alarm",
|
|
9
9
|
};
|
|
10
10
|
/** Every kind the container's `POST /invocations` dispatches on. */
|
|
11
|
-
export const ENVELOPE_KINDS = ["webhook", "
|
|
11
|
+
export const ENVELOPE_KINDS = ["webhook", "schedule-fire", "wake-poke", "probe"];
|
|
12
12
|
/**
|
|
13
13
|
* Did this envelope come from the FORWARDER, rather than from some other principal holding
|
|
14
14
|
* `bedrock-agentcore:InvokeAgentRuntime`?
|
|
@@ -17,8 +17,8 @@ export const ENVELOPE_KINDS = ["webhook", "routine-fire", "routine-run", "invoke
|
|
|
17
17
|
* (`envelope.wake.url`) is where the container later POSTs its wake alarms, carrying `FASTAGENT_WAKE_SECRET` — so a
|
|
18
18
|
* principal who could set it would redirect that callback and collect the secret along with every pending wake-up.
|
|
19
19
|
*
|
|
20
|
-
* The other thing it gates — the
|
|
21
|
-
* the `
|
|
20
|
+
* The other thing it gates — the kinds other than `api` — is DEPTH, not a boundary. Every one of them is weaker than
|
|
21
|
+
* the `api` the same caller may already send: `schedule-fire` runs a prompt the definition wrote down,
|
|
22
22
|
* `webhook` reaches only channel routes that verify their own platform's signature, `wake-poke` wakes, `probe`
|
|
23
23
|
* reports. IAM is what decides who gets to ask at all.
|
|
24
24
|
*
|
|
@@ -1,28 +1,18 @@
|
|
|
1
|
-
/** The AgentCore serving assembly — the same product as `
|
|
2
|
-
import type { Agent } from "../agent.ts";
|
|
1
|
+
/** The AgentCore serving assembly — the same product as `serveAgent`, built differently because the host is. */
|
|
2
|
+
import type { Agent } from "../agent-api.ts";
|
|
3
3
|
import type { Routes } from "../channel.ts";
|
|
4
|
-
import type {
|
|
5
|
-
import { type
|
|
4
|
+
import type { Schedule } from "../schedule/schedule.ts";
|
|
5
|
+
import { type ServableAgent, type ServedAgent, type Service } from "../service.ts";
|
|
6
6
|
import { type AgentcoreAdapterOptions } from "./agentcore.ts";
|
|
7
|
-
import type { ChannelHandler } from "../channel.ts";
|
|
8
7
|
/**
|
|
9
8
|
* Runtime filesystems appear on invocation, so even opening the definition must be deferred — in the TWO stages that
|
|
10
9
|
* differ in what a retry would cost.
|
|
11
10
|
*/
|
|
12
11
|
export declare function deferAgentcoreService<T>(stages: {
|
|
13
12
|
prepare: () => Promise<T>;
|
|
14
|
-
assemble: (prepared: T) => Promise<
|
|
15
|
-
}):
|
|
16
|
-
|
|
17
|
-
close: () => Promise<void>;
|
|
18
|
-
};
|
|
19
|
-
export interface MountAgentcoreServiceOptions {
|
|
20
|
-
/** Wrap the opened agent before anything binds to it (the CLI's turn trace). */
|
|
21
|
-
wrapAgent?: (agent: Agent) => Agent;
|
|
22
|
-
/** The process entry owns the global wake-alarm sink; activation reconciles it once. */
|
|
23
|
-
onStateReady?: () => void;
|
|
24
|
-
}
|
|
25
|
-
export declare function mountAgentcoreService(opened: MountableAgent, options?: MountAgentcoreServiceOptions): Promise<AgentService>;
|
|
13
|
+
assemble: (prepared: T) => Promise<ServedAgent>;
|
|
14
|
+
}): Service;
|
|
15
|
+
export declare function mountAgentcoreService(opened: ServableAgent): Promise<ServedAgent>;
|
|
26
16
|
/**
|
|
27
17
|
* Mount the AgentCore Runtime adapter (`POST /invocations` + `GET /ping`) — the deployed container's ONLY reachable
|
|
28
18
|
* surface (channels/agentcore.ts).
|
|
@@ -30,7 +20,7 @@ export declare function mountAgentcoreService(opened: MountableAgent, options?:
|
|
|
30
20
|
export declare function mountAgentcore(options: {
|
|
31
21
|
agent: Agent;
|
|
32
22
|
stateRoot: string;
|
|
33
|
-
|
|
23
|
+
schedules: () => readonly Schedule[];
|
|
34
24
|
onStateReady?: () => void;
|
|
35
25
|
/** The channel surface, initialized once by the adapter on trusted ingress. */
|
|
36
26
|
channels: AgentcoreAdapterOptions["channels"];
|