@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,52 @@
|
|
|
1
|
+
import { type BoundContent, type ContentDeclaration, type DeclaredContent } from "./declare.ts";
|
|
2
|
+
import { type CloneOutcome } from "./git.ts";
|
|
3
|
+
/** A content entry, resolved for this instance. */
|
|
4
|
+
export type ResolvedContent = {
|
|
5
|
+
/** Unique within the agent, ignoring case; one path segment. */
|
|
6
|
+
name: string;
|
|
7
|
+
/** The agent knows it and does not write it. */
|
|
8
|
+
readonly: boolean;
|
|
9
|
+
/** What the declaration tells the agent about it. */
|
|
10
|
+
description?: string;
|
|
11
|
+
/** Where the agent reaches it on this instance, absolute. */
|
|
12
|
+
location: string;
|
|
13
|
+
/** What to tell the user about how it resolved: a checkout off its `ref`, a clone not made yet. */
|
|
14
|
+
notices: string[];
|
|
15
|
+
} & ({
|
|
16
|
+
/** A directory only this machine has, bound in `context.local.json`. */
|
|
17
|
+
kind: "local";
|
|
18
|
+
} | {
|
|
19
|
+
kind: "github";
|
|
20
|
+
/** `owner/repo`. */
|
|
21
|
+
repo: string;
|
|
22
|
+
ref?: string;
|
|
23
|
+
/**
|
|
24
|
+
* A clone fastagent makes at `content/<name>` and brings up to date at each start while it holds nothing of the
|
|
25
|
+
* agent's. False when this machine binds its own checkout, which is never touched.
|
|
26
|
+
*/
|
|
27
|
+
clone: boolean;
|
|
28
|
+
});
|
|
29
|
+
/** Resolve the agent's content for this instance. Refuses, naming the entry, what cannot be. */
|
|
30
|
+
export declare function resolveContent(agentDir: string, { declared, bound }: ContentDeclaration): ResolvedContent[];
|
|
31
|
+
/**
|
|
32
|
+
* The bindings of a directory only this machine has that point at nothing here: the directory was moved or removed.
|
|
33
|
+
* Not an error, since the binding is this machine's alone; the agent is not told of it, and whoever opens the agent
|
|
34
|
+
* says so.
|
|
35
|
+
*/
|
|
36
|
+
export declare function contentAbsentHere({ bound }: ContentDeclaration): BoundContent[];
|
|
37
|
+
/** What is said of a binding {@link contentAbsentHere} returns, after the word "content". */
|
|
38
|
+
export declare function absentNotice(binding: BoundContent): string;
|
|
39
|
+
/**
|
|
40
|
+
* Whether the content `name` can be bound to the directory `target` of this machine: a directory, apart from the agent
|
|
41
|
+
* directory, and for a declared repository the root of a checkout of it. Returns what to tell the user (a checkout off
|
|
42
|
+
* its `ref`); refuses, naming the entry, what cannot be.
|
|
43
|
+
*/
|
|
44
|
+
export declare function checkBinding(agentDir: string, name: string, target: string, repository?: Pick<DeclaredContent, "repo" | "ref">): string[];
|
|
45
|
+
/**
|
|
46
|
+
* Make a clone real, or bring it up to date at its `ref` in place, by git's rules, which never overwrite what the
|
|
47
|
+
* agent did in it (git.ts `refreshClone`): what git refuses, or a remote that cannot be reached, keeps it as it is,
|
|
48
|
+
* with the reason. Only a process that runs the agent calls this. A checkout this machine binds is never cloned over.
|
|
49
|
+
*/
|
|
50
|
+
export declare function cloneContent(entry: Extract<ResolvedContent, {
|
|
51
|
+
kind: "github";
|
|
52
|
+
}>): Promise<CloneOutcome>;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WHERE each content entry is, for THIS instance: the one answer the prompt, the coding tools, authored tools, `info`
|
|
3
|
+
* and `deploy` all read (docs/design/core.md §2). A repository `context.json` declares is fastagent's clone at
|
|
4
|
+
* `content/<name>`, or this machine's own checkout of it where `context.local.json` binds one; a directory only this
|
|
5
|
+
* machine has is where its binding says. Reads the disk (git included); never the network, never a write. Making a
|
|
6
|
+
* clone real is `cloneContent`'s, and only a process that runs the agent asks for it.
|
|
7
|
+
*/
|
|
8
|
+
import { lstatSync, realpathSync, statSync } from "node:fs";
|
|
9
|
+
import { basename, dirname, join } from "node:path";
|
|
10
|
+
import { LOCAL_CONTEXT_FILE, contentEntryPath } from "../paths.js";
|
|
11
|
+
import { nestingError } from "./declare.js";
|
|
12
|
+
import { checkoutProblem, refNotice, refreshClone } from "./git.js";
|
|
13
|
+
import { ensureContentDir } from "./mount.js";
|
|
14
|
+
/** Resolve the agent's content for this instance. Refuses, naming the entry, what cannot be. */
|
|
15
|
+
export function resolveContent(agentDir, { declared, bound }) {
|
|
16
|
+
const shared = declared.map((entry) => resolveRepository(agentDir, entry, bound.find((binding) => binding.kind === "checkout" && binding.name === entry.name)));
|
|
17
|
+
const local = bound
|
|
18
|
+
.filter((binding) => binding.kind === "local" && statOrMissing(binding.path) !== undefined)
|
|
19
|
+
.map((binding) => resolveLocal(agentDir, binding));
|
|
20
|
+
return [...shared, ...local];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The bindings of a directory only this machine has that point at nothing here: the directory was moved or removed.
|
|
24
|
+
* Not an error, since the binding is this machine's alone; the agent is not told of it, and whoever opens the agent
|
|
25
|
+
* says so.
|
|
26
|
+
*/
|
|
27
|
+
export function contentAbsentHere({ bound }) {
|
|
28
|
+
return bound.filter((binding) => binding.kind === "local" && statOrMissing(binding.path) === undefined);
|
|
29
|
+
}
|
|
30
|
+
/** What is said of a binding {@link contentAbsentHere} returns, after the word "content". */
|
|
31
|
+
export function absentNotice(binding) {
|
|
32
|
+
return (`${binding.name}: bound in ${LOCAL_CONTEXT_FILE} to ${binding.path}, which does not exist here: the agent is ` +
|
|
33
|
+
`not told of it`);
|
|
34
|
+
}
|
|
35
|
+
function resolveRepository(agentDir, entry, checkout) {
|
|
36
|
+
const { name, readonly, description } = entry;
|
|
37
|
+
const repository = {
|
|
38
|
+
name,
|
|
39
|
+
readonly,
|
|
40
|
+
...(description !== undefined ? { description } : {}),
|
|
41
|
+
kind: "github",
|
|
42
|
+
repo: entry.repo,
|
|
43
|
+
...(entry.ref !== undefined ? { ref: entry.ref } : {}),
|
|
44
|
+
};
|
|
45
|
+
if (checkout !== undefined && statOrMissing(checkout.path) !== undefined) {
|
|
46
|
+
const location = realpathSync(checkout.path);
|
|
47
|
+
const notices = checkBinding(agentDir, name, location, entry);
|
|
48
|
+
return { ...repository, location, notices, clone: false };
|
|
49
|
+
}
|
|
50
|
+
const location = contentEntryPath(agentDir, name);
|
|
51
|
+
const found = lstatOrMissing(location);
|
|
52
|
+
if (found?.isSymbolicLink()) {
|
|
53
|
+
throw new Error(`content "${name}": content/${name} is a link, and content/ holds only the clones fastagent makes — remove ` +
|
|
54
|
+
`the link, and bind a checkout of your own in ${LOCAL_CONTEXT_FILE} instead (fastagent content add <dir>)`);
|
|
55
|
+
}
|
|
56
|
+
if (found && !found.isDirectory())
|
|
57
|
+
throw new Error(`content "${name}": ${location} is not a directory`);
|
|
58
|
+
const notices = found ? [] : ["not cloned yet: it is cloned when the agent starts"];
|
|
59
|
+
if (checkout !== undefined) {
|
|
60
|
+
notices.unshift(`bound in ${LOCAL_CONTEXT_FILE} to ${checkout.path}, which does not exist here: the clone is used`);
|
|
61
|
+
}
|
|
62
|
+
return { ...repository, location, notices, clone: true };
|
|
63
|
+
}
|
|
64
|
+
function resolveLocal(agentDir, binding) {
|
|
65
|
+
const { name, readonly, description } = binding;
|
|
66
|
+
const location = realpathSync(binding.path);
|
|
67
|
+
checkBinding(agentDir, name, location);
|
|
68
|
+
return {
|
|
69
|
+
name,
|
|
70
|
+
readonly,
|
|
71
|
+
...(description !== undefined ? { description } : {}),
|
|
72
|
+
location,
|
|
73
|
+
notices: [],
|
|
74
|
+
kind: "local",
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Whether the content `name` can be bound to the directory `target` of this machine: a directory, apart from the agent
|
|
79
|
+
* directory, and for a declared repository the root of a checkout of it. Returns what to tell the user (a checkout off
|
|
80
|
+
* its `ref`); refuses, naming the entry, what cannot be.
|
|
81
|
+
*/
|
|
82
|
+
export function checkBinding(agentDir, name, target, repository) {
|
|
83
|
+
const stat = statOrMissing(target);
|
|
84
|
+
if (!stat)
|
|
85
|
+
throw new Error(`content "${name}": ${target} does not exist`);
|
|
86
|
+
if (!stat.isDirectory())
|
|
87
|
+
throw new Error(`content "${name}": ${target} is not a directory`);
|
|
88
|
+
// A symlink can still put one inside the other, so ask of the real paths — including for an agent directory `init`
|
|
89
|
+
// is about to create, which a symlinked ancestor still places.
|
|
90
|
+
const nested = nestingError(realPathOf(agentDir), realpathSync(target), name);
|
|
91
|
+
if (nested)
|
|
92
|
+
throw new Error(nested);
|
|
93
|
+
if (repository === undefined)
|
|
94
|
+
return [];
|
|
95
|
+
const problem = checkoutProblem(target, repository.repo);
|
|
96
|
+
if (problem)
|
|
97
|
+
throw new Error(`content "${name}": ${target} ${problem}`);
|
|
98
|
+
const offRef = repository.ref === undefined ? undefined : refNotice(target, repository.ref);
|
|
99
|
+
return offRef ? [offRef] : [];
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Make a clone real, or bring it up to date at its `ref` in place, by git's rules, which never overwrite what the
|
|
103
|
+
* agent did in it (git.ts `refreshClone`): what git refuses, or a remote that cannot be reached, keeps it as it is,
|
|
104
|
+
* with the reason. Only a process that runs the agent calls this. A checkout this machine binds is never cloned over.
|
|
105
|
+
*/
|
|
106
|
+
export async function cloneContent(entry) {
|
|
107
|
+
if (!entry.clone)
|
|
108
|
+
throw new Error(`content "${entry.name}" is bound to the checkout ${entry.location}, not a clone`);
|
|
109
|
+
ensureContentDir(dirname(entry.location));
|
|
110
|
+
return refreshClone(entry.repo, entry.ref, entry.location).catch((error) => {
|
|
111
|
+
throw new Error(`content "${entry.name}": ${error.message}`);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Where `path` really is, whether or not it exists yet: its nearest existing ancestor resolved, and the segments below
|
|
116
|
+
* it appended as written. A directory that does not exist yet links nowhere itself, but an ancestor can.
|
|
117
|
+
*/
|
|
118
|
+
function realPathOf(path) {
|
|
119
|
+
const below = [];
|
|
120
|
+
for (let current = path;; current = dirname(current)) {
|
|
121
|
+
try {
|
|
122
|
+
return join(realpathSync(current), ...below.reverse());
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
if (error.code !== "ENOENT" || dirname(current) === current)
|
|
126
|
+
throw error;
|
|
127
|
+
below.push(basename(current));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function lstatOrMissing(path) {
|
|
132
|
+
try {
|
|
133
|
+
return lstatSync(path);
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
if (error.code === "ENOENT")
|
|
137
|
+
return undefined;
|
|
138
|
+
throw error;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function statOrMissing(path) {
|
|
142
|
+
try {
|
|
143
|
+
return statSync(path);
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
const code = error.code;
|
|
147
|
+
if (code === "ENOENT" || code === "ENOTDIR")
|
|
148
|
+
return undefined;
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type ContentBinding, type ContentEntry } from "./declare.ts";
|
|
2
|
+
export interface SourceOptions {
|
|
3
|
+
readonly?: boolean;
|
|
4
|
+
name?: string;
|
|
5
|
+
/** A github entry's branch, tag or commit. */
|
|
6
|
+
ref?: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* A content entry to add, by name: the repository `context.json` declares for every instance, this machine's binding
|
|
11
|
+
* in `context.local.json`, or both (a checkout of the declared repository). At least one.
|
|
12
|
+
*/
|
|
13
|
+
export interface ContentAddition {
|
|
14
|
+
name: string;
|
|
15
|
+
entry?: ContentEntry;
|
|
16
|
+
binding?: ContentBinding;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The addition `source` asks for, with what to tell the user about how it was read. `github:owner/repo` is a
|
|
20
|
+
* repository fastagent clones. The root of a checkout whose `origin` is on GitHub is that repository, declared for
|
|
21
|
+
* every instance and bound to this checkout here. Any other directory, a subdirectory of such a checkout included, is
|
|
22
|
+
* bound on this machine alone. The name defaults to the repository's or the directory's.
|
|
23
|
+
*/
|
|
24
|
+
export declare function readContentSource(source: string, cwd: string, options?: SourceOptions): {
|
|
25
|
+
addition: ContentAddition;
|
|
26
|
+
notes: string[];
|
|
27
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a command's `<source>` adds (`init --content`, `fastagent content add`; docs/design/agent-cli.md §3), read the
|
|
3
|
+
* same way by both: `github:owner/repo`, the root of a GitHub checkout, or any other directory.
|
|
4
|
+
*/
|
|
5
|
+
import { realpathSync } from "node:fs";
|
|
6
|
+
import { basename, resolve } from "node:path";
|
|
7
|
+
import { isGithubRepo } from "./declare.js";
|
|
8
|
+
import { checkoutOf, githubRepoOf } from "./git.js";
|
|
9
|
+
/**
|
|
10
|
+
* The addition `source` asks for, with what to tell the user about how it was read. `github:owner/repo` is a
|
|
11
|
+
* repository fastagent clones. The root of a checkout whose `origin` is on GitHub is that repository, declared for
|
|
12
|
+
* every instance and bound to this checkout here. Any other directory, a subdirectory of such a checkout included, is
|
|
13
|
+
* bound on this machine alone. The name defaults to the repository's or the directory's.
|
|
14
|
+
*/
|
|
15
|
+
export function readContentSource(source, cwd, options = {}) {
|
|
16
|
+
const treated = {
|
|
17
|
+
...(options.readonly ? { readonly: true } : {}),
|
|
18
|
+
...(options.description !== undefined ? { description: options.description } : {}),
|
|
19
|
+
};
|
|
20
|
+
const ref = options.ref !== undefined ? { ref: options.ref } : {};
|
|
21
|
+
const repoName = (repo) => repo.slice(repo.indexOf("/") + 1);
|
|
22
|
+
if (source.startsWith("github:")) {
|
|
23
|
+
const repo = source.slice("github:".length);
|
|
24
|
+
if (!isGithubRepo(repo))
|
|
25
|
+
throw new Error(`${source} names no repository: write github:owner/repo`);
|
|
26
|
+
return {
|
|
27
|
+
addition: { name: options.name ?? repoName(repo), entry: { github: repo, ...ref, ...treated } },
|
|
28
|
+
notes: [],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
const dir = resolve(cwd, source);
|
|
32
|
+
const checkout = checkoutOf(dir);
|
|
33
|
+
const repo = checkout?.origin === undefined ? undefined : githubRepoOf(checkout.origin);
|
|
34
|
+
const atRoot = checkout !== undefined && realpathSync(dir) === realpathSync(checkout.root);
|
|
35
|
+
if (repo !== undefined && atRoot) {
|
|
36
|
+
const root = checkout.root;
|
|
37
|
+
return {
|
|
38
|
+
addition: {
|
|
39
|
+
name: options.name ?? repoName(repo),
|
|
40
|
+
entry: { github: repo, ...ref, ...treated },
|
|
41
|
+
binding: { path: root },
|
|
42
|
+
},
|
|
43
|
+
notes: [],
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (options.ref !== undefined) {
|
|
47
|
+
throw new Error(`--ref applies to a repository, and ${dir} is bound as a directory of this machine`);
|
|
48
|
+
}
|
|
49
|
+
const notes = repo !== undefined && !atRoot
|
|
50
|
+
? [`${dir} is in a checkout of github ${repo}: add github:${repo} for the whole repository`]
|
|
51
|
+
: [];
|
|
52
|
+
return { addition: { name: options.name ?? basename(dir), binding: { path: dir, ...treated } }, notes };
|
|
53
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type Agent, type CreateSessionOptions } from "./agent-api.ts";
|
|
2
|
+
/** What the map asks of the Agent: whether a recorded session is still there, and a new one when it is not. */
|
|
3
|
+
type SessionsAgent = {
|
|
4
|
+
sessions: Pick<Agent["sessions"], "get" | "create">;
|
|
5
|
+
};
|
|
6
|
+
/** A new, empty session: what a conversation the agent has not talked in starts with. */
|
|
7
|
+
export declare function newSession(agent: SessionsAgent): Promise<string>;
|
|
8
|
+
/** A new session forked from `from`, or an empty one when there is nothing to fork. */
|
|
9
|
+
export declare function forkedSession(agent: SessionsAgent, from: CreateSessionOptions["forkFrom"]): Promise<string>;
|
|
10
|
+
export interface ConversationSessions {
|
|
11
|
+
/** The session `conversation` was recorded with, when it has one, as recorded. */
|
|
12
|
+
get(conversation: string): string | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* The session `conversation` talks in: the one it has, or the one `create` makes (an empty one by default), recorded
|
|
15
|
+
* before it is returned. A recorded session the Agent no longer holds (its storage was reset, or restored from an
|
|
16
|
+
* older copy) is replaced the same way, and said so, rather than failing every message after it.
|
|
17
|
+
*/
|
|
18
|
+
of(conversation: string, agent: SessionsAgent, create?: () => Promise<string>): Promise<string>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The map kept in `file`, read once and kept in memory: one process owns an instance's state, so nothing else writes
|
|
22
|
+
* it while this process runs, and a turn costs no read of a file that grows with every conversation. Written whole,
|
|
23
|
+
* synchronously, when a conversation gets a session.
|
|
24
|
+
*/
|
|
25
|
+
export declare function conversationSessions(file: string): ConversationSessions;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which Agent session each of a Caller's conversations talks in: a channel's chats and threads (its `sessionFor`), a
|
|
3
|
+
* schedule's runs. The Agent names sessions, so a Caller keeps this map, in its own state (a channel's
|
|
4
|
+
* `<stateDir>/sessions.json`, the schedules' `schedule/sessions.json`), and creates a conversation's session in one
|
|
5
|
+
* order (architecture.md §2): the session, then the record, then the message. The map takes one conversation's calls
|
|
6
|
+
* one at a time, so two messages for one new conversation meet it one after the other and get one session. A crash
|
|
7
|
+
* between the session and the record leaves a session nothing refers to, which the retry does not reuse; no message is
|
|
8
|
+
* answered twice, since a message is sent only once its session is recorded.
|
|
9
|
+
*/
|
|
10
|
+
import { dirname } from "node:path";
|
|
11
|
+
import { AgentError } from "./agent-api.js";
|
|
12
|
+
import { log } from "./log.js";
|
|
13
|
+
import { ensureStateHome, loadStateFile, saveStateFile } from "./state-file.js";
|
|
14
|
+
/** A new, empty session: what a conversation the agent has not talked in starts with. */
|
|
15
|
+
export async function newSession(agent) {
|
|
16
|
+
const created = await agent.sessions.create().catch((error) => {
|
|
17
|
+
if (!(error instanceof AgentError))
|
|
18
|
+
throw error;
|
|
19
|
+
throw new AgentError({ ...error, message: `creating a session failed: ${error.message}` });
|
|
20
|
+
});
|
|
21
|
+
return created.id;
|
|
22
|
+
}
|
|
23
|
+
/** A new session forked from `from`, or an empty one when there is nothing to fork. */
|
|
24
|
+
export async function forkedSession(agent, from) {
|
|
25
|
+
if (from === undefined)
|
|
26
|
+
return newSession(agent);
|
|
27
|
+
const created = await agent.sessions.create({ forkFrom: from }).catch((error) => {
|
|
28
|
+
if (!(error instanceof AgentError))
|
|
29
|
+
throw error;
|
|
30
|
+
throw new AgentError({
|
|
31
|
+
...error,
|
|
32
|
+
message: `starting a session forked from ${from.sessionId} failed: ${error.message}`,
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
return created.id;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The map kept in `file`, read once and kept in memory: one process owns an instance's state, so nothing else writes
|
|
39
|
+
* it while this process runs, and a turn costs no read of a file that grows with every conversation. Written whole,
|
|
40
|
+
* synchronously, when a conversation gets a session.
|
|
41
|
+
*/
|
|
42
|
+
export function conversationSessions(file) {
|
|
43
|
+
let recorded;
|
|
44
|
+
const map = () => {
|
|
45
|
+
if (recorded === undefined) {
|
|
46
|
+
const stored = loadStateFile(file);
|
|
47
|
+
recorded = new Map(stored !== null && typeof stored === "object" ? Object.entries(stored) : []);
|
|
48
|
+
}
|
|
49
|
+
return recorded;
|
|
50
|
+
};
|
|
51
|
+
// A session asked about once is the Agent's for as long as this process runs: sessions are never deleted.
|
|
52
|
+
const confirmed = new Set();
|
|
53
|
+
const held = async (agent, sessionId) => {
|
|
54
|
+
if (confirmed.has(sessionId))
|
|
55
|
+
return true;
|
|
56
|
+
const held = await agent.sessions.get(sessionId).then(() => true, (error) => {
|
|
57
|
+
if (error instanceof AgentError && error.code === "not_found")
|
|
58
|
+
return false;
|
|
59
|
+
throw error;
|
|
60
|
+
});
|
|
61
|
+
if (held)
|
|
62
|
+
confirmed.add(sessionId);
|
|
63
|
+
return held;
|
|
64
|
+
};
|
|
65
|
+
const resolve = async (conversation, agent, create) => {
|
|
66
|
+
const known = map().get(conversation);
|
|
67
|
+
if (known !== undefined && (await held(agent, known)))
|
|
68
|
+
return known;
|
|
69
|
+
if (known !== undefined) {
|
|
70
|
+
log.warn(`[fastagent] ${conversation}: its session ${known} is not in the agent's storage (reset, or restored from ` +
|
|
71
|
+
`an older copy) — starting it a new one, recorded in ${file}`);
|
|
72
|
+
}
|
|
73
|
+
const sessionId = await create();
|
|
74
|
+
map().set(conversation, sessionId);
|
|
75
|
+
ensureStateHome(dirname(file));
|
|
76
|
+
saveStateFile(file, Object.fromEntries(map()));
|
|
77
|
+
confirmed.add(sessionId);
|
|
78
|
+
return sessionId;
|
|
79
|
+
};
|
|
80
|
+
/** Each conversation's last call: the next one waits for it, whatever it ended with. */
|
|
81
|
+
const calls = new Map();
|
|
82
|
+
return {
|
|
83
|
+
get: (conversation) => map().get(conversation),
|
|
84
|
+
of(conversation, agent, create = () => newSession(agent)) {
|
|
85
|
+
const previous = calls.get(conversation);
|
|
86
|
+
// Without one before it, the call starts now, as an unqueued one would: its Caller reads no turn of the loop.
|
|
87
|
+
const call = previous === undefined
|
|
88
|
+
? resolve(conversation, agent, create)
|
|
89
|
+
: previous.then(() => resolve(conversation, agent, create), () => resolve(conversation, agent, create));
|
|
90
|
+
calls.set(conversation, call);
|
|
91
|
+
const forget = () => {
|
|
92
|
+
if (calls.get(conversation) === call)
|
|
93
|
+
calls.delete(conversation);
|
|
94
|
+
};
|
|
95
|
+
call.then(forget, forget);
|
|
96
|
+
return call;
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
@@ -1,55 +1,37 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* WHICH ENV VARS THIS AGENT
|
|
3
|
-
*
|
|
2
|
+
* WHICH ENV VARS THIS AGENT NEEDS, in ONE shape, wherever it was declared: `needs(...)`, next to the code that reads
|
|
3
|
+
* the value, and the `variables` of `context.json`, for the commands the agent runs.
|
|
4
4
|
*
|
|
5
5
|
* One list, two consequences:
|
|
6
|
-
* -
|
|
7
|
-
*
|
|
6
|
+
* - opening the agent ASSERTS the values first, so a missing one is a startup failure naming the file, not a 401
|
|
7
|
+
* three days later;
|
|
8
8
|
* - `deploy --run` refuses a value file that does not supply one.
|
|
9
9
|
*
|
|
10
|
-
* Agent code does not read `process.env`:
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* declaration makes a value REQUIRED, it does not decide
|
|
10
|
+
* Agent code does not read `process.env`: `needs` hands back exactly the values it declared, so the declaration cannot
|
|
11
|
+
* drift from the read, and a typo is a type error. A command the agent runs (`gh`) reads its own variable from the
|
|
12
|
+
* process env, so a `context.json` declaration hands nothing back. The values travel through the process env, and
|
|
13
|
+
* `deploy` carries the whole value file (deploy/secrets.ts) — a declaration makes a value REQUIRED, it does not decide
|
|
14
|
+
* what travels.
|
|
14
15
|
*/
|
|
15
16
|
/** One env var some part of the definition declared, and where that declaration is. */
|
|
16
17
|
export interface DeclaredSecret {
|
|
17
18
|
/** The env-var name. */
|
|
18
19
|
name: string;
|
|
19
|
-
/** Where it was declared: "tools/x-post.ts", "
|
|
20
|
+
/** Where it was declared: "src/tools/x-post.ts", "fastagent.config.ts providers[0]", "context.json" — printed in
|
|
20
21
|
* runbooks and failures, so it must name a place the author can open. */
|
|
21
22
|
source: string;
|
|
23
|
+
/** What it is for, when the declaration says (`context.json`'s variables do): printed beside it in runbooks. */
|
|
24
|
+
description?: string;
|
|
25
|
+
/** The code runs without it: no start is refused for its absence. */
|
|
26
|
+
optional?: boolean;
|
|
22
27
|
}
|
|
23
|
-
/**
|
|
24
|
-
|
|
25
|
-
* `tools/`, `routines/` and `channels/`.
|
|
26
|
-
*
|
|
27
|
-
* One function, so every code input gets the same shape check: a `secrets: "FOO"` is that file's load
|
|
28
|
-
* failure, wherever it is. What a caller DOES with a bad declaration differs (push a failure and skip, or throw
|
|
29
|
-
* inside its own per-file try), so the verdict travels back as data rather than as an exception.
|
|
30
|
-
*/
|
|
31
|
-
export declare function readSecretDeclaration(moduleDefault: unknown, label: string): {
|
|
32
|
-
secrets: DeclaredSecret[];
|
|
33
|
-
error?: undefined;
|
|
34
|
-
} | {
|
|
35
|
-
secrets?: undefined;
|
|
36
|
-
error: string;
|
|
37
|
-
};
|
|
38
|
-
/** Every owner's declarations as one list — what a path that runs ALL of them (a serve, a deploy)
|
|
39
|
-
* asserts or carries. A path that runs ONE reads that owner's entry instead. */
|
|
40
|
-
export declare function allSecrets(byOwner: ReadonlyMap<string, readonly DeclaredSecret[]>): DeclaredSecret[];
|
|
28
|
+
/** Whether `name` has the shape of an env-var name ({@link ENV_NAME}). */
|
|
29
|
+
export declare function isEnvName(name: string): boolean;
|
|
41
30
|
/** Declared names as a stable list, first declaration winning — the form a carrier iterates. */
|
|
42
31
|
export declare function dedupeSecrets(declared: readonly DeclaredSecret[]): DeclaredSecret[];
|
|
43
|
-
/**
|
|
44
|
-
*
|
|
45
|
-
* value reads as `""` rather than throwing: the deploy pre-flight IMPORTS these modules on a machine
|
|
46
|
-
* that legitimately holds no secrets, and a throwing accessor would make the channel whose secrets we
|
|
47
|
-
* came to collect unloadable. Presence is guaranteed by the gate (src/secrets-gate.ts) on the paths
|
|
48
|
-
* that run the code, which is the one place that can tell "not set" from "not needed here".
|
|
49
|
-
*/
|
|
50
|
-
export declare function secretValues<const S extends readonly string[]>(names: S | undefined, env?: NodeJS.ProcessEnv): Record<S[number], string>;
|
|
51
|
-
/** Declared names with no value in `env` — empty string counts as missing (an unset `.env` line). */
|
|
32
|
+
/** Required names with no value in `env` — empty string counts as missing (an unset `.env` line). A name some
|
|
33
|
+
* declaration requires is required, whatever another says. */
|
|
52
34
|
export declare function missingSecrets(declared: readonly DeclaredSecret[], env?: NodeJS.ProcessEnv): DeclaredSecret[];
|
|
53
|
-
/** "X_API_KEY, X_API_SECRET (tools/x-post.ts); SLACK_TOKEN (
|
|
35
|
+
/** "X_API_KEY, X_API_SECRET (src/tools/x-post.ts); SLACK_TOKEN (src/channels/slack.ts)" — grouped by the
|
|
54
36
|
* file to open, since that is the unit the author fixes. */
|
|
55
37
|
export declare function describeSecrets(declared: readonly DeclaredSecret[]): string;
|
package/dist/declared-secrets.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* WHICH ENV VARS THIS AGENT
|
|
3
|
-
*
|
|
2
|
+
* WHICH ENV VARS THIS AGENT NEEDS, in ONE shape, wherever it was declared: `needs(...)`, next to the code that reads
|
|
3
|
+
* the value, and the `variables` of `context.json`, for the commands the agent runs.
|
|
4
4
|
*
|
|
5
5
|
* One list, two consequences:
|
|
6
|
-
* -
|
|
7
|
-
*
|
|
6
|
+
* - opening the agent ASSERTS the values first, so a missing one is a startup failure naming the file, not a 401
|
|
7
|
+
* three days later;
|
|
8
8
|
* - `deploy --run` refuses a value file that does not supply one.
|
|
9
9
|
*
|
|
10
|
-
* Agent code does not read `process.env`:
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* declaration makes a value REQUIRED, it does not decide
|
|
10
|
+
* Agent code does not read `process.env`: `needs` hands back exactly the values it declared, so the declaration cannot
|
|
11
|
+
* drift from the read, and a typo is a type error. A command the agent runs (`gh`) reads its own variable from the
|
|
12
|
+
* process env, so a `context.json` declaration hands nothing back. The values travel through the process env, and
|
|
13
|
+
* `deploy` carries the whole value file (deploy/secrets.ts) — a declaration makes a value REQUIRED, it does not decide
|
|
14
|
+
* what travels.
|
|
14
15
|
*/
|
|
15
16
|
/**
|
|
16
17
|
* What an env-var NAME may look like. Checked at the declaration, not left to the host: these names
|
|
@@ -20,64 +21,21 @@
|
|
|
20
21
|
* a real variable — only the shape a shell and every artifact format agree on.
|
|
21
22
|
*/
|
|
22
23
|
const ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
23
|
-
/**
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
function secretNamesProblem(value) {
|
|
27
|
-
if (value === undefined)
|
|
28
|
-
return undefined;
|
|
29
|
-
if (!Array.isArray(value))
|
|
30
|
-
return "secrets must be an array of env-var names";
|
|
31
|
-
for (const name of value) {
|
|
32
|
-
if (typeof name !== "string" || !ENV_NAME.test(name)) {
|
|
33
|
-
return `secrets must be an array of env-var names — ${JSON.stringify(name)} is not one`;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return undefined;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* THE READ: what a code-input module declared, attributed to its file — the one implementation for
|
|
40
|
-
* `tools/`, `routines/` and `channels/`.
|
|
41
|
-
*
|
|
42
|
-
* One function, so every code input gets the same shape check: a `secrets: "FOO"` is that file's load
|
|
43
|
-
* failure, wherever it is. What a caller DOES with a bad declaration differs (push a failure and skip, or throw
|
|
44
|
-
* inside its own per-file try), so the verdict travels back as data rather than as an exception.
|
|
45
|
-
*/
|
|
46
|
-
export function readSecretDeclaration(moduleDefault, label) {
|
|
47
|
-
const declared = moduleDefault?.secrets;
|
|
48
|
-
const problem = secretNamesProblem(declared);
|
|
49
|
-
if (problem !== undefined)
|
|
50
|
-
return { error: `${label}: ${problem}` };
|
|
51
|
-
return { secrets: (declared ?? []).map((name) => ({ name, source: label })) };
|
|
52
|
-
}
|
|
53
|
-
/** Every owner's declarations as one list — what a path that runs ALL of them (a serve, a deploy)
|
|
54
|
-
* asserts or carries. A path that runs ONE reads that owner's entry instead. */
|
|
55
|
-
export function allSecrets(byOwner) {
|
|
56
|
-
return [...byOwner.values()].flat();
|
|
24
|
+
/** Whether `name` has the shape of an env-var name ({@link ENV_NAME}). */
|
|
25
|
+
export function isEnvName(name) {
|
|
26
|
+
return ENV_NAME.test(name);
|
|
57
27
|
}
|
|
58
28
|
/** Declared names as a stable list, first declaration winning — the form a carrier iterates. */
|
|
59
29
|
export function dedupeSecrets(declared) {
|
|
60
30
|
const seen = new Set();
|
|
61
31
|
return declared.filter((s) => !seen.has(s.name) && seen.add(s.name));
|
|
62
32
|
}
|
|
63
|
-
/**
|
|
64
|
-
*
|
|
65
|
-
* value reads as `""` rather than throwing: the deploy pre-flight IMPORTS these modules on a machine
|
|
66
|
-
* that legitimately holds no secrets, and a throwing accessor would make the channel whose secrets we
|
|
67
|
-
* came to collect unloadable. Presence is guaranteed by the gate (src/secrets-gate.ts) on the paths
|
|
68
|
-
* that run the code, which is the one place that can tell "not set" from "not needed here".
|
|
69
|
-
*/
|
|
70
|
-
export function secretValues(names, env = process.env) {
|
|
71
|
-
const values = {};
|
|
72
|
-
for (const name of names ?? [])
|
|
73
|
-
values[name] = env[name] ?? "";
|
|
74
|
-
return values;
|
|
75
|
-
}
|
|
76
|
-
/** Declared names with no value in `env` — empty string counts as missing (an unset `.env` line). */
|
|
33
|
+
/** Required names with no value in `env` — empty string counts as missing (an unset `.env` line). A name some
|
|
34
|
+
* declaration requires is required, whatever another says. */
|
|
77
35
|
export function missingSecrets(declared, env = process.env) {
|
|
78
|
-
return dedupeSecrets(declared).filter((s) => !env[s.name]);
|
|
36
|
+
return dedupeSecrets(declared.filter((s) => s.optional !== true)).filter((s) => !env[s.name]);
|
|
79
37
|
}
|
|
80
|
-
/** "X_API_KEY, X_API_SECRET (tools/x-post.ts); SLACK_TOKEN (
|
|
38
|
+
/** "X_API_KEY, X_API_SECRET (src/tools/x-post.ts); SLACK_TOKEN (src/channels/slack.ts)" — grouped by the
|
|
81
39
|
* file to open, since that is the unit the author fixes. */
|
|
82
40
|
export function describeSecrets(declared) {
|
|
83
41
|
const bySource = new Map();
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
* the runtime's image from them), so they cannot be stack resources;
|
|
9
9
|
* - the forwarder's log group is created by AWS on the Lambda's first WRITE, so no template ever mentions it —
|
|
10
10
|
* and the deploy put a 14-day retention on it, i.e. it holds data;
|
|
11
|
-
* -
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* - the EventBridge schedules are minted at RUNTIME by the container: a recurring one per `schedules/` file, which
|
|
12
|
+
* nothing ever deletes but the container's next sync, and a one-shot per pending wake-up, whose
|
|
13
|
+
* `ActionAfterCompletion: DELETE` only runs once it FIRES. Either left behind retries into a deleted Lambda.
|
|
14
14
|
*
|
|
15
15
|
* This file is the RESOURCE LIST, the order the dependencies demand, and one policy decision per resource for
|
|
16
16
|
* what to do when AWS cannot answer. What an AWS answer MEANS — there, gone, or unreadable — belongs to
|