@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
package/dist/engines/pi/tool.js
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
/** Tool authoring: `defineTool` (the authoring surface) and `loadTools` (filesystem discovery). */
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import { assertInsideAgentDir } from "../../paths.js";
|
|
4
|
-
import { z } from "zod";
|
|
5
|
-
import { loadModuleDir } from "../../loader.js";
|
|
6
|
-
import { readSecretDeclaration, secretValues } from "../../declared-secrets.js";
|
|
7
|
-
import { turnContext } from "./tool-context.js";
|
|
8
|
-
/**
|
|
9
|
-
* Ask the provider to constrain sampling to the tool's schema, the posture pi's own built-ins take. `"prefer"`
|
|
10
|
-
* rather than `"require"`: a schema pi cannot express strictly, one using a keyword the provider's strict mode rejects
|
|
11
|
-
* (Anthropic: numeric bounds, which every `z.number().int()` carries), or a provider without strict mode silently
|
|
12
|
-
* falls back to an ordinary function tool instead of failing the turn.
|
|
13
|
-
*
|
|
14
|
-
* Nothing here has to undo pi's strict rewrite. To express "optional" strictly, pi marks every property required and
|
|
15
|
-
* unions the optional ones with `null`, so a constrained model emits `null` where it would have omitted the key — and
|
|
16
|
-
* pi-ai's `validateToolArguments` drops those nulls (`normalizeOptionalNulls`) before `execute` is called. It drops
|
|
17
|
-
* one only where the author's OWN schema rejects null, so any nullable property keeps its `null`, and a
|
|
18
|
-
* `.nullable().optional()` property can no longer distinguish "absent" from "null" — the one place this changes
|
|
19
|
-
* what an author's `execute` receives.
|
|
20
|
-
*/
|
|
21
|
-
const CONSTRAINED_SAMPLING = { type: "json_schema", strict: "prefer" };
|
|
22
|
-
/** Wrap a plain return value into pi's tool-result shape; pass a full result through unchanged. */
|
|
23
|
-
function wrapResult(value, output) {
|
|
24
|
-
if (value && typeof value === "object" && Array.isArray(value.content)) {
|
|
25
|
-
return value;
|
|
26
|
-
}
|
|
27
|
-
const structuredContent = output ? output.parse(value) : undefined;
|
|
28
|
-
const text = typeof value === "string" ? value : JSON.stringify(value ?? null);
|
|
29
|
-
return { content: [{ type: "text", text }], details: value, ...(output ? { structuredContent } : {}) };
|
|
30
|
-
}
|
|
31
|
-
// `S` defaults to the EMPTY tuple, not `readonly string[]`: a tool that declares nothing then gets
|
|
32
|
-
// `ctx.secrets` with no keys, so `ctx.secrets.X_API_KEY` fails to compile instead of type-checking as
|
|
33
|
-
// a `string` that is `undefined` at run time. "A typo is a compile error" has to hold for the tool
|
|
34
|
-
// that forgot to declare, which is the one making the mistake.
|
|
35
|
-
export function defineTool(options) {
|
|
36
|
-
const { $schema: _drop, ...parameters } = z.toJSONSchema(options.input);
|
|
37
|
-
const tool = {
|
|
38
|
-
name: options.name ?? "",
|
|
39
|
-
label: options.name ?? "",
|
|
40
|
-
description: options.description,
|
|
41
|
-
parameters,
|
|
42
|
-
constrainedSampling: CONSTRAINED_SAMPLING,
|
|
43
|
-
...(options.exposure ? { exposure: options.exposure } : {}),
|
|
44
|
-
...(options.defaultActive !== undefined ? { defaultActive: options.defaultActive } : {}),
|
|
45
|
-
...(options.annotations ? { annotations: options.annotations } : {}),
|
|
46
|
-
...(options.namespace ? { namespace: options.namespace } : {}),
|
|
47
|
-
...(options.output ? { outputSchema: z.toJSONSchema(options.output) } : {}),
|
|
48
|
-
...(options.executionMode ? { executionMode: options.executionMode } : {}),
|
|
49
|
-
...(options.secrets?.length ? { secrets: options.secrets } : {}),
|
|
50
|
-
async execute(_toolCallId, rawParams, signal, onUpdate, context) {
|
|
51
|
-
const parsed = options.input.safeParse(rawParams);
|
|
52
|
-
if (!parsed.success) {
|
|
53
|
-
// Validation failure is reported TO THE MODEL (it can correct and retry), not thrown.
|
|
54
|
-
const detail = parsed.error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ");
|
|
55
|
-
return {
|
|
56
|
-
content: [{ type: "text", text: `Invalid arguments: ${detail}` }],
|
|
57
|
-
details: { error: detail },
|
|
58
|
-
isError: true,
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
const store = turnContext.getStore();
|
|
62
|
-
return wrapResult(await options.execute(parsed.data, {
|
|
63
|
-
cwd: store?.cwd ?? process.cwd(),
|
|
64
|
-
signal,
|
|
65
|
-
sessionManager: store?.sessionManager,
|
|
66
|
-
tools: store?.tools,
|
|
67
|
-
// Per CALL, not per turn: pi binds `executeTool` to this call's id, the parent of what it runs.
|
|
68
|
-
executeTool: context?.executeTool,
|
|
69
|
-
onUpdate: onUpdate && ((partial) => onUpdate(wrapResult(partial))),
|
|
70
|
-
secrets: secretValues(options.secrets),
|
|
71
|
-
}), options.output);
|
|
72
|
-
},
|
|
73
|
-
};
|
|
74
|
-
return tool;
|
|
75
|
-
}
|
|
76
|
-
/** Discover code tools in `<dir>/tools/`: each `*.ts|.js|.mjs` default-exports a tool, named from its filename. */
|
|
77
|
-
export async function loadTools(dir) {
|
|
78
|
-
// The same containment guard channels/routines/skills get.
|
|
79
|
-
await assertInsideAgentDir(dir, "tools");
|
|
80
|
-
const { modules, failures } = await loadModuleDir(join(dir, "tools"));
|
|
81
|
-
const byName = new Map();
|
|
82
|
-
const collisions = [];
|
|
83
|
-
const secrets = new Map();
|
|
84
|
-
for (const { name, label, file, mod } of modules) {
|
|
85
|
-
const tool = mod.default;
|
|
86
|
-
if (!tool || typeof tool.execute !== "function") {
|
|
87
|
-
failures.push({ label, file, message: `${label} must default-export defineTool({...})` });
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
const declaration = readSecretDeclaration(tool, label);
|
|
91
|
-
if (declaration.error !== undefined) {
|
|
92
|
-
failures.push({ label, file, message: declaration.error });
|
|
93
|
-
continue;
|
|
94
|
-
}
|
|
95
|
-
if (byName.has(name)) {
|
|
96
|
-
collisions.push({ name, source: label });
|
|
97
|
-
continue;
|
|
98
|
-
}
|
|
99
|
-
byName.set(name, { ...tool, name });
|
|
100
|
-
secrets.set(name, declaration.secrets);
|
|
101
|
-
}
|
|
102
|
-
return { tools: [...byName.values()], secrets, collisions, failures };
|
|
103
|
-
}
|
|
104
|
-
/** Merge resolved tools (pi coding tools + `config.tools`) with discovered `tools/`, deduped by name. */
|
|
105
|
-
export function mergeDiscoveredTools(existing, discovered) {
|
|
106
|
-
const names = new Set(existing.map((t) => t.name));
|
|
107
|
-
const tools = [...existing];
|
|
108
|
-
const collisions = [];
|
|
109
|
-
for (const tool of discovered) {
|
|
110
|
-
if (names.has(tool.name)) {
|
|
111
|
-
collisions.push({ name: tool.name, source: `tools/${tool.name}` });
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
names.add(tool.name);
|
|
115
|
-
tools.push(tool);
|
|
116
|
-
}
|
|
117
|
-
return { tools, collisions };
|
|
118
|
-
}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { type AssistantMessage, type ImageContent, type ToolResultMessage } from "@earendil-works/pi-ai";
|
|
2
|
-
import { type AgentEvent, type Prompt } from "../../agent.ts";
|
|
3
|
-
import type { AnswerOutcome, PromptDisposition, SessionEvent } from "../../session.ts";
|
|
4
|
-
export type Release = () => void;
|
|
5
|
-
export interface Lease {
|
|
6
|
-
/** Try to acquire exclusive write access for the session (fail-fast). */
|
|
7
|
-
tryAcquire(session: string): Release | null;
|
|
8
|
-
}
|
|
9
|
-
export declare function inProcessLease(): Lease;
|
|
10
|
-
/** Classify `retryable`: structured status/code first, message prose only as the last-resort ceiling. */
|
|
11
|
-
export declare function classifyRetryable(details: string, signal: {
|
|
12
|
-
status?: number;
|
|
13
|
-
code?: unknown;
|
|
14
|
-
}): boolean;
|
|
15
|
-
/**
|
|
16
|
-
* How an answer ended, read off the stopReason pi records on the message. The ONE reading: `message_finished`,
|
|
17
|
-
* the `assistant` entry `entries()` publishes, and the invoke terminal all derive from it, so the live outcome and
|
|
18
|
-
* the recorded one cannot disagree.
|
|
19
|
-
*/
|
|
20
|
-
export declare function answerOutcome(message: AssistantMessage): AnswerOutcome | undefined;
|
|
21
|
-
/**
|
|
22
|
-
* An answer that failed while its run's abort was in effect, as what it was: aborted. Undefined when that is not the
|
|
23
|
-
* case (no abort, or not a failure). pi's own reading is `signal.aborted ? "aborted" : "error"` (`handleRunFailure`,
|
|
24
|
-
* the providers), but its request-setup path (`lazyStream`: auth, request preparation) writes "error" whatever the
|
|
25
|
-
* signal (pi 0.99.2). A run stopped during a tool lands there: the loop asks the model once more, and the setup throws
|
|
26
|
-
* the abort. Recorded this way, the answer's {@link answerOutcome} is the `aborted` the run settled with, live and read
|
|
27
|
-
* back. A failure recorded BEFORE the abort (a provider error whose retry was then stopped) stays as recorded.
|
|
28
|
-
*/
|
|
29
|
-
export declare function abortedAnswer(message: AssistantMessage, runSignal: AbortSignal | undefined): AssistantMessage | undefined;
|
|
30
|
-
/**
|
|
31
|
-
* An answer's recorded thinking: its published thinking blocks, in order, joined with nothing between them, exactly as
|
|
32
|
-
* their live deltas add up (the stream marks no block boundary, and the answer's `text` is joined the same way).
|
|
33
|
-
* Undefined when it has none.
|
|
34
|
-
*/
|
|
35
|
-
export declare function answerThinking(message: AssistantMessage): string | undefined;
|
|
36
|
-
/** Whether a live thinking delta is streamed: the block it extends is one {@link answerThinking} will publish. */
|
|
37
|
-
export declare function streamsThinkingDelta(event: {
|
|
38
|
-
contentIndex: number;
|
|
39
|
-
partial: AssistantMessage;
|
|
40
|
-
}): boolean;
|
|
41
|
-
/**
|
|
42
|
-
* Whether a finished tool call asked to end its run (pi's `terminate`: returned by the tool, or set by a `tool_call`
|
|
43
|
-
* hook that blocks it; pi 0.99.2's `tool_result` hook cannot set it). After a batch whose EVERY result asks it, pi
|
|
44
|
-
* makes no further model call for that batch, so unless a queued steer or follow-up continues the run, it completes on
|
|
45
|
-
* `tool` entries with no answer after them: the same shape a process killed after its tools leaves. A call made from
|
|
46
|
-
* inside another tool (`parentToolCallId`, a codemode script) is not in the batch and does not count.
|
|
47
|
-
* The ONE reading: the live `tool_finished` and the flag {@link markEndsRun} records both come from it.
|
|
48
|
-
*/
|
|
49
|
-
export declare function asksToEndRun(event: {
|
|
50
|
-
result?: unknown;
|
|
51
|
-
parentToolCallId?: string;
|
|
52
|
-
}): boolean;
|
|
53
|
-
/**
|
|
54
|
-
* The tool result message as pi then records it, carrying the request: pi's `createToolResultMessage` drops
|
|
55
|
-
* `terminate` (as of pi 0.99.2), so without this nothing in the record says the run ended on purpose.
|
|
56
|
-
*/
|
|
57
|
-
export declare function markEndsRun(message: ToolResultMessage): ToolResultMessage;
|
|
58
|
-
/** Whether a recorded tool result carries {@link markEndsRun}'s flag. */
|
|
59
|
-
export declare function endsRun(message: ToolResultMessage): boolean;
|
|
60
|
-
/**
|
|
61
|
-
* Terminal mapping, decided by the resolved message's outcome: pi's `prompt()` RESOLVES a message with stopReason
|
|
62
|
-
* "error"/"aborted" rather than throwing, so relying on catch alone would miss that whole failure class and violate
|
|
63
|
-
* SPEC MUST 1. A truncated final answer still completes the run.
|
|
64
|
-
*/
|
|
65
|
-
export declare function toTerminal(message: AssistantMessage): AgentEvent;
|
|
66
|
-
export declare function errorToTerminal(error: unknown): Extract<AgentEvent, {
|
|
67
|
-
type: "failed";
|
|
68
|
-
}>;
|
|
69
|
-
/**
|
|
70
|
-
* Map prompt images to pi ImageContent. `prompt()` normalizes its images itself, with the bound model's resize
|
|
71
|
-
* profile (`inputLimits.images.resize`) and format conversion, so a `"prompt"` delivery hands them over as-is.
|
|
72
|
-
* `steer`/`followUp` do not, so a `"queued"` delivery resizes here with pi's default profile: the model is not known
|
|
73
|
-
* yet when a queued message is prepared. pi's resizer is lazy-imported so the no-image path never loads its module
|
|
74
|
-
* graph.
|
|
75
|
-
*/
|
|
76
|
-
export declare function toPiPromptOptions(prompt: Prompt, delivery: "prompt" | "queued"): Promise<{
|
|
77
|
-
images?: ImageContent[];
|
|
78
|
-
} | undefined>;
|
|
79
|
-
/** Live modulation handles for one active run — what the control plane's `dispatch` routes to. */
|
|
80
|
-
export interface RunControls {
|
|
81
|
-
steer(prompt: Prompt): Promise<PromptDisposition>;
|
|
82
|
-
followUp(prompt: Prompt): Promise<PromptDisposition>;
|
|
83
|
-
abort(): Promise<void>;
|
|
84
|
-
}
|
|
85
|
-
/** The DATA-plane observation seam: every rich event of every run, pushed as it happens. */
|
|
86
|
-
export type SessionObserver = (session: string, event: SessionEvent, run?: RunControls) => void;
|
|
87
|
-
/**
|
|
88
|
-
* The SPEC projection of ONE run's rich stream. Stateful only for `tool_progress`, the one event that is a status
|
|
89
|
-
* rather than a fact: an outer call's status line is sent when it changes, and a call that call makes, at any depth,
|
|
90
|
-
* is its status. Nested calls are otherwise the observation plane's alone.
|
|
91
|
-
*/
|
|
92
|
-
export declare function agentEventProjection(): (se: SessionEvent) => AgentEvent | null;
|
|
@@ -1,288 +0,0 @@
|
|
|
1
|
-
/** The turn mechanism's ENGINE-agnostic half: the parts that describe a turn rather than pi. */
|
|
2
|
-
import { stripVTControlCharacters } from "node:util";
|
|
3
|
-
import { contentText, } from "@earendil-works/pi-ai";
|
|
4
|
-
import { ABORTED_CODE } from "../../agent.js";
|
|
5
|
-
import { log } from "../../log.js";
|
|
6
|
-
export function inProcessLease() {
|
|
7
|
-
const busy = new Set();
|
|
8
|
-
return {
|
|
9
|
-
tryAcquire(session) {
|
|
10
|
-
if (busy.has(session))
|
|
11
|
-
return null;
|
|
12
|
-
busy.add(session);
|
|
13
|
-
let released = false;
|
|
14
|
-
return () => {
|
|
15
|
-
if (released)
|
|
16
|
-
return;
|
|
17
|
-
released = true;
|
|
18
|
-
busy.delete(session);
|
|
19
|
-
};
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
/** Clearly-transient network error codes (Node/undici), decisive on their own. */
|
|
24
|
-
const RETRYABLE_CODES = new Set([
|
|
25
|
-
"ECONNRESET",
|
|
26
|
-
"ETIMEDOUT",
|
|
27
|
-
"ENETUNREACH",
|
|
28
|
-
"ENETDOWN",
|
|
29
|
-
"EAI_AGAIN",
|
|
30
|
-
"EPIPE",
|
|
31
|
-
"UND_ERR_CONNECT_TIMEOUT",
|
|
32
|
-
"UND_ERR_SOCKET",
|
|
33
|
-
]);
|
|
34
|
-
/** 429 (rate limit) and 5xx (server) are worth retrying; other statuses are decisive NON-retryable. */
|
|
35
|
-
const statusIsRetryable = (status) => status === 429 || (status >= 500 && status < 600);
|
|
36
|
-
/** Last-resort prose match, used only when no structured status/code is available. */
|
|
37
|
-
const RETRYABLE_MESSAGE = /\b(429|5\d\d|timeout|timed out|rate.?limit|overloaded|ECONNRESET|ETIMEDOUT|ENETUNREACH|EAI_AGAIN|socket hang up)\b/i;
|
|
38
|
-
/** A structured status/code decision, or `null` when the signal is absent/undecisive → fall to prose. */
|
|
39
|
-
function retryableFromSignal(signal) {
|
|
40
|
-
if (typeof signal.status === "number")
|
|
41
|
-
return statusIsRetryable(signal.status);
|
|
42
|
-
const { code } = signal;
|
|
43
|
-
if (typeof code === "number")
|
|
44
|
-
return statusIsRetryable(code);
|
|
45
|
-
if (typeof code === "string") {
|
|
46
|
-
if (RETRYABLE_CODES.has(code))
|
|
47
|
-
return true;
|
|
48
|
-
if (/^\d{3}$/.test(code))
|
|
49
|
-
return statusIsRetryable(Number(code)); // a status carried as a string
|
|
50
|
-
}
|
|
51
|
-
return null; // no code, or an unknown one — not decisive on its own
|
|
52
|
-
}
|
|
53
|
-
/** Classify `retryable`: structured status/code first, message prose only as the last-resort ceiling. */
|
|
54
|
-
export function classifyRetryable(details, signal) {
|
|
55
|
-
return retryableFromSignal(signal) ?? RETRYABLE_MESSAGE.test(details);
|
|
56
|
-
}
|
|
57
|
-
/** Pull a structured status/code off a thrown error (HTTP status or a network code, incl. its cause). */
|
|
58
|
-
function errorSignal(error) {
|
|
59
|
-
if (!error || typeof error !== "object")
|
|
60
|
-
return {};
|
|
61
|
-
const e = error;
|
|
62
|
-
const status = typeof e.status === "number" ? e.status : typeof e.statusCode === "number" ? e.statusCode : undefined;
|
|
63
|
-
const causeCode = e.cause && typeof e.cause === "object" ? e.cause.code : undefined;
|
|
64
|
-
return { status, code: e.code ?? causeCode };
|
|
65
|
-
}
|
|
66
|
-
/** Pull the structured error `code` pi records on a failed message's diagnostics. */
|
|
67
|
-
function messageSignal(message) {
|
|
68
|
-
const diagnostics = message.diagnostics ?? [];
|
|
69
|
-
for (let i = diagnostics.length - 1; i >= 0; i--) {
|
|
70
|
-
const code = diagnostics[i]?.error?.code;
|
|
71
|
-
if (code !== undefined)
|
|
72
|
-
return { code };
|
|
73
|
-
}
|
|
74
|
-
return {};
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* How an answer ended, read off the stopReason pi records on the message. The ONE reading: `message_finished`,
|
|
78
|
-
* the `assistant` entry `entries()` publishes, and the invoke terminal all derive from it, so the live outcome and
|
|
79
|
-
* the recorded one cannot disagree.
|
|
80
|
-
*/
|
|
81
|
-
export function answerOutcome(message) {
|
|
82
|
-
const error = message.errorMessage ? { error: { message: message.errorMessage } } : {};
|
|
83
|
-
switch (message.stopReason) {
|
|
84
|
-
case "error":
|
|
85
|
-
return { status: "failed", ...error };
|
|
86
|
-
case "aborted":
|
|
87
|
-
return { status: "aborted", ...error };
|
|
88
|
-
case "length":
|
|
89
|
-
return { status: "truncated" };
|
|
90
|
-
default:
|
|
91
|
-
return undefined;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* An answer that failed while its run's abort was in effect, as what it was: aborted. Undefined when that is not the
|
|
96
|
-
* case (no abort, or not a failure). pi's own reading is `signal.aborted ? "aborted" : "error"` (`handleRunFailure`,
|
|
97
|
-
* the providers), but its request-setup path (`lazyStream`: auth, request preparation) writes "error" whatever the
|
|
98
|
-
* signal (pi 0.99.2). A run stopped during a tool lands there: the loop asks the model once more, and the setup throws
|
|
99
|
-
* the abort. Recorded this way, the answer's {@link answerOutcome} is the `aborted` the run settled with, live and read
|
|
100
|
-
* back. A failure recorded BEFORE the abort (a provider error whose retry was then stopped) stays as recorded.
|
|
101
|
-
*/
|
|
102
|
-
export function abortedAnswer(message, runSignal) {
|
|
103
|
-
return message.stopReason === "error" && runSignal?.aborted === true
|
|
104
|
-
? { ...message, stopReason: "aborted" }
|
|
105
|
-
: undefined;
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Whether a thinking block is PUBLISHED: readable reasoning. A redacted one holds a provider's opaque payload and a
|
|
109
|
-
* placeholder (pi writes "[Reasoning redacted]" for it), not reasoning anyone can read, so it is neither streamed nor
|
|
110
|
-
* read back. The ONE rule: the live `message_delta { channel: "thinking" }` ({@link streamsThinkingDelta}) and the
|
|
111
|
-
* `assistant` entry's `thinking` ({@link answerThinking}) both apply it, so a client reads the same text either way.
|
|
112
|
-
*
|
|
113
|
-
* One exception, by when the flag is read: live reads it as each delta arrives, the record as the answer ended. pi's
|
|
114
|
-
* Bedrock path flags a block redacted when its first encrypted chunk arrives, and its readable text and its encrypted
|
|
115
|
-
* chunks are separate fields, so a block that streamed readable text BEFORE turning redacted had that text streamed
|
|
116
|
-
* and is then not read back. Not separable after the fact: the record keeps one flag and one string per block, with
|
|
117
|
-
* pi's placeholder appended. Whether a Bedrock model sends both in one block is unverified.
|
|
118
|
-
*/
|
|
119
|
-
function isPublishedThinking(block) {
|
|
120
|
-
return block?.type === "thinking" && block.redacted !== true;
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* An answer's recorded thinking: its published thinking blocks, in order, joined with nothing between them, exactly as
|
|
124
|
-
* their live deltas add up (the stream marks no block boundary, and the answer's `text` is joined the same way).
|
|
125
|
-
* Undefined when it has none.
|
|
126
|
-
*/
|
|
127
|
-
export function answerThinking(message) {
|
|
128
|
-
const text = message.content
|
|
129
|
-
.filter(isPublishedThinking)
|
|
130
|
-
.map((block) => block.thinking)
|
|
131
|
-
.join("");
|
|
132
|
-
return text === "" ? undefined : text;
|
|
133
|
-
}
|
|
134
|
-
/** Whether a live thinking delta is streamed: the block it extends is one {@link answerThinking} will publish. */
|
|
135
|
-
export function streamsThinkingDelta(event) {
|
|
136
|
-
return isPublishedThinking(event.partial.content[event.contentIndex]);
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* Whether a finished tool call asked to end its run (pi's `terminate`: returned by the tool, or set by a `tool_call`
|
|
140
|
-
* hook that blocks it; pi 0.99.2's `tool_result` hook cannot set it). After a batch whose EVERY result asks it, pi
|
|
141
|
-
* makes no further model call for that batch, so unless a queued steer or follow-up continues the run, it completes on
|
|
142
|
-
* `tool` entries with no answer after them: the same shape a process killed after its tools leaves. A call made from
|
|
143
|
-
* inside another tool (`parentToolCallId`, a codemode script) is not in the batch and does not count.
|
|
144
|
-
* The ONE reading: the live `tool_finished` and the flag {@link markEndsRun} records both come from it.
|
|
145
|
-
*/
|
|
146
|
-
export function asksToEndRun(event) {
|
|
147
|
-
return !event.parentToolCallId && event.result?.terminate === true;
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* The tool result message as pi then records it, carrying the request: pi's `createToolResultMessage` drops
|
|
151
|
-
* `terminate` (as of pi 0.99.2), so without this nothing in the record says the run ended on purpose.
|
|
152
|
-
*/
|
|
153
|
-
export function markEndsRun(message) {
|
|
154
|
-
return { ...message, terminate: true };
|
|
155
|
-
}
|
|
156
|
-
/** Whether a recorded tool result carries {@link markEndsRun}'s flag. */
|
|
157
|
-
export function endsRun(message) {
|
|
158
|
-
return message.terminate === true;
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* Terminal mapping, decided by the resolved message's outcome: pi's `prompt()` RESOLVES a message with stopReason
|
|
162
|
-
* "error"/"aborted" rather than throwing, so relying on catch alone would miss that whole failure class and violate
|
|
163
|
-
* SPEC MUST 1. A truncated final answer still completes the run.
|
|
164
|
-
*/
|
|
165
|
-
export function toTerminal(message) {
|
|
166
|
-
const outcome = answerOutcome(message);
|
|
167
|
-
if (outcome?.status === "aborted") {
|
|
168
|
-
// A deliberate stop (a control-plane or consumer abort), not an error — see {@link ABORTED_CODE} for the consumer
|
|
169
|
-
// contract (design §6).
|
|
170
|
-
const details = outcome.error?.message ?? "run aborted";
|
|
171
|
-
return { type: "failed", details, retryable: false, code: ABORTED_CODE };
|
|
172
|
-
}
|
|
173
|
-
if (outcome?.status === "failed") {
|
|
174
|
-
const details = outcome.error?.message ?? "model stopped: error";
|
|
175
|
-
return { type: "failed", details, retryable: classifyRetryable(details, messageSignal(message)) };
|
|
176
|
-
}
|
|
177
|
-
return { type: "completed" };
|
|
178
|
-
}
|
|
179
|
-
export function errorToTerminal(error) {
|
|
180
|
-
const details = error instanceof Error ? error.message : String(error);
|
|
181
|
-
return { type: "failed", details, retryable: classifyRetryable(details, errorSignal(error)) };
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* Map prompt images to pi ImageContent. `prompt()` normalizes its images itself, with the bound model's resize
|
|
185
|
-
* profile (`inputLimits.images.resize`) and format conversion, so a `"prompt"` delivery hands them over as-is.
|
|
186
|
-
* `steer`/`followUp` do not, so a `"queued"` delivery resizes here with pi's default profile: the model is not known
|
|
187
|
-
* yet when a queued message is prepared. pi's resizer is lazy-imported so the no-image path never loads its module
|
|
188
|
-
* graph.
|
|
189
|
-
*/
|
|
190
|
-
export async function toPiPromptOptions(prompt, delivery) {
|
|
191
|
-
if (!prompt.images || prompt.images.length === 0)
|
|
192
|
-
return undefined;
|
|
193
|
-
if (delivery === "prompt") {
|
|
194
|
-
return { images: prompt.images.map((img) => ({ type: "image", data: img.data, mimeType: img.mimeType })) };
|
|
195
|
-
}
|
|
196
|
-
const { resizeImage } = await import("@earendil-works/pi-coding-agent");
|
|
197
|
-
const images = await Promise.all(prompt.images.map(async (img, i) => {
|
|
198
|
-
const resized = await resizeImage(Buffer.from(img.data, "base64"), img.mimeType);
|
|
199
|
-
if (resized)
|
|
200
|
-
return { type: "image", data: resized.data, mimeType: resized.mimeType };
|
|
201
|
-
// `null` covers an image it cannot decode or shrink under the limit AND an image backend that did not load,
|
|
202
|
-
// and does not say which. pi's own tool-result path keeps the original in that case rather than drop what the
|
|
203
|
-
// sender attached, and so does this; a provider that refuses it fails the turn with its own message.
|
|
204
|
-
log.warn(`[fastagent] queued image ${i + 1} (${img.mimeType}) could not be resized; sending it as given — ` +
|
|
205
|
-
"the provider may refuse it");
|
|
206
|
-
return { type: "image", data: img.data, mimeType: img.mimeType };
|
|
207
|
-
}));
|
|
208
|
-
return { images };
|
|
209
|
-
}
|
|
210
|
-
/**
|
|
211
|
-
* The SPEC projection of ONE run's rich stream. Stateful only for `tool_progress`, the one event that is a status
|
|
212
|
-
* rather than a fact: an outer call's status line is sent when it changes, and a call that call makes, at any depth,
|
|
213
|
-
* is its status. Nested calls are otherwise the observation plane's alone.
|
|
214
|
-
*/
|
|
215
|
-
export function agentEventProjection() {
|
|
216
|
-
/** Each nested call's outer call, the one the stream announced with `tool_started`. */
|
|
217
|
-
const outerOf = new Map();
|
|
218
|
-
/** The status line each outer call last reported. */
|
|
219
|
-
const shown = new Map();
|
|
220
|
-
const progress = (id, text) => {
|
|
221
|
-
if (text === undefined || shown.get(id) === text)
|
|
222
|
-
return null;
|
|
223
|
-
shown.set(id, text);
|
|
224
|
-
return { type: "tool_progress", id, text };
|
|
225
|
-
};
|
|
226
|
-
return (se) => {
|
|
227
|
-
switch (se.type) {
|
|
228
|
-
case "message_delta": {
|
|
229
|
-
const d = se.data;
|
|
230
|
-
return d.channel === "text" ? { type: "text", delta: d.delta } : { type: "thinking", delta: d.delta };
|
|
231
|
-
}
|
|
232
|
-
case "tool_started": {
|
|
233
|
-
const d = se.data;
|
|
234
|
-
if (!d.parentToolCallId)
|
|
235
|
-
return { type: "tool_started", id: d.id, name: d.name, args: d.args };
|
|
236
|
-
const outer = outerOf.get(d.parentToolCallId) ?? d.parentToolCallId;
|
|
237
|
-
outerOf.set(d.id, outer);
|
|
238
|
-
return progress(outer, callLine(d.name, d.args));
|
|
239
|
-
}
|
|
240
|
-
case "tool_progress": {
|
|
241
|
-
const d = se.data;
|
|
242
|
-
// A nested call's own output is not its caller's status; the nested call starting is (above).
|
|
243
|
-
if (d.parentToolCallId || !Array.isArray(d.partialResult.content))
|
|
244
|
-
return null;
|
|
245
|
-
return progress(d.id, lastLine(contentText(d.partialResult.content, "\n")));
|
|
246
|
-
}
|
|
247
|
-
case "tool_finished": {
|
|
248
|
-
const d = se.data;
|
|
249
|
-
if (d.parentToolCallId)
|
|
250
|
-
return null;
|
|
251
|
-
return { type: "tool_ended", id: d.id, isError: d.isError, content: d.content };
|
|
252
|
-
}
|
|
253
|
-
case "retry_scheduled": {
|
|
254
|
-
// `operation` (compaction | branch_summary) stays session-plane vocabulary.
|
|
255
|
-
const d = se.data;
|
|
256
|
-
return {
|
|
257
|
-
type: "retrying",
|
|
258
|
-
attempt: d.attempt,
|
|
259
|
-
maxAttempts: d.maxAttempts,
|
|
260
|
-
delayMs: d.delayMs,
|
|
261
|
-
reason: d.error,
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
default:
|
|
265
|
-
return null;
|
|
266
|
-
}
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
/**
|
|
270
|
-
* The line a terminal shows last: control sequences removed, and a bare `\r`, a progress bar redrawing in place, ends a
|
|
271
|
-
* line like `\n` does. Undefined when there is no visible text yet (a shell that has printed nothing).
|
|
272
|
-
*/
|
|
273
|
-
function lastLine(text) {
|
|
274
|
-
const lines = stripVTControlCharacters(text).split(/\r\n|\r|\n/);
|
|
275
|
-
for (let i = lines.length - 1; i >= 0; i--) {
|
|
276
|
-
const line = lines[i]?.trim();
|
|
277
|
-
if (line)
|
|
278
|
-
return line;
|
|
279
|
-
}
|
|
280
|
-
return undefined;
|
|
281
|
-
}
|
|
282
|
-
/** A nested call as its caller's status: the tool and its first plain argument, on one line (`weather London`). */
|
|
283
|
-
function callLine(name, args) {
|
|
284
|
-
const first = args !== null && typeof args === "object" && !Array.isArray(args)
|
|
285
|
-
? Object.values(args).find((value) => typeof value === "string" || typeof value === "number")
|
|
286
|
-
: undefined;
|
|
287
|
-
return first === undefined ? name : `${name} ${String(first).replace(/\s+/g, " ").trim()}`.trim();
|
|
288
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { type MountedTool } from "./tool.ts";
|
|
2
|
-
/**
|
|
3
|
-
* Parse a delay to milliseconds: a number is SECONDS; a string MUST carry a unit — `"<n><s|m|h|d>"` ("30m", "2h",
|
|
4
|
-
* "1d").
|
|
5
|
-
*/
|
|
6
|
-
export declare function parseDelayMs(input: string | number): number | undefined;
|
|
7
|
-
export declare function withWakeTool(tools: MountedTool[], stateRoot: string, enabled: boolean): MountedTool[];
|
|
8
|
-
/** Build the `wake` tool bound to `stateRoot` (where wake-ups persist). */
|
|
9
|
-
export declare function makeWakeTool(stateRoot: string, now?: () => Date): MountedTool;
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
/** The built-in `wake` tool: the agent's self-scheduling surface. */
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
import { addWakeup, removeWakeup } from "../../schedule/wakeups.js";
|
|
4
|
-
import { defineTool } from "./tool.js";
|
|
5
|
-
/**
|
|
6
|
-
* Parse a delay to milliseconds: a number is SECONDS; a string MUST carry a unit — `"<n><s|m|h|d>"` ("30m", "2h",
|
|
7
|
-
* "1d").
|
|
8
|
-
*/
|
|
9
|
-
export function parseDelayMs(input) {
|
|
10
|
-
if (typeof input === "number")
|
|
11
|
-
return Number.isFinite(input) && input > 0 ? input * 1000 : undefined;
|
|
12
|
-
const m = input.trim().match(/^(\d+(?:\.\d+)?)\s*(s|m|h|d)$/i); // unit REQUIRED on a string
|
|
13
|
-
if (!m)
|
|
14
|
-
return undefined;
|
|
15
|
-
const mult = { s: 1_000, m: 60_000, h: 3_600_000, d: 86_400_000 }[m[2].toLowerCase()];
|
|
16
|
-
return Number(m[1]) * mult;
|
|
17
|
-
}
|
|
18
|
-
export function withWakeTool(tools, stateRoot, enabled) {
|
|
19
|
-
if (!enabled)
|
|
20
|
-
return tools;
|
|
21
|
-
// wake/unwake are a PAIR over one store: if the workspace defines EITHER name, mount NEITHER built-in.
|
|
22
|
-
if (tools.some((t) => t.name === "wake" || t.name === "unwake"))
|
|
23
|
-
return tools;
|
|
24
|
-
return [...tools, makeWakeTool(stateRoot), makeUnwakeTool(stateRoot)];
|
|
25
|
-
}
|
|
26
|
-
/** Build the `wake` tool bound to `stateRoot` (where wake-ups persist). */
|
|
27
|
-
export function makeWakeTool(stateRoot, now = () => new Date()) {
|
|
28
|
-
return defineTool({
|
|
29
|
-
name: "wake",
|
|
30
|
-
description: "Schedule yourself to wake up later and continue in THIS conversation. ONE-SHOT: pass `in` — a " +
|
|
31
|
-
'duration string with a unit ("30m", "2h", "1d") or a number of seconds — to resume a task after a ' +
|
|
32
|
-
"delay. RECURRING: pass `cron` (5-field, optional `tz`) to wake repeatedly — use sparingly, and " +
|
|
33
|
-
"`unwake` with the returned id when the job is done. Exactly one of `in`/`cron`. When the time " +
|
|
34
|
-
"comes, a new turn runs in this same session with `prompt` as its instruction (tagged with the wake-up's " +
|
|
35
|
-
"id so you can tell it from a user message) — you keep the full context of this conversation. IMPORTANT: the woken turn's plain reply is NOT delivered to anyone — " +
|
|
36
|
-
"to reach the user it must call a delivery tool (e.g. a channel's send tool), exactly as a scheduled " +
|
|
37
|
-
"job would.",
|
|
38
|
-
input: z.object({
|
|
39
|
-
in: z
|
|
40
|
-
.union([z.string(), z.number()])
|
|
41
|
-
.optional()
|
|
42
|
-
.describe('one-shot delay: a duration string with a unit ("30m" / "2h" / "1d"), or a number of seconds'),
|
|
43
|
-
cron: z.string().optional().describe('recurring: a 5-field cron expression (e.g. "0 9 * * *")'),
|
|
44
|
-
tz: z.string().optional().describe('IANA timezone for `cron` (default "UTC")'),
|
|
45
|
-
prompt: z.string().min(1).describe("the instruction for the woken turn (runs in this same conversation)"),
|
|
46
|
-
}),
|
|
47
|
-
execute(input, ctx) {
|
|
48
|
-
const session = ctx.sessionManager?.getSessionId();
|
|
49
|
-
if (!session)
|
|
50
|
-
return "wake is only available inside a conversation (there is no session to resume).";
|
|
51
|
-
if ((input.in === undefined) === (input.cron === undefined)) {
|
|
52
|
-
return "pass exactly one of `in` (one-shot) or `cron` (recurring).";
|
|
53
|
-
}
|
|
54
|
-
if (input.cron !== undefined) {
|
|
55
|
-
// addWakeup validates the cron and DERIVES the first instant itself — one computation, one truth.
|
|
56
|
-
const r = addWakeup(stateRoot, { session, prompt: input.prompt, cron: input.cron, tz: input.tz }, now());
|
|
57
|
-
if (!r.ok)
|
|
58
|
-
return r.error; // guardrail message the model can act on
|
|
59
|
-
return `OK — recurring wake ${r.id} (cron "${input.cron}"${input.tz ? ` ${input.tz}` : ""}), first at ${r.fireAt}: ${input.prompt}. Use unwake({ id: "${r.id}" }) to stop it.`;
|
|
60
|
-
}
|
|
61
|
-
const ms = parseDelayMs(input.in);
|
|
62
|
-
if (ms === undefined) {
|
|
63
|
-
return `couldn't parse "in" (${JSON.stringify(input.in)}) — use a unit like "30m" / "2h" / "1d", or a number of seconds (a bare number as text like "120" is rejected).`;
|
|
64
|
-
}
|
|
65
|
-
const at = new Date(now().getTime() + ms);
|
|
66
|
-
const r = addWakeup(stateRoot, { session, prompt: input.prompt, fireAt: at }, now());
|
|
67
|
-
if (!r.ok)
|
|
68
|
-
return r.error; // guardrail message the model can act on
|
|
69
|
-
return `OK — I'll wake up at ${r.fireAt} (id ${r.id}) to: ${input.prompt}. Use unwake({ id: "${r.id}" }) if it becomes unnecessary.`;
|
|
70
|
-
},
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Build the `unwake` tool: cancel one of THIS conversation's pending wake-ups by id (a wake/recurring that is no
|
|
75
|
-
* longer needed).
|
|
76
|
-
*/
|
|
77
|
-
function makeUnwakeTool(stateRoot) {
|
|
78
|
-
return defineTool({
|
|
79
|
-
name: "unwake",
|
|
80
|
-
description: "Cancel one of YOUR pending wake-ups (one-shot or recurring) by the id `wake` returned. Use it when " +
|
|
81
|
-
"a scheduled follow-up is no longer needed — especially to stop a recurring wake once its job is done.",
|
|
82
|
-
input: z.object({ id: z.string().min(1).describe("the wake-up id (returned by `wake`)") }),
|
|
83
|
-
execute(input, ctx) {
|
|
84
|
-
const session = ctx.sessionManager?.getSessionId();
|
|
85
|
-
if (!session)
|
|
86
|
-
return "unwake is only available inside a conversation.";
|
|
87
|
-
return removeWakeup(stateRoot, input.id, session)
|
|
88
|
-
? `OK — wake-up ${input.id} cancelled.`
|
|
89
|
-
: `no pending wake-up ${input.id} in this conversation (already fired, or not yours).`;
|
|
90
|
-
},
|
|
91
|
-
});
|
|
92
|
-
}
|
package/dist/loader.d.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
export interface DiscoveredModule {
|
|
2
|
-
/** Basename without extension — the authoritative name for tools/channels. */
|
|
3
|
-
name: string;
|
|
4
|
-
/** "tools/foo.ts"-style label for errors and collisions. */
|
|
5
|
-
label: string;
|
|
6
|
-
file: string;
|
|
7
|
-
mod: {
|
|
8
|
-
default?: unknown;
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
/** An agent module that failed to load, surfaced as data so its caller can report the exact file. */
|
|
12
|
-
export interface ModuleLoadFailure {
|
|
13
|
-
/** "tools/foo.ts"-style label. */
|
|
14
|
-
label: string;
|
|
15
|
-
file: string;
|
|
16
|
-
/** The failure message (an import error carries {@link moduleLoadHint}). */
|
|
17
|
-
message: string;
|
|
18
|
-
}
|
|
19
|
-
/** A module the loader skipped, said once, the same way for tools, channels and routines. */
|
|
20
|
-
export declare function reportModuleLoadFailures(failures: readonly ModuleLoadFailure[]): void;
|
|
21
|
-
/**
|
|
22
|
-
* THE REFUSAL every path that is about to RUN the agent shares: an enabled file under `tools/`, `channels/` or
|
|
23
|
-
* `routines/` is a declaration, so one that cannot load means the agent is missing something its author said it
|
|
24
|
-
* has. Starting anyway announces a ready service over an absent capability — a schedule that never fires, a tool the
|
|
25
|
-
* model simply never gets — with nothing but one warning to find it by. Every failure is reported before this
|
|
26
|
-
* throws, so a boot fixes all of them at once rather than one per restart.
|
|
27
|
-
*
|
|
28
|
-
* Inspecting a definition (`info`, `fastagent tool`) is NOT this path: it must survive a broken file in order to
|
|
29
|
-
* report it.
|
|
30
|
-
*/
|
|
31
|
-
export declare function refuseBrokenDeclarations(failures: readonly ModuleLoadFailure[]): void;
|
|
32
|
-
/** Import every module the directory declares ({@link moduleInventory}). */
|
|
33
|
-
export declare function loadModuleDir(subDir: string): Promise<{
|
|
34
|
-
modules: DiscoveredModule[];
|
|
35
|
-
failures: ModuleLoadFailure[];
|
|
36
|
-
}>;
|
|
37
|
-
/**
|
|
38
|
-
* A hint for the two common dynamic-import failures — an uninstalled dependency or a non-ESM package — and empty
|
|
39
|
-
* otherwise, so an unrelated error is reported on its own.
|
|
40
|
-
*/
|
|
41
|
-
export declare function moduleLoadHint(error: NodeJS.ErrnoException): string;
|