@fastagent-sh/fastagent 0.24.4 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -82
- package/dist/agent-api.d.ts +452 -0
- package/dist/agent-api.js +201 -0
- package/dist/answer-text.d.ts +8 -0
- package/dist/answer-text.js +18 -0
- package/dist/atomic-write.d.ts +2 -2
- package/dist/atomic-write.js +2 -2
- package/dist/authoring.d.ts +77 -0
- package/dist/authoring.js +238 -0
- package/dist/channel.d.ts +29 -15
- package/dist/channel.js +4 -1
- package/dist/channels/agentcore-protocol.d.ts +36 -50
- package/dist/channels/agentcore-protocol.js +3 -3
- package/dist/channels/agentcore-service.d.ts +8 -18
- package/dist/channels/agentcore-service.js +108 -127
- package/dist/channels/agentcore.d.ts +8 -24
- package/dist/channels/agentcore.js +32 -65
- package/dist/channels/body.d.ts +0 -16
- package/dist/channels/body.js +0 -25
- package/dist/channels/busy.js +6 -1
- package/dist/channels/context.d.ts +4 -0
- package/dist/channels/context.js +35 -0
- package/dist/channels/discover.d.ts +18 -20
- package/dist/channels/discover.js +41 -99
- package/dist/channels/feishu/feishu-api.d.ts +54 -4
- package/dist/channels/feishu/feishu-api.js +192 -149
- package/dist/channels/feishu/feishu.d.ts +3 -0
- package/dist/channels/feishu/feishu.js +117 -106
- package/dist/channels/feishu/history.d.ts +55 -0
- package/dist/channels/feishu/history.js +199 -0
- package/dist/channels/feishu/invoke-turn.d.ts +13 -11
- package/dist/channels/feishu/invoke-turn.js +9 -10
- package/dist/channels/feishu/model.d.ts +2 -1
- package/dist/channels/feishu/normalize.js +100 -0
- package/dist/channels/feishu/preview.d.ts +2 -2
- package/dist/channels/feishu/register-webhook.d.ts +1 -0
- package/dist/channels/feishu/register-webhook.js +3 -2
- package/dist/channels/feishu/scaffold/channel.ts +65 -46
- package/dist/channels/feishu/scaffold/feishu-send.ts +38 -33
- package/dist/channels/feishu/scaffold/feishu-threads.ts +25 -0
- package/dist/channels/feishu/setup-mode.d.ts +45 -25
- package/dist/channels/feishu/setup-mode.js +74 -23
- package/dist/channels/feishu/shared-api.d.ts +24 -6
- package/dist/channels/feishu/shared-api.js +30 -24
- package/dist/channels/kit/context-buffer.d.ts +11 -2
- package/dist/channels/kit/context-buffer.js +7 -4
- package/dist/channels/kit/delivery.d.ts +19 -3
- package/dist/channels/kit/delivery.js +74 -15
- package/dist/channels/kit/event-stream.js +2 -1
- package/dist/channels/kit/invoke-turn-kit.d.ts +41 -41
- package/dist/channels/kit/invoke-turn-kit.js +62 -71
- package/dist/channels/kit/place-history.d.ts +107 -0
- package/dist/channels/kit/place-history.js +182 -0
- package/dist/channels/kit/preview-kit.d.ts +9 -5
- package/dist/channels/kit/preview-kit.js +36 -15
- package/dist/channels/kit/room-threads.d.ts +46 -0
- package/dist/channels/kit/room-threads.js +81 -0
- package/dist/channels/kit/seen.js +1 -1
- package/dist/channels/kit/stop-command.d.ts +6 -3
- package/dist/channels/kit/stop-command.js +20 -18
- package/dist/channels/kit/thread-fork.d.ts +17 -0
- package/dist/channels/kit/thread-fork.js +43 -0
- package/dist/channels/kit/thread-participants.js +1 -1
- package/dist/channels/kit/transport.d.ts +5 -0
- package/dist/channels/kit/transport.js +5 -0
- package/dist/channels/kit/turn-runner.d.ts +10 -9
- package/dist/channels/kit/turn-runner.js +17 -19
- package/dist/channels/kit/turn-store.d.ts +5 -4
- package/dist/channels/kit/turn-store.js +5 -5
- package/dist/channels/lark/lark.d.ts +3 -0
- package/dist/channels/lark/lark.js +5 -0
- package/dist/channels/lark/onboard.d.ts +5 -3
- package/dist/channels/lark/onboard.js +14 -14
- package/dist/channels/lark/scaffold/channel.ts +67 -44
- package/dist/channels/lark/scaffold/lark-send.ts +38 -33
- package/dist/channels/lark/scaffold/lark-threads.ts +25 -0
- package/dist/channels/respond.d.ts +0 -4
- package/dist/channels/respond.js +1 -1
- package/dist/channels/router.d.ts +18 -0
- package/dist/channels/router.js +68 -0
- package/dist/channels/serve.d.ts +5 -70
- package/dist/channels/serve.js +105 -287
- package/dist/channels/slack/history.d.ts +42 -0
- package/dist/channels/slack/history.js +282 -0
- package/dist/channels/slack/invoke-turn.d.ts +12 -5
- package/dist/channels/slack/invoke-turn.js +7 -5
- package/dist/channels/slack/manifest.d.ts +1 -4
- package/dist/channels/slack/manifest.js +22 -10
- package/dist/channels/slack/model.d.ts +2 -1
- package/dist/channels/slack/onboard.d.ts +0 -2
- package/dist/channels/slack/onboard.js +2 -4
- package/dist/channels/slack/onboarding-state.d.ts +0 -2
- package/dist/channels/slack/onboarding-state.js +0 -1
- package/dist/channels/slack/parse.d.ts +0 -5
- package/dist/channels/slack/parse.js +1 -16
- package/dist/channels/slack/preview.d.ts +2 -3
- package/dist/channels/slack/preview.js +78 -52
- package/dist/channels/slack/register-webhook.d.ts +1 -0
- package/dist/channels/slack/register-webhook.js +6 -5
- package/dist/channels/slack/scaffold/channel.ts +23 -24
- package/dist/channels/slack/scaffold/slack-send.ts +50 -43
- package/dist/channels/slack/scaffold/slack-threads.ts +29 -0
- package/dist/channels/slack/setup-server.d.ts +19 -0
- package/dist/channels/slack/setup-server.js +113 -11
- package/dist/channels/slack/shared-api.d.ts +15 -4
- package/dist/channels/slack/shared-api.js +19 -14
- package/dist/channels/slack/slack-api.d.ts +61 -2
- package/dist/channels/slack/slack-api.js +28 -5
- package/dist/channels/slack/slack.js +97 -52
- package/dist/channels/slack/welcomed.js +1 -1
- package/dist/channels/telegram/context-buffer.d.ts +6 -1
- package/dist/channels/telegram/context-buffer.js +19 -0
- package/dist/channels/telegram/invoke-turn.d.ts +8 -4
- package/dist/channels/telegram/invoke-turn.js +7 -7
- package/dist/channels/telegram/parse.d.ts +7 -2
- package/dist/channels/telegram/parse.js +7 -0
- package/dist/channels/telegram/preview.d.ts +2 -2
- package/dist/channels/telegram/register-webhook.d.ts +1 -0
- package/dist/channels/telegram/register-webhook.js +3 -2
- package/dist/channels/telegram/scaffold/channel.ts +27 -28
- package/dist/channels/telegram/scaffold/telegram-send.ts +61 -108
- package/dist/channels/telegram/shared-api.d.ts +34 -0
- package/dist/channels/telegram/shared-api.js +79 -0
- package/dist/channels/telegram/telegram-api.d.ts +15 -5
- package/dist/channels/telegram/telegram-api.js +10 -6
- package/dist/channels/telegram/telegram.js +27 -21
- package/dist/channels/telegram/turn-store.js +1 -1
- package/dist/channels/{kit/turn-queue.d.ts → turn-queue.d.ts} +2 -2
- package/dist/channels/{kit/turn-queue.js → turn-queue.js} +10 -10
- package/dist/cli/add-feishu.d.ts +42 -12
- package/dist/cli/add-feishu.js +177 -124
- package/dist/cli/add-slack.d.ts +8 -3
- package/dist/cli/add-slack.js +115 -63
- package/dist/cli/auth-view.d.ts +10 -3
- package/dist/cli/auth-view.js +8 -6
- package/dist/cli/box-login.d.ts +17 -7
- package/dist/cli/box-login.js +46 -12
- package/dist/cli/commands/add.d.ts +15 -4
- package/dist/cli/commands/add.js +252 -143
- package/dist/cli/commands/auth.d.ts +6 -0
- package/dist/cli/commands/auth.js +50 -0
- package/dist/cli/commands/content.d.ts +6 -0
- package/dist/cli/commands/content.js +45 -0
- package/dist/cli/commands/deploy/agentcore.js +50 -77
- package/dist/cli/commands/deploy/docker.js +38 -39
- package/dist/cli/commands/deploy/fly.js +21 -18
- package/dist/cli/commands/deploy/host-login.d.ts +26 -0
- package/dist/cli/commands/deploy/host-login.js +90 -0
- package/dist/cli/commands/deploy/railway.js +21 -26
- package/dist/cli/commands/deploy/shared.d.ts +45 -17
- package/dist/cli/commands/deploy/shared.js +34 -15
- package/dist/cli/commands/deploy.d.ts +0 -4
- package/dist/cli/commands/deploy.js +237 -50
- package/dist/cli/commands/destroy.js +8 -6
- package/dist/cli/commands/dev.d.ts +0 -2
- package/dist/cli/commands/dev.js +20 -19
- package/dist/cli/commands/env.d.ts +12 -0
- package/dist/cli/commands/env.js +190 -0
- package/dist/cli/commands/info.js +95 -156
- package/dist/cli/commands/init.d.ts +2 -2
- package/dist/cli/commands/init.js +35 -33
- package/dist/cli/commands/invoke.d.ts +6 -0
- package/dist/cli/commands/invoke.js +131 -16
- package/dist/cli/commands/login.d.ts +31 -2
- package/dist/cli/commands/login.js +413 -64
- package/dist/cli/commands/logout.d.ts +4 -0
- package/dist/cli/commands/logout.js +53 -0
- package/dist/cli/commands/logs.js +8 -6
- package/dist/cli/commands/models.d.ts +2 -1
- package/dist/cli/commands/models.js +39 -37
- package/dist/cli/commands/schedules.d.ts +21 -0
- package/dist/cli/commands/schedules.js +143 -0
- package/dist/cli/commands/start.d.ts +11 -10
- package/dist/cli/commands/start.js +35 -62
- package/dist/cli/content-view.d.ts +9 -0
- package/dist/cli/content-view.js +26 -0
- package/dist/cli/fail.d.ts +9 -12
- package/dist/cli/fail.js +17 -14
- package/dist/cli/invoke-stream.d.ts +12 -3
- package/dist/cli/invoke-stream.js +85 -23
- package/dist/cli/kernel.d.ts +9 -2
- package/dist/cli/kernel.js +15 -6
- package/dist/cli/login-relay.d.ts +3 -2
- package/dist/cli/login-relay.js +18 -6
- package/dist/cli/models-view.d.ts +5 -1
- package/dist/cli/models-view.js +1 -1
- package/dist/cli/person.d.ts +10 -0
- package/dist/cli/person.js +23 -0
- package/dist/cli/program.js +421 -203
- package/dist/cli/serve.d.ts +13 -63
- package/dist/cli/serve.js +31 -121
- package/dist/cli/shared.d.ts +21 -48
- package/dist/cli/shared.js +68 -89
- package/dist/cli/ticket.d.ts +136 -0
- package/dist/cli/ticket.js +476 -0
- package/dist/client.d.ts +7 -0
- package/dist/client.js +2 -0
- package/dist/content/declare.d.ts +70 -0
- package/dist/content/declare.js +163 -0
- package/dist/content/file.d.ts +32 -0
- package/dist/content/file.js +119 -0
- package/dist/content/git.d.ts +41 -0
- package/dist/content/git.js +217 -0
- package/dist/content/mount.d.ts +2 -0
- package/dist/content/mount.js +15 -0
- package/dist/content/resolve.d.ts +52 -0
- package/dist/content/resolve.js +151 -0
- package/dist/content/source.d.ts +27 -0
- package/dist/content/source.js +53 -0
- package/dist/conversation-sessions.d.ts +26 -0
- package/dist/conversation-sessions.js +99 -0
- package/dist/declared-secrets.d.ts +19 -37
- package/dist/declared-secrets.js +16 -58
- package/dist/deploy/agentcore/destroy.d.ts +3 -3
- package/dist/deploy/agentcore/destroy.js +46 -28
- package/dist/deploy/agentcore/forwarder.js +105 -22
- package/dist/deploy/agentcore/logs.js +1 -1
- package/dist/deploy/agentcore/plan.d.ts +10 -24
- package/dist/deploy/agentcore/plan.js +31 -135
- package/dist/deploy/agentcore/run.d.ts +1 -1
- package/dist/deploy/agentcore/run.js +8 -5
- package/dist/deploy/agentcore/shell.d.ts +1 -1
- package/dist/deploy/agentcore/shell.js +5 -5
- package/dist/deploy/api.d.ts +34 -0
- package/dist/deploy/api.js +50 -0
- package/dist/deploy/box-shell.d.ts +6 -0
- package/dist/deploy/box-shell.js +7 -0
- package/dist/deploy/build-context.d.ts +7 -5
- package/dist/deploy/build-context.js +41 -35
- package/dist/deploy/channel-ingress.d.ts +6 -1
- package/dist/deploy/channel-ingress.js +18 -5
- package/dist/deploy/container.d.ts +22 -9
- package/dist/deploy/container.js +96 -55
- package/dist/deploy/docker/plan.d.ts +3 -2
- package/dist/deploy/docker/plan.js +13 -14
- package/dist/deploy/docker/run.d.ts +2 -2
- package/dist/deploy/docker/run.js +8 -4
- package/dist/deploy/fly/plan.d.ts +1 -1
- package/dist/deploy/fly/plan.js +12 -21
- package/dist/deploy/fly/run.d.ts +10 -6
- package/dist/deploy/fly/run.js +11 -6
- package/dist/deploy/hosts.d.ts +2 -1
- package/dist/deploy/hosts.js +2 -1
- package/dist/deploy/preflight.d.ts +21 -23
- package/dist/deploy/preflight.js +222 -201
- package/dist/deploy/railway/plan.d.ts +8 -6
- package/dist/deploy/railway/plan.js +15 -58
- package/dist/deploy/railway/run.d.ts +8 -3
- package/dist/deploy/railway/run.js +12 -8
- package/dist/deploy/residency.d.ts +5 -11
- package/dist/deploy/residency.js +0 -6
- package/dist/deploy/runner.d.ts +1 -1
- package/dist/deploy/runner.js +1 -1
- package/dist/deploy/secrets.d.ts +16 -2
- package/dist/deploy/secrets.js +33 -6
- package/dist/deploy/workspace.d.ts +11 -6
- package/dist/deploy/workspace.js +55 -38
- package/dist/dev-supervisor.d.ts +11 -2
- package/dist/dev-supervisor.js +51 -26
- package/dist/effect-port.d.ts +4 -4
- package/dist/effect-port.js +4 -4
- package/dist/environment/apt.d.ts +4 -0
- package/dist/environment/apt.js +32 -0
- package/dist/environment/declare.d.ts +59 -0
- package/dist/environment/declare.js +210 -0
- package/dist/environment/mise.d.ts +50 -0
- package/dist/environment/mise.js +268 -0
- package/dist/feishu.d.ts +2 -2
- package/dist/feishu.js +2 -2
- package/dist/git.d.ts +13 -0
- package/dist/git.js +55 -0
- package/dist/harnesses/models/catalog.d.ts +20 -0
- package/dist/harnesses/models/catalog.js +254 -0
- package/dist/{engines/pi/auth.d.ts → harnesses/models/credentials.d.ts} +3 -3
- package/dist/{engines/pi/auth.js → harnesses/models/credentials.js} +3 -3
- package/dist/harnesses/models/environment.d.ts +43 -0
- package/dist/harnesses/models/environment.js +82 -0
- package/dist/{engines/pi → harnesses/models}/login.d.ts +57 -26
- package/dist/{engines/pi → harnesses/models}/login.js +187 -79
- package/dist/harnesses/models/models.d.ts +83 -0
- package/dist/harnesses/models/models.js +158 -0
- package/dist/harnesses/pi-durable/agent.d.ts +42 -0
- package/dist/harnesses/pi-durable/agent.js +579 -0
- package/dist/harnesses/pi-durable/defaults.d.ts +28 -0
- package/dist/harnesses/pi-durable/defaults.js +26 -0
- package/dist/harnesses/pi-durable/define.d.ts +77 -0
- package/dist/harnesses/pi-durable/define.js +28 -0
- package/dist/harnesses/pi-durable/entries.d.ts +32 -0
- package/dist/harnesses/pi-durable/entries.js +126 -0
- package/dist/harnesses/pi-durable/events.d.ts +25 -0
- package/dist/harnesses/pi-durable/events.js +238 -0
- package/dist/harnesses/pi-durable/ids.d.ts +16 -0
- package/dist/harnesses/pi-durable/ids.js +55 -0
- package/dist/harnesses/pi-durable/messages.d.ts +41 -0
- package/dist/harnesses/pi-durable/messages.js +116 -0
- package/dist/harnesses/pi-durable/open.d.ts +88 -0
- package/dist/harnesses/pi-durable/open.js +329 -0
- package/dist/harnesses/pi-durable/reads.d.ts +30 -0
- package/dist/harnesses/pi-durable/reads.js +94 -0
- package/dist/harnesses/pi-durable/registry.d.ts +18 -0
- package/dist/harnesses/pi-durable/registry.js +56 -0
- package/dist/harnesses/pi-durable/release.d.ts +13 -0
- package/dist/harnesses/pi-durable/release.js +40 -0
- package/dist/harnesses/pi-durable/serve.d.ts +80 -0
- package/dist/harnesses/pi-durable/serve.js +156 -0
- package/dist/harnesses/pi-durable/sessions.d.ts +27 -0
- package/dist/harnesses/pi-durable/sessions.js +47 -0
- package/dist/harnesses/pi-durable/storage.d.ts +4 -0
- package/dist/harnesses/pi-durable/storage.js +49 -0
- package/dist/harnesses/pi-durable/stream.d.ts +20 -0
- package/dist/harnesses/pi-durable/stream.js +221 -0
- package/dist/harnesses/pi-durable/text.d.ts +30 -0
- package/dist/harnesses/pi-durable/text.js +292 -0
- package/dist/harnesses/pi-durable/wake.d.ts +4 -0
- package/dist/harnesses/pi-durable/wake.js +81 -0
- package/dist/http/client.d.ts +6 -0
- package/dist/http/client.js +256 -0
- package/dist/http/contract.d.ts +541 -0
- package/dist/http/contract.js +179 -0
- package/dist/http/server.d.ts +34 -0
- package/dist/http/server.js +194 -0
- package/dist/index.d.ts +17 -4
- package/dist/index.js +10 -5
- package/dist/lark.d.ts +2 -2
- package/dist/lark.js +2 -2
- package/dist/locked-file.d.ts +17 -0
- package/dist/{engines/pi/locked-file.js → locked-file.js} +16 -10
- package/dist/once.d.ts +6 -0
- package/dist/once.js +23 -0
- package/dist/paths.d.ts +36 -52
- package/dist/paths.js +66 -182
- package/dist/runtime.d.ts +25 -2
- package/dist/runtime.js +27 -0
- package/dist/scaffold/add-channel.d.ts +14 -27
- package/dist/scaffold/add-channel.js +82 -180
- package/dist/scaffold/init.d.ts +17 -18
- package/dist/scaffold/init.js +87 -99
- package/dist/scaffold/templates/SYSTEM.md +12 -0
- package/dist/scaffold/templates/env.example +4 -10
- package/dist/scaffold/templates/fastagent.config.ts +21 -33
- package/dist/scaffold/templates/gitignore +8 -1
- package/dist/scaffold/templates/skills/writing-great-skills/SKILL.md +1 -2
- package/dist/scaffold/templates.d.ts +9 -4
- package/dist/scaffold/templates.js +7 -5
- package/dist/scaffold/vendor-skill.d.ts +1 -4
- package/dist/scaffold/vendor-skill.js +5 -6
- package/dist/schedule/cron.d.ts +13 -0
- package/dist/schedule/cron.js +52 -0
- package/dist/schedule/eventbridge-cron.d.ts +17 -0
- package/dist/schedule/eventbridge-cron.js +88 -0
- package/dist/schedule/schedule.d.ts +23 -0
- package/dist/schedule/schedule.js +34 -0
- package/dist/schedule/scheduler.d.ts +34 -33
- package/dist/schedule/scheduler.js +251 -137
- package/dist/schedule/state.d.ts +4 -14
- package/dist/schedule/state.js +7 -7
- package/dist/schedule/wake-alarm.d.ts +22 -2
- package/dist/schedule/wake-alarm.js +66 -20
- package/dist/schedule/wakeups.d.ts +16 -15
- package/dist/schedule/wakeups.js +47 -45
- package/dist/service.d.ts +56 -169
- package/dist/service.js +91 -187
- package/dist/serving-command.d.ts +10 -0
- package/dist/serving-command.js +16 -0
- package/dist/slack.d.ts +1 -1
- package/dist/slack.js +1 -1
- package/dist/{channels/kit/state.js → state-file.js} +6 -6
- package/dist/telegram.d.ts +1 -0
- package/dist/telegram.js +1 -0
- package/dist/tunnel.d.ts +3 -0
- package/dist/tunnel.js +12 -4
- package/dist/value-file.d.ts +21 -0
- package/dist/value-file.js +108 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.js +14 -1
- package/package.json +18 -28
- package/dist/agent.d.ts +0 -106
- package/dist/agent.js +0 -21
- package/dist/channels/control.d.ts +0 -31
- package/dist/channels/control.js +0 -329
- package/dist/channels/define-channel.d.ts +0 -39
- package/dist/channels/define-channel.js +0 -9
- package/dist/channels/feishu/context-buffer.d.ts +0 -35
- package/dist/channels/feishu/context-buffer.js +0 -65
- package/dist/channels/feishu/scaffold/channel.websocket.ts +0 -31
- package/dist/channels/http.d.ts +0 -23
- package/dist/channels/http.js +0 -57
- package/dist/channels/lark/scaffold/channel.websocket.ts +0 -31
- package/dist/channels/slack/context-buffer.d.ts +0 -23
- package/dist/channels/slack/context-buffer.js +0 -37
- package/dist/channels/sse.d.ts +0 -4
- package/dist/channels/sse.js +0 -66
- package/dist/cli/commands/chat.d.ts +0 -3
- package/dist/cli/commands/chat.js +0 -14
- package/dist/cli/commands/routine-run.d.ts +0 -6
- package/dist/cli/commands/routine-run.js +0 -46
- package/dist/cli/commands/routine.d.ts +0 -25
- package/dist/cli/commands/routine.js +0 -122
- package/dist/cli/commands/tool.d.ts +0 -1
- package/dist/cli/commands/tool.js +0 -57
- package/dist/collect.d.ts +0 -63
- package/dist/collect.js +0 -90
- package/dist/core.d.ts +0 -13
- package/dist/core.js +0 -15
- package/dist/engines/pi/agent-models.d.ts +0 -83
- package/dist/engines/pi/agent-models.js +0 -120
- package/dist/engines/pi/agent-session-factory.d.ts +0 -121
- package/dist/engines/pi/agent-session-factory.js +0 -535
- package/dist/engines/pi/chat.d.ts +0 -3
- package/dist/engines/pi/chat.js +0 -8
- package/dist/engines/pi/config.d.ts +0 -71
- package/dist/engines/pi/config.js +0 -199
- package/dist/engines/pi/create.d.ts +0 -170
- package/dist/engines/pi/create.js +0 -343
- package/dist/engines/pi/definition.d.ts +0 -74
- package/dist/engines/pi/definition.js +0 -236
- package/dist/engines/pi/entry-images.d.ts +0 -14
- package/dist/engines/pi/entry-images.js +0 -23
- package/dist/engines/pi/invoke-session.d.ts +0 -18
- package/dist/engines/pi/invoke-session.js +0 -403
- package/dist/engines/pi/locked-file.d.ts +0 -9
- package/dist/engines/pi/machine.d.ts +0 -53
- package/dist/engines/pi/machine.js +0 -137
- package/dist/engines/pi/models.d.ts +0 -200
- package/dist/engines/pi/models.js +0 -533
- package/dist/engines/pi/open.d.ts +0 -180
- package/dist/engines/pi/open.js +0 -270
- package/dist/engines/pi/openai-account-models.d.ts +0 -35
- package/dist/engines/pi/openai-account-models.js +0 -116
- package/dist/engines/pi/report.d.ts +0 -18
- package/dist/engines/pi/report.js +0 -59
- package/dist/engines/pi/retry-event.d.ts +0 -6
- package/dist/engines/pi/retry-event.js +0 -15
- package/dist/engines/pi/service.d.ts +0 -9
- package/dist/engines/pi/service.js +0 -14
- package/dist/engines/pi/session-builder.d.ts +0 -13
- package/dist/engines/pi/session-builder.js +0 -117
- package/dist/engines/pi/session-control.d.ts +0 -77
- package/dist/engines/pi/session-control.js +0 -908
- package/dist/engines/pi/session-effects.d.ts +0 -14
- package/dist/engines/pi/session-effects.js +0 -30
- package/dist/engines/pi/session-inheritance.d.ts +0 -21
- package/dist/engines/pi/session-inheritance.js +0 -204
- package/dist/engines/pi/session-markers.d.ts +0 -49
- package/dist/engines/pi/session-markers.js +0 -60
- package/dist/engines/pi/session-settings.d.ts +0 -67
- package/dist/engines/pi/session-settings.js +0 -119
- package/dist/engines/pi/session-store.d.ts +0 -69
- package/dist/engines/pi/session-store.js +0 -430
- package/dist/engines/pi/tool-context.d.ts +0 -45
- package/dist/engines/pi/tool-context.js +0 -31
- package/dist/engines/pi/tool.d.ts +0 -99
- package/dist/engines/pi/tool.js +0 -118
- package/dist/engines/pi/turn-kit.d.ts +0 -92
- package/dist/engines/pi/turn-kit.js +0 -288
- package/dist/engines/pi/wake-tool.d.ts +0 -9
- package/dist/engines/pi/wake-tool.js +0 -92
- package/dist/loader.d.ts +0 -41
- package/dist/loader.js +0 -116
- package/dist/node.d.ts +0 -3
- package/dist/node.js +0 -4
- package/dist/observe.d.ts +0 -6
- package/dist/observe.js +0 -47
- package/dist/pi.d.ts +0 -25
- package/dist/pi.js +0 -15
- package/dist/scaffold/templates/APPEND_SYSTEM.md +0 -12
- package/dist/scaffold/templates/tools/fetch-url.ts +0 -25
- package/dist/schedule/discover.d.ts +0 -17
- package/dist/schedule/discover.js +0 -61
- package/dist/schedule/routine.d.ts +0 -43
- package/dist/schedule/routine.js +0 -32
- package/dist/schedule/run.d.ts +0 -55
- package/dist/schedule/run.js +0 -146
- package/dist/secrets-gate.d.ts +0 -32
- package/dist/secrets-gate.js +0 -33
- package/dist/session-remote.d.ts +0 -47
- package/dist/session-remote.js +0 -460
- package/dist/session.d.ts +0 -466
- package/dist/session.js +0 -57
- /package/dist/{channels/kit/state.d.ts → state-file.d.ts} +0 -0
|
@@ -1,430 +0,0 @@
|
|
|
1
|
-
/** Session persistence for the `AgentSession` L0. */
|
|
2
|
-
import { existsSync, mkdirSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
-
import { basename, dirname, join, resolve } from "node:path";
|
|
4
|
-
import { contentText } from "@earendil-works/pi-ai";
|
|
5
|
-
import { SessionManager } from "@earendil-works/pi-coding-agent";
|
|
6
|
-
import { log } from "../../log.js";
|
|
7
|
-
import { LEAF_ANCHOR, isConversationMessage, publishedLeaf, stampProvenance } from "./session-markers.js";
|
|
8
|
-
import { activePath } from "./session-settings.js";
|
|
9
|
-
import { copyBranchForInheritance, copyBranchInto, inheritanceCut, } from "./session-inheritance.js";
|
|
10
|
-
/** A Caller's session id, as a name pi will accept. */
|
|
11
|
-
export function piSessionId(sessionId) {
|
|
12
|
-
const hex = (c) => {
|
|
13
|
-
const code = c.charCodeAt(0);
|
|
14
|
-
return code < 0x100
|
|
15
|
-
? `_${code.toString(16).toUpperCase().padStart(2, "0")}`
|
|
16
|
-
: `_u${code.toString(16).toUpperCase().padStart(4, "0")}`;
|
|
17
|
-
};
|
|
18
|
-
const body = sessionId.replace(/[^A-Za-z0-9.-]/g, hex).replace(/[.-]$/, hex);
|
|
19
|
-
return `s${body}`;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* {@link piSessionId} backwards — what `list()` needs, because a session id belongs to the CALLER and a record name is
|
|
23
|
-
* storage detail.
|
|
24
|
-
*/
|
|
25
|
-
export function callerSessionId(recordId) {
|
|
26
|
-
if (!recordId.startsWith("s"))
|
|
27
|
-
return undefined;
|
|
28
|
-
let out = "";
|
|
29
|
-
for (let i = 1; i < recordId.length; i++) {
|
|
30
|
-
const c = recordId[i];
|
|
31
|
-
if (c !== "_") {
|
|
32
|
-
out += c;
|
|
33
|
-
continue;
|
|
34
|
-
}
|
|
35
|
-
const wide = recordId[i + 1] === "u";
|
|
36
|
-
const start = i + (wide ? 2 : 1);
|
|
37
|
-
const width = wide ? 4 : 2;
|
|
38
|
-
const hex = recordId.slice(start, start + width);
|
|
39
|
-
if (hex.length !== width || !/^[0-9A-F]+$/.test(hex))
|
|
40
|
-
return undefined;
|
|
41
|
-
out += String.fromCharCode(Number.parseInt(hex, 16));
|
|
42
|
-
i = start + width - 1;
|
|
43
|
-
}
|
|
44
|
-
return out;
|
|
45
|
-
}
|
|
46
|
-
/** Disk-backed store under `dir`: restart the process, conversations continue. */
|
|
47
|
-
export function piSessionRecordStore(options) {
|
|
48
|
-
const cwd = options.cwd ?? process.cwd();
|
|
49
|
-
// Resolved against the workspace this store serves, not against wherever the process happens to have been started.
|
|
50
|
-
const root = resolve(cwd, options.dir);
|
|
51
|
-
const own = join(root, OWN_RECORDS_DIR);
|
|
52
|
-
/** Where a forked record is finished before it becomes discoverable. */
|
|
53
|
-
const staging = join(own, ".staging");
|
|
54
|
-
/** An empty record under `id`, ON DISK (see {@link materialize}) and not yet discoverable. */
|
|
55
|
-
const stage = (id) => {
|
|
56
|
-
mkdirSync(staging, { recursive: true });
|
|
57
|
-
return materialize(SessionManager.create(cwd, staging, { id }), staging);
|
|
58
|
-
};
|
|
59
|
-
/** Fill a staged record and move it in — or leave nothing behind. */
|
|
60
|
-
const fillStaged = (id, fill) => {
|
|
61
|
-
const staged = stage(id);
|
|
62
|
-
// WHERE the record is, so cleanup deletes the file that exists rather than the path it used to have.
|
|
63
|
-
let published;
|
|
64
|
-
try {
|
|
65
|
-
fill(staged);
|
|
66
|
-
// Publishing is a mkdir + rename, and both can fail (EACCES, a store root on another filesystem).
|
|
67
|
-
published = publishStaged(staged);
|
|
68
|
-
return SessionManager.open(published, own);
|
|
69
|
-
}
|
|
70
|
-
catch (error) {
|
|
71
|
-
rmSync(published ?? staged.getSessionFile() ?? "", { force: true });
|
|
72
|
-
throw error;
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
/**
|
|
76
|
-
* Move a finished record into the store: one same-filesystem rename, so a reader sees the whole thing or nothing at
|
|
77
|
-
* all.
|
|
78
|
-
*/
|
|
79
|
-
const publishStaged = (staged) => {
|
|
80
|
-
const file = staged.getSessionFile();
|
|
81
|
-
if (!file)
|
|
82
|
-
throw new Error(`staged record ${staged.getSessionId()} has no file to publish`);
|
|
83
|
-
mkdirSync(own, { recursive: true });
|
|
84
|
-
const target = join(own, basename(file));
|
|
85
|
-
renameSync(file, target);
|
|
86
|
-
return target;
|
|
87
|
-
};
|
|
88
|
-
/** Fork the named parent into `id`, or answer undefined so the caller starts empty. */
|
|
89
|
-
const inheritInto = async (sessionId, inherit) => {
|
|
90
|
-
const found = locate(inherit.parentSession);
|
|
91
|
-
if (!found) {
|
|
92
|
-
log.warn(`[fastagent] session "${sessionId}" names parent "${inherit.parentSession}", which has no record — starting empty`);
|
|
93
|
-
return undefined;
|
|
94
|
-
}
|
|
95
|
-
try {
|
|
96
|
-
const parent = SessionManager.open(found.path, found.dir);
|
|
97
|
-
const cut = inheritanceCut(parent, inherit.branchHints);
|
|
98
|
-
if (!cut)
|
|
99
|
-
return undefined;
|
|
100
|
-
return fillStaged(piSessionId(sessionId), (staged) => copyBranchForInheritance(parent, staged, cut.at));
|
|
101
|
-
}
|
|
102
|
-
catch (error) {
|
|
103
|
-
// Unattributed on purpose: this spans reading the parent AND writing the child.
|
|
104
|
-
log.warn(`[fastagent] could not inherit from "${inherit.parentSession}" into "${sessionId}" (${String(error)}) — starting empty`);
|
|
105
|
-
return undefined;
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
/**
|
|
109
|
-
* The unreadable records the last listing reported, so a polled endpoint states the condition once rather than once
|
|
110
|
-
* a second.
|
|
111
|
-
*/
|
|
112
|
-
let lastUnreadable = "";
|
|
113
|
-
/**
|
|
114
|
-
* WHERE a session's record is — the one lookup every caller shares, so a fix to it (this store's own directory
|
|
115
|
-
* rather than pi's cwd-filtered listing) cannot reach three of the four.
|
|
116
|
-
*/
|
|
117
|
-
const locate = (sessionId) => {
|
|
118
|
-
const path = recordPathIn(own, sessionId);
|
|
119
|
-
return path ? { path, dir: own } : undefined;
|
|
120
|
-
};
|
|
121
|
-
/** Open an existing record, or undefined. */
|
|
122
|
-
const openExisting = async (sessionId) => {
|
|
123
|
-
const found = locate(sessionId);
|
|
124
|
-
return found ? SessionManager.open(found.path, found.dir) : undefined;
|
|
125
|
-
};
|
|
126
|
-
return {
|
|
127
|
-
async openOrCreate(sessionId, inherit) {
|
|
128
|
-
const found = locate(sessionId);
|
|
129
|
-
if (found)
|
|
130
|
-
return SessionManager.open(found.path, found.dir);
|
|
131
|
-
mkdirSync(own, { recursive: true });
|
|
132
|
-
// Inheritance is a CREATE-path decision: an existing session above ignores it entirely, which is what makes it
|
|
133
|
-
// one-time by construction.
|
|
134
|
-
if (inherit) {
|
|
135
|
-
const inherited = await inheritInto(sessionId, inherit);
|
|
136
|
-
if (inherited)
|
|
137
|
-
return inherited;
|
|
138
|
-
}
|
|
139
|
-
// The CALLER's id in every message above; pi's spelling only where pi names the file.
|
|
140
|
-
return materialize(SessionManager.create(cwd, own, { id: piSessionId(sessionId) }), own);
|
|
141
|
-
},
|
|
142
|
-
openIfExists: openExisting,
|
|
143
|
-
applyProperties: (sessionId, writes) => applyProperties(() => openExisting(sessionId), writes),
|
|
144
|
-
async list() {
|
|
145
|
-
const files = recordFiles(own);
|
|
146
|
-
const rows = [];
|
|
147
|
-
const unreadable = [];
|
|
148
|
-
for (const file of files) {
|
|
149
|
-
// A name this store did not write cannot be decoded back to a Caller id, and a row nobody can dial is worse
|
|
150
|
-
// than a row that is missing.
|
|
151
|
-
const session = callerSessionId(file.id);
|
|
152
|
-
if (!session)
|
|
153
|
-
continue;
|
|
154
|
-
try {
|
|
155
|
-
rows.push(summarize(session, SessionManager.open(file.path, own)));
|
|
156
|
-
}
|
|
157
|
-
catch (error) {
|
|
158
|
-
// ONE unreadable record must not take the listing down — the other conversations are fine, and a GUI that
|
|
159
|
-
// shows nothing is worse than one missing a row.
|
|
160
|
-
unreadable.push(`${basename(file.path)} (${String(error)})`);
|
|
161
|
-
}
|
|
162
|
-
// A TURN for everything else.
|
|
163
|
-
await new Promise((resolve) => setImmediate(resolve));
|
|
164
|
-
}
|
|
165
|
-
// NEWEST ACTIVITY first.
|
|
166
|
-
rows.sort((a, b) => b.updatedAt - a.updatedAt);
|
|
167
|
-
// Said when the SET changes, not on every poll: this endpoint is polled once a second or so, and an unreadable
|
|
168
|
-
// record stays unreadable until someone acts on it.
|
|
169
|
-
const reported = unreadable.join("; ");
|
|
170
|
-
if (reported !== lastUnreadable) {
|
|
171
|
-
lastUnreadable = reported;
|
|
172
|
-
if (unreadable.length > 0) {
|
|
173
|
-
log.warn(`[fastagent] ${unreadable.length} of ${files.length} session records in ${own} could not be read and are missing from this listing: ${reported}`);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
return rows;
|
|
177
|
-
},
|
|
178
|
-
async fork(from, at, into, provenance) {
|
|
179
|
-
const parent = await openExisting(from);
|
|
180
|
-
if (!parent)
|
|
181
|
-
throw new Error(`session "${from}" has no record`);
|
|
182
|
-
// The port promises a NEW record, so the guarantee belongs here rather than in the one caller that happens to
|
|
183
|
-
// check.
|
|
184
|
-
if (await openExisting(into))
|
|
185
|
-
throw new Error(`session "${into}" already exists`);
|
|
186
|
-
fillStaged(piSessionId(into), (staged) => {
|
|
187
|
-
// METADATA FIRST, history last. pi has one leaf pointer and every append advances it, so whatever is written
|
|
188
|
-
// last becomes the fork's `leafEntryId`.
|
|
189
|
-
const name = parent.getSessionName();
|
|
190
|
-
// The name travels: a fork of "Deploy notes" that lists as untitled is a row a user cannot place.
|
|
191
|
-
if (name)
|
|
192
|
-
staged.appendSessionInfo(name);
|
|
193
|
-
stampProvenance(staged, provenance);
|
|
194
|
-
copyBranchInto(parent, staged, at);
|
|
195
|
-
});
|
|
196
|
-
},
|
|
197
|
-
async delete(sessionId) {
|
|
198
|
-
const found = locate(sessionId);
|
|
199
|
-
if (!found)
|
|
200
|
-
return false;
|
|
201
|
-
// A record that cannot be deleted must not report success — the caller turns the throw into a coded failure,
|
|
202
|
-
// and the session is still there for the next attempt.
|
|
203
|
-
rmSync(found.path);
|
|
204
|
-
return true;
|
|
205
|
-
},
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
/** The property write, for both backends: the ONE place that knows how pi records a property. */
|
|
209
|
-
async function applyProperties(open, writes) {
|
|
210
|
-
const record = await open();
|
|
211
|
-
if (!record)
|
|
212
|
-
return undefined;
|
|
213
|
-
const landed = [];
|
|
214
|
-
let moved = false;
|
|
215
|
-
let failure;
|
|
216
|
-
try {
|
|
217
|
-
if (writes.leafEntryId !== undefined) {
|
|
218
|
-
// A move to where the head ALREADY is asks for nothing: a client retry, or a UI firing on every selection, must
|
|
219
|
-
// not grow the session.
|
|
220
|
-
if (publishedLeaf(record) !== writes.leafEntryId) {
|
|
221
|
-
record.branch(writes.leafEntryId);
|
|
222
|
-
moved = true;
|
|
223
|
-
}
|
|
224
|
-
landed.push("leafEntryId");
|
|
225
|
-
}
|
|
226
|
-
if (writes.model) {
|
|
227
|
-
record.appendModelChange(writes.model.provider, writes.model.id);
|
|
228
|
-
landed.push("model");
|
|
229
|
-
}
|
|
230
|
-
if (writes.thinkingLevel !== undefined) {
|
|
231
|
-
record.appendThinkingLevelChange(writes.thinkingLevel);
|
|
232
|
-
landed.push("thinkingLevel");
|
|
233
|
-
}
|
|
234
|
-
if (writes.name !== undefined) {
|
|
235
|
-
record.appendSessionInfo(writes.name);
|
|
236
|
-
landed.push("name");
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
catch (error) {
|
|
240
|
-
// Held, not rethrown: what already landed still has to be reported, and the report is the only way a caller
|
|
241
|
-
// learns the record moved.
|
|
242
|
-
failure = error;
|
|
243
|
-
}
|
|
244
|
-
// THE ANCHOR, outside the try so a failed property write cannot skip it.
|
|
245
|
-
if (moved && record.getLeafId() === writes.leafEntryId) {
|
|
246
|
-
try {
|
|
247
|
-
record.appendCustomEntry(LEAF_ANCHOR, {});
|
|
248
|
-
}
|
|
249
|
-
catch (error) {
|
|
250
|
-
// The move is runtime-only and will not survive the next open, so it did NOT land: saying it did is the one
|
|
251
|
-
// thing a partial report cannot afford.
|
|
252
|
-
landed.splice(landed.indexOf("leafEntryId"), 1);
|
|
253
|
-
failure ??= error;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
// READ BACK, never echo: pi rewrites a name (newlines collapse, ends trim), and the settings a path resolves to can
|
|
257
|
-
// change under a moved leaf.
|
|
258
|
-
const name = record.getSessionName();
|
|
259
|
-
// The PUBLISHED head, not pi's: the anchor above is ours, and a client must be told the position it asked for — the
|
|
260
|
-
// one it can find in `entries()`.
|
|
261
|
-
const leafEntryId = publishedLeaf(record);
|
|
262
|
-
let path;
|
|
263
|
-
try {
|
|
264
|
-
path = activePath(record);
|
|
265
|
-
}
|
|
266
|
-
catch (error) {
|
|
267
|
-
// An unreadable chain is the caller's decision (design §7), not a silent short path.
|
|
268
|
-
log.warn(`[fastagent] session ${record.getSessionId()}: written, active path unreadable: ${String(error)}`);
|
|
269
|
-
}
|
|
270
|
-
return {
|
|
271
|
-
landed,
|
|
272
|
-
...(failure !== undefined ? { failure } : {}),
|
|
273
|
-
...(name ? { name } : {}),
|
|
274
|
-
...(leafEntryId ? { leafEntryId } : {}),
|
|
275
|
-
...(path ? { path } : {}),
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
/**
|
|
279
|
-
* The record files in a directory, newest first — pi names them `<ISO timestamp>_<id>.jsonl`, so the name sorts by
|
|
280
|
-
* time and carries the id without opening anything.
|
|
281
|
-
*/
|
|
282
|
-
/** WHERE a session's record file is, WITHOUT opening it. */
|
|
283
|
-
function recordPathIn(own, sessionId) {
|
|
284
|
-
return recordFiles(own).find((f) => f.id === piSessionId(sessionId))?.path;
|
|
285
|
-
}
|
|
286
|
-
function recordFiles(dir) {
|
|
287
|
-
let names;
|
|
288
|
-
try {
|
|
289
|
-
names = readdirSync(dir);
|
|
290
|
-
}
|
|
291
|
-
catch (error) {
|
|
292
|
-
if (error.code !== "ENOENT")
|
|
293
|
-
throw error;
|
|
294
|
-
return [];
|
|
295
|
-
}
|
|
296
|
-
// UNORDERED.
|
|
297
|
-
return names
|
|
298
|
-
.filter((name) => name.endsWith(RECORD_SUFFIX))
|
|
299
|
-
.flatMap((name) => {
|
|
300
|
-
// The FIRST underscore: the timestamp holds none, and an encoded id may hold several (`piSessionId` escapes
|
|
301
|
-
// with `_`).
|
|
302
|
-
const cut = name.indexOf("_");
|
|
303
|
-
return cut < 0 ? [] : [{ path: join(dir, name), id: name.slice(cut + 1, -RECORD_SUFFIX.length) }];
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
/** One record as a conversation-list row. */
|
|
307
|
-
function summarize(session, record) {
|
|
308
|
-
const entries = record.getEntries();
|
|
309
|
-
const createdAt = Date.parse(record.getHeader()?.timestamp ?? "") || 0;
|
|
310
|
-
// `|| 0` on both: an unparseable timestamp is NaN, and NaN in `updatedAt` serializes to `null` — which the contract
|
|
311
|
-
// types as a number and a client sorts by.
|
|
312
|
-
const lastAt = Date.parse(entries.at(-1)?.timestamp ?? "") || 0;
|
|
313
|
-
// A list row counts turns in the conversation, not the engine's system bookkeeping (`isConversationMessage`).
|
|
314
|
-
const messages = entries.filter(isConversationMessage);
|
|
315
|
-
const name = record.getSessionName();
|
|
316
|
-
const preview = firstUserText(messages);
|
|
317
|
-
return {
|
|
318
|
-
session,
|
|
319
|
-
...(name ? { name } : {}),
|
|
320
|
-
createdAt,
|
|
321
|
-
updatedAt: Math.max(lastAt, createdAt),
|
|
322
|
-
messageCount: messages.length,
|
|
323
|
-
...(preview ? { preview } : {}),
|
|
324
|
-
};
|
|
325
|
-
}
|
|
326
|
-
/**
|
|
327
|
-
* The first user message with text in it, truncated by CODE POINT (a cut through a surrogate pair would put a lone
|
|
328
|
-
* half in the row, which renders as U+FFFD).
|
|
329
|
-
*/
|
|
330
|
-
function firstUserText(messages) {
|
|
331
|
-
for (const entry of messages) {
|
|
332
|
-
const message = entry.message;
|
|
333
|
-
if (message?.role !== "user")
|
|
334
|
-
continue;
|
|
335
|
-
// The engine's own reading of message text, on a SPACE: this is a one-line preview, where adjacent
|
|
336
|
-
// blocks running together would read as one word.
|
|
337
|
-
const text = contentText(message.content, " ");
|
|
338
|
-
// Cut to UTF-16 units FIRST: a pasted megabyte would otherwise become a million-element array on the way to
|
|
339
|
-
// keeping 200 of them.
|
|
340
|
-
if (text.trim())
|
|
341
|
-
return [...text.slice(0, PREVIEW_CHARS * 2)].slice(0, PREVIEW_CHARS).join("");
|
|
342
|
-
}
|
|
343
|
-
return undefined;
|
|
344
|
-
}
|
|
345
|
-
/** What pi names a record file. */
|
|
346
|
-
const RECORD_SUFFIX = ".jsonl";
|
|
347
|
-
/** How much of the first message a list row carries. */
|
|
348
|
-
const PREVIEW_CHARS = 200;
|
|
349
|
-
/** Where the records live, under the sessions directory the store is pointed at. */
|
|
350
|
-
const OWN_RECORDS_DIR = "agent-session";
|
|
351
|
-
/** Make a NEW record exist on disk before anyone can act on it. */
|
|
352
|
-
function materialize(session, dir) {
|
|
353
|
-
const file = session.getSessionFile();
|
|
354
|
-
if (!file || existsSync(file))
|
|
355
|
-
return session; // in-memory, or already on disk
|
|
356
|
-
const header = session.getHeader();
|
|
357
|
-
if (!header)
|
|
358
|
-
return session;
|
|
359
|
-
mkdirSync(dirname(file), { recursive: true });
|
|
360
|
-
writeFileSync(file, `${JSON.stringify(header)}\n`, { flag: "wx" });
|
|
361
|
-
return SessionManager.open(file, dir);
|
|
362
|
-
}
|
|
363
|
-
/** In-process store: continuity lives and dies with the instance. */
|
|
364
|
-
export function piInMemorySessionRecordStore(options = {}) {
|
|
365
|
-
const cwd = options.cwd ?? process.cwd();
|
|
366
|
-
const live = new Map();
|
|
367
|
-
return {
|
|
368
|
-
async openOrCreate(sessionId, inherit) {
|
|
369
|
-
// Keyed by the CALLER's id: the encoding exists to satisfy pi's filename rule, and in memory there are no
|
|
370
|
-
// filenames.
|
|
371
|
-
const existing = live.get(sessionId);
|
|
372
|
-
if (existing)
|
|
373
|
-
return existing;
|
|
374
|
-
const fresh = () => SessionManager.inMemory(cwd, { id: piSessionId(sessionId) });
|
|
375
|
-
// Same semantics as the durable store, different mechanism: with no file to fork, the parent's path is copied
|
|
376
|
-
// entry by entry.
|
|
377
|
-
const parent = inherit ? live.get(inherit.parentSession) : undefined;
|
|
378
|
-
if (inherit && !parent) {
|
|
379
|
-
log.warn(`[fastagent] session "${sessionId}" names parent "${inherit.parentSession}", which has no record — starting empty`);
|
|
380
|
-
}
|
|
381
|
-
let created;
|
|
382
|
-
if (inherit && parent) {
|
|
383
|
-
try {
|
|
384
|
-
const staged = fresh();
|
|
385
|
-
const cut = inheritanceCut(parent, inherit.branchHints);
|
|
386
|
-
if (cut)
|
|
387
|
-
copyBranchForInheritance(parent, staged, cut.at);
|
|
388
|
-
created = staged;
|
|
389
|
-
}
|
|
390
|
-
catch (error) {
|
|
391
|
-
log.warn(`[fastagent] could not inherit from "${inherit.parentSession}" into "${sessionId}" (${String(error)}) — starting empty`);
|
|
392
|
-
created = fresh(); // the partially-copied one is discarded, never registered
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
else {
|
|
396
|
-
created = fresh();
|
|
397
|
-
}
|
|
398
|
-
live.set(sessionId, created);
|
|
399
|
-
return created;
|
|
400
|
-
},
|
|
401
|
-
async openIfExists(sessionId) {
|
|
402
|
-
return live.get(sessionId);
|
|
403
|
-
},
|
|
404
|
-
applyProperties: (sessionId, writes) => applyProperties(async () => live.get(sessionId), writes),
|
|
405
|
-
async list() {
|
|
406
|
-
// The SAME row builder the disk store uses, ordered the same way.
|
|
407
|
-
return [...live].map(([session, record]) => summarize(session, record)).sort((a, b) => b.updatedAt - a.updatedAt);
|
|
408
|
-
},
|
|
409
|
-
async fork(from, at, into, provenance) {
|
|
410
|
-
const parent = live.get(from);
|
|
411
|
-
if (!parent)
|
|
412
|
-
throw new Error(`session "${from}" has no record`);
|
|
413
|
-
// The port's promise, not the caller's: registering over a live session would replace its history outright.
|
|
414
|
-
if (live.has(into))
|
|
415
|
-
throw new Error(`session "${into}" already exists`);
|
|
416
|
-
// Entry-by-entry, like the in-memory inheritance path: there is no file to fork.
|
|
417
|
-
const staged = SessionManager.inMemory(cwd, { id: piSessionId(into) });
|
|
418
|
-
// METADATA FIRST, history last — the same order the disk store writes in, and for the same reason.
|
|
419
|
-
const name = parent.getSessionName();
|
|
420
|
-
if (name)
|
|
421
|
-
staged.appendSessionInfo(name);
|
|
422
|
-
stampProvenance(staged, provenance);
|
|
423
|
-
copyBranchInto(parent, staged, at);
|
|
424
|
-
live.set(into, staged);
|
|
425
|
-
},
|
|
426
|
-
async delete(sessionId) {
|
|
427
|
-
return live.delete(sessionId);
|
|
428
|
-
},
|
|
429
|
-
};
|
|
430
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
/** Per-turn capabilities shared by every FastAgent-defined tool. */
|
|
2
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
|
-
import type { SessionEntry as PiSessionEntry, AgentSession } from "@earendil-works/pi-coding-agent";
|
|
4
|
-
/** FastAgent's read-only port over the current conversation manager. */
|
|
5
|
-
export interface ReadonlySessionManager {
|
|
6
|
-
getSessionId(): string;
|
|
7
|
-
getHeader(): Promise<{
|
|
8
|
-
id: string;
|
|
9
|
-
timestamp: string;
|
|
10
|
-
}>;
|
|
11
|
-
getBranch(): Promise<PiSessionEntry[]>;
|
|
12
|
-
}
|
|
13
|
-
/** pi's AgentSession as the port above — the SAME adapter for both of its consumers. */
|
|
14
|
-
export declare function agentSessionManager(session: AgentSession, sessionId: string): ReadonlySessionManager;
|
|
15
|
-
/**
|
|
16
|
-
* The turn's tool-activation bridge — narrow closures over the CURRENT session (bound per turn), so a loader tool can
|
|
17
|
-
* activate deferred tools mid-turn without tool.ts importing the engine. pi anchors the addition in the transcript
|
|
18
|
-
* (a system message carrying `toolsAdded`, written after the batch of tool results the activating call belongs to),
|
|
19
|
-
* so providers with native deferred loading keep their
|
|
20
|
-
* prompt-cache prefix. The same transcript declarations restore the loadout on the next binding.
|
|
21
|
-
*/
|
|
22
|
-
export interface ToolActivation {
|
|
23
|
-
/** Names of the currently ACTIVE tools. */
|
|
24
|
-
active(): string[];
|
|
25
|
-
/** Every registered tool (active or not). */
|
|
26
|
-
registered(): Array<{
|
|
27
|
-
name: string;
|
|
28
|
-
description: string;
|
|
29
|
-
}>;
|
|
30
|
-
/**
|
|
31
|
-
* ADDITIVE activation. Returns ONLY the names this call actually added — a name a batch sibling activated first
|
|
32
|
-
* is not in it. That return value is the caller's truth for both what to report and what to charge an activation
|
|
33
|
-
* cap: the call is atomic, but an `active()` -> await -> `activate()` sequence around it is not.
|
|
34
|
-
*/
|
|
35
|
-
activate(names: string[]): string[];
|
|
36
|
-
}
|
|
37
|
-
/** The activation bridge over a live pi session — the ONE implementation, for both consumers. */
|
|
38
|
-
export declare function sessionToolActivation(session: AgentSession): ToolActivation;
|
|
39
|
-
export interface TurnContext {
|
|
40
|
-
/** Working directory for this execution. */
|
|
41
|
-
cwd?: string;
|
|
42
|
-
sessionManager?: ReadonlySessionManager;
|
|
43
|
-
tools?: ToolActivation;
|
|
44
|
-
}
|
|
45
|
-
export declare const turnContext: AsyncLocalStorage<TurnContext>;
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/** Per-turn capabilities shared by every FastAgent-defined tool. */
|
|
2
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
|
-
/** pi's AgentSession as the port above — the SAME adapter for both of its consumers. */
|
|
4
|
-
export function agentSessionManager(session, sessionId) {
|
|
5
|
-
return {
|
|
6
|
-
getSessionId: () => sessionId,
|
|
7
|
-
async getHeader() {
|
|
8
|
-
const header = session.sessionManager.getHeader();
|
|
9
|
-
if (!header)
|
|
10
|
-
throw new Error("session has no metadata header");
|
|
11
|
-
return { id: sessionId, timestamp: header.timestamp };
|
|
12
|
-
},
|
|
13
|
-
async getBranch() {
|
|
14
|
-
return session.sessionManager.getBranch();
|
|
15
|
-
},
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
/** The activation bridge over a live pi session — the ONE implementation, for both consumers. */
|
|
19
|
-
export function sessionToolActivation(session) {
|
|
20
|
-
return {
|
|
21
|
-
active: () => session.getActiveToolNames(),
|
|
22
|
-
registered: () => session.getAllTools().map((t) => ({ name: t.name, description: t.description ?? "" })),
|
|
23
|
-
activate(names) {
|
|
24
|
-
const current = session.getActiveToolNames();
|
|
25
|
-
session.setActiveToolsByName([...current, ...names]);
|
|
26
|
-
const before = new Set(current);
|
|
27
|
-
return session.getActiveToolNames().filter((name) => !before.has(name));
|
|
28
|
-
},
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
export const turnContext = new AsyncLocalStorage();
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import type { AgentTool } from "@earendil-works/pi-agent-core";
|
|
2
|
-
import type { ExtensionToolContext, ToolAnnotations, ToolDefinition, ToolExposure, ToolNamespace } from "@earendil-works/pi-coding-agent";
|
|
3
|
-
import { z } from "zod";
|
|
4
|
-
import { type ModuleLoadFailure } from "../../loader.ts";
|
|
5
|
-
import { type DeclaredSecret } from "../../declared-secrets.ts";
|
|
6
|
-
import { type ReadonlySessionManager, type ToolActivation } from "./tool-context.ts";
|
|
7
|
-
export interface ToolContext {
|
|
8
|
-
/** Working directory for this execution. */
|
|
9
|
-
cwd: string;
|
|
10
|
-
/** Abort signal for the current turn — honor it to cancel in-flight work on cancellation. */
|
|
11
|
-
signal?: AbortSignal;
|
|
12
|
-
sessionManager?: ReadonlySessionManager;
|
|
13
|
-
/**
|
|
14
|
-
* Tool activation for the current turn; Pi records changes in the transcript.
|
|
15
|
-
*/
|
|
16
|
-
tools?: ToolActivation;
|
|
17
|
-
/**
|
|
18
|
-
* Run another mounted tool through pi's own pipeline: argument validation, the definition's `tool_call` and
|
|
19
|
-
* `tool_result` hooks, cancellation (this call's signal by default). It reaches the active `direct` tools and every
|
|
20
|
-
* `codemode` or `deferred` one. A tool failure comes back as `isError: true`, never as a rejection. The nested call
|
|
21
|
-
* is observed with `parentToolCallId` and does not enter the transcript. Undefined without a session
|
|
22
|
-
* (`fastagent tool`).
|
|
23
|
-
*/
|
|
24
|
-
executeTool?: ExtensionToolContext["executeTool"];
|
|
25
|
-
/**
|
|
26
|
-
* Report progress while this call runs: a snapshot of everything so far (each call replaces the last), wrapped the
|
|
27
|
-
* way a return value is. Its last line is the call's status (`tool_progress` on the invoke stream); session-control
|
|
28
|
-
* observers receive the whole snapshot. Undefined when the caller takes no progress (`fastagent tool`).
|
|
29
|
-
*/
|
|
30
|
-
onUpdate?: (partial: unknown) => void;
|
|
31
|
-
/** THE values of {@link DefineToolOptions.secrets}, keyed by the names this tool declared — read
|
|
32
|
-
* from the process environment per call, so a value rotated THERE takes effect without a restart
|
|
33
|
-
* (one rotated in `.secrets/.env` does not: that file is loaded once at startup). This is how a
|
|
34
|
-
* tool gets a credential: reaching into `process.env` instead leaves the name undeclared, which
|
|
35
|
-
* means nothing carries it to a deployed box and nothing checks it before the call fails. */
|
|
36
|
-
secrets: Record<string, string>;
|
|
37
|
-
}
|
|
38
|
-
export interface DefineToolOptions<I extends z.ZodType, S extends readonly string[] = readonly []> {
|
|
39
|
-
name?: string;
|
|
40
|
-
description: string;
|
|
41
|
-
input: I;
|
|
42
|
-
/** Pi's native visibility: direct (default), model-only, codemode, deferred, or hidden. */
|
|
43
|
-
exposure?: ToolExposure;
|
|
44
|
-
/** Direct tools start active unless false; settings may still select them. */
|
|
45
|
-
defaultActive?: boolean;
|
|
46
|
-
/**
|
|
47
|
-
* MCP-style hints about what the tool does (`readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`).
|
|
48
|
-
* Pi does not enforce them; a permission extension reads them from `pi.getAllTools()` to decide which calls to
|
|
49
|
-
* confirm, and treats a tool without them as possibly destructive.
|
|
50
|
-
*/
|
|
51
|
-
annotations?: ToolAnnotations;
|
|
52
|
-
/** Groups the tool with related ones (`{ name, description? }`): codemode lists a namespace under one heading. */
|
|
53
|
-
namespace?: ToolNamespace;
|
|
54
|
-
/** Structured output schema for programmatic callers such as codemode. */
|
|
55
|
-
output?: z.ZodType;
|
|
56
|
-
/** pi's per-tool execution mode: "sequential" makes pi run any batch containing this tool serially. */
|
|
57
|
-
executionMode?: "sequential" | "parallel";
|
|
58
|
-
/**
|
|
59
|
-
* Env vars this tool needs (`secrets: ["X_API_KEY"]`). Their values arrive as `ctx.secrets.X_API_KEY`,
|
|
60
|
-
* typed from this list. Declaring buys the two guarantees a bare `process.env` read cannot have:
|
|
61
|
-
* `deploy` carries the value to the host without it being listed anywhere else, and `dev`/`start`
|
|
62
|
-
* REFUSE TO START while it is unset, naming this file — instead of the tool failing on its first
|
|
63
|
-
* real call (see src/declared-secrets.ts).
|
|
64
|
-
*/
|
|
65
|
-
secrets?: S;
|
|
66
|
-
execute: (input: z.infer<I>, ctx: Omit<ToolContext, "secrets"> & {
|
|
67
|
-
secrets: Record<S[number], string>;
|
|
68
|
-
}) => unknown | Promise<unknown>;
|
|
69
|
-
}
|
|
70
|
-
/** AgentTool with Pi's optional per-call context; absent for sessionless CLI execution. */
|
|
71
|
-
export type MountedTool = Omit<AgentTool, "execute"> & Pick<ToolDefinition, "exposure" | "defaultActive" | "annotations" | "namespace"> & {
|
|
72
|
-
execute(...args: [...Parameters<AgentTool["execute"]>, context?: ExtensionToolContext]): ReturnType<AgentTool["execute"]>;
|
|
73
|
-
};
|
|
74
|
-
/** A Pi tool with fastagent's declared secrets. */
|
|
75
|
-
export type FastagentTool = MountedTool & {
|
|
76
|
-
/** {@link DefineToolOptions.secrets} — read back by `readSecretDeclaration`; pi ignores it. */
|
|
77
|
-
secrets?: readonly string[];
|
|
78
|
-
};
|
|
79
|
-
export declare function defineTool<I extends z.ZodType, const S extends readonly string[] = readonly []>(options: DefineToolOptions<I, S>): FastagentTool;
|
|
80
|
-
/** A discarded same-name tool (within `tools/`, or against an existing tool). */
|
|
81
|
-
export interface ToolCollision {
|
|
82
|
-
name: string;
|
|
83
|
-
source: string;
|
|
84
|
-
}
|
|
85
|
-
/** Discover code tools in `<dir>/tools/`: each `*.ts|.js|.mjs` default-exports a tool, named from its filename. */
|
|
86
|
-
export declare function loadTools(dir: string): Promise<{
|
|
87
|
-
tools: AgentTool[];
|
|
88
|
-
/** What each loaded tool declared it needs, BY TOOL NAME and attributed to the file. Per tool
|
|
89
|
-
* because whether a declaration counts depends on whether that tool ends up MOUNTED — a name
|
|
90
|
-
* shadowed by a coding tool never runs ({@link resolveAgentTools} makes that call). */
|
|
91
|
-
secrets: Map<string, DeclaredSecret[]>;
|
|
92
|
-
collisions: ToolCollision[];
|
|
93
|
-
failures: ModuleLoadFailure[];
|
|
94
|
-
}>;
|
|
95
|
-
/** Merge resolved tools (pi coding tools + `config.tools`) with discovered `tools/`, deduped by name. */
|
|
96
|
-
export declare function mergeDiscoveredTools(existing: MountedTool[], discovered: AgentTool[]): {
|
|
97
|
-
tools: MountedTool[];
|
|
98
|
-
collisions: ToolCollision[];
|
|
99
|
-
};
|