@fastagent-sh/fastagent 0.24.3 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -82
- package/dist/agent-api.d.ts +452 -0
- package/dist/agent-api.js +201 -0
- package/dist/answer-text.d.ts +8 -0
- package/dist/answer-text.js +18 -0
- package/dist/atomic-write.d.ts +2 -2
- package/dist/atomic-write.js +2 -2
- package/dist/authoring.d.ts +77 -0
- package/dist/authoring.js +238 -0
- package/dist/channel.d.ts +29 -15
- package/dist/channel.js +4 -1
- package/dist/channels/agentcore-protocol.d.ts +36 -50
- package/dist/channels/agentcore-protocol.js +3 -3
- package/dist/channels/agentcore-service.d.ts +8 -18
- package/dist/channels/agentcore-service.js +108 -127
- package/dist/channels/agentcore.d.ts +8 -24
- package/dist/channels/agentcore.js +32 -65
- package/dist/channels/body.d.ts +0 -16
- package/dist/channels/body.js +0 -25
- package/dist/channels/busy.js +6 -1
- package/dist/channels/context.d.ts +4 -0
- package/dist/channels/context.js +35 -0
- package/dist/channels/discover.d.ts +18 -20
- package/dist/channels/discover.js +41 -99
- package/dist/channels/feishu/feishu-api.d.ts +54 -4
- package/dist/channels/feishu/feishu-api.js +192 -149
- package/dist/channels/feishu/feishu.d.ts +3 -0
- package/dist/channels/feishu/feishu.js +117 -106
- package/dist/channels/feishu/history.d.ts +55 -0
- package/dist/channels/feishu/history.js +199 -0
- package/dist/channels/feishu/invoke-turn.d.ts +13 -11
- package/dist/channels/feishu/invoke-turn.js +9 -10
- package/dist/channels/feishu/model.d.ts +2 -1
- package/dist/channels/feishu/normalize.js +100 -0
- package/dist/channels/feishu/preview.d.ts +2 -2
- package/dist/channels/feishu/register-webhook.d.ts +1 -0
- package/dist/channels/feishu/register-webhook.js +3 -2
- package/dist/channels/feishu/scaffold/channel.ts +65 -46
- package/dist/channels/feishu/scaffold/feishu-send.ts +38 -33
- package/dist/channels/feishu/scaffold/feishu-threads.ts +25 -0
- package/dist/channels/feishu/setup-mode.d.ts +45 -25
- package/dist/channels/feishu/setup-mode.js +74 -23
- package/dist/channels/feishu/shared-api.d.ts +24 -6
- package/dist/channels/feishu/shared-api.js +30 -24
- package/dist/channels/kit/context-buffer.d.ts +11 -2
- package/dist/channels/kit/context-buffer.js +7 -4
- package/dist/channels/kit/delivery.d.ts +19 -3
- package/dist/channels/kit/delivery.js +74 -15
- package/dist/channels/kit/event-stream.js +2 -1
- package/dist/channels/kit/invoke-turn-kit.d.ts +41 -41
- package/dist/channels/kit/invoke-turn-kit.js +62 -71
- package/dist/channels/kit/place-history.d.ts +107 -0
- package/dist/channels/kit/place-history.js +182 -0
- package/dist/channels/kit/preview-kit.d.ts +9 -5
- package/dist/channels/kit/preview-kit.js +36 -15
- package/dist/channels/kit/room-threads.d.ts +46 -0
- package/dist/channels/kit/room-threads.js +81 -0
- package/dist/channels/kit/seen.js +1 -1
- package/dist/channels/kit/stop-command.d.ts +6 -3
- package/dist/channels/kit/stop-command.js +20 -18
- package/dist/channels/kit/thread-fork.d.ts +17 -0
- package/dist/channels/kit/thread-fork.js +43 -0
- package/dist/channels/kit/thread-participants.js +1 -1
- package/dist/channels/kit/transport.d.ts +5 -0
- package/dist/channels/kit/transport.js +5 -0
- package/dist/channels/kit/turn-runner.d.ts +10 -9
- package/dist/channels/kit/turn-runner.js +17 -19
- package/dist/channels/kit/turn-store.d.ts +5 -4
- package/dist/channels/kit/turn-store.js +5 -5
- package/dist/channels/lark/lark.d.ts +3 -0
- package/dist/channels/lark/lark.js +5 -0
- package/dist/channels/lark/onboard.d.ts +5 -3
- package/dist/channels/lark/onboard.js +14 -14
- package/dist/channels/lark/scaffold/channel.ts +67 -44
- package/dist/channels/lark/scaffold/lark-send.ts +38 -33
- package/dist/channels/lark/scaffold/lark-threads.ts +25 -0
- package/dist/channels/respond.d.ts +0 -4
- package/dist/channels/respond.js +1 -1
- package/dist/channels/router.d.ts +18 -0
- package/dist/channels/router.js +68 -0
- package/dist/channels/serve.d.ts +5 -70
- package/dist/channels/serve.js +105 -287
- package/dist/channels/slack/history.d.ts +42 -0
- package/dist/channels/slack/history.js +282 -0
- package/dist/channels/slack/invoke-turn.d.ts +12 -5
- package/dist/channels/slack/invoke-turn.js +7 -5
- package/dist/channels/slack/manifest.d.ts +1 -4
- package/dist/channels/slack/manifest.js +22 -10
- package/dist/channels/slack/model.d.ts +2 -1
- package/dist/channels/slack/onboard.d.ts +0 -2
- package/dist/channels/slack/onboard.js +2 -4
- package/dist/channels/slack/onboarding-state.d.ts +0 -2
- package/dist/channels/slack/onboarding-state.js +0 -1
- package/dist/channels/slack/parse.d.ts +0 -5
- package/dist/channels/slack/parse.js +1 -16
- package/dist/channels/slack/preview.d.ts +2 -3
- package/dist/channels/slack/preview.js +78 -52
- package/dist/channels/slack/register-webhook.d.ts +1 -0
- package/dist/channels/slack/register-webhook.js +6 -5
- package/dist/channels/slack/scaffold/channel.ts +23 -24
- package/dist/channels/slack/scaffold/slack-send.ts +50 -43
- package/dist/channels/slack/scaffold/slack-threads.ts +29 -0
- package/dist/channels/slack/setup-server.d.ts +19 -0
- package/dist/channels/slack/setup-server.js +113 -11
- package/dist/channels/slack/shared-api.d.ts +15 -4
- package/dist/channels/slack/shared-api.js +19 -14
- package/dist/channels/slack/slack-api.d.ts +61 -2
- package/dist/channels/slack/slack-api.js +28 -5
- package/dist/channels/slack/slack.js +97 -52
- package/dist/channels/slack/welcomed.js +1 -1
- package/dist/channels/telegram/context-buffer.d.ts +6 -1
- package/dist/channels/telegram/context-buffer.js +19 -0
- package/dist/channels/telegram/invoke-turn.d.ts +8 -4
- package/dist/channels/telegram/invoke-turn.js +7 -7
- package/dist/channels/telegram/parse.d.ts +7 -2
- package/dist/channels/telegram/parse.js +7 -0
- package/dist/channels/telegram/preview.d.ts +2 -2
- package/dist/channels/telegram/register-webhook.d.ts +1 -0
- package/dist/channels/telegram/register-webhook.js +3 -2
- package/dist/channels/telegram/scaffold/channel.ts +27 -28
- package/dist/channels/telegram/scaffold/telegram-send.ts +61 -108
- package/dist/channels/telegram/shared-api.d.ts +34 -0
- package/dist/channels/telegram/shared-api.js +79 -0
- package/dist/channels/telegram/telegram-api.d.ts +15 -5
- package/dist/channels/telegram/telegram-api.js +10 -6
- package/dist/channels/telegram/telegram.js +27 -21
- package/dist/channels/telegram/turn-store.js +1 -1
- package/dist/channels/{kit/turn-queue.d.ts → turn-queue.d.ts} +2 -2
- package/dist/channels/{kit/turn-queue.js → turn-queue.js} +10 -10
- package/dist/cli/add-feishu.d.ts +42 -12
- package/dist/cli/add-feishu.js +177 -124
- package/dist/cli/add-slack.d.ts +8 -3
- package/dist/cli/add-slack.js +115 -63
- package/dist/cli/auth-view.d.ts +10 -3
- package/dist/cli/auth-view.js +8 -6
- package/dist/cli/box-login.d.ts +17 -7
- package/dist/cli/box-login.js +46 -12
- package/dist/cli/commands/add.d.ts +15 -4
- package/dist/cli/commands/add.js +252 -143
- package/dist/cli/commands/auth.d.ts +6 -0
- package/dist/cli/commands/auth.js +50 -0
- package/dist/cli/commands/content.d.ts +6 -0
- package/dist/cli/commands/content.js +45 -0
- package/dist/cli/commands/deploy/agentcore.js +50 -77
- package/dist/cli/commands/deploy/docker.js +38 -39
- package/dist/cli/commands/deploy/fly.js +21 -18
- package/dist/cli/commands/deploy/host-login.d.ts +26 -0
- package/dist/cli/commands/deploy/host-login.js +90 -0
- package/dist/cli/commands/deploy/railway.js +21 -26
- package/dist/cli/commands/deploy/shared.d.ts +45 -17
- package/dist/cli/commands/deploy/shared.js +34 -15
- package/dist/cli/commands/deploy.d.ts +0 -4
- package/dist/cli/commands/deploy.js +237 -50
- package/dist/cli/commands/destroy.js +8 -6
- package/dist/cli/commands/dev.d.ts +0 -2
- package/dist/cli/commands/dev.js +20 -19
- package/dist/cli/commands/env.d.ts +12 -0
- package/dist/cli/commands/env.js +190 -0
- package/dist/cli/commands/info.js +95 -156
- package/dist/cli/commands/init.d.ts +2 -2
- package/dist/cli/commands/init.js +35 -33
- package/dist/cli/commands/invoke.d.ts +6 -0
- package/dist/cli/commands/invoke.js +131 -16
- package/dist/cli/commands/login.d.ts +31 -2
- package/dist/cli/commands/login.js +413 -64
- package/dist/cli/commands/logout.d.ts +4 -0
- package/dist/cli/commands/logout.js +53 -0
- package/dist/cli/commands/logs.js +8 -6
- package/dist/cli/commands/models.d.ts +2 -1
- package/dist/cli/commands/models.js +39 -37
- package/dist/cli/commands/schedules.d.ts +21 -0
- package/dist/cli/commands/schedules.js +143 -0
- package/dist/cli/commands/start.d.ts +11 -10
- package/dist/cli/commands/start.js +35 -62
- package/dist/cli/content-view.d.ts +9 -0
- package/dist/cli/content-view.js +26 -0
- package/dist/cli/fail.d.ts +9 -12
- package/dist/cli/fail.js +17 -14
- package/dist/cli/invoke-stream.d.ts +12 -3
- package/dist/cli/invoke-stream.js +85 -23
- package/dist/cli/kernel.d.ts +9 -2
- package/dist/cli/kernel.js +15 -6
- package/dist/cli/login-relay.d.ts +3 -2
- package/dist/cli/login-relay.js +18 -6
- package/dist/cli/models-view.d.ts +5 -1
- package/dist/cli/models-view.js +1 -1
- package/dist/cli/person.d.ts +10 -0
- package/dist/cli/person.js +23 -0
- package/dist/cli/program.js +421 -203
- package/dist/cli/serve.d.ts +13 -63
- package/dist/cli/serve.js +31 -121
- package/dist/cli/shared.d.ts +21 -48
- package/dist/cli/shared.js +68 -89
- package/dist/cli/ticket.d.ts +136 -0
- package/dist/cli/ticket.js +476 -0
- package/dist/client.d.ts +7 -0
- package/dist/client.js +2 -0
- package/dist/content/declare.d.ts +70 -0
- package/dist/content/declare.js +163 -0
- package/dist/content/file.d.ts +32 -0
- package/dist/content/file.js +119 -0
- package/dist/content/git.d.ts +41 -0
- package/dist/content/git.js +217 -0
- package/dist/content/mount.d.ts +2 -0
- package/dist/content/mount.js +15 -0
- package/dist/content/resolve.d.ts +52 -0
- package/dist/content/resolve.js +151 -0
- package/dist/content/source.d.ts +27 -0
- package/dist/content/source.js +53 -0
- package/dist/conversation-sessions.d.ts +26 -0
- package/dist/conversation-sessions.js +99 -0
- package/dist/declared-secrets.d.ts +19 -37
- package/dist/declared-secrets.js +16 -58
- package/dist/deploy/agentcore/destroy.d.ts +3 -3
- package/dist/deploy/agentcore/destroy.js +46 -28
- package/dist/deploy/agentcore/forwarder.js +105 -22
- package/dist/deploy/agentcore/logs.js +1 -1
- package/dist/deploy/agentcore/plan.d.ts +10 -24
- package/dist/deploy/agentcore/plan.js +31 -135
- package/dist/deploy/agentcore/run.d.ts +1 -1
- package/dist/deploy/agentcore/run.js +8 -5
- package/dist/deploy/agentcore/shell.d.ts +1 -1
- package/dist/deploy/agentcore/shell.js +5 -5
- package/dist/deploy/api.d.ts +34 -0
- package/dist/deploy/api.js +50 -0
- package/dist/deploy/box-shell.d.ts +6 -0
- package/dist/deploy/box-shell.js +7 -0
- package/dist/deploy/build-context.d.ts +7 -5
- package/dist/deploy/build-context.js +41 -35
- package/dist/deploy/channel-ingress.d.ts +6 -1
- package/dist/deploy/channel-ingress.js +18 -5
- package/dist/deploy/container.d.ts +22 -9
- package/dist/deploy/container.js +96 -55
- package/dist/deploy/docker/plan.d.ts +3 -2
- package/dist/deploy/docker/plan.js +13 -14
- package/dist/deploy/docker/run.d.ts +2 -2
- package/dist/deploy/docker/run.js +8 -4
- package/dist/deploy/fly/plan.d.ts +1 -1
- package/dist/deploy/fly/plan.js +12 -21
- package/dist/deploy/fly/run.d.ts +10 -6
- package/dist/deploy/fly/run.js +11 -6
- package/dist/deploy/hosts.d.ts +2 -1
- package/dist/deploy/hosts.js +2 -1
- package/dist/deploy/preflight.d.ts +21 -23
- package/dist/deploy/preflight.js +222 -201
- package/dist/deploy/railway/plan.d.ts +8 -6
- package/dist/deploy/railway/plan.js +15 -58
- package/dist/deploy/railway/run.d.ts +8 -3
- package/dist/deploy/railway/run.js +12 -8
- package/dist/deploy/residency.d.ts +5 -11
- package/dist/deploy/residency.js +0 -6
- package/dist/deploy/runner.d.ts +1 -1
- package/dist/deploy/runner.js +1 -1
- package/dist/deploy/secrets.d.ts +16 -2
- package/dist/deploy/secrets.js +33 -6
- package/dist/deploy/workspace.d.ts +11 -6
- package/dist/deploy/workspace.js +55 -38
- package/dist/dev-supervisor.d.ts +11 -2
- package/dist/dev-supervisor.js +51 -26
- package/dist/effect-port.d.ts +4 -4
- package/dist/effect-port.js +4 -4
- package/dist/environment/apt.d.ts +4 -0
- package/dist/environment/apt.js +32 -0
- package/dist/environment/declare.d.ts +59 -0
- package/dist/environment/declare.js +210 -0
- package/dist/environment/mise.d.ts +50 -0
- package/dist/environment/mise.js +268 -0
- package/dist/feishu.d.ts +2 -2
- package/dist/feishu.js +2 -2
- package/dist/git.d.ts +13 -0
- package/dist/git.js +55 -0
- package/dist/harnesses/models/catalog.d.ts +20 -0
- package/dist/harnesses/models/catalog.js +254 -0
- package/dist/{engines/pi/auth.d.ts → harnesses/models/credentials.d.ts} +3 -3
- package/dist/{engines/pi/auth.js → harnesses/models/credentials.js} +3 -3
- package/dist/harnesses/models/environment.d.ts +43 -0
- package/dist/harnesses/models/environment.js +82 -0
- package/dist/{engines/pi → harnesses/models}/login.d.ts +57 -26
- package/dist/{engines/pi → harnesses/models}/login.js +187 -79
- package/dist/harnesses/models/models.d.ts +83 -0
- package/dist/harnesses/models/models.js +158 -0
- package/dist/harnesses/pi-durable/agent.d.ts +42 -0
- package/dist/harnesses/pi-durable/agent.js +579 -0
- package/dist/harnesses/pi-durable/defaults.d.ts +28 -0
- package/dist/harnesses/pi-durable/defaults.js +26 -0
- package/dist/harnesses/pi-durable/define.d.ts +77 -0
- package/dist/harnesses/pi-durable/define.js +28 -0
- package/dist/harnesses/pi-durable/entries.d.ts +32 -0
- package/dist/harnesses/pi-durable/entries.js +126 -0
- package/dist/harnesses/pi-durable/events.d.ts +25 -0
- package/dist/harnesses/pi-durable/events.js +238 -0
- package/dist/harnesses/pi-durable/ids.d.ts +16 -0
- package/dist/harnesses/pi-durable/ids.js +55 -0
- package/dist/harnesses/pi-durable/messages.d.ts +41 -0
- package/dist/harnesses/pi-durable/messages.js +116 -0
- package/dist/harnesses/pi-durable/open.d.ts +88 -0
- package/dist/harnesses/pi-durable/open.js +329 -0
- package/dist/harnesses/pi-durable/reads.d.ts +30 -0
- package/dist/harnesses/pi-durable/reads.js +94 -0
- package/dist/harnesses/pi-durable/registry.d.ts +18 -0
- package/dist/harnesses/pi-durable/registry.js +56 -0
- package/dist/harnesses/pi-durable/release.d.ts +13 -0
- package/dist/harnesses/pi-durable/release.js +40 -0
- package/dist/harnesses/pi-durable/serve.d.ts +80 -0
- package/dist/harnesses/pi-durable/serve.js +156 -0
- package/dist/harnesses/pi-durable/sessions.d.ts +27 -0
- package/dist/harnesses/pi-durable/sessions.js +47 -0
- package/dist/harnesses/pi-durable/storage.d.ts +4 -0
- package/dist/harnesses/pi-durable/storage.js +49 -0
- package/dist/harnesses/pi-durable/stream.d.ts +20 -0
- package/dist/harnesses/pi-durable/stream.js +221 -0
- package/dist/harnesses/pi-durable/text.d.ts +30 -0
- package/dist/harnesses/pi-durable/text.js +292 -0
- package/dist/harnesses/pi-durable/wake.d.ts +4 -0
- package/dist/harnesses/pi-durable/wake.js +81 -0
- package/dist/http/client.d.ts +6 -0
- package/dist/http/client.js +256 -0
- package/dist/http/contract.d.ts +541 -0
- package/dist/http/contract.js +179 -0
- package/dist/http/server.d.ts +34 -0
- package/dist/http/server.js +194 -0
- package/dist/index.d.ts +17 -4
- package/dist/index.js +10 -5
- package/dist/lark.d.ts +2 -2
- package/dist/lark.js +2 -2
- package/dist/locked-file.d.ts +17 -0
- package/dist/{engines/pi/locked-file.js → locked-file.js} +16 -10
- package/dist/once.d.ts +6 -0
- package/dist/once.js +23 -0
- package/dist/paths.d.ts +36 -52
- package/dist/paths.js +66 -182
- package/dist/runtime.d.ts +25 -2
- package/dist/runtime.js +27 -0
- package/dist/scaffold/add-channel.d.ts +14 -27
- package/dist/scaffold/add-channel.js +82 -180
- package/dist/scaffold/init.d.ts +17 -18
- package/dist/scaffold/init.js +87 -99
- package/dist/scaffold/templates/SYSTEM.md +12 -0
- package/dist/scaffold/templates/env.example +4 -10
- package/dist/scaffold/templates/fastagent.config.ts +21 -33
- package/dist/scaffold/templates/gitignore +8 -1
- package/dist/scaffold/templates/skills/writing-great-skills/SKILL.md +1 -2
- package/dist/scaffold/templates.d.ts +9 -4
- package/dist/scaffold/templates.js +7 -5
- package/dist/scaffold/vendor-skill.d.ts +1 -4
- package/dist/scaffold/vendor-skill.js +5 -6
- package/dist/schedule/cron.d.ts +13 -0
- package/dist/schedule/cron.js +52 -0
- package/dist/schedule/eventbridge-cron.d.ts +17 -0
- package/dist/schedule/eventbridge-cron.js +88 -0
- package/dist/schedule/schedule.d.ts +23 -0
- package/dist/schedule/schedule.js +34 -0
- package/dist/schedule/scheduler.d.ts +34 -33
- package/dist/schedule/scheduler.js +251 -137
- package/dist/schedule/state.d.ts +4 -14
- package/dist/schedule/state.js +7 -7
- package/dist/schedule/wake-alarm.d.ts +22 -2
- package/dist/schedule/wake-alarm.js +66 -20
- package/dist/schedule/wakeups.d.ts +16 -15
- package/dist/schedule/wakeups.js +47 -45
- package/dist/service.d.ts +56 -169
- package/dist/service.js +91 -187
- package/dist/serving-command.d.ts +10 -0
- package/dist/serving-command.js +16 -0
- package/dist/slack.d.ts +1 -1
- package/dist/slack.js +1 -1
- package/dist/{channels/kit/state.js → state-file.js} +6 -6
- package/dist/telegram.d.ts +1 -0
- package/dist/telegram.js +1 -0
- package/dist/tunnel.d.ts +3 -0
- package/dist/tunnel.js +12 -4
- package/dist/value-file.d.ts +21 -0
- package/dist/value-file.js +108 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.js +14 -1
- package/package.json +18 -28
- package/dist/agent.d.ts +0 -106
- package/dist/agent.js +0 -21
- package/dist/channels/control.d.ts +0 -31
- package/dist/channels/control.js +0 -329
- package/dist/channels/define-channel.d.ts +0 -39
- package/dist/channels/define-channel.js +0 -9
- package/dist/channels/feishu/context-buffer.d.ts +0 -35
- package/dist/channels/feishu/context-buffer.js +0 -65
- package/dist/channels/feishu/scaffold/channel.websocket.ts +0 -31
- package/dist/channels/http.d.ts +0 -23
- package/dist/channels/http.js +0 -57
- package/dist/channels/lark/scaffold/channel.websocket.ts +0 -31
- package/dist/channels/slack/context-buffer.d.ts +0 -23
- package/dist/channels/slack/context-buffer.js +0 -37
- package/dist/channels/sse.d.ts +0 -4
- package/dist/channels/sse.js +0 -66
- package/dist/cli/commands/chat.d.ts +0 -3
- package/dist/cli/commands/chat.js +0 -14
- package/dist/cli/commands/routine-run.d.ts +0 -6
- package/dist/cli/commands/routine-run.js +0 -46
- package/dist/cli/commands/routine.d.ts +0 -25
- package/dist/cli/commands/routine.js +0 -122
- package/dist/cli/commands/tool.d.ts +0 -1
- package/dist/cli/commands/tool.js +0 -57
- package/dist/collect.d.ts +0 -63
- package/dist/collect.js +0 -90
- package/dist/core.d.ts +0 -13
- package/dist/core.js +0 -15
- package/dist/engines/pi/agent-models.d.ts +0 -83
- package/dist/engines/pi/agent-models.js +0 -120
- package/dist/engines/pi/agent-session-factory.d.ts +0 -121
- package/dist/engines/pi/agent-session-factory.js +0 -517
- package/dist/engines/pi/chat.d.ts +0 -3
- package/dist/engines/pi/chat.js +0 -8
- package/dist/engines/pi/config.d.ts +0 -71
- package/dist/engines/pi/config.js +0 -199
- package/dist/engines/pi/create.d.ts +0 -170
- package/dist/engines/pi/create.js +0 -343
- package/dist/engines/pi/definition.d.ts +0 -74
- package/dist/engines/pi/definition.js +0 -236
- package/dist/engines/pi/entry-images.d.ts +0 -14
- package/dist/engines/pi/entry-images.js +0 -23
- package/dist/engines/pi/invoke-session.d.ts +0 -18
- package/dist/engines/pi/invoke-session.js +0 -403
- package/dist/engines/pi/locked-file.d.ts +0 -9
- package/dist/engines/pi/machine.d.ts +0 -53
- package/dist/engines/pi/machine.js +0 -137
- package/dist/engines/pi/models.d.ts +0 -200
- package/dist/engines/pi/models.js +0 -533
- package/dist/engines/pi/open.d.ts +0 -180
- package/dist/engines/pi/open.js +0 -270
- package/dist/engines/pi/openai-account-models.d.ts +0 -35
- package/dist/engines/pi/openai-account-models.js +0 -116
- package/dist/engines/pi/report.d.ts +0 -18
- package/dist/engines/pi/report.js +0 -59
- package/dist/engines/pi/retry-event.d.ts +0 -6
- package/dist/engines/pi/retry-event.js +0 -15
- package/dist/engines/pi/service.d.ts +0 -9
- package/dist/engines/pi/service.js +0 -14
- package/dist/engines/pi/session-builder.d.ts +0 -13
- package/dist/engines/pi/session-builder.js +0 -117
- package/dist/engines/pi/session-control.d.ts +0 -77
- package/dist/engines/pi/session-control.js +0 -908
- package/dist/engines/pi/session-effects.d.ts +0 -14
- package/dist/engines/pi/session-effects.js +0 -30
- package/dist/engines/pi/session-inheritance.d.ts +0 -21
- package/dist/engines/pi/session-inheritance.js +0 -204
- package/dist/engines/pi/session-markers.d.ts +0 -49
- package/dist/engines/pi/session-markers.js +0 -60
- package/dist/engines/pi/session-settings.d.ts +0 -67
- package/dist/engines/pi/session-settings.js +0 -119
- package/dist/engines/pi/session-store.d.ts +0 -69
- package/dist/engines/pi/session-store.js +0 -430
- package/dist/engines/pi/tool-context.d.ts +0 -45
- package/dist/engines/pi/tool-context.js +0 -31
- package/dist/engines/pi/tool.d.ts +0 -99
- package/dist/engines/pi/tool.js +0 -118
- package/dist/engines/pi/turn-kit.d.ts +0 -83
- package/dist/engines/pi/turn-kit.js +0 -275
- package/dist/engines/pi/wake-tool.d.ts +0 -9
- package/dist/engines/pi/wake-tool.js +0 -92
- package/dist/loader.d.ts +0 -41
- package/dist/loader.js +0 -116
- package/dist/node.d.ts +0 -3
- package/dist/node.js +0 -4
- package/dist/observe.d.ts +0 -6
- package/dist/observe.js +0 -47
- package/dist/pi.d.ts +0 -25
- package/dist/pi.js +0 -15
- package/dist/scaffold/templates/APPEND_SYSTEM.md +0 -12
- package/dist/scaffold/templates/tools/fetch-url.ts +0 -25
- package/dist/schedule/discover.d.ts +0 -17
- package/dist/schedule/discover.js +0 -61
- package/dist/schedule/routine.d.ts +0 -43
- package/dist/schedule/routine.js +0 -32
- package/dist/schedule/run.d.ts +0 -55
- package/dist/schedule/run.js +0 -146
- package/dist/secrets-gate.d.ts +0 -32
- package/dist/secrets-gate.js +0 -33
- package/dist/session-remote.d.ts +0 -47
- package/dist/session-remote.js +0 -460
- package/dist/session.d.ts +0 -466
- package/dist/session.js +0 -57
- /package/dist/{channels/kit/state.d.ts → state-file.d.ts} +0 -0
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { FeishuSubscriptionMode } from "../feishu/setup-mode.ts";
|
|
2
2
|
/** Guided Lark-international onboarding. */
|
|
3
3
|
export declare const LARK_CONSOLE_URL = "https://open.larksuite.com/page/launcher?from=backend_oneclick";
|
|
4
4
|
/** Directly where the fallback token lives (and where the successful automatic mode change is visible). */
|
|
5
5
|
export declare function larkEventSecurityUrl(appId: string): string;
|
|
6
6
|
export interface LarkOnboardIO {
|
|
7
|
-
|
|
7
|
+
/** A page for the person, and what they do there. */
|
|
8
|
+
openUrl(url: string, action: string): void;
|
|
8
9
|
note(message: string): void;
|
|
9
10
|
prompt(message: string, opts?: {
|
|
10
11
|
hidden?: boolean;
|
|
@@ -20,9 +21,10 @@ export interface LarkOnboardOptions {
|
|
|
20
21
|
/** Existing active .env values. */
|
|
21
22
|
existing?: Readonly<Record<string, string | undefined>>;
|
|
22
23
|
ingress?: FeishuSubscriptionMode;
|
|
23
|
-
groupBehavior?: FeishuGroupBehavior;
|
|
24
24
|
verifyCredentials(appId: string, appSecret: string): Promise<void>;
|
|
25
25
|
bootstrapWebhook?(appId: string, appSecret: string): Promise<LarkBootstrapResult>;
|
|
26
|
+
/** The command that continues an interrupted setup: the one that started it (`add lark`, `deploy <host> --run`). */
|
|
27
|
+
rerun?: string;
|
|
26
28
|
}
|
|
27
29
|
export interface LarkOnboardCredentials {
|
|
28
30
|
LARK_APP_ID: string;
|
|
@@ -4,35 +4,33 @@ export const LARK_CONSOLE_URL = "https://open.larksuite.com/page/launcher?from=b
|
|
|
4
4
|
export function larkEventSecurityUrl(appId) {
|
|
5
5
|
return `https://open.larksuite.com/app/${encodeURIComponent(appId)}/event?tab=safe`;
|
|
6
6
|
}
|
|
7
|
-
function required(value, name) {
|
|
7
|
+
function required(value, name, rerun) {
|
|
8
8
|
const trimmed = value?.trim();
|
|
9
9
|
if (!trimmed)
|
|
10
|
-
throw new Error(`${name} is required — re-run \`
|
|
10
|
+
throw new Error(`${name} is required — re-run \`${rerun}\` to continue setup`);
|
|
11
11
|
return trimmed;
|
|
12
12
|
}
|
|
13
13
|
/** Open the stable app console and collect everything the runtime needs. */
|
|
14
14
|
export async function onboardLarkApp(io, opts) {
|
|
15
|
+
const rerun = opts.rerun ?? "fastagent add lark";
|
|
15
16
|
const existingId = opts.existing?.LARK_APP_ID?.trim();
|
|
16
17
|
const existingSecret = opts.existing?.LARK_APP_SECRET?.trim();
|
|
17
18
|
const reuseExistingApp = Boolean(existingId && existingSecret);
|
|
18
19
|
// Credentials are one App-scoped set.
|
|
19
20
|
if (reuseExistingApp) {
|
|
20
|
-
io.note(`Reusing Lark app ${existingId}
|
|
21
|
+
io.note(`Reusing Lark app ${existingId}.`);
|
|
21
22
|
}
|
|
22
23
|
else {
|
|
23
|
-
io.
|
|
24
|
-
io.openUrl(LARK_CONSOLE_URL);
|
|
24
|
+
io.openUrl(LARK_CONSOLE_URL, "create the app on Lark's one-click launcher; LARK_APP_ID and LARK_APP_SECRET are under Credentials & Basic Info");
|
|
25
25
|
}
|
|
26
|
-
const appId = required(reuseExistingApp ? existingId : await io.prompt("LARK_APP_ID (Credentials & Basic Info)", { hidden: false }), "LARK_APP_ID");
|
|
27
|
-
const appSecret = required(reuseExistingApp ? existingSecret : await io.prompt("LARK_APP_SECRET (Credentials & Basic Info)", { hidden: true }), "LARK_APP_SECRET");
|
|
26
|
+
const appId = required(reuseExistingApp ? existingId : await io.prompt("LARK_APP_ID (Credentials & Basic Info)", { hidden: false }), "LARK_APP_ID", rerun);
|
|
27
|
+
const appSecret = required(reuseExistingApp ? existingSecret : await io.prompt("LARK_APP_SECRET (Credentials & Basic Info)", { hidden: true }), "LARK_APP_SECRET", rerun);
|
|
28
28
|
await opts.verifyCredentials(appId, appSecret);
|
|
29
29
|
const eventSecurityUrl = larkEventSecurityUrl(appId);
|
|
30
|
-
io.note(
|
|
31
|
-
io.openUrl(eventSecurityUrl);
|
|
30
|
+
io.note("App ID / Secret verified.");
|
|
32
31
|
if (opts.ingress === "websocket") {
|
|
33
|
-
io.
|
|
34
|
-
|
|
35
|
-
: "Choose long connection and subscribe im.message.receive_v1, but do not publish yet — context-aware group permission setup follows. No Verification Token or Request URL is needed.");
|
|
32
|
+
io.openUrl(eventSecurityUrl, "in Events & Callbacks, choose long connection and subscribe im.message.receive_v1, but do not publish yet: " +
|
|
33
|
+
"the permission check follows (no Verification Token or Request URL is needed)");
|
|
36
34
|
return { LARK_APP_ID: appId, LARK_APP_SECRET: appSecret };
|
|
37
35
|
}
|
|
38
36
|
io.note("Trying automatic webhook-mode + Verification-Token bootstrap…");
|
|
@@ -43,11 +41,13 @@ export async function onboardLarkApp(io, opts) {
|
|
|
43
41
|
io.note("Verification Token captured; Subscription mode changed to webhook in the app draft.");
|
|
44
42
|
}
|
|
45
43
|
else {
|
|
46
|
-
io.note(
|
|
44
|
+
io.note(bootstrap.manualReason ?? "Automatic bootstrap unavailable.");
|
|
45
|
+
io.openUrl(eventSecurityUrl, "in Events & Callbacks → Encryption Strategy, copy the Verification Token, and switch Subscription mode to " +
|
|
46
|
+
"webhook when setting the Request URL");
|
|
47
47
|
}
|
|
48
48
|
const verificationToken = required(bootstrap.token ||
|
|
49
49
|
(reuseExistingApp ? opts.existing?.LARK_VERIFICATION_TOKEN?.trim() : undefined) ||
|
|
50
|
-
(await io.prompt("LARK_VERIFICATION_TOKEN (Events & Callbacks → Encryption Strategy)", { hidden: true })), "LARK_VERIFICATION_TOKEN");
|
|
50
|
+
(await io.prompt("LARK_VERIFICATION_TOKEN (Events & Callbacks → Encryption Strategy)", { hidden: true })), "LARK_VERIFICATION_TOKEN", rerun);
|
|
51
51
|
return {
|
|
52
52
|
LARK_APP_ID: appId,
|
|
53
53
|
LARK_APP_SECRET: appSecret,
|
|
@@ -1,48 +1,71 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { needs } from "@fastagent-sh/fastagent";
|
|
2
|
+
import {
|
|
3
|
+
type LarkChannelOptions,
|
|
4
|
+
larkChannel,
|
|
5
|
+
larkIngress,
|
|
6
|
+
larkWebSocketChannel,
|
|
7
|
+
} from "@fastagent-sh/fastagent/lark";
|
|
3
8
|
|
|
4
|
-
//
|
|
5
|
-
// with YOUR policy.
|
|
6
|
-
//
|
|
7
|
-
//
|
|
9
|
+
// The branded Lark adapter over fastagent's canonical Feishu engine (verify + run + reply), configured
|
|
10
|
+
// with YOUR policy. Lark international (open.larksuite.com) only; a Feishu tenant uses `fastagent add
|
|
11
|
+
// feishu` instead.
|
|
12
|
+
//
|
|
13
|
+
// How it receives is LARK_INGRESS (webhook | websocket). Unset, `fastagent dev` connects OUT by
|
|
14
|
+
// WebSocket (no public URL, no tunnel), and everything else — `fastagent start`, every deployment —
|
|
15
|
+
// receives by webhook at POST /lark. Dev reads .secrets/.env; production reads
|
|
16
|
+
// .secrets/production/.env. Interactive `deploy --run` guides creation of a separate production app;
|
|
17
|
+
// if Lark refuses its config API, set the Request URL in the console once.
|
|
18
|
+
//
|
|
19
|
+
// `fastagent add lark` guides the console setup and validates the credentials. In the developer
|
|
20
|
+
// console:
|
|
8
21
|
// 1. create a custom app → enable the BOT capability → copy App ID / App Secret into .env
|
|
9
22
|
// 2. Permissions: add `im:message.p2p_msg:readonly` (direct messages), `im:message.group_at_msg:readonly`
|
|
10
23
|
// (group @mentions), `im:message:send_as_bot` (reply), `im:resource` (attachments), and the
|
|
11
|
-
// card scope ("Create and update card" — the live preview streams through a card).
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
-
//
|
|
20
|
-
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
channel
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
24
|
+
// card scope ("Create and update card" — the live preview streams through a card). So the Agent
|
|
25
|
+
// hears its group chats, also add `im:message.group_msg` (sensitive), `im:message:readonly` and
|
|
26
|
+
// `im:chat.members:read`; for webhook, `application:application:patch` lets fastagent set the
|
|
27
|
+
// Request URL. What each is for is in the channel guide; the channel warns about any it lacks.
|
|
28
|
+
// 3. Events & Callbacks → subscribe to `im.message.receive_v1`. For webhook, copy the Verification
|
|
29
|
+
// Token into .env (RECOMMENDED: set an Encrypt Key there and mirror it in LARK_ENCRYPT_KEY).
|
|
30
|
+
// 4. create a version and publish the app (a tenant admin approves it), then add the bot to a chat
|
|
31
|
+
|
|
32
|
+
// Your policy, the same whichever way the channel receives.
|
|
33
|
+
const policy: Pick<LarkChannelOptions, "onError" | "route"> = {
|
|
34
|
+
// A chat is one conversation and a thread is another, each with a session of its own, and where the
|
|
35
|
+
// answer goes follows from that (docs/design/participant-model.md).
|
|
36
|
+
// Dev/personal bot: surface raw errors to the chat so you (and your AI agent) can act on them. The
|
|
37
|
+
// chat is customer-facing by default — for a public bot, drop this or return a neutral string;
|
|
38
|
+
// full details always go to the server log regardless.
|
|
39
|
+
onError: (failed) => `⚠️ ${failed.details}`,
|
|
40
|
+
// The channel owns transport + format (markdown card) + attachments (image→vision, file→disk) +
|
|
41
|
+
// the live streaming preview. `route` (POLICY) is OPTIONAL — omitted, it uses defaultLarkRoute:
|
|
42
|
+
// p2p chats always answer; groups answer on @this-bot, plus bare messages in a thread where the
|
|
43
|
+
// Agent takes part and exactly ONE human does. Other group/thread discussion is read from the
|
|
44
|
+
// platform by that place's next answered turn; @other-only messages are discussion, not asks.
|
|
45
|
+
// Override to customise explicit routing, reusing the export:
|
|
46
|
+
// route: (e) => defaultLarkRoute(e, { botOpenId: "ou_xxx" }) && { conversation: `user:${e.sender?.sender_id?.open_id}` },
|
|
47
|
+
// route: (e) => defaultLarkRoute(e, { botOpenId: "ou_xxx" }) && { text: `${larkEnvelope(e)}\n[extra]` },
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// `needs` declares the env vars this channel reads: fastagent carries them to a deployed box and
|
|
51
|
+
// refuses to serve while a required one is unset. LARK_ENCRYPT_KEY is optional.
|
|
52
|
+
export default larkIngress() === "webhook"
|
|
53
|
+
? needs(
|
|
54
|
+
[
|
|
55
|
+
"LARK_APP_ID",
|
|
56
|
+
"LARK_APP_SECRET",
|
|
57
|
+
"LARK_VERIFICATION_TOKEN",
|
|
58
|
+
{ name: "LARK_ENCRYPT_KEY", description: "when set, plaintext events are refused", optional: true },
|
|
59
|
+
],
|
|
60
|
+
(secrets) =>
|
|
61
|
+
larkChannel({
|
|
62
|
+
appId: secrets.LARK_APP_ID,
|
|
63
|
+
appSecret: secrets.LARK_APP_SECRET,
|
|
64
|
+
verificationToken: secrets.LARK_VERIFICATION_TOKEN, // authenticates inbound events
|
|
65
|
+
encryptKey: secrets.LARK_ENCRYPT_KEY,
|
|
66
|
+
...policy,
|
|
67
|
+
}),
|
|
68
|
+
)
|
|
69
|
+
: needs(["LARK_APP_ID", "LARK_APP_SECRET"], (secrets) =>
|
|
70
|
+
larkWebSocketChannel({ appId: secrets.LARK_APP_ID, appSecret: secrets.LARK_APP_SECRET, ...policy }),
|
|
71
|
+
);
|
|
@@ -1,37 +1,42 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Type } from "@earendil-works/pi-ai";
|
|
2
|
+
import { defineTool } from "@earendil-works/pi-durable";
|
|
3
|
+
import { needs } from "@fastagent-sh/fastagent";
|
|
2
4
|
import { larkTransport } from "@fastagent-sh/fastagent/lark";
|
|
3
5
|
|
|
4
6
|
// Proactive delivery uses the mounted channel's credentials, gateway and token cache. With no
|
|
5
|
-
// channel mounted
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
7
|
+
// channel mounted, it signs in with LARK_APP_ID / LARK_APP_SECRET itself.
|
|
8
|
+
export default needs(["LARK_APP_ID", "LARK_APP_SECRET"], (secrets) =>
|
|
9
|
+
defineTool({
|
|
10
|
+
name: "lark_send",
|
|
11
|
+
description:
|
|
12
|
+
"Send a message to a Lark chat, OUTSIDE the normal reply path. Call it only for a message NO " +
|
|
13
|
+
"channel is carrying (a scheduled or self-scheduled one, whose plain reply goes " +
|
|
14
|
+
"nowhere) or to reach a chat OTHER than the one you are answering. In a normal chat turn the " +
|
|
15
|
+
"channel streams and delivers your reply itself, so do NOT call this to answer the current " +
|
|
16
|
+
"chat: it would post the message twice, outside the conversation thread. `chatId` (oc_…) names " +
|
|
17
|
+
"the DESTINATION and must come from your instructions (the asking message, the schedule prompt, " +
|
|
18
|
+
"or memory); the [lark: chat …] context line only identifies the chat you are answering, the " +
|
|
19
|
+
"one chat this tool must not target in a chat turn. Pass exactly ONE of `text` (plain) or " +
|
|
20
|
+
"`markdown` (rendered as a card: headings, bold, code blocks, links).",
|
|
21
|
+
parameters: Type.Object({
|
|
22
|
+
chatId: Type.String({ description: "target chat id (oc_…)" }),
|
|
23
|
+
text: Type.Optional(Type.String({ description: "plain text message to send" })),
|
|
24
|
+
markdown: Type.Optional(Type.String({ description: "markdown to send as a card" })),
|
|
25
|
+
}),
|
|
26
|
+
execute: async ({ chatId, text, markdown }) => {
|
|
27
|
+
if ((text === undefined) === (markdown === undefined)) {
|
|
28
|
+
throw new Error("pass exactly one of `text` (plain) or `markdown` (a card)");
|
|
29
|
+
}
|
|
30
|
+
const api = larkTransport({ appId: secrets.LARK_APP_ID, appSecret: secrets.LARK_APP_SECRET });
|
|
31
|
+
if (text !== undefined) await api.sendText({ chatId }, text);
|
|
32
|
+
else {
|
|
33
|
+
await api.sendMessage(
|
|
34
|
+
chatId,
|
|
35
|
+
"interactive",
|
|
36
|
+
JSON.stringify({ schema: "2.0", body: { elements: [{ tag: "markdown", content: markdown }] } }),
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
return { output: [{ type: "text", text: `sent ${text !== undefined ? "message" : "card"} to chat ${chatId}` }] };
|
|
40
|
+
},
|
|
22
41
|
}),
|
|
23
|
-
|
|
24
|
-
if ((text === undefined) === (markdown === undefined)) {
|
|
25
|
-
throw new Error("pass exactly one of `text` (plain) or `markdown` (a card)");
|
|
26
|
-
}
|
|
27
|
-
const api = larkTransport(ctx.cwd);
|
|
28
|
-
if (text !== undefined) await api.sendText({ chatId }, text);
|
|
29
|
-
else {
|
|
30
|
-
await api.sendMessage(chatId, "interactive", JSON.stringify({
|
|
31
|
-
schema: "2.0",
|
|
32
|
-
body: { elements: [{ tag: "markdown", content: markdown }] },
|
|
33
|
-
}));
|
|
34
|
-
}
|
|
35
|
-
return `sent ${text !== undefined ? "message" : "card"} to chat ${chatId}`;
|
|
36
|
-
},
|
|
37
|
-
});
|
|
42
|
+
);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Type } from "@earendil-works/pi-ai";
|
|
2
|
+
import { defineTool } from "@earendil-works/pi-durable";
|
|
3
|
+
import { sessionIdOf } from "@fastagent-sh/fastagent";
|
|
4
|
+
import { larkThreads } from "@fastagent-sh/fastagent/lark";
|
|
5
|
+
|
|
6
|
+
// Reads the threads (topics) of the Lark group chat this message was asked in, and no other chat's:
|
|
7
|
+
// the channel names where the message runs, so the tool takes no chat id. It works in a group turn
|
|
8
|
+
// served by `fastagent dev`/`start`.
|
|
9
|
+
export default defineTool({
|
|
10
|
+
name: "lark_threads",
|
|
11
|
+
description:
|
|
12
|
+
"Read the threads (topics) of the Lark group chat you are answering in. Without `threadId`, list its recent " +
|
|
13
|
+
"threads, newest first, each with its id; with a `threadId` from that list, read that thread. Use " +
|
|
14
|
+
"it when a question here concerns something discussed in a thread, such as whether a problem raised there was " +
|
|
15
|
+
"resolved: the answer is often what a person wrote in the thread. Only this chat's threads can be read, and " +
|
|
16
|
+
"only in a group chat turn.",
|
|
17
|
+
parameters: Type.Object({
|
|
18
|
+
threadId: Type.Optional(Type.String({ description: "a thread id from the list (omt_…); omit it to list" })),
|
|
19
|
+
}),
|
|
20
|
+
execute: async ({ threadId }, api, context) => {
|
|
21
|
+
const threads = larkThreads(await sessionIdOf(api, context));
|
|
22
|
+
const text = threadId === undefined ? await threads.list() : await threads.read(threadId);
|
|
23
|
+
return { output: [{ type: "text", text }] };
|
|
24
|
+
},
|
|
25
|
+
});
|
package/dist/channels/respond.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/** Shared `text/plain` reply for channels + the host (error/status responses). */
|
|
2
|
-
|
|
2
|
+
const textHeaders = { "content-type": "text/plain" };
|
|
3
3
|
export const text = (body, status) => new Response(body, { status, headers: textHeaders });
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a {@link Routes} table becomes one Fetch handler: the path rule and dispatch. Every route a serve answers
|
|
3
|
+
* verifies its own caller (a channel's platform signature, a host's IAM), or answers nothing worth guarding (the
|
|
4
|
+
* health check), so the router adds no guard of its own. Fetch-only, so any runtime can serve it; serve.ts binds it to
|
|
5
|
+
* node:http.
|
|
6
|
+
*/
|
|
7
|
+
import type { ChannelHandler, Routes } from "../channel.ts";
|
|
8
|
+
/** Parse a route key: `"METHOD /path"` → `{ method, path }`, or `"/path"` → `{ path }` (any method). */
|
|
9
|
+
export declare function parseRouteKey(key: string): {
|
|
10
|
+
method?: string;
|
|
11
|
+
path: string;
|
|
12
|
+
};
|
|
13
|
+
/** A route key is `"METHOD /path"` or `"/path"`, with a literal path. */
|
|
14
|
+
export declare function assertRouteKey(key: string, describe: (problem: string) => string): void;
|
|
15
|
+
/** Do these two keys fight over the same request? */
|
|
16
|
+
export declare function routeKeysConflict(a: string, b: string): boolean;
|
|
17
|
+
/** One handler over `routes`: a literal path, its method or any, HEAD answered from GET, else 405 or 404. */
|
|
18
|
+
export declare function router(routes: Routes): ChannelHandler;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { text } from "./respond.js";
|
|
2
|
+
/** Parse a route key: `"METHOD /path"` → `{ method, path }`, or `"/path"` → `{ path }` (any method). */
|
|
3
|
+
export function parseRouteKey(key) {
|
|
4
|
+
const sp = key.indexOf(" ");
|
|
5
|
+
return sp === -1 ? { path: key } : { method: key.slice(0, sp).toUpperCase(), path: key.slice(sp + 1) };
|
|
6
|
+
}
|
|
7
|
+
/** A route key is `"METHOD /path"` or `"/path"`, with a literal path. */
|
|
8
|
+
export function assertRouteKey(key, describe) {
|
|
9
|
+
const { method, path } = parseRouteKey(key);
|
|
10
|
+
if (method === "")
|
|
11
|
+
throw new Error(describe('a leading space is not a method — write "/path" for any method'));
|
|
12
|
+
if (!path.startsWith("/"))
|
|
13
|
+
throw new Error(describe('must start with "/"'));
|
|
14
|
+
// Asked of `URL` rather than by listing what it rewrites (`?`/`#`, `.`/`..`, `\`, `%2e`).
|
|
15
|
+
const arrives = new URL(path, "http://x").pathname;
|
|
16
|
+
if (arrives !== path) {
|
|
17
|
+
throw new Error(describe(`is not the path a request would carry — that request arrives as "${arrives}"`));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** Do these two keys fight over the same request? */
|
|
21
|
+
export function routeKeysConflict(a, b) {
|
|
22
|
+
const ka = parseRouteKey(a);
|
|
23
|
+
const kb = parseRouteKey(b);
|
|
24
|
+
if (ka.path !== kb.path)
|
|
25
|
+
return false;
|
|
26
|
+
return ka.method === undefined || kb.method === undefined || ka.method === kb.method;
|
|
27
|
+
}
|
|
28
|
+
/** Same status and headers, no content (RFC 9110's HEAD). */
|
|
29
|
+
function withoutBody(res) {
|
|
30
|
+
void res.body?.cancel().catch(() => { });
|
|
31
|
+
return new Response(null, { status: res.status, statusText: res.statusText, headers: res.headers });
|
|
32
|
+
}
|
|
33
|
+
/** One handler over `routes`: a literal path, its method or any, HEAD answered from GET, else 405 or 404. */
|
|
34
|
+
export function router(routes) {
|
|
35
|
+
const byKey = new Map();
|
|
36
|
+
const paths = new Set();
|
|
37
|
+
for (const [key, handler] of Object.entries(routes)) {
|
|
38
|
+
assertRouteKey(key, (problem) => `route "${key}" is not a valid route key — ${problem}`);
|
|
39
|
+
const shadowed = [...byKey.keys()].find((other) => routeKeysConflict(other, key));
|
|
40
|
+
if (shadowed) {
|
|
41
|
+
throw new Error(`route "${key}" conflicts with "${shadowed}" — one of them would never receive a request`);
|
|
42
|
+
}
|
|
43
|
+
// Stored normalised: `parseRouteKey` upper-cases the method, so `"get /x"` validates under `GET` and would
|
|
44
|
+
// otherwise be looked up under a name nothing stores.
|
|
45
|
+
const { method, path } = parseRouteKey(key);
|
|
46
|
+
byKey.set(method ? `${method} ${path}` : path, handler);
|
|
47
|
+
paths.add(path);
|
|
48
|
+
}
|
|
49
|
+
return (req) => {
|
|
50
|
+
// `URL` normalises the path (`/a/../x` → `/x`) and drops query/fragment.
|
|
51
|
+
const path = new URL(req.url).pathname;
|
|
52
|
+
const answer = () => {
|
|
53
|
+
const exact = byKey.get(`${req.method} ${path}`) ?? byKey.get(path);
|
|
54
|
+
if (exact)
|
|
55
|
+
return exact(req);
|
|
56
|
+
if (req.method === "HEAD") {
|
|
57
|
+
const get = byKey.get(`GET ${path}`);
|
|
58
|
+
if (get)
|
|
59
|
+
return get(req);
|
|
60
|
+
}
|
|
61
|
+
return paths.has(path) ? text("method not allowed\n", 405) : text("not found\n", 404);
|
|
62
|
+
};
|
|
63
|
+
if (req.method !== "HEAD")
|
|
64
|
+
return answer();
|
|
65
|
+
const res = answer();
|
|
66
|
+
return res instanceof Promise ? res.then(withoutBody) : withoutBody(res);
|
|
67
|
+
};
|
|
68
|
+
}
|
package/dist/channels/serve.d.ts
CHANGED
|
@@ -1,76 +1,11 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
path: string;
|
|
7
|
-
};
|
|
8
|
-
/** A route key is `"METHOD /path"` or `"/path"`, with a literal path. */
|
|
9
|
-
export declare function assertRouteKey(key: string, describe: (problem: string) => string): void;
|
|
10
|
-
/** Do these two keys fight over the same request? */
|
|
11
|
-
export declare function routeKeysConflict(a: string, b: string): boolean;
|
|
12
|
-
/** A handler owning a path prefix and everything beneath it — the session control plane is the one user. */
|
|
13
|
-
export interface PrefixMount {
|
|
14
|
-
/** Absolute, no trailing slash, and not `/` (`/control`). */
|
|
15
|
-
prefix: string;
|
|
16
|
-
handler: ChannelHandler;
|
|
17
|
-
}
|
|
18
|
-
/** Same status and headers, no content (RFC 9110's HEAD). */
|
|
19
|
-
export declare function withoutBody(res: Response): Response;
|
|
20
|
-
export declare function pathUnderPrefix(path: string, prefix: string): boolean;
|
|
21
|
-
/**
|
|
22
|
-
* Refuse a cross-origin allow-list that cannot match anything.
|
|
23
|
-
*
|
|
24
|
-
* ONE check for BOTH ways in: `http.cors` in a config file, and `corsOrigins` handed to `mountAgentService` by an
|
|
25
|
-
* embedder. `allowedOrigin` compares exact strings, so `"https://app.example.com/"` — one trailing slash — never
|
|
26
|
-
* matches and the front end is refused with nothing pointing at the rule. A rule that silently matches nothing is
|
|
27
|
-
* worse than one that refuses to load.
|
|
28
|
-
*/
|
|
29
|
-
export declare function assertCorsOrigins(origins: unknown, where: string): asserts origins is string[];
|
|
30
|
-
/**
|
|
31
|
-
* The tables a router composes, NAMED rather than ordered.
|
|
32
|
-
*
|
|
33
|
-
* Two same-typed positional arguments encoded which side of the trust axis a table was on, and getting them the
|
|
34
|
-
* wrong way round type-checked: the AgentCore adapter passed its IAM-gated routes as `unverified` and they were
|
|
35
|
-
* reported as unauthenticated for two commits. A caller now spells the axis at the call site.
|
|
36
|
-
*/
|
|
37
|
-
export interface RouterSurface {
|
|
38
|
-
/** Routes that authenticate NOBODY — the router applies the JSON body gate and the cross-origin policy to them. */
|
|
39
|
-
unverified?: Routes;
|
|
40
|
-
/** Routes that verify their own caller (a channel's platform signature, a host's IAM). Neither guard applies. */
|
|
41
|
-
selfVerifying?: Routes;
|
|
42
|
-
/** Prefix-owning handlers. Always treated as unverified — the control plane is the only one. */
|
|
43
|
-
mounts?: readonly PrefixMount[];
|
|
44
|
-
/** `http.cors` — exact origins, or `["*"]`. Set, it REPLACES the `*` default; unset, the default stands. */
|
|
45
|
-
corsOrigins?: readonly string[];
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Compose the routes that AUTHENTICATE NOBODY, the self-verifying channel routes, and the {@link PrefixMount}s
|
|
49
|
-
* into one handler.
|
|
50
|
-
*
|
|
51
|
-
* That is the axis, not authorship. Two things follow from it and nothing else does: whether a browser may drive
|
|
52
|
-
* the route, and whether its body must declare JSON. A channel route is exempt from both because it checks its
|
|
53
|
-
* platform's signature inside itself — a Telegram webhook is public on purpose. Ours check nothing, so the router
|
|
54
|
-
* checks for them.
|
|
55
|
-
*
|
|
56
|
-
* TWO TABLES, not one table plus a list of which keys are which, so the three readers (browser reachability, the JSON
|
|
57
|
-
* body gate, the startup report) cannot answer differently.
|
|
58
|
-
*
|
|
59
|
-
* CAVEAT, stated because we cannot enforce it: a CUSTOM channel that verifies nothing lands in `selfVerifying`
|
|
60
|
-
* anyway and gets neither guard. That is decision B (docs/design/session-control.md §14) and it belongs to the
|
|
61
|
-
* channel's author, who owns the credential the platform issued — but it is an assumption here, not a property.
|
|
62
|
-
*/
|
|
63
|
-
export declare function router(surface: RouterSurface): ChannelHandler;
|
|
64
|
-
/**
|
|
65
|
-
* The node:http adapter for a Fetch handler — the embedded server uses it, and an embedder mounting fastagent on its
|
|
66
|
-
* OWN node:http server can too.
|
|
67
|
-
*/
|
|
68
|
-
export declare function nodeListener(handler: ChannelHandler): (req: IncomingMessage, res: ServerResponse) => void;
|
|
69
|
-
export declare function serveNode(handler: ChannelHandler, options: {
|
|
1
|
+
import type { ChannelHandler } from "../channel.ts";
|
|
2
|
+
/** The totality boundary every serving path shares; `prepare` shapes the handler's response inside it. */
|
|
3
|
+
export declare function totalFetch(handler: ChannelHandler, prepare?: (response: Response) => Response): (req: Request) => Promise<Response>;
|
|
4
|
+
/** Serve `handler` on this runtime's own server: Node's `http.Server`, or `Bun.serve`. */
|
|
5
|
+
export declare function serveHandler(handler: ChannelHandler, options: {
|
|
70
6
|
port: number;
|
|
71
7
|
host?: string;
|
|
72
8
|
}): {
|
|
73
9
|
listening: Promise<number>;
|
|
74
10
|
close: () => Promise<void>;
|
|
75
|
-
closeAllConnections: () => void;
|
|
76
11
|
};
|