@fastagent-sh/fastagent 0.24.4 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -82
- package/dist/agent-api.d.ts +452 -0
- package/dist/agent-api.js +201 -0
- package/dist/answer-text.d.ts +8 -0
- package/dist/answer-text.js +18 -0
- package/dist/atomic-write.d.ts +2 -2
- package/dist/atomic-write.js +2 -2
- package/dist/authoring.d.ts +77 -0
- package/dist/authoring.js +238 -0
- package/dist/channel.d.ts +29 -15
- package/dist/channel.js +4 -1
- package/dist/channels/agentcore-protocol.d.ts +36 -50
- package/dist/channels/agentcore-protocol.js +3 -3
- package/dist/channels/agentcore-service.d.ts +8 -18
- package/dist/channels/agentcore-service.js +108 -127
- package/dist/channels/agentcore.d.ts +8 -24
- package/dist/channels/agentcore.js +32 -65
- package/dist/channels/body.d.ts +0 -16
- package/dist/channels/body.js +0 -25
- package/dist/channels/busy.js +6 -1
- package/dist/channels/context.d.ts +4 -0
- package/dist/channels/context.js +35 -0
- package/dist/channels/discover.d.ts +18 -20
- package/dist/channels/discover.js +41 -99
- package/dist/channels/feishu/feishu-api.d.ts +54 -4
- package/dist/channels/feishu/feishu-api.js +192 -149
- package/dist/channels/feishu/feishu.d.ts +3 -0
- package/dist/channels/feishu/feishu.js +117 -106
- package/dist/channels/feishu/history.d.ts +55 -0
- package/dist/channels/feishu/history.js +199 -0
- package/dist/channels/feishu/invoke-turn.d.ts +13 -11
- package/dist/channels/feishu/invoke-turn.js +9 -10
- package/dist/channels/feishu/model.d.ts +2 -1
- package/dist/channels/feishu/normalize.js +100 -0
- package/dist/channels/feishu/preview.d.ts +2 -2
- package/dist/channels/feishu/register-webhook.d.ts +1 -0
- package/dist/channels/feishu/register-webhook.js +3 -2
- package/dist/channels/feishu/scaffold/channel.ts +65 -46
- package/dist/channels/feishu/scaffold/feishu-send.ts +38 -33
- package/dist/channels/feishu/scaffold/feishu-threads.ts +25 -0
- package/dist/channels/feishu/setup-mode.d.ts +45 -25
- package/dist/channels/feishu/setup-mode.js +74 -23
- package/dist/channels/feishu/shared-api.d.ts +24 -6
- package/dist/channels/feishu/shared-api.js +30 -24
- package/dist/channels/kit/context-buffer.d.ts +11 -2
- package/dist/channels/kit/context-buffer.js +7 -4
- package/dist/channels/kit/delivery.d.ts +19 -3
- package/dist/channels/kit/delivery.js +74 -15
- package/dist/channels/kit/event-stream.js +2 -1
- package/dist/channels/kit/invoke-turn-kit.d.ts +41 -41
- package/dist/channels/kit/invoke-turn-kit.js +62 -71
- package/dist/channels/kit/place-history.d.ts +107 -0
- package/dist/channels/kit/place-history.js +182 -0
- package/dist/channels/kit/preview-kit.d.ts +9 -5
- package/dist/channels/kit/preview-kit.js +36 -15
- package/dist/channels/kit/room-threads.d.ts +46 -0
- package/dist/channels/kit/room-threads.js +81 -0
- package/dist/channels/kit/seen.js +1 -1
- package/dist/channels/kit/stop-command.d.ts +6 -3
- package/dist/channels/kit/stop-command.js +20 -18
- package/dist/channels/kit/thread-fork.d.ts +17 -0
- package/dist/channels/kit/thread-fork.js +43 -0
- package/dist/channels/kit/thread-participants.js +1 -1
- package/dist/channels/kit/transport.d.ts +5 -0
- package/dist/channels/kit/transport.js +5 -0
- package/dist/channels/kit/turn-runner.d.ts +10 -9
- package/dist/channels/kit/turn-runner.js +17 -19
- package/dist/channels/kit/turn-store.d.ts +5 -4
- package/dist/channels/kit/turn-store.js +5 -5
- package/dist/channels/lark/lark.d.ts +3 -0
- package/dist/channels/lark/lark.js +5 -0
- package/dist/channels/lark/onboard.d.ts +5 -3
- package/dist/channels/lark/onboard.js +14 -14
- package/dist/channels/lark/scaffold/channel.ts +67 -44
- package/dist/channels/lark/scaffold/lark-send.ts +38 -33
- package/dist/channels/lark/scaffold/lark-threads.ts +25 -0
- package/dist/channels/respond.d.ts +0 -4
- package/dist/channels/respond.js +1 -1
- package/dist/channels/router.d.ts +18 -0
- package/dist/channels/router.js +68 -0
- package/dist/channels/serve.d.ts +5 -70
- package/dist/channels/serve.js +105 -287
- package/dist/channels/slack/history.d.ts +42 -0
- package/dist/channels/slack/history.js +282 -0
- package/dist/channels/slack/invoke-turn.d.ts +12 -5
- package/dist/channels/slack/invoke-turn.js +7 -5
- package/dist/channels/slack/manifest.d.ts +1 -4
- package/dist/channels/slack/manifest.js +22 -10
- package/dist/channels/slack/model.d.ts +2 -1
- package/dist/channels/slack/onboard.d.ts +0 -2
- package/dist/channels/slack/onboard.js +2 -4
- package/dist/channels/slack/onboarding-state.d.ts +0 -2
- package/dist/channels/slack/onboarding-state.js +0 -1
- package/dist/channels/slack/parse.d.ts +0 -5
- package/dist/channels/slack/parse.js +1 -16
- package/dist/channels/slack/preview.d.ts +2 -3
- package/dist/channels/slack/preview.js +78 -52
- package/dist/channels/slack/register-webhook.d.ts +1 -0
- package/dist/channels/slack/register-webhook.js +6 -5
- package/dist/channels/slack/scaffold/channel.ts +23 -24
- package/dist/channels/slack/scaffold/slack-send.ts +50 -43
- package/dist/channels/slack/scaffold/slack-threads.ts +29 -0
- package/dist/channels/slack/setup-server.d.ts +19 -0
- package/dist/channels/slack/setup-server.js +113 -11
- package/dist/channels/slack/shared-api.d.ts +15 -4
- package/dist/channels/slack/shared-api.js +19 -14
- package/dist/channels/slack/slack-api.d.ts +61 -2
- package/dist/channels/slack/slack-api.js +28 -5
- package/dist/channels/slack/slack.js +97 -52
- package/dist/channels/slack/welcomed.js +1 -1
- package/dist/channels/telegram/context-buffer.d.ts +6 -1
- package/dist/channels/telegram/context-buffer.js +19 -0
- package/dist/channels/telegram/invoke-turn.d.ts +8 -4
- package/dist/channels/telegram/invoke-turn.js +7 -7
- package/dist/channels/telegram/parse.d.ts +7 -2
- package/dist/channels/telegram/parse.js +7 -0
- package/dist/channels/telegram/preview.d.ts +2 -2
- package/dist/channels/telegram/register-webhook.d.ts +1 -0
- package/dist/channels/telegram/register-webhook.js +3 -2
- package/dist/channels/telegram/scaffold/channel.ts +27 -28
- package/dist/channels/telegram/scaffold/telegram-send.ts +61 -108
- package/dist/channels/telegram/shared-api.d.ts +34 -0
- package/dist/channels/telegram/shared-api.js +79 -0
- package/dist/channels/telegram/telegram-api.d.ts +15 -5
- package/dist/channels/telegram/telegram-api.js +10 -6
- package/dist/channels/telegram/telegram.js +27 -21
- package/dist/channels/telegram/turn-store.js +1 -1
- package/dist/channels/{kit/turn-queue.d.ts → turn-queue.d.ts} +2 -2
- package/dist/channels/{kit/turn-queue.js → turn-queue.js} +10 -10
- package/dist/cli/add-feishu.d.ts +42 -12
- package/dist/cli/add-feishu.js +177 -124
- package/dist/cli/add-slack.d.ts +8 -3
- package/dist/cli/add-slack.js +115 -63
- package/dist/cli/auth-view.d.ts +10 -3
- package/dist/cli/auth-view.js +8 -6
- package/dist/cli/box-login.d.ts +17 -7
- package/dist/cli/box-login.js +46 -12
- package/dist/cli/commands/add.d.ts +15 -4
- package/dist/cli/commands/add.js +252 -143
- package/dist/cli/commands/auth.d.ts +6 -0
- package/dist/cli/commands/auth.js +50 -0
- package/dist/cli/commands/content.d.ts +6 -0
- package/dist/cli/commands/content.js +45 -0
- package/dist/cli/commands/deploy/agentcore.js +50 -77
- package/dist/cli/commands/deploy/docker.js +38 -39
- package/dist/cli/commands/deploy/fly.js +21 -18
- package/dist/cli/commands/deploy/host-login.d.ts +26 -0
- package/dist/cli/commands/deploy/host-login.js +90 -0
- package/dist/cli/commands/deploy/railway.js +21 -26
- package/dist/cli/commands/deploy/shared.d.ts +45 -17
- package/dist/cli/commands/deploy/shared.js +34 -15
- package/dist/cli/commands/deploy.d.ts +0 -4
- package/dist/cli/commands/deploy.js +237 -50
- package/dist/cli/commands/destroy.js +8 -6
- package/dist/cli/commands/dev.d.ts +0 -2
- package/dist/cli/commands/dev.js +20 -19
- package/dist/cli/commands/env.d.ts +12 -0
- package/dist/cli/commands/env.js +190 -0
- package/dist/cli/commands/info.js +95 -156
- package/dist/cli/commands/init.d.ts +2 -2
- package/dist/cli/commands/init.js +35 -33
- package/dist/cli/commands/invoke.d.ts +6 -0
- package/dist/cli/commands/invoke.js +131 -16
- package/dist/cli/commands/login.d.ts +31 -2
- package/dist/cli/commands/login.js +413 -64
- package/dist/cli/commands/logout.d.ts +4 -0
- package/dist/cli/commands/logout.js +53 -0
- package/dist/cli/commands/logs.js +8 -6
- package/dist/cli/commands/models.d.ts +2 -1
- package/dist/cli/commands/models.js +39 -37
- package/dist/cli/commands/schedules.d.ts +21 -0
- package/dist/cli/commands/schedules.js +143 -0
- package/dist/cli/commands/start.d.ts +11 -10
- package/dist/cli/commands/start.js +35 -62
- package/dist/cli/content-view.d.ts +9 -0
- package/dist/cli/content-view.js +26 -0
- package/dist/cli/fail.d.ts +9 -12
- package/dist/cli/fail.js +17 -14
- package/dist/cli/invoke-stream.d.ts +12 -3
- package/dist/cli/invoke-stream.js +85 -23
- package/dist/cli/kernel.d.ts +9 -2
- package/dist/cli/kernel.js +15 -6
- package/dist/cli/login-relay.d.ts +3 -2
- package/dist/cli/login-relay.js +18 -6
- package/dist/cli/models-view.d.ts +5 -1
- package/dist/cli/models-view.js +1 -1
- package/dist/cli/person.d.ts +10 -0
- package/dist/cli/person.js +23 -0
- package/dist/cli/program.js +421 -203
- package/dist/cli/serve.d.ts +13 -63
- package/dist/cli/serve.js +31 -121
- package/dist/cli/shared.d.ts +21 -48
- package/dist/cli/shared.js +68 -89
- package/dist/cli/ticket.d.ts +136 -0
- package/dist/cli/ticket.js +476 -0
- package/dist/client.d.ts +7 -0
- package/dist/client.js +2 -0
- package/dist/content/declare.d.ts +70 -0
- package/dist/content/declare.js +163 -0
- package/dist/content/file.d.ts +32 -0
- package/dist/content/file.js +119 -0
- package/dist/content/git.d.ts +41 -0
- package/dist/content/git.js +217 -0
- package/dist/content/mount.d.ts +2 -0
- package/dist/content/mount.js +15 -0
- package/dist/content/resolve.d.ts +52 -0
- package/dist/content/resolve.js +151 -0
- package/dist/content/source.d.ts +27 -0
- package/dist/content/source.js +53 -0
- package/dist/conversation-sessions.d.ts +26 -0
- package/dist/conversation-sessions.js +99 -0
- package/dist/declared-secrets.d.ts +19 -37
- package/dist/declared-secrets.js +16 -58
- package/dist/deploy/agentcore/destroy.d.ts +3 -3
- package/dist/deploy/agentcore/destroy.js +46 -28
- package/dist/deploy/agentcore/forwarder.js +105 -22
- package/dist/deploy/agentcore/logs.js +1 -1
- package/dist/deploy/agentcore/plan.d.ts +10 -24
- package/dist/deploy/agentcore/plan.js +31 -135
- package/dist/deploy/agentcore/run.d.ts +1 -1
- package/dist/deploy/agentcore/run.js +8 -5
- package/dist/deploy/agentcore/shell.d.ts +1 -1
- package/dist/deploy/agentcore/shell.js +5 -5
- package/dist/deploy/api.d.ts +34 -0
- package/dist/deploy/api.js +50 -0
- package/dist/deploy/box-shell.d.ts +6 -0
- package/dist/deploy/box-shell.js +7 -0
- package/dist/deploy/build-context.d.ts +7 -5
- package/dist/deploy/build-context.js +41 -35
- package/dist/deploy/channel-ingress.d.ts +6 -1
- package/dist/deploy/channel-ingress.js +18 -5
- package/dist/deploy/container.d.ts +22 -9
- package/dist/deploy/container.js +96 -55
- package/dist/deploy/docker/plan.d.ts +3 -2
- package/dist/deploy/docker/plan.js +13 -14
- package/dist/deploy/docker/run.d.ts +2 -2
- package/dist/deploy/docker/run.js +8 -4
- package/dist/deploy/fly/plan.d.ts +1 -1
- package/dist/deploy/fly/plan.js +12 -21
- package/dist/deploy/fly/run.d.ts +10 -6
- package/dist/deploy/fly/run.js +11 -6
- package/dist/deploy/hosts.d.ts +2 -1
- package/dist/deploy/hosts.js +2 -1
- package/dist/deploy/preflight.d.ts +21 -23
- package/dist/deploy/preflight.js +222 -201
- package/dist/deploy/railway/plan.d.ts +8 -6
- package/dist/deploy/railway/plan.js +15 -58
- package/dist/deploy/railway/run.d.ts +8 -3
- package/dist/deploy/railway/run.js +12 -8
- package/dist/deploy/residency.d.ts +5 -11
- package/dist/deploy/residency.js +0 -6
- package/dist/deploy/runner.d.ts +1 -1
- package/dist/deploy/runner.js +1 -1
- package/dist/deploy/secrets.d.ts +16 -2
- package/dist/deploy/secrets.js +33 -6
- package/dist/deploy/workspace.d.ts +11 -6
- package/dist/deploy/workspace.js +55 -38
- package/dist/dev-supervisor.d.ts +11 -2
- package/dist/dev-supervisor.js +51 -26
- package/dist/effect-port.d.ts +4 -4
- package/dist/effect-port.js +4 -4
- package/dist/environment/apt.d.ts +4 -0
- package/dist/environment/apt.js +32 -0
- package/dist/environment/declare.d.ts +59 -0
- package/dist/environment/declare.js +210 -0
- package/dist/environment/mise.d.ts +50 -0
- package/dist/environment/mise.js +268 -0
- package/dist/feishu.d.ts +2 -2
- package/dist/feishu.js +2 -2
- package/dist/git.d.ts +13 -0
- package/dist/git.js +55 -0
- package/dist/harnesses/models/catalog.d.ts +20 -0
- package/dist/harnesses/models/catalog.js +254 -0
- package/dist/{engines/pi/auth.d.ts → harnesses/models/credentials.d.ts} +3 -3
- package/dist/{engines/pi/auth.js → harnesses/models/credentials.js} +3 -3
- package/dist/harnesses/models/environment.d.ts +43 -0
- package/dist/harnesses/models/environment.js +82 -0
- package/dist/{engines/pi → harnesses/models}/login.d.ts +57 -26
- package/dist/{engines/pi → harnesses/models}/login.js +187 -79
- package/dist/harnesses/models/models.d.ts +83 -0
- package/dist/harnesses/models/models.js +158 -0
- package/dist/harnesses/pi-durable/agent.d.ts +42 -0
- package/dist/harnesses/pi-durable/agent.js +579 -0
- package/dist/harnesses/pi-durable/defaults.d.ts +28 -0
- package/dist/harnesses/pi-durable/defaults.js +26 -0
- package/dist/harnesses/pi-durable/define.d.ts +77 -0
- package/dist/harnesses/pi-durable/define.js +28 -0
- package/dist/harnesses/pi-durable/entries.d.ts +32 -0
- package/dist/harnesses/pi-durable/entries.js +126 -0
- package/dist/harnesses/pi-durable/events.d.ts +25 -0
- package/dist/harnesses/pi-durable/events.js +238 -0
- package/dist/harnesses/pi-durable/ids.d.ts +16 -0
- package/dist/harnesses/pi-durable/ids.js +55 -0
- package/dist/harnesses/pi-durable/messages.d.ts +41 -0
- package/dist/harnesses/pi-durable/messages.js +116 -0
- package/dist/harnesses/pi-durable/open.d.ts +88 -0
- package/dist/harnesses/pi-durable/open.js +329 -0
- package/dist/harnesses/pi-durable/reads.d.ts +30 -0
- package/dist/harnesses/pi-durable/reads.js +94 -0
- package/dist/harnesses/pi-durable/registry.d.ts +18 -0
- package/dist/harnesses/pi-durable/registry.js +56 -0
- package/dist/harnesses/pi-durable/release.d.ts +13 -0
- package/dist/harnesses/pi-durable/release.js +40 -0
- package/dist/harnesses/pi-durable/serve.d.ts +80 -0
- package/dist/harnesses/pi-durable/serve.js +156 -0
- package/dist/harnesses/pi-durable/sessions.d.ts +27 -0
- package/dist/harnesses/pi-durable/sessions.js +47 -0
- package/dist/harnesses/pi-durable/storage.d.ts +4 -0
- package/dist/harnesses/pi-durable/storage.js +49 -0
- package/dist/harnesses/pi-durable/stream.d.ts +20 -0
- package/dist/harnesses/pi-durable/stream.js +221 -0
- package/dist/harnesses/pi-durable/text.d.ts +30 -0
- package/dist/harnesses/pi-durable/text.js +292 -0
- package/dist/harnesses/pi-durable/wake.d.ts +4 -0
- package/dist/harnesses/pi-durable/wake.js +81 -0
- package/dist/http/client.d.ts +6 -0
- package/dist/http/client.js +256 -0
- package/dist/http/contract.d.ts +541 -0
- package/dist/http/contract.js +179 -0
- package/dist/http/server.d.ts +34 -0
- package/dist/http/server.js +194 -0
- package/dist/index.d.ts +17 -4
- package/dist/index.js +10 -5
- package/dist/lark.d.ts +2 -2
- package/dist/lark.js +2 -2
- package/dist/locked-file.d.ts +17 -0
- package/dist/{engines/pi/locked-file.js → locked-file.js} +16 -10
- package/dist/once.d.ts +6 -0
- package/dist/once.js +23 -0
- package/dist/paths.d.ts +36 -52
- package/dist/paths.js +66 -182
- package/dist/runtime.d.ts +25 -2
- package/dist/runtime.js +27 -0
- package/dist/scaffold/add-channel.d.ts +14 -27
- package/dist/scaffold/add-channel.js +82 -180
- package/dist/scaffold/init.d.ts +17 -18
- package/dist/scaffold/init.js +87 -99
- package/dist/scaffold/templates/SYSTEM.md +12 -0
- package/dist/scaffold/templates/env.example +4 -10
- package/dist/scaffold/templates/fastagent.config.ts +21 -33
- package/dist/scaffold/templates/gitignore +8 -1
- package/dist/scaffold/templates/skills/writing-great-skills/SKILL.md +1 -2
- package/dist/scaffold/templates.d.ts +9 -4
- package/dist/scaffold/templates.js +7 -5
- package/dist/scaffold/vendor-skill.d.ts +1 -4
- package/dist/scaffold/vendor-skill.js +5 -6
- package/dist/schedule/cron.d.ts +13 -0
- package/dist/schedule/cron.js +52 -0
- package/dist/schedule/eventbridge-cron.d.ts +17 -0
- package/dist/schedule/eventbridge-cron.js +88 -0
- package/dist/schedule/schedule.d.ts +23 -0
- package/dist/schedule/schedule.js +34 -0
- package/dist/schedule/scheduler.d.ts +34 -33
- package/dist/schedule/scheduler.js +251 -137
- package/dist/schedule/state.d.ts +4 -14
- package/dist/schedule/state.js +7 -7
- package/dist/schedule/wake-alarm.d.ts +22 -2
- package/dist/schedule/wake-alarm.js +66 -20
- package/dist/schedule/wakeups.d.ts +16 -15
- package/dist/schedule/wakeups.js +47 -45
- package/dist/service.d.ts +56 -169
- package/dist/service.js +91 -187
- package/dist/serving-command.d.ts +10 -0
- package/dist/serving-command.js +16 -0
- package/dist/slack.d.ts +1 -1
- package/dist/slack.js +1 -1
- package/dist/{channels/kit/state.js → state-file.js} +6 -6
- package/dist/telegram.d.ts +1 -0
- package/dist/telegram.js +1 -0
- package/dist/tunnel.d.ts +3 -0
- package/dist/tunnel.js +12 -4
- package/dist/value-file.d.ts +21 -0
- package/dist/value-file.js +108 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.js +14 -1
- package/package.json +18 -28
- package/dist/agent.d.ts +0 -106
- package/dist/agent.js +0 -21
- package/dist/channels/control.d.ts +0 -31
- package/dist/channels/control.js +0 -329
- package/dist/channels/define-channel.d.ts +0 -39
- package/dist/channels/define-channel.js +0 -9
- package/dist/channels/feishu/context-buffer.d.ts +0 -35
- package/dist/channels/feishu/context-buffer.js +0 -65
- package/dist/channels/feishu/scaffold/channel.websocket.ts +0 -31
- package/dist/channels/http.d.ts +0 -23
- package/dist/channels/http.js +0 -57
- package/dist/channels/lark/scaffold/channel.websocket.ts +0 -31
- package/dist/channels/slack/context-buffer.d.ts +0 -23
- package/dist/channels/slack/context-buffer.js +0 -37
- package/dist/channels/sse.d.ts +0 -4
- package/dist/channels/sse.js +0 -66
- package/dist/cli/commands/chat.d.ts +0 -3
- package/dist/cli/commands/chat.js +0 -14
- package/dist/cli/commands/routine-run.d.ts +0 -6
- package/dist/cli/commands/routine-run.js +0 -46
- package/dist/cli/commands/routine.d.ts +0 -25
- package/dist/cli/commands/routine.js +0 -122
- package/dist/cli/commands/tool.d.ts +0 -1
- package/dist/cli/commands/tool.js +0 -57
- package/dist/collect.d.ts +0 -63
- package/dist/collect.js +0 -90
- package/dist/core.d.ts +0 -13
- package/dist/core.js +0 -15
- package/dist/engines/pi/agent-models.d.ts +0 -83
- package/dist/engines/pi/agent-models.js +0 -120
- package/dist/engines/pi/agent-session-factory.d.ts +0 -121
- package/dist/engines/pi/agent-session-factory.js +0 -535
- package/dist/engines/pi/chat.d.ts +0 -3
- package/dist/engines/pi/chat.js +0 -8
- package/dist/engines/pi/config.d.ts +0 -71
- package/dist/engines/pi/config.js +0 -199
- package/dist/engines/pi/create.d.ts +0 -170
- package/dist/engines/pi/create.js +0 -343
- package/dist/engines/pi/definition.d.ts +0 -74
- package/dist/engines/pi/definition.js +0 -236
- package/dist/engines/pi/entry-images.d.ts +0 -14
- package/dist/engines/pi/entry-images.js +0 -23
- package/dist/engines/pi/invoke-session.d.ts +0 -18
- package/dist/engines/pi/invoke-session.js +0 -403
- package/dist/engines/pi/locked-file.d.ts +0 -9
- package/dist/engines/pi/machine.d.ts +0 -53
- package/dist/engines/pi/machine.js +0 -137
- package/dist/engines/pi/models.d.ts +0 -200
- package/dist/engines/pi/models.js +0 -533
- package/dist/engines/pi/open.d.ts +0 -180
- package/dist/engines/pi/open.js +0 -270
- package/dist/engines/pi/openai-account-models.d.ts +0 -35
- package/dist/engines/pi/openai-account-models.js +0 -116
- package/dist/engines/pi/report.d.ts +0 -18
- package/dist/engines/pi/report.js +0 -59
- package/dist/engines/pi/retry-event.d.ts +0 -6
- package/dist/engines/pi/retry-event.js +0 -15
- package/dist/engines/pi/service.d.ts +0 -9
- package/dist/engines/pi/service.js +0 -14
- package/dist/engines/pi/session-builder.d.ts +0 -13
- package/dist/engines/pi/session-builder.js +0 -117
- package/dist/engines/pi/session-control.d.ts +0 -77
- package/dist/engines/pi/session-control.js +0 -908
- package/dist/engines/pi/session-effects.d.ts +0 -14
- package/dist/engines/pi/session-effects.js +0 -30
- package/dist/engines/pi/session-inheritance.d.ts +0 -21
- package/dist/engines/pi/session-inheritance.js +0 -204
- package/dist/engines/pi/session-markers.d.ts +0 -49
- package/dist/engines/pi/session-markers.js +0 -60
- package/dist/engines/pi/session-settings.d.ts +0 -67
- package/dist/engines/pi/session-settings.js +0 -119
- package/dist/engines/pi/session-store.d.ts +0 -69
- package/dist/engines/pi/session-store.js +0 -430
- package/dist/engines/pi/tool-context.d.ts +0 -45
- package/dist/engines/pi/tool-context.js +0 -31
- package/dist/engines/pi/tool.d.ts +0 -99
- package/dist/engines/pi/tool.js +0 -118
- package/dist/engines/pi/turn-kit.d.ts +0 -92
- package/dist/engines/pi/turn-kit.js +0 -288
- package/dist/engines/pi/wake-tool.d.ts +0 -9
- package/dist/engines/pi/wake-tool.js +0 -92
- package/dist/loader.d.ts +0 -41
- package/dist/loader.js +0 -116
- package/dist/node.d.ts +0 -3
- package/dist/node.js +0 -4
- package/dist/observe.d.ts +0 -6
- package/dist/observe.js +0 -47
- package/dist/pi.d.ts +0 -25
- package/dist/pi.js +0 -15
- package/dist/scaffold/templates/APPEND_SYSTEM.md +0 -12
- package/dist/scaffold/templates/tools/fetch-url.ts +0 -25
- package/dist/schedule/discover.d.ts +0 -17
- package/dist/schedule/discover.js +0 -61
- package/dist/schedule/routine.d.ts +0 -43
- package/dist/schedule/routine.js +0 -32
- package/dist/schedule/run.d.ts +0 -55
- package/dist/schedule/run.js +0 -146
- package/dist/secrets-gate.d.ts +0 -32
- package/dist/secrets-gate.js +0 -33
- package/dist/session-remote.d.ts +0 -47
- package/dist/session-remote.js +0 -460
- package/dist/session.d.ts +0 -466
- package/dist/session.js +0 -57
- /package/dist/{channels/kit/state.d.ts → state-file.d.ts} +0 -0
|
@@ -1,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 { feishuTransport } from "@fastagent-sh/fastagent/feishu";
|
|
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 FEISHU_APP_ID / FEISHU_APP_SECRET itself.
|
|
8
|
+
export default needs(["FEISHU_APP_ID", "FEISHU_APP_SECRET"], (secrets) =>
|
|
9
|
+
defineTool({
|
|
10
|
+
name: "feishu_send",
|
|
11
|
+
description:
|
|
12
|
+
"Send a message to a Feishu 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 [feishu: 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 = feishuTransport({ appId: secrets.FEISHU_APP_ID, appSecret: secrets.FEISHU_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 = feishuTransport(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 { feishuThreads } from "@fastagent-sh/fastagent/feishu";
|
|
5
|
+
|
|
6
|
+
// Reads the threads (topics) of the Feishu 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: "feishu_threads",
|
|
11
|
+
description:
|
|
12
|
+
"Read the threads (topics) of the Feishu 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 = feishuThreads(await sessionIdOf(api, context));
|
|
22
|
+
const text = threadId === undefined ? await threads.list() : await threads.read(threadId);
|
|
23
|
+
return { output: [{ type: "text", text }] };
|
|
24
|
+
},
|
|
25
|
+
});
|
|
@@ -1,19 +1,54 @@
|
|
|
1
|
-
|
|
1
|
+
import { type FeishuCloudKind } from "./cloud.ts";
|
|
2
|
+
/** Feishu/Lark app-level event subscription choice: how a channel receives, and what an app is set up for. */
|
|
2
3
|
export type FeishuSubscriptionMode = "webhook" | "websocket";
|
|
3
|
-
/**
|
|
4
|
-
export
|
|
4
|
+
/** The settings {@link feishuIngressFor} reads, one per cloud: what `deploy` must read the way the box will. */
|
|
5
|
+
export declare const FEISHU_INGRESS_SETTINGS: string[];
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
7
|
+
* How THIS process receives a Feishu/Lark channel (docs/design/channel-environments.md): `<PREFIX>_INGRESS` when the
|
|
8
|
+
* environment names one, else WebSocket under `dev` (no public URL, no reviewed scope) and webhook everywhere else,
|
|
9
|
+
* which is what every deployment runs. The channel file asks at import, and so does every reader of its shape: `deploy`
|
|
10
|
+
* inspects it in a process that is not `dev`, with the same value file loaded, so it sees what the box will serve.
|
|
11
|
+
*/
|
|
12
|
+
export declare function feishuIngressFor(kind: FeishuCloudKind, env?: NodeJS.ProcessEnv): FeishuSubscriptionMode;
|
|
13
|
+
/**
|
|
14
|
+
* Configuring THIS app through the v7 config API: registering a webhook Request URL and switching the subscription
|
|
15
|
+
* mode. Requested for a webhook app only. A tenant may review it, and a scope under review holds the app's whole first
|
|
16
|
+
* version in review, so a WebSocket app, which never uses it, would wait on an admin for nothing (measured: the same
|
|
17
|
+
* creation without it came back active).
|
|
8
18
|
*/
|
|
9
19
|
export declare const FEISHU_APP_CONFIG_SCOPE = "application:application:patch";
|
|
10
20
|
/** The one event an agent app cannot serve without: an inbound message. */
|
|
11
21
|
export declare const FEISHU_MESSAGE_RECEIVE_EVENT = "im.message.receive_v1";
|
|
22
|
+
/** A scope the onboarding asks for, plus any BROADER spelling that already satisfies it. */
|
|
23
|
+
export interface FeishuScopeRequest {
|
|
24
|
+
/** What to request when nothing satisfies it. */
|
|
25
|
+
request: string;
|
|
26
|
+
/** EXTRA spellings that also count — supersets. */
|
|
27
|
+
supersets?: string[];
|
|
28
|
+
/** What the agent loses without it, for the warning that names it. */
|
|
29
|
+
withoutIt: string;
|
|
30
|
+
}
|
|
31
|
+
/** Whether `predicate` holds for any spelling that satisfies this request. */
|
|
32
|
+
export declare function scopeSatisfied(entry: FeishuScopeRequest, predicate: (name: string) => boolean): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* What an agent may know about the rooms it is in, on top of the platform's agent template. There is one posture: the
|
|
35
|
+
* agent takes part in its rooms like a colleague (participant-model.md), so every app gets all of it, requested at
|
|
36
|
+
* creation in the one round a tenant may want to approve. What a scope is for is the agent's, not only the channel's:
|
|
37
|
+
* the agent can call the Open API with the app's credentials. A scope belongs here only once something uses it:
|
|
38
|
+
* `im:message.group_msg.include_bot:read` (other bots' group messages) is an event-delivery scope. The channel reads
|
|
39
|
+
* other bots' messages from a chat's history, which does not need it (measured), and drops every non-user event.
|
|
40
|
+
*/
|
|
41
|
+
export declare const FEISHU_AGENT_SCOPES: FeishuScopeRequest[];
|
|
42
|
+
/**
|
|
43
|
+
* Every scope an app of this ingress needs: what onboarding requests at creation AND what it checks the app holds, so a
|
|
44
|
+
* scope the app is asked for is one whose absence is reported.
|
|
45
|
+
*/
|
|
46
|
+
export declare function feishuAppScopes(ingress: FeishuSubscriptionMode): FeishuScopeRequest[];
|
|
12
47
|
/**
|
|
13
|
-
* What a created app carries on top of the platform's agent template
|
|
14
|
-
*
|
|
48
|
+
* What a created app carries on top of the platform's agent template — the `addons` merged onto the confirm page. A
|
|
49
|
+
* scope that arrives here needs no console visit; one a tenant withholds is reported after creation (`add-feishu.ts`).
|
|
15
50
|
*/
|
|
16
|
-
export declare function feishuAppAddons(): {
|
|
51
|
+
export declare function feishuAppAddons(ingress: FeishuSubscriptionMode): {
|
|
17
52
|
scopes: {
|
|
18
53
|
tenant: string[];
|
|
19
54
|
};
|
|
@@ -23,20 +58,5 @@ export declare function feishuAppAddons(): {
|
|
|
23
58
|
};
|
|
24
59
|
};
|
|
25
60
|
};
|
|
26
|
-
/** The
|
|
27
|
-
export declare
|
|
28
|
-
/** Reading a QUOTED message by id, so an ask carries what it replies to (participant-model.md §8). */
|
|
29
|
-
export declare const FEISHU_MESSAGE_READ_SCOPE = "im:message:readonly";
|
|
30
|
-
/** A scope the onboarding asks for, plus any BROADER spelling that already satisfies it. */
|
|
31
|
-
export interface FeishuScopeRequest {
|
|
32
|
-
/** What to add to the app draft when nothing satisfies it. */
|
|
33
|
-
request: string;
|
|
34
|
-
/** EXTRA spellings that also count — supersets. */
|
|
35
|
-
supersets?: string[];
|
|
36
|
-
}
|
|
37
|
-
/** Whether `predicate` holds for any spelling that satisfies this request. */
|
|
38
|
-
export declare function scopeSatisfied(entry: FeishuScopeRequest, predicate: (name: string) => boolean): boolean;
|
|
39
|
-
/** Reading a quoted message: `im:message` is the read/write superset, so an app holding it can already do so. */
|
|
40
|
-
export declare const FEISHU_MESSAGE_READ_REQUEST: FeishuScopeRequest;
|
|
41
|
-
/** What `--group-behavior context` REQUESTS in one approval round — not a dependency set. */
|
|
42
|
-
export declare const FEISHU_CONTEXT_ONBOARDING_SCOPES: FeishuScopeRequest[];
|
|
61
|
+
/** The console page that requests `scopes` for this app, pre-filled: the platform's own link for a missing scope. */
|
|
62
|
+
export declare function feishuScopeRequestUrl(apiBase: string, appId: string, scopes: readonly string[]): string;
|
|
@@ -1,35 +1,86 @@
|
|
|
1
|
+
import { servedByDev } from "../../serving-command.js";
|
|
2
|
+
import { cloudFor } from "./cloud.js";
|
|
3
|
+
/** The settings {@link feishuIngressFor} reads, one per cloud: what `deploy` must read the way the box will. */
|
|
4
|
+
export const FEISHU_INGRESS_SETTINGS = ["feishu", "lark"].map((kind) => `${cloudFor(kind).envPrefix}_INGRESS`);
|
|
1
5
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
6
|
+
* How THIS process receives a Feishu/Lark channel (docs/design/channel-environments.md): `<PREFIX>_INGRESS` when the
|
|
7
|
+
* environment names one, else WebSocket under `dev` (no public URL, no reviewed scope) and webhook everywhere else,
|
|
8
|
+
* which is what every deployment runs. The channel file asks at import, and so does every reader of its shape: `deploy`
|
|
9
|
+
* inspects it in a process that is not `dev`, with the same value file loaded, so it sees what the box will serve.
|
|
10
|
+
*/
|
|
11
|
+
export function feishuIngressFor(kind, env = process.env) {
|
|
12
|
+
const name = `${cloudFor(kind).envPrefix}_INGRESS`;
|
|
13
|
+
const raw = env[name]?.trim();
|
|
14
|
+
if (!raw)
|
|
15
|
+
return servedByDev(env) ? "websocket" : "webhook";
|
|
16
|
+
if (raw !== "webhook" && raw !== "websocket") {
|
|
17
|
+
throw new Error(`${name} must be "webhook" or "websocket", got "${raw}"`);
|
|
18
|
+
}
|
|
19
|
+
return raw;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Configuring THIS app through the v7 config API: registering a webhook Request URL and switching the subscription
|
|
23
|
+
* mode. Requested for a webhook app only. A tenant may review it, and a scope under review holds the app's whole first
|
|
24
|
+
* version in review, so a WebSocket app, which never uses it, would wait on an admin for nothing (measured: the same
|
|
25
|
+
* creation without it came back active).
|
|
4
26
|
*/
|
|
5
27
|
export const FEISHU_APP_CONFIG_SCOPE = "application:application:patch";
|
|
6
28
|
/** The one event an agent app cannot serve without: an inbound message. */
|
|
7
29
|
export const FEISHU_MESSAGE_RECEIVE_EVENT = "im.message.receive_v1";
|
|
30
|
+
/** Whether `predicate` holds for any spelling that satisfies this request. */
|
|
31
|
+
export function scopeSatisfied(entry, predicate) {
|
|
32
|
+
return [entry.request, ...(entry.supersets ?? [])].some(predicate);
|
|
33
|
+
}
|
|
8
34
|
/**
|
|
9
|
-
* What
|
|
10
|
-
*
|
|
35
|
+
* What an agent may know about the rooms it is in, on top of the platform's agent template. There is one posture: the
|
|
36
|
+
* agent takes part in its rooms like a colleague (participant-model.md), so every app gets all of it, requested at
|
|
37
|
+
* creation in the one round a tenant may want to approve. What a scope is for is the agent's, not only the channel's:
|
|
38
|
+
* the agent can call the Open API with the app's credentials. A scope belongs here only once something uses it:
|
|
39
|
+
* `im:message.group_msg.include_bot:read` (other bots' group messages) is an event-delivery scope. The channel reads
|
|
40
|
+
* other bots' messages from a chat's history, which does not need it (measured), and drops every non-user event.
|
|
11
41
|
*/
|
|
12
|
-
export
|
|
42
|
+
export const FEISHU_AGENT_SCOPES = [
|
|
43
|
+
{
|
|
44
|
+
request: "im:message.group_msg", // sensitive: some tenants approve it by hand
|
|
45
|
+
withoutIt: "only @mentions arrive: no bare replies in the agent's threads, no group discussion as context",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
request: "im:message:readonly",
|
|
49
|
+
supersets: ["im:message"], // the read/write superset
|
|
50
|
+
withoutIt: "the discussion before an ask cannot be read (the prompt says so), and a quoted message degrades to a marker",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
request: "im:chat.members:read",
|
|
54
|
+
withoutIt: "people in the discussion the agent reads are shown by open_id, not by name",
|
|
55
|
+
},
|
|
56
|
+
];
|
|
57
|
+
/** The config scope as an app needs it: webhook only ({@link FEISHU_APP_CONFIG_SCOPE}). */
|
|
58
|
+
const FEISHU_APP_CONFIG_REQUEST = {
|
|
59
|
+
request: FEISHU_APP_CONFIG_SCOPE,
|
|
60
|
+
withoutIt: "the Verification Token is not captured and no Request URL is registered for you (add, dev --tunnel, deploy --run)",
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Every scope an app of this ingress needs: what onboarding requests at creation AND what it checks the app holds, so a
|
|
64
|
+
* scope the app is asked for is one whose absence is reported.
|
|
65
|
+
*/
|
|
66
|
+
export function feishuAppScopes(ingress) {
|
|
67
|
+
return [...(ingress === "webhook" ? [FEISHU_APP_CONFIG_REQUEST] : []), ...FEISHU_AGENT_SCOPES];
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* What a created app carries on top of the platform's agent template — the `addons` merged onto the confirm page. A
|
|
71
|
+
* scope that arrives here needs no console visit; one a tenant withholds is reported after creation (`add-feishu.ts`).
|
|
72
|
+
*/
|
|
73
|
+
export function feishuAppAddons(ingress) {
|
|
13
74
|
return {
|
|
14
|
-
scopes: { tenant:
|
|
75
|
+
scopes: { tenant: feishuAppScopes(ingress).map((entry) => entry.request) },
|
|
15
76
|
events: { items: { tenant: [FEISHU_MESSAGE_RECEIVE_EVENT] } },
|
|
16
77
|
};
|
|
17
78
|
}
|
|
18
|
-
/** The
|
|
19
|
-
export
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return
|
|
79
|
+
/** The console page that requests `scopes` for this app, pre-filled: the platform's own link for a missing scope. */
|
|
80
|
+
export function feishuScopeRequestUrl(apiBase, appId, scopes) {
|
|
81
|
+
const url = new URL(`${apiBase}/app/${encodeURIComponent(appId)}/auth`);
|
|
82
|
+
url.searchParams.set("q", scopes.join(","));
|
|
83
|
+
url.searchParams.set("op_from", "openapi");
|
|
84
|
+
url.searchParams.set("token_type", "tenant");
|
|
85
|
+
return url.toString();
|
|
25
86
|
}
|
|
26
|
-
/** Reading a quoted message: `im:message` is the read/write superset, so an app holding it can already do so. */
|
|
27
|
-
export const FEISHU_MESSAGE_READ_REQUEST = {
|
|
28
|
-
request: FEISHU_MESSAGE_READ_SCOPE,
|
|
29
|
-
supersets: ["im:message"],
|
|
30
|
-
};
|
|
31
|
-
/** What `--group-behavior context` REQUESTS in one approval round — not a dependency set. */
|
|
32
|
-
export const FEISHU_CONTEXT_ONBOARDING_SCOPES = [
|
|
33
|
-
{ request: FEISHU_GROUP_CONTEXT_SCOPE },
|
|
34
|
-
FEISHU_MESSAGE_READ_REQUEST,
|
|
35
|
-
];
|
|
@@ -1,10 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The mounted channel and proactive tools share credentials, token cache, gateway and retry policy: one transport per
|
|
3
|
+
* app a process holds, found by the app id both hold.
|
|
4
|
+
*/
|
|
5
|
+
import { roomThreads } from "../kit/room-threads.ts";
|
|
1
6
|
import { type FeishuCloudKind } from "./cloud.ts";
|
|
2
7
|
import { type FeishuApi } from "./feishu-api.ts";
|
|
3
8
|
/** The delivery methods a proactive sender needs. */
|
|
4
9
|
export type FeishuTransport = Pick<FeishuApi, "sendText" | "sendMessage">;
|
|
5
|
-
/**
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
/** The app a transport signs in as. */
|
|
11
|
+
export interface FeishuAppCredentials {
|
|
12
|
+
appId: string;
|
|
13
|
+
appSecret: string;
|
|
14
|
+
}
|
|
15
|
+
/** A remount replaces the transport: the channel's is the authoritative one for its app. */
|
|
16
|
+
export declare function registerFeishuApi(appId: string, kind: FeishuCloudKind, api: FeishuApi): void;
|
|
17
|
+
/** The Feishu transport of an app: its mounted channel's, or the app's own when none is mounted. */
|
|
18
|
+
export declare function feishuTransport(app: FeishuAppCredentials): FeishuTransport;
|
|
19
|
+
/** The Lark transport of an app: its mounted channel's, or the app's own when none is mounted. */
|
|
20
|
+
export declare function larkTransport(app: FeishuAppCredentials): FeishuTransport;
|
|
21
|
+
/**
|
|
22
|
+
* The threads of the group chat the message running in `sessionId` was asked in, and only those
|
|
23
|
+
* (`kit/room-threads.ts`): `list()` its recent threads, `read(threadId)` one of them. Throws outside a Feishu group
|
|
24
|
+
* turn served by this process.
|
|
25
|
+
*/
|
|
26
|
+
export declare function feishuThreads(sessionId: string | undefined): ReturnType<typeof roomThreads>;
|
|
27
|
+
/** {@link feishuThreads}, for a Lark group turn. */
|
|
28
|
+
export declare function larkThreads(sessionId: string | undefined): ReturnType<typeof roomThreads>;
|
|
@@ -1,38 +1,44 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* The mounted channel and proactive tools share credentials, token cache, gateway and retry policy: one transport per
|
|
3
|
+
* app a process holds, found by the app id both hold.
|
|
4
|
+
*/
|
|
5
|
+
import { roomThreads } from "../kit/room-threads.js";
|
|
3
6
|
import { cloudFor } from "./cloud.js";
|
|
4
7
|
import { createFeishuApi } from "./feishu-api.js";
|
|
5
8
|
const byKind = {
|
|
6
9
|
feishu: new Map(),
|
|
7
10
|
lark: new Map(),
|
|
8
11
|
};
|
|
9
|
-
/** A remount replaces the transport
|
|
10
|
-
export function registerFeishuApi(
|
|
11
|
-
byKind[kind].set(
|
|
12
|
+
/** A remount replaces the transport: the channel's is the authoritative one for its app. */
|
|
13
|
+
export function registerFeishuApi(appId, kind, api) {
|
|
14
|
+
byKind[kind].set(appId, api);
|
|
12
15
|
}
|
|
13
|
-
function cloudTransport(
|
|
14
|
-
// Embedded senders may use a bare definition directory or an independent workspace.
|
|
15
|
-
const stateRoot = resolveStateRoot(findAgentDir(cwd) ?? cwd);
|
|
16
|
+
function cloudTransport({ appId, appSecret }, kind) {
|
|
16
17
|
const transports = byKind[kind];
|
|
17
|
-
let api = transports.get(
|
|
18
|
+
let api = transports.get(appId);
|
|
18
19
|
if (!api) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const appId = process.env[`${envPrefix}_APP_ID`];
|
|
22
|
-
const appSecret = process.env[`${envPrefix}_APP_SECRET`];
|
|
23
|
-
if (!appId || !appSecret) {
|
|
24
|
-
throw new Error(`${envPrefix}_APP_ID / ${envPrefix}_APP_SECRET are not set and no ${kind} channel is mounted`);
|
|
25
|
-
}
|
|
26
|
-
api = createFeishuApi({ kind, baseUrl: apiBase, appId, appSecret });
|
|
27
|
-
transports.set(stateRoot, api);
|
|
20
|
+
api = createFeishuApi({ kind, baseUrl: cloudFor(kind).apiBase, appId, appSecret });
|
|
21
|
+
transports.set(appId, api);
|
|
28
22
|
}
|
|
29
23
|
return api;
|
|
30
24
|
}
|
|
31
|
-
/**
|
|
32
|
-
export function feishuTransport(
|
|
33
|
-
return cloudTransport(
|
|
25
|
+
/** The Feishu transport of an app: its mounted channel's, or the app's own when none is mounted. */
|
|
26
|
+
export function feishuTransport(app) {
|
|
27
|
+
return cloudTransport(app, "feishu");
|
|
34
28
|
}
|
|
35
|
-
/**
|
|
36
|
-
export function larkTransport(
|
|
37
|
-
return cloudTransport(
|
|
29
|
+
/** The Lark transport of an app: its mounted channel's, or the app's own when none is mounted. */
|
|
30
|
+
export function larkTransport(app) {
|
|
31
|
+
return cloudTransport(app, "lark");
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The threads of the group chat the message running in `sessionId` was asked in, and only those
|
|
35
|
+
* (`kit/room-threads.ts`): `list()` its recent threads, `read(threadId)` one of them. Throws outside a Feishu group
|
|
36
|
+
* turn served by this process.
|
|
37
|
+
*/
|
|
38
|
+
export function feishuThreads(sessionId) {
|
|
39
|
+
return roomThreads("feishu", sessionId);
|
|
40
|
+
}
|
|
41
|
+
/** {@link feishuThreads}, for a Lark group turn. */
|
|
42
|
+
export function larkThreads(sessionId) {
|
|
43
|
+
return roomThreads("lark", sessionId);
|
|
38
44
|
}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import type { DiscussionSource } from "./place-history.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Char budget for the per-place buffer — bounds the cost of folding it into a prompt; when exceeded the OLDEST
|
|
4
|
+
* un-summoned messages are dropped. Not a time window: a quiet group keeps its sparse-but-relevant lines.
|
|
5
|
+
*/
|
|
6
|
+
export declare const BUFFER_MAX_CHARS = 4000;
|
|
1
7
|
/** Per-message bound INSIDE that budget. */
|
|
2
8
|
export declare const BUFFER_LINE_MAX_CHARS = 280;
|
|
3
9
|
/** How many buffered files and images (each, most recent first) a summon pulls in with the folded discussion. */
|
|
@@ -10,9 +16,12 @@ export declare function capBufferedRefs<R>(refs: R[]): {
|
|
|
10
16
|
kept: R[];
|
|
11
17
|
skipped: number;
|
|
12
18
|
};
|
|
13
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* The folded discussion as it reaches the model — the prompt block, or nothing when the buffer is empty. "Here", not
|
|
21
|
+
* "group": a direct chat's buffer holds what the agent sent there itself.
|
|
22
|
+
*/
|
|
14
23
|
export declare function discussionBlock(text: string): string;
|
|
15
|
-
export interface ContextBuffer<E> {
|
|
24
|
+
export interface ContextBuffer<E> extends DiscussionSource<E> {
|
|
16
25
|
/** Record an un-summoned message. */
|
|
17
26
|
push(placeKey: string, entry: E): void;
|
|
18
27
|
/** Render the fold text and snapshot the consumed entries (see the module header's consume protocol). */
|
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
* never flowing in as trusted data.
|
|
15
15
|
*/
|
|
16
16
|
import { log } from "../../log.js";
|
|
17
|
-
import { loadStateFile, saveStateFile } from "
|
|
17
|
+
import { loadStateFile, saveStateFile } from "../../state-file.js";
|
|
18
18
|
/**
|
|
19
19
|
* Char budget for the per-place buffer — bounds the cost of folding it into a prompt; when exceeded the OLDEST
|
|
20
20
|
* un-summoned messages are dropped. Not a time window: a quiet group keeps its sparse-but-relevant lines.
|
|
21
21
|
*/
|
|
22
|
-
const BUFFER_MAX_CHARS = 4000;
|
|
22
|
+
export const BUFFER_MAX_CHARS = 4000;
|
|
23
23
|
/** Per-message bound INSIDE that budget. */
|
|
24
24
|
export const BUFFER_LINE_MAX_CHARS = 280;
|
|
25
25
|
/** How many buffered files and images (each, most recent first) a summon pulls in with the folded discussion. */
|
|
@@ -31,9 +31,12 @@ export const BUFFER_ATTACH_MAX = 3;
|
|
|
31
31
|
export function capBufferedRefs(refs) {
|
|
32
32
|
return { kept: refs.slice(-BUFFER_ATTACH_MAX), skipped: Math.max(0, refs.length - BUFFER_ATTACH_MAX) };
|
|
33
33
|
}
|
|
34
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* The folded discussion as it reaches the model — the prompt block, or nothing when the buffer is empty. "Here", not
|
|
36
|
+
* "group": a direct chat's buffer holds what the agent sent there itself.
|
|
37
|
+
*/
|
|
35
38
|
export function discussionBlock(text) {
|
|
36
|
-
return text ? `[recent
|
|
39
|
+
return text ? `[recent discussion here:\n${text}\n]\n\n` : "";
|
|
37
40
|
}
|
|
38
41
|
export function createContextBuffer(options) {
|
|
39
42
|
const { path, label, isEntry, line } = options;
|
|
@@ -1,13 +1,29 @@
|
|
|
1
1
|
import * as Effect from "effect/Effect";
|
|
2
2
|
import type * as Scope from "effect/Scope";
|
|
3
3
|
import * as Stream from "effect/Stream";
|
|
4
|
-
import type {
|
|
4
|
+
import type { TurnEvent } from "./invoke-turn-kit.ts";
|
|
5
5
|
import type { ChannelFailure } from "./preview-kit.ts";
|
|
6
6
|
import { PortFailure } from "../../effect-port.ts";
|
|
7
|
+
/** How a turn ended: answered, or the failure to tell the asker about. */
|
|
8
|
+
export type TurnEnd = {
|
|
9
|
+
answered: true;
|
|
10
|
+
} | {
|
|
11
|
+
failure: ChannelFailure;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Whether this event ends the turn, and how: the message was refused, or the turn's message ended. A message the
|
|
15
|
+
* agent stopped answering at its output limit still answers with what was written.
|
|
16
|
+
*/
|
|
17
|
+
export declare function turnEnd(event: TurnEvent, messageId: string | undefined): TurnEnd | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* A turn whose stream ended before its message did, after the agent said why (`stream_error`: the message's end could
|
|
20
|
+
* not be recorded, or missed events could not be read back): a failure worth trying again. Undefined when nothing was said.
|
|
21
|
+
*/
|
|
22
|
+
export declare function unfinishedTurn(streamError: string | undefined): ChannelFailure | undefined;
|
|
7
23
|
/** Snapshot/edit renderers share terminal ownership; platform-specific settle policies stay injected. */
|
|
8
|
-
export declare function renderReply(events: Stream.Stream<
|
|
24
|
+
export declare function renderReply(events: Stream.Stream<TurnEvent, PortFailure>, opts: {
|
|
9
25
|
label: string;
|
|
10
|
-
onEvent: (event:
|
|
26
|
+
onEvent: (event: TurnEvent) => void;
|
|
11
27
|
finish: Effect.Effect<void>;
|
|
12
28
|
answer: () => string;
|
|
13
29
|
settle: (text: string) => Effect.Effect<void, PortFailure>;
|
|
@@ -6,7 +6,44 @@ import * as Fiber from "effect/Fiber";
|
|
|
6
6
|
import * as Queue from "effect/Queue";
|
|
7
7
|
import * as Stream from "effect/Stream";
|
|
8
8
|
import { log } from "../../log.js";
|
|
9
|
-
import { PortFailure, portJoin } from "../../effect-port.js";
|
|
9
|
+
import { PortFailure, portError, portJoin } from "../../effect-port.js";
|
|
10
|
+
/**
|
|
11
|
+
* Whether this event ends the turn, and how: the message was refused, or the turn's message ended. A message the
|
|
12
|
+
* agent stopped answering at its output limit still answers with what was written.
|
|
13
|
+
*/
|
|
14
|
+
export function turnEnd(event, messageId) {
|
|
15
|
+
if (event.type === "rejected") {
|
|
16
|
+
const { code, message, retryable } = event.error;
|
|
17
|
+
return { failure: { details: message, retryable, code } };
|
|
18
|
+
}
|
|
19
|
+
if (event.type !== "done" || event.message.id !== messageId)
|
|
20
|
+
return undefined;
|
|
21
|
+
const { status, error } = event.message;
|
|
22
|
+
switch (status) {
|
|
23
|
+
case "completed":
|
|
24
|
+
case "incomplete":
|
|
25
|
+
return { answered: true };
|
|
26
|
+
case "failed":
|
|
27
|
+
return {
|
|
28
|
+
failure: {
|
|
29
|
+
details: error?.message ?? "the message failed",
|
|
30
|
+
retryable: error?.retryable ?? false,
|
|
31
|
+
code: error?.code ?? "failed",
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
case "canceled":
|
|
35
|
+
return { failure: { details: "the message was canceled", retryable: false, code: "canceled" } };
|
|
36
|
+
default:
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* A turn whose stream ended before its message did, after the agent said why (`stream_error`: the message's end could
|
|
42
|
+
* not be recorded, or missed events could not be read back): a failure worth trying again. Undefined when nothing was said.
|
|
43
|
+
*/
|
|
44
|
+
export function unfinishedTurn(streamError) {
|
|
45
|
+
return streamError === undefined ? undefined : { details: streamError, retryable: true, code: "stream_error" };
|
|
46
|
+
}
|
|
10
47
|
/** Snapshot/edit renderers share terminal ownership; platform-specific settle policies stay injected. */
|
|
11
48
|
export function renderReply(events, opts) {
|
|
12
49
|
return Effect.gen(function* () {
|
|
@@ -17,8 +54,19 @@ export function renderReply(events, opts) {
|
|
|
17
54
|
if (!finalized)
|
|
18
55
|
yield* notify({ details: "the turn ended without completing", retryable: false }, "abnormal-turn");
|
|
19
56
|
}));
|
|
57
|
+
let messageId;
|
|
58
|
+
let streamError;
|
|
59
|
+
const failWith = (failure) => Effect.gen(function* () {
|
|
60
|
+
yield* notify(failure, "agent-failure");
|
|
61
|
+
return yield* Effect.fail(new PortFailure(new Error(`agent failed: ${failure.details} (retryable=${failure.retryable})`)));
|
|
62
|
+
});
|
|
20
63
|
yield* Stream.runForEachWhile(events, (event) => {
|
|
21
|
-
if (event.type
|
|
64
|
+
if (event.type === "message")
|
|
65
|
+
messageId = event.message.id;
|
|
66
|
+
if (event.type === "stream_error")
|
|
67
|
+
streamError = event.error.message;
|
|
68
|
+
const end = turnEnd(event, messageId);
|
|
69
|
+
if (end === undefined) {
|
|
22
70
|
return Effect.try({
|
|
23
71
|
try: () => {
|
|
24
72
|
opts.onEvent(event);
|
|
@@ -30,7 +78,7 @@ export function renderReply(events, opts) {
|
|
|
30
78
|
return Effect.gen(function* () {
|
|
31
79
|
yield* opts.finish;
|
|
32
80
|
finalized = true;
|
|
33
|
-
if (
|
|
81
|
+
if ("answered" in end) {
|
|
34
82
|
const answer = opts.answer();
|
|
35
83
|
yield* Effect.try({
|
|
36
84
|
try: () => opts.onAnswered?.(answer),
|
|
@@ -39,18 +87,20 @@ export function renderReply(events, opts) {
|
|
|
39
87
|
yield* opts.settle(answer);
|
|
40
88
|
}
|
|
41
89
|
else {
|
|
42
|
-
yield*
|
|
43
|
-
details: event.details,
|
|
44
|
-
retryable: event.retryable,
|
|
45
|
-
...(event.code !== undefined ? { code: event.code } : {}),
|
|
46
|
-
}, "agent-failure");
|
|
47
|
-
return yield* Effect.fail(new PortFailure(new Error(`agent failed: ${event.details} (retryable=${event.retryable})`)));
|
|
90
|
+
return yield* failWith(end.failure);
|
|
48
91
|
}
|
|
49
92
|
return false;
|
|
50
93
|
}).pipe(Effect.uninterruptible);
|
|
51
94
|
});
|
|
52
|
-
if (
|
|
53
|
-
|
|
95
|
+
if (finalized)
|
|
96
|
+
return;
|
|
97
|
+
const unfinished = unfinishedTurn(streamError);
|
|
98
|
+
if (unfinished === undefined) {
|
|
99
|
+
return yield* Effect.fail(new PortFailure(new Error("stream ended without a terminal event")));
|
|
100
|
+
}
|
|
101
|
+
yield* opts.finish;
|
|
102
|
+
finalized = true;
|
|
103
|
+
yield* failWith(unfinished).pipe(Effect.uninterruptible);
|
|
54
104
|
});
|
|
55
105
|
}
|
|
56
106
|
export function previewPump(opts) {
|
|
@@ -113,11 +163,20 @@ export function serialWriter() {
|
|
|
113
163
|
}
|
|
114
164
|
}).pipe(Effect.catchTag("Done", () => Effect.void));
|
|
115
165
|
const fiber = yield* Effect.forkScoped(work);
|
|
116
|
-
const
|
|
166
|
+
const end = Effect.sync(() => {
|
|
117
167
|
Queue.endUnsafe(queue);
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
|
|
168
|
+
});
|
|
169
|
+
let reported = false;
|
|
170
|
+
const finish = end.pipe(Effect.andThen(Fiber.join(fiber)), Effect.onExit((exit) => Effect.sync(() => {
|
|
171
|
+
if (!Exit.hasInterrupts(exit))
|
|
172
|
+
reported = true;
|
|
173
|
+
})));
|
|
174
|
+
// This finalizer precedes forkScoped's interruption: accepted append/status writes must drain. It must not fail:
|
|
175
|
+
// a defect makes the scope's typed failure one too, and a `catchTag` downstream misses it. So a write failure no
|
|
176
|
+
// `finish` reported is said in the log.
|
|
177
|
+
yield* Effect.addFinalizer(() => end.pipe(Effect.andThen(Fiber.await(fiber)), Effect.flatMap((exit) => Exit.isFailure(exit) && !reported && !Cause.hasInterruptsOnly(exit.cause)
|
|
178
|
+
? Effect.sync(() => log.error(`[delivery] a write failed after its turn stopped: ${String(portError(exit.cause))}`))
|
|
179
|
+
: Effect.void)));
|
|
121
180
|
return {
|
|
122
181
|
enqueue: (next) => {
|
|
123
182
|
if (!Queue.offerUnsafe(queue, next))
|