@fastagent-sh/fastagent 0.21.1 → 0.22.1
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 +9 -12
- package/dist/agent.d.ts +24 -37
- package/dist/agent.js +7 -15
- package/dist/atomic-write.d.ts +13 -17
- package/dist/atomic-write.js +18 -29
- package/dist/bind.d.ts +12 -22
- package/dist/bind.js +18 -27
- package/dist/channel.d.ts +11 -33
- package/dist/channels/agentcore-limits.d.ts +2 -13
- package/dist/channels/agentcore-limits.js +2 -13
- package/dist/channels/agentcore-protocol.d.ts +67 -58
- package/dist/channels/agentcore-protocol.js +23 -15
- package/dist/channels/agentcore-service.d.ts +19 -33
- package/dist/channels/agentcore-service.js +176 -59
- package/dist/channels/agentcore.d.ts +39 -33
- package/dist/channels/agentcore.js +90 -224
- package/dist/channels/body.d.ts +15 -2
- package/dist/channels/body.js +24 -2
- package/dist/channels/busy.d.ts +1 -21
- package/dist/channels/busy.js +2 -39
- package/dist/channels/control.d.ts +17 -62
- package/dist/channels/control.js +74 -182
- package/dist/channels/define-channel.d.ts +39 -0
- package/dist/channels/define-channel.js +9 -0
- package/dist/channels/discover.d.ts +10 -31
- package/dist/channels/discover.js +37 -31
- package/dist/channels/feishu/bootstrap-token.d.ts +1 -8
- package/dist/channels/feishu/bootstrap-token.js +7 -23
- package/dist/channels/feishu/card.d.ts +14 -28
- package/dist/channels/feishu/card.js +16 -30
- package/dist/channels/feishu/cloud.d.ts +1 -5
- package/dist/channels/feishu/context-buffer.d.ts +4 -23
- package/dist/channels/feishu/context-buffer.js +8 -31
- package/dist/channels/feishu/crypto.d.ts +10 -5
- package/dist/channels/feishu/crypto.js +12 -19
- package/dist/channels/feishu/feishu-api.d.ts +2 -1
- package/dist/channels/feishu/feishu-api.js +5 -4
- package/dist/channels/feishu/feishu.d.ts +4 -10
- package/dist/channels/feishu/feishu.js +113 -227
- package/dist/channels/feishu/invoke-turn.d.ts +5 -4
- package/dist/channels/feishu/invoke-turn.js +36 -54
- package/dist/channels/feishu/model.d.ts +4 -21
- package/dist/channels/feishu/model.js +1 -8
- package/dist/channels/feishu/normalize.d.ts +2 -10
- package/dist/channels/feishu/normalize.js +7 -42
- package/dist/channels/feishu/parse.d.ts +9 -29
- package/dist/channels/feishu/parse.js +8 -26
- package/dist/channels/feishu/preview.d.ts +12 -14
- package/dist/channels/feishu/preview.js +108 -207
- package/dist/channels/feishu/register-app.d.ts +8 -23
- package/dist/channels/feishu/register-app.js +7 -20
- package/dist/channels/feishu/register-webhook.d.ts +2 -9
- package/dist/channels/feishu/register-webhook.js +9 -33
- package/dist/channels/feishu/scaffold/channel.ts +27 -19
- package/dist/channels/feishu/scaffold/channel.websocket.ts +31 -0
- package/dist/channels/feishu/setup-mode.d.ts +11 -36
- package/dist/channels/feishu/setup-mode.js +7 -26
- package/dist/channels/feishu/ws-ingress.d.ts +1 -2
- package/dist/channels/feishu/ws-ingress.js +6 -8
- package/dist/channels/http.d.ts +15 -15
- package/dist/channels/http.js +19 -9
- package/dist/channels/kit/attachment-path.d.ts +4 -5
- package/dist/channels/kit/attachment-path.js +10 -34
- package/dist/channels/kit/context-buffer.d.ts +14 -21
- package/dist/channels/kit/context-buffer.js +25 -38
- package/dist/channels/kit/delivery.d.ts +35 -0
- package/dist/channels/kit/delivery.js +129 -0
- package/dist/channels/kit/event-stream.d.ts +5 -0
- package/dist/channels/kit/event-stream.js +29 -0
- package/dist/channels/kit/invoke-turn-kit.d.ts +53 -26
- package/dist/channels/kit/invoke-turn-kit.js +89 -32
- package/dist/channels/kit/preview-kit.d.ts +18 -72
- package/dist/channels/kit/preview-kit.js +22 -88
- package/dist/channels/kit/signature.d.ts +3 -9
- package/dist/channels/kit/signature.js +3 -9
- package/dist/channels/kit/state.d.ts +1 -2
- package/dist/channels/kit/state.js +5 -14
- package/dist/channels/kit/stop-command.d.ts +1 -2
- package/dist/channels/kit/stop-command.js +6 -9
- package/dist/channels/kit/tasks.d.ts +1 -1
- package/dist/channels/kit/tasks.js +8 -21
- package/dist/channels/kit/text.d.ts +2 -16
- package/dist/channels/kit/text.js +23 -31
- package/dist/channels/kit/thread-participants.d.ts +4 -17
- package/dist/channels/kit/thread-participants.js +8 -55
- package/dist/channels/kit/transport.d.ts +26 -0
- package/dist/channels/kit/transport.js +20 -0
- package/dist/channels/kit/turn-queue.d.ts +7 -11
- package/dist/channels/kit/turn-queue.js +21 -39
- package/dist/channels/kit/turn-runner.d.ts +32 -18
- package/dist/channels/kit/turn-runner.js +98 -53
- package/dist/channels/kit/turn-store.d.ts +32 -32
- package/dist/channels/kit/turn-store.js +45 -88
- package/dist/channels/lark/lark.d.ts +1 -5
- package/dist/channels/lark/onboard.d.ts +3 -12
- package/dist/channels/lark/onboard.js +3 -13
- package/dist/channels/lark/scaffold/channel.ts +27 -19
- package/dist/channels/lark/scaffold/channel.websocket.ts +31 -0
- package/dist/channels/registration.d.ts +9 -35
- package/dist/channels/registration.js +6 -37
- package/dist/channels/secret.js +2 -5
- package/dist/channels/serve.d.ts +47 -44
- package/dist/channels/serve.js +165 -101
- package/dist/channels/slack/config-api.d.ts +4 -27
- package/dist/channels/slack/config-api.js +5 -34
- package/dist/channels/slack/context-buffer.d.ts +2 -3
- package/dist/channels/slack/context-buffer.js +5 -5
- package/dist/channels/slack/invoke-turn.d.ts +3 -1
- package/dist/channels/slack/invoke-turn.js +25 -34
- package/dist/channels/slack/manifest.js +1 -3
- package/dist/channels/slack/model.d.ts +1 -2
- package/dist/channels/slack/model.js +1 -1
- package/dist/channels/slack/onboard.d.ts +4 -3
- package/dist/channels/slack/onboard.js +8 -11
- package/dist/channels/slack/onboarding-state.d.ts +3 -5
- package/dist/channels/slack/onboarding-state.js +9 -6
- package/dist/channels/slack/parse.d.ts +4 -13
- package/dist/channels/slack/parse.js +7 -28
- package/dist/channels/slack/preview.d.ts +12 -2
- package/dist/channels/slack/preview.js +292 -269
- package/dist/channels/slack/reaction.d.ts +11 -3
- package/dist/channels/slack/reaction.js +19 -8
- package/dist/channels/slack/register-webhook.js +4 -7
- package/dist/channels/slack/scaffold/channel.ts +20 -13
- package/dist/channels/slack/scaffold/slack-send.ts +2 -2
- package/dist/channels/slack/setup-server.d.ts +1 -5
- package/dist/channels/slack/setup-server.js +1 -5
- package/dist/channels/slack/shared-api.d.ts +1 -4
- package/dist/channels/slack/shared-api.js +2 -13
- package/dist/channels/slack/slack-api.d.ts +2 -1
- package/dist/channels/slack/slack-api.js +6 -4
- package/dist/channels/slack/slack.d.ts +11 -14
- package/dist/channels/slack/slack.js +121 -122
- package/dist/channels/sse.d.ts +1 -1
- package/dist/channels/sse.js +1 -1
- package/dist/channels/telegram/context-buffer.d.ts +7 -22
- package/dist/channels/telegram/context-buffer.js +6 -23
- package/dist/channels/telegram/invoke-turn.d.ts +7 -7
- package/dist/channels/telegram/invoke-turn.js +24 -43
- package/dist/channels/telegram/parse.d.ts +24 -51
- package/dist/channels/telegram/parse.js +32 -84
- package/dist/channels/telegram/preview.d.ts +10 -1
- package/dist/channels/telegram/preview.js +79 -100
- package/dist/channels/telegram/register-webhook.js +5 -23
- package/dist/channels/telegram/scaffold/channel.ts +25 -18
- package/dist/channels/telegram/scaffold/telegram-send.ts +6 -4
- package/dist/channels/telegram/telegram-api.d.ts +4 -3
- package/dist/channels/telegram/telegram-api.js +9 -7
- package/dist/channels/telegram/telegram.d.ts +4 -18
- package/dist/channels/telegram/telegram.js +38 -94
- package/dist/channels/telegram/turn-store.d.ts +11 -14
- package/dist/channels/telegram/turn-store.js +8 -6
- package/dist/channels/wait-health.d.ts +4 -6
- package/dist/channels/wait-health.js +10 -14
- package/dist/cli/add-feishu.d.ts +2 -12
- package/dist/cli/add-feishu.js +24 -71
- package/dist/cli/add-slack.d.ts +5 -3
- package/dist/cli/add-slack.js +53 -76
- package/dist/cli/auth-view.d.ts +2 -16
- package/dist/cli/auth-view.js +2 -16
- package/dist/cli/commands/add.js +25 -40
- package/dist/cli/commands/chat.d.ts +0 -1
- package/dist/cli/commands/chat.js +5 -6
- package/dist/cli/commands/deploy/agentcore.js +60 -65
- package/dist/cli/commands/deploy/docker.js +50 -23
- package/dist/cli/commands/deploy/fly.js +23 -61
- package/dist/cli/commands/deploy/railway.js +23 -18
- package/dist/cli/commands/deploy/shared.d.ts +38 -57
- package/dist/cli/commands/deploy/shared.js +40 -59
- package/dist/cli/commands/deploy.d.ts +10 -27
- package/dist/cli/commands/deploy.js +38 -60
- package/dist/cli/commands/destroy.d.ts +4 -0
- package/dist/cli/commands/destroy.js +56 -0
- package/dist/cli/commands/dev.d.ts +2 -1
- package/dist/cli/commands/dev.js +20 -23
- package/dist/cli/commands/info.d.ts +0 -2
- package/dist/cli/commands/info.js +83 -49
- package/dist/cli/commands/init.d.ts +1 -2
- package/dist/cli/commands/init.js +16 -55
- package/dist/cli/commands/invoke.d.ts +0 -1
- package/dist/cli/commands/invoke.js +5 -7
- package/dist/cli/commands/login.d.ts +2 -1
- package/dist/cli/commands/login.js +33 -38
- package/dist/cli/commands/logs.js +3 -4
- package/dist/cli/commands/models.js +1 -5
- package/dist/cli/commands/routine-run.d.ts +6 -0
- package/dist/cli/commands/routine-run.js +47 -0
- package/dist/cli/commands/routine.d.ts +25 -0
- package/dist/cli/commands/routine.js +122 -0
- package/dist/cli/commands/start.d.ts +31 -3
- package/dist/cli/commands/start.js +131 -81
- package/dist/cli/commands/tool.js +26 -12
- package/dist/cli/fail.d.ts +13 -23
- package/dist/cli/fail.js +20 -23
- package/dist/cli/invoke-stream.d.ts +1 -8
- package/dist/cli/kernel.d.ts +6 -38
- package/dist/cli/kernel.js +14 -77
- package/dist/cli/models-view.d.ts +1 -9
- package/dist/cli/models-view.js +11 -22
- package/dist/cli/program.d.ts +5 -6
- package/dist/cli/program.js +120 -157
- package/dist/cli/serve.d.ts +57 -41
- package/dist/cli/serve.js +94 -121
- package/dist/cli/shared.d.ts +15 -61
- package/dist/cli/shared.js +55 -181
- package/dist/cli.js +1 -8
- package/dist/collect.d.ts +6 -0
- package/dist/collect.js +6 -0
- package/dist/core.d.ts +4 -1
- package/dist/core.js +9 -7
- package/dist/declared-secrets.d.ts +55 -0
- package/dist/declared-secrets.js +88 -0
- package/dist/deploy/agentcore/aws-cli.d.ts +91 -0
- package/dist/deploy/agentcore/aws-cli.js +64 -0
- package/dist/deploy/agentcore/destroy.d.ts +51 -0
- package/dist/deploy/agentcore/destroy.js +273 -0
- package/dist/deploy/agentcore/forwarder.js +28 -79
- package/dist/deploy/agentcore/logs.d.ts +2 -18
- package/dist/deploy/agentcore/logs.js +27 -51
- package/dist/deploy/agentcore/plan.d.ts +85 -105
- package/dist/deploy/agentcore/plan.js +152 -314
- package/dist/deploy/agentcore/run.d.ts +28 -28
- package/dist/deploy/agentcore/run.js +227 -306
- package/dist/deploy/agentcore/zip.d.ts +2 -15
- package/dist/deploy/agentcore/zip.js +3 -17
- package/dist/deploy/build-context.d.ts +21 -0
- package/dist/deploy/build-context.js +137 -0
- package/dist/deploy/channel-ingress.d.ts +26 -39
- package/dist/deploy/channel-ingress.js +57 -28
- package/dist/deploy/container.d.ts +20 -34
- package/dist/deploy/container.js +49 -100
- package/dist/deploy/docker/plan.d.ts +12 -11
- package/dist/deploy/docker/plan.js +43 -24
- package/dist/deploy/docker/run.d.ts +22 -25
- package/dist/deploy/docker/run.js +39 -37
- package/dist/deploy/fly/plan.d.ts +15 -44
- package/dist/deploy/fly/plan.js +41 -73
- package/dist/deploy/fly/run.d.ts +16 -51
- package/dist/deploy/fly/run.js +42 -95
- package/dist/deploy/hosts.d.ts +24 -3
- package/dist/deploy/hosts.js +24 -3
- package/dist/deploy/preflight.d.ts +47 -41
- package/dist/deploy/preflight.js +282 -383
- package/dist/deploy/railway/plan.d.ts +16 -42
- package/dist/deploy/railway/plan.js +42 -60
- package/dist/deploy/railway/run.d.ts +30 -68
- package/dist/deploy/railway/run.js +86 -100
- package/dist/deploy/registration-gate.d.ts +6 -13
- package/dist/deploy/residency.d.ts +37 -0
- package/dist/deploy/residency.js +24 -0
- package/dist/deploy/runner.d.ts +10 -9
- package/dist/deploy/runner.js +7 -18
- package/dist/deploy/secrets.d.ts +40 -41
- package/dist/deploy/secrets.js +117 -103
- package/dist/deploy/workspace.d.ts +50 -0
- package/dist/deploy/workspace.js +197 -0
- package/dist/dev-supervisor.d.ts +1 -9
- package/dist/dev-supervisor.js +21 -64
- package/dist/effect-port.d.ts +50 -0
- package/dist/effect-port.js +77 -0
- package/dist/engines/pi/agent-session-factory.d.ts +50 -69
- package/dist/engines/pi/agent-session-factory.js +249 -146
- package/dist/engines/pi/auth.d.ts +15 -11
- package/dist/engines/pi/auth.js +96 -99
- package/dist/engines/pi/chat.d.ts +1 -5
- package/dist/engines/pi/chat.js +2 -14
- package/dist/engines/pi/config.d.ts +53 -51
- package/dist/engines/pi/config.js +83 -92
- package/dist/engines/pi/create.d.ts +60 -75
- package/dist/engines/pi/create.js +108 -141
- package/dist/engines/pi/definition.d.ts +14 -58
- package/dist/engines/pi/definition.js +21 -85
- package/dist/engines/pi/invoke-session.d.ts +5 -25
- package/dist/engines/pi/invoke-session.js +233 -244
- package/dist/engines/pi/login.d.ts +95 -35
- package/dist/engines/pi/login.js +259 -107
- package/dist/engines/pi/machine.d.ts +31 -0
- package/dist/engines/pi/machine.js +106 -0
- package/dist/engines/pi/models.d.ts +70 -89
- package/dist/engines/pi/models.js +188 -81
- package/dist/engines/pi/open.d.ts +65 -53
- package/dist/engines/pi/open.js +129 -69
- package/dist/engines/pi/report.d.ts +3 -12
- package/dist/engines/pi/report.js +2 -16
- package/dist/engines/pi/search-tools.d.ts +1 -9
- package/dist/engines/pi/search-tools.js +26 -57
- package/dist/engines/pi/service.d.ts +2 -16
- package/dist/engines/pi/service.js +2 -16
- package/dist/engines/pi/session-builder.d.ts +5 -9
- package/dist/engines/pi/session-builder.js +44 -82
- package/dist/engines/pi/session-control.js +286 -269
- package/dist/engines/pi/session-effects.d.ts +14 -0
- package/dist/engines/pi/session-effects.js +30 -0
- package/dist/engines/pi/session-inheritance.d.ts +9 -18
- package/dist/engines/pi/session-inheritance.js +103 -160
- package/dist/engines/pi/session-markers.d.ts +31 -30
- package/dist/engines/pi/session-markers.js +26 -25
- package/dist/engines/pi/session-settings.d.ts +6 -22
- package/dist/engines/pi/session-settings.js +10 -21
- package/dist/engines/pi/session-store.d.ts +26 -92
- package/dist/engines/pi/session-store.js +96 -310
- package/dist/engines/pi/tool-context.d.ts +17 -45
- package/dist/engines/pi/tool-context.js +7 -26
- package/dist/engines/pi/tool.d.ts +45 -36
- package/dist/engines/pi/tool.js +43 -57
- package/dist/engines/pi/turn-kit.d.ts +14 -52
- package/dist/engines/pi/turn-kit.js +18 -67
- package/dist/engines/pi/wake-tool.d.ts +2 -10
- package/dist/engines/pi/wake-tool.js +7 -27
- package/dist/env.d.ts +27 -28
- package/dist/env.js +45 -50
- package/dist/index.js +0 -2
- package/dist/lark.d.ts +1 -2
- package/dist/lark.js +1 -2
- package/dist/loader.d.ts +14 -55
- package/dist/loader.js +24 -43
- package/dist/log.d.ts +2 -12
- package/dist/log.js +3 -24
- package/dist/node.d.ts +2 -15
- package/dist/node.js +2 -18
- package/dist/observe.d.ts +2 -8
- package/dist/open-url.d.ts +1 -1
- package/dist/open-url.js +1 -1
- package/dist/paths.d.ts +70 -134
- package/dist/paths.js +165 -232
- package/dist/pi.d.ts +4 -6
- package/dist/pi.js +3 -3
- package/dist/proxy.d.ts +16 -6
- package/dist/proxy.js +52 -16
- package/dist/runtime.d.ts +18 -12
- package/dist/runtime.js +18 -11
- package/dist/scaffold/add-channel.d.ts +14 -31
- package/dist/scaffold/add-channel.js +48 -112
- package/dist/scaffold/init.d.ts +9 -31
- package/dist/scaffold/init.js +45 -138
- package/dist/scaffold/templates/env.example +6 -4
- package/dist/scaffold/templates/fastagent.config.ts +36 -0
- package/dist/scaffold/templates.d.ts +3 -3
- package/dist/scaffold/templates.js +5 -8
- package/dist/scaffold/vendor-skill.d.ts +2 -5
- package/dist/scaffold/vendor-skill.js +19 -29
- package/dist/schedule/cron.d.ts +9 -5
- package/dist/schedule/cron.js +9 -11
- package/dist/schedule/discover.d.ts +12 -12
- package/dist/schedule/discover.js +43 -34
- package/dist/schedule/routine.d.ts +43 -0
- package/dist/schedule/routine.js +32 -0
- package/dist/schedule/run.d.ts +55 -0
- package/dist/schedule/run.js +146 -0
- package/dist/schedule/scheduler.d.ts +44 -55
- package/dist/schedule/scheduler.js +291 -265
- package/dist/schedule/state.d.ts +105 -10
- package/dist/schedule/state.js +293 -19
- package/dist/schedule/wake-alarm.d.ts +10 -23
- package/dist/schedule/wake-alarm.js +91 -121
- package/dist/schedule/wakeups.d.ts +23 -39
- package/dist/schedule/wakeups.js +33 -75
- package/dist/secrets-gate.d.ts +32 -0
- package/dist/secrets-gate.js +33 -0
- package/dist/service.d.ts +137 -98
- package/dist/service.js +250 -252
- package/dist/session-remote.d.ts +33 -44
- package/dist/session-remote.js +203 -192
- package/dist/session.d.ts +166 -229
- package/dist/session.js +33 -55
- package/dist/tunnel.d.ts +8 -36
- package/dist/tunnel.js +24 -65
- package/dist/version.d.ts +2 -2
- package/dist/version.js +2 -2
- package/package.json +10 -16
- package/dist/channels/agentcore-state.d.ts +0 -77
- package/dist/channels/agentcore-state.js +0 -276
- package/dist/channels/github/github.d.ts +0 -31
- package/dist/channels/github/github.js +0 -89
- package/dist/channels/github/scaffold/channel.ts +0 -25
- package/dist/cli/commands/attach.d.ts +0 -108
- package/dist/cli/commands/attach.js +0 -637
- package/dist/cli/commands/fire.d.ts +0 -7
- package/dist/cli/commands/fire.js +0 -38
- package/dist/cli/commands/schedule.d.ts +0 -12
- package/dist/cli/commands/schedule.js +0 -87
- package/dist/github.d.ts +0 -3
- package/dist/github.js +0 -2
- package/dist/scaffold/templates/fastagent.config.mjs +0 -23
- package/dist/schedule/audit.d.ts +0 -18
- package/dist/schedule/audit.js +0 -57
- package/dist/schedule/schedule.d.ts +0 -35
- package/dist/schedule/schedule.js +0 -23
package/dist/dev-supervisor.js
CHANGED
|
@@ -1,73 +1,42 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The `fastagent dev` process supervisor: re-spawn the CLI as a worker (`FASTAGENT_DEV_WORKER=1`) and
|
|
3
|
-
*
|
|
4
|
-
* (always-latest, no stale module cache). The supervisor never exits on a bad edit — the worker fails
|
|
5
|
-
* loudly and it waits for the next save.
|
|
6
|
-
*
|
|
7
|
-
* Watch scope is deliberately narrow: only inputs whose changes REQUIRE a new process — imported
|
|
8
|
-
* code (tools/, channels/), fastagent.config.*, package.json, .env. The definition (AGENTS.md,
|
|
9
|
-
* persona.md, skills/) is re-read per invoke by the directory rung, so its edits go live on the next turn with no
|
|
10
|
-
* restart — and, critically, an agent that writes files into its own workspace (its normal work
|
|
11
|
-
* product, including editing its own AGENTS.md) never has its in-flight turn killed by the watcher.
|
|
2
|
+
* The `fastagent dev` process supervisor: re-spawn the CLI as a worker (`FASTAGENT_DEV_WORKER=1`) and restart it on
|
|
3
|
+
* debounced edits to the agent's CODE inputs.
|
|
12
4
|
*/
|
|
13
5
|
import { spawn } from "node:child_process";
|
|
14
6
|
import { relative, sep } from "node:path";
|
|
15
7
|
import { watch as watchTree } from "chokidar";
|
|
16
|
-
import {
|
|
8
|
+
import { AGENT_CONFIG_FILE, AGENT_MODELS_FILE, resolveStateRoot, isUnderDir } from "./paths.js";
|
|
17
9
|
import { dotEnvPath } from "./env.js";
|
|
18
10
|
import { log } from "./log.js";
|
|
19
|
-
import { installProxyFetch } from "./proxy.js";
|
|
20
11
|
import { openExternalUrl } from "./open-url.js";
|
|
21
12
|
import { declaredChannels } from "./channels/discover.js";
|
|
22
13
|
import { announceWebhooks, startCloudflareTunnel } from "./tunnel.js";
|
|
23
14
|
/** What the dev watcher restarts on (agent-dir-relative): the process-bound code inputs only. */
|
|
24
|
-
/**
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
*/
|
|
29
|
-
const CODE_INPUT_DIRS = ["tools", "channels", "schedules", "extensions"];
|
|
30
|
-
const WATCHED_HINT = `${CODE_INPUT_DIRS.map((dir) => `${dir}/`).join(", ")}, package.json, fastagent.config.*, models.json, .secrets/.env`;
|
|
31
|
-
/**
|
|
32
|
-
* chokidar `ignored` matcher for the narrow watch scope (true = ignore), rooted at the AGENT DIR. When
|
|
33
|
-
* the agent sits INSIDE the workspace that means the surrounding tree never triggers a restart at all;
|
|
34
|
-
* when the agent IS the workspace the root is that tree, and the allowlist below is what keeps the
|
|
35
|
-
* author's own files out of scope. Ignoring a directory prunes the whole subtree, so everything outside it —
|
|
36
|
-
* `.state/` machine state, node_modules, .git, and any file/dir the agent writes as work product —
|
|
37
|
-
* costs no watchers and triggers no restarts. Helper code imported from OUTSIDE tools//channels/ is
|
|
38
|
-
* out of scope by design (keep it under tools/, or restart manually) — the startup log names the set.
|
|
39
|
-
*/
|
|
15
|
+
/** The agent-dir directories loaded ONCE per worker: a restart is their only re-read. */
|
|
16
|
+
const CODE_INPUT_DIRS = ["tools", "channels", "routines", "extensions"];
|
|
17
|
+
const WATCHED_HINT = `${CODE_INPUT_DIRS.map((dir) => `${dir}/`).join(", ")}, package.json, fastagent.config.ts, models.json, .secrets/.env`;
|
|
18
|
+
/** chokidar `ignored` matcher for the narrow watch scope (true = ignore), rooted at the AGENT DIR. */
|
|
40
19
|
export function devWatchIgnored(root, envFile) {
|
|
41
|
-
// The `.env` is allow-listed by its RESOLVED path, not by the `.secrets` name
|
|
42
|
-
// can put it in an in-agent directory called anything, and a name-based rule would prune the very
|
|
43
|
-
// file the worker loads (a credential edit would then silently never restart it).
|
|
20
|
+
// The `.env` is allow-listed by its RESOLVED path, not by the `.secrets` name.
|
|
44
21
|
const envRel = relative(root, envFile).split(sep);
|
|
45
22
|
return (path) => {
|
|
46
23
|
if (path === root)
|
|
47
24
|
return false; // the root itself must not be pruned
|
|
48
25
|
const rel = relative(root, path);
|
|
49
|
-
// Code inputs at the agent dir root: config, package.json, and the dirs loaded once per worker
|
|
50
|
-
//
|
|
51
|
-
|
|
52
|
-
// The config NAMES come from paths.ts, not a regex spelled here: adding a name there must not
|
|
53
|
-
// silently stop `dev` restarting on edits to it.
|
|
54
|
-
if (AGENT_CONFIG_NAMES.includes(rel))
|
|
26
|
+
// Code inputs at the agent dir root: config, package.json, and the dirs loaded once per worker (a restart is
|
|
27
|
+
// their only re-read).
|
|
28
|
+
if (rel === AGENT_CONFIG_FILE)
|
|
55
29
|
return false;
|
|
56
30
|
if (rel === "package.json")
|
|
57
31
|
return false;
|
|
58
|
-
// models.json is read ONCE per worker (the model hub is built during assembly), so an edit needs a
|
|
59
|
-
//
|
|
60
|
-
// malformed file fails assembly — so leaving it unwatched would strand the author: the fix that
|
|
61
|
-
// repairs it would not be the edit that restarts.
|
|
32
|
+
// models.json is read ONCE per worker (the model hub is built during assembly), so an edit needs a restart like
|
|
33
|
+
// any other code input.
|
|
62
34
|
if (rel === AGENT_MODELS_FILE)
|
|
63
35
|
return false;
|
|
64
36
|
const segments = rel.split(sep);
|
|
65
37
|
if (CODE_INPUT_DIRS.includes(segments[0]))
|
|
66
38
|
return false;
|
|
67
|
-
// The `.env` restarts too (credentials are process-bound).
|
|
68
|
-
// un-pruned so chokidar can descend to it; every sibling inside them (auth.json, .env.example)
|
|
69
|
-
// prunes normally. An out-of-agent `.env` yields a `..`-prefixed envRel that matches nothing here
|
|
70
|
-
// — the supervisor warns about that case instead of pretending to watch it.
|
|
39
|
+
// The `.env` restarts too (credentials are process-bound).
|
|
71
40
|
if (segments.length <= envRel.length && segments.every((seg, i) => seg === envRel[i]))
|
|
72
41
|
return false;
|
|
73
42
|
return true;
|
|
@@ -75,22 +44,14 @@ export function devWatchIgnored(root, envFile) {
|
|
|
75
44
|
}
|
|
76
45
|
/** Spawn the dev worker and restart it on agent-dir edits; supervise its lifecycle until the process exits. */
|
|
77
46
|
export async function runDevSupervisor(placement, options = {}) {
|
|
78
|
-
// The placement arrives RESOLVED from the command (which already routed its refusal through
|
|
79
|
-
// failStartup): re-resolving here would duplicate the rule and surface the same user-fixable
|
|
80
|
-
// refusal as a raw stack. The watch root is the AGENT DIR — every restart-relevant code input lives
|
|
81
|
-
// under it, so the surrounding workspace costs no watchers at all. Placement is assumed STATIC for
|
|
82
|
-
// the session (creating/removing `fastagent/` mid-session is out of scope for watch re-sync).
|
|
47
|
+
// The placement arrives RESOLVED from the command (which already routed its refusal through failStartup).
|
|
83
48
|
let worker;
|
|
84
49
|
let reloadPending = false;
|
|
85
50
|
let everServed = false; // has any worker successfully bound (sent `ready`) yet?
|
|
86
51
|
let timer;
|
|
87
|
-
// The supervisor owns the tunnel so the public URL survives worker reloads (a fresh tunnel per save
|
|
88
|
-
//
|
|
52
|
+
// The supervisor owns the tunnel so the public URL survives worker reloads (a fresh tunnel per save would mean a
|
|
53
|
+
// new URL + re-registering the webhook on every edit).
|
|
89
54
|
let tunnel;
|
|
90
|
-
// The supervisor itself calls the channel webhook APIs (setWebhook) when announcing the tunnel, so
|
|
91
|
-
// it needs the proxy too (workers install their own). A region-blocked api.telegram.org fails otherwise.
|
|
92
|
-
if (options.tunnel)
|
|
93
|
-
installProxyFetch();
|
|
94
55
|
const spawnWorker = () => {
|
|
95
56
|
// ipc fd so the worker can signal readiness once it binds; stdio otherwise inherited.
|
|
96
57
|
// biome-ignore lint/style/noNonNullAssertion: argv[1] is always the script path under a node entry
|
|
@@ -125,9 +86,8 @@ export async function runDevSupervisor(placement, options = {}) {
|
|
|
125
86
|
spawnWorker(); // restart requested: the old worker has exited, so the port is free
|
|
126
87
|
}
|
|
127
88
|
else if (!everServed) {
|
|
128
|
-
// Failed BEFORE ever serving — a non-editable startup failure (bad flag, EADDRINUSE, broken
|
|
129
|
-
//
|
|
130
|
-
// printed the error via inherited stdio).
|
|
89
|
+
// Failed BEFORE ever serving — a non-editable startup failure (bad flag, EADDRINUSE, broken initial
|
|
90
|
+
// workspace) that saving cannot fix.
|
|
131
91
|
process.exit(code ?? 1);
|
|
132
92
|
}
|
|
133
93
|
else {
|
|
@@ -146,8 +106,7 @@ export async function runDevSupervisor(placement, options = {}) {
|
|
|
146
106
|
spawnWorker(); // worker was down (broken edit) — retry now
|
|
147
107
|
}
|
|
148
108
|
};
|
|
149
|
-
// chokidar gives reliable cross-platform recursion + structural ignore that native fs.watch
|
|
150
|
-
// cannot; devWatchIgnored (above) narrows the scope to the process-bound code inputs.
|
|
109
|
+
// chokidar gives reliable cross-platform recursion + structural ignore that native fs.watch cannot.
|
|
151
110
|
const watcher = watchTree(placement.agentDir, {
|
|
152
111
|
ignoreInitial: true, // the startup scan is not a change
|
|
153
112
|
ignored: devWatchIgnored(placement.agentDir, dotEnvPath(placement.agentDir)),
|
|
@@ -158,9 +117,7 @@ export async function runDevSupervisor(placement, options = {}) {
|
|
|
158
117
|
});
|
|
159
118
|
watcher.on("error", (error) => log.warn(`[fastagent] file watching error (${error.message}); some edits may need a manual restart`));
|
|
160
119
|
log.info(`[fastagent] watching ${WATCHED_HINT} — code edits restart the dev worker (--no-watch to disable); AGENTS.md/persona.md/skills edits go live next turn without a restart`);
|
|
161
|
-
// FASTAGENT_SECRETS_DIR can move the `.env` OUT of the agent dir entirely
|
|
162
|
-
// anywhere inside (the resolved path is allow-listed above), but outside the watch root the worker
|
|
163
|
-
// would load a file no watcher sees. Say so once instead of leaving the hint above lying.
|
|
120
|
+
// FASTAGENT_SECRETS_DIR can move the `.env` OUT of the agent dir entirely.
|
|
164
121
|
if (!isUnderDir(dotEnvPath(placement.agentDir), placement.agentDir)) {
|
|
165
122
|
log.warn(`[fastagent] .env lives outside the agent dir (FASTAGENT_SECRETS_DIR → ${dotEnvPath(placement.agentDir)}) — it is NOT watched; restart dev after editing it`);
|
|
166
123
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ONE crossing between this codebase's Promise-shaped ports and Effect execution.
|
|
3
|
+
*
|
|
4
|
+
* The ports are everywhere and none of them are ours to change: the SPEC fixes `Agent.invoke` as an
|
|
5
|
+
* AsyncIterable and `SessionControl` as Promises, pi's SDK is Promise-based, every platform client
|
|
6
|
+
* is `fetch`, and so is the filesystem. Two properties have to hold at each crossing:
|
|
7
|
+
*
|
|
8
|
+
* 1. INTERRUPTION MUST JOIN. A Promise exposes no abort hook, so cancelling the fiber that awaits
|
|
9
|
+
* one does not stop the work behind it. Releasing its resources anyway is how a disposed session
|
|
10
|
+
* gets written to, or a lease is handed to the next turn while the previous one is still
|
|
11
|
+
* running. {@link portJoin}, {@link portAbort} and {@link portRequest} therefore wait for the
|
|
12
|
+
* pending promise to settle before releasing, and abort first when the port gives us a door.
|
|
13
|
+
* {@link port} is the explicit opt-out, for work a caller may walk away from — so a call site
|
|
14
|
+
* holding a lease, a session or any other resource must not reach for it.
|
|
15
|
+
* 2. THE CAUSE SURVIVES. Retry classification (`turn-kit.classifyRetryable`), the channels'
|
|
16
|
+
* platform error types and every operator-facing message read the ORIGINAL error, so the
|
|
17
|
+
* wrapper carries it verbatim and {@link portError} is how a caller gets it back.
|
|
18
|
+
*
|
|
19
|
+
* The channel kit, the pi engine, the AgentCore runtime and the scheduler all cross through here, so each rule is
|
|
20
|
+
* written once.
|
|
21
|
+
*
|
|
22
|
+
* What is NOT here is a policy: whether a failure rejects a request, is logged, or ends a turn stays
|
|
23
|
+
* with the caller that knows. The only opinion this module holds is the one above.
|
|
24
|
+
*/
|
|
25
|
+
import * as Cause from "effect/Cause";
|
|
26
|
+
import * as Effect from "effect/Effect";
|
|
27
|
+
/** A Promise port's failure, carrying the original error as `cause`. One tag, because every caller
|
|
28
|
+
* that discriminates does so on WHAT FAILED (its own control flow), never on which module wrapped it. */
|
|
29
|
+
export declare class PortFailure extends Error {
|
|
30
|
+
readonly _tag = "PortFailure";
|
|
31
|
+
constructor(cause: unknown);
|
|
32
|
+
}
|
|
33
|
+
/** The original error behind a failed port, for classification and messages. */
|
|
34
|
+
export declare function portError(cause: Cause.Cause<unknown>): unknown;
|
|
35
|
+
/** A Promise port whose work is abandonable: interruption does not wait for it. Use for reads and
|
|
36
|
+
* for writes a caller is free to walk away from; anything holding a resource wants {@link portJoin}. */
|
|
37
|
+
export declare function port<A>(run: () => Promise<A>): Effect.Effect<A, PortFailure>;
|
|
38
|
+
/** A Promise port with no abort hook: interruption joins the issued work before releasing. */
|
|
39
|
+
export declare function portJoin<A>(run: () => Promise<A>): Effect.Effect<A, PortFailure>;
|
|
40
|
+
/** A Promise port WITH an abort hook: interruption stops the work, then joins it. The hook runs only
|
|
41
|
+
* on interruption — a settled operation must not be told to abort (`session.abort()` on a finished
|
|
42
|
+
* run would reach the next one). A failing hook is diagnosed, never rethrown, under `label`: the
|
|
43
|
+
* tag is one thing, but a serve running an invoke and a manual compaction at once needs the warn to
|
|
44
|
+
* say WHICH abort could not be delivered. */
|
|
45
|
+
export declare function portAbort<A>(label: string, run: () => Promise<A>, abort: () => void | Promise<void>): Effect.Effect<A, PortFailure>;
|
|
46
|
+
/** A request with a deadline: the signal is closed on EVERY exit (it owns the response body, which a
|
|
47
|
+
* settled call has to release too), and the real request is joined before ownership is given up. */
|
|
48
|
+
export declare function portRequest<A>(run: (signal: AbortSignal) => Promise<A>, timeoutMs: number): Effect.Effect<A, PortFailure>;
|
|
49
|
+
/** Cleanup anomalies are diagnostic: they cannot change an already-published outcome. */
|
|
50
|
+
export declare function portCleanup(operation: string, run: () => void | Promise<void>): Effect.Effect<void>;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ONE crossing between this codebase's Promise-shaped ports and Effect execution.
|
|
3
|
+
*
|
|
4
|
+
* The ports are everywhere and none of them are ours to change: the SPEC fixes `Agent.invoke` as an
|
|
5
|
+
* AsyncIterable and `SessionControl` as Promises, pi's SDK is Promise-based, every platform client
|
|
6
|
+
* is `fetch`, and so is the filesystem. Two properties have to hold at each crossing:
|
|
7
|
+
*
|
|
8
|
+
* 1. INTERRUPTION MUST JOIN. A Promise exposes no abort hook, so cancelling the fiber that awaits
|
|
9
|
+
* one does not stop the work behind it. Releasing its resources anyway is how a disposed session
|
|
10
|
+
* gets written to, or a lease is handed to the next turn while the previous one is still
|
|
11
|
+
* running. {@link portJoin}, {@link portAbort} and {@link portRequest} therefore wait for the
|
|
12
|
+
* pending promise to settle before releasing, and abort first when the port gives us a door.
|
|
13
|
+
* {@link port} is the explicit opt-out, for work a caller may walk away from — so a call site
|
|
14
|
+
* holding a lease, a session or any other resource must not reach for it.
|
|
15
|
+
* 2. THE CAUSE SURVIVES. Retry classification (`turn-kit.classifyRetryable`), the channels'
|
|
16
|
+
* platform error types and every operator-facing message read the ORIGINAL error, so the
|
|
17
|
+
* wrapper carries it verbatim and {@link portError} is how a caller gets it back.
|
|
18
|
+
*
|
|
19
|
+
* The channel kit, the pi engine, the AgentCore runtime and the scheduler all cross through here, so each rule is
|
|
20
|
+
* written once.
|
|
21
|
+
*
|
|
22
|
+
* What is NOT here is a policy: whether a failure rejects a request, is logged, or ends a turn stays
|
|
23
|
+
* with the caller that knows. The only opinion this module holds is the one above.
|
|
24
|
+
*/
|
|
25
|
+
import * as Cause from "effect/Cause";
|
|
26
|
+
import * as Effect from "effect/Effect";
|
|
27
|
+
import * as Exit from "effect/Exit";
|
|
28
|
+
import { log } from "./log.js";
|
|
29
|
+
/** A Promise port's failure, carrying the original error as `cause`. One tag, because every caller
|
|
30
|
+
* that discriminates does so on WHAT FAILED (its own control flow), never on which module wrapped it. */
|
|
31
|
+
export class PortFailure extends Error {
|
|
32
|
+
_tag = "PortFailure";
|
|
33
|
+
constructor(cause) {
|
|
34
|
+
super(cause instanceof Error ? cause.message : String(cause), { cause });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** The original error behind a failed port, for classification and messages. */
|
|
38
|
+
export function portError(cause) {
|
|
39
|
+
const error = Cause.squash(cause);
|
|
40
|
+
return error instanceof PortFailure ? error.cause : error;
|
|
41
|
+
}
|
|
42
|
+
/** Await a promise we already own, as a typed failure. */
|
|
43
|
+
const wait = (pending) => Effect.tryPromise({ try: () => pending, catch: (cause) => new PortFailure(cause) });
|
|
44
|
+
/** A Promise port whose work is abandonable: interruption does not wait for it. Use for reads and
|
|
45
|
+
* for writes a caller is free to walk away from; anything holding a resource wants {@link portJoin}. */
|
|
46
|
+
export function port(run) {
|
|
47
|
+
return Effect.tryPromise({ try: run, catch: (cause) => new PortFailure(cause) });
|
|
48
|
+
}
|
|
49
|
+
/** A Promise port with no abort hook: interruption joins the issued work before releasing. */
|
|
50
|
+
export function portJoin(run) {
|
|
51
|
+
return Effect.acquireUseRelease(Effect.try({ try: run, catch: (cause) => new PortFailure(cause) }), wait, (pending, exit) => (Exit.hasInterrupts(exit) ? Effect.exit(wait(pending)) : Effect.void));
|
|
52
|
+
}
|
|
53
|
+
/** A Promise port WITH an abort hook: interruption stops the work, then joins it. The hook runs only
|
|
54
|
+
* on interruption — a settled operation must not be told to abort (`session.abort()` on a finished
|
|
55
|
+
* run would reach the next one). A failing hook is diagnosed, never rethrown, under `label`: the
|
|
56
|
+
* tag is one thing, but a serve running an invoke and a manual compaction at once needs the warn to
|
|
57
|
+
* say WHICH abort could not be delivered. */
|
|
58
|
+
export function portAbort(label, run, abort) {
|
|
59
|
+
return Effect.acquireUseRelease(Effect.try({ try: run, catch: (cause) => new PortFailure(cause) }), wait, (pending, exit) => Exit.hasInterrupts(exit)
|
|
60
|
+
? portCleanup(`${label} abort`, abort).pipe(
|
|
61
|
+
// Cancellation silences the port's result, but its work must settle before release.
|
|
62
|
+
Effect.andThen(Effect.exit(wait(pending))))
|
|
63
|
+
: Effect.void);
|
|
64
|
+
}
|
|
65
|
+
/** A request with a deadline: the signal is closed on EVERY exit (it owns the response body, which a
|
|
66
|
+
* settled call has to release too), and the real request is joined before ownership is given up. */
|
|
67
|
+
export function portRequest(run, timeoutMs) {
|
|
68
|
+
return Effect.acquireUseRelease(Effect.sync(() => {
|
|
69
|
+
const controller = new AbortController();
|
|
70
|
+
// Publish the controller before entering foreign code, including a synchronous fetch throw.
|
|
71
|
+
return { controller, pending: Promise.resolve().then(() => run(controller.signal)) };
|
|
72
|
+
}), ({ pending }) => wait(pending).pipe(Effect.timeout(timeoutMs), Effect.mapError((error) => (error instanceof PortFailure ? error : new PortFailure(error)))), ({ controller, pending }) => Effect.sync(() => controller.abort()).pipe(Effect.andThen(Effect.exit(wait(pending)))));
|
|
73
|
+
}
|
|
74
|
+
/** Cleanup anomalies are diagnostic: they cannot change an already-published outcome. */
|
|
75
|
+
export function portCleanup(operation, run) {
|
|
76
|
+
return port(async () => run()).pipe(Effect.catchCause((cause) => Effect.sync(() => log.warn(`[fastagent] ${operation} failed during cleanup: ${String(portError(cause))}`))));
|
|
77
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { type Machine } from "./machine.ts";
|
|
1
2
|
import type { Skill, ThinkingLevel } from "@earendil-works/pi-agent-core";
|
|
2
|
-
import { type AgentSessionServices, type CreateAgentSessionServicesOptions, type ModelRuntime, type SessionManager, createAgentSessionFromServices } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
import { type AgentSession, type AgentSessionServices, type CompactionResult, type CreateAgentSessionServicesOptions, type ModelRuntime, type ResolvedCommand, SessionManager, createAgentSessionFromServices } from "@earendil-works/pi-coding-agent";
|
|
3
4
|
import type { PiAgentSessionFactory } from "./invoke-session.ts";
|
|
4
5
|
import type { PiSessionRecordStore } from "./session-store.ts";
|
|
5
6
|
import { type MountedTool } from "./tool.ts";
|
|
@@ -9,16 +10,9 @@ interface PiSessionDefinition {
|
|
|
9
10
|
skills: Skill[];
|
|
10
11
|
}
|
|
11
12
|
export interface PiAgentSessionFactoryOptions {
|
|
12
|
-
/** Where conversations live.
|
|
13
|
+
/** Where conversations live. */
|
|
13
14
|
sessions: PiSessionRecordStore;
|
|
14
|
-
/**
|
|
15
|
-
* The model to run and the hub that authenticates it, resolved on FIRST USE and kept.
|
|
16
|
-
*
|
|
17
|
-
* A thunk because building a `ModelRuntime` is async while assembling an agent is not: the L1
|
|
18
|
-
* surface hands back an `Agent` synchronously, so the credential read that a runtime performs
|
|
19
|
-
* belongs on the first turn rather than in the caller's constructor. The two travel together
|
|
20
|
-
* because a model must be resolved against the runtime that holds its provider's auth.
|
|
21
|
-
*/
|
|
15
|
+
/** The model to run and the hub that authenticates it, resolved on FIRST USE and kept. */
|
|
22
16
|
engine: () => Promise<{
|
|
23
17
|
modelRuntime: ModelRuntime;
|
|
24
18
|
model: AnyModel;
|
|
@@ -29,34 +23,7 @@ export interface PiAgentSessionFactoryOptions {
|
|
|
29
23
|
readDefinition: () => PiSessionDefinition | Promise<PiSessionDefinition>;
|
|
30
24
|
/** The agent's working directory — what fastagent-defined tools see as `cwd`. */
|
|
31
25
|
cwd: string;
|
|
32
|
-
/**
|
|
33
|
-
* Where pi looks for ITS settings (retry budget, compaction thresholds, default thinking level).
|
|
34
|
-
*
|
|
35
|
-
* Deliberately NOT pi's machine-global `~/.pi/agent`: a served agent must behave the same on the
|
|
36
|
-
* author's laptop and in a container, and reading the operator's personal pi configuration is the
|
|
37
|
-
* artifact losing to the machine. Point it at a definition-scoped path; a missing directory simply
|
|
38
|
-
* means pi's own defaults, which is the intended baseline.
|
|
39
|
-
*/
|
|
40
|
-
agentDir?: string;
|
|
41
|
-
/**
|
|
42
|
-
* The definition's own extension entry points, for ANNOUNCING that serving does not run them.
|
|
43
|
-
*
|
|
44
|
-
* pi's extension machinery is built for one process serving one session: `bindCore()` copies the
|
|
45
|
-
* session's actions into a runtime the pi source itself calls "the shared runtime", extension
|
|
46
|
-
* modules are cached per assembly, and `session_start`/`session_shutdown` are a matched pair.
|
|
47
|
-
* Serving breaks every one of those assumptions — concurrent turns for unrelated conversations —
|
|
48
|
-
* and the failure is silent cross-talk: with two turns in flight, an extension calling
|
|
49
|
-
* `pi.sendMessage()` can deliver into the other conversation.
|
|
50
|
-
*
|
|
51
|
-
* Loading them anyway would be a correctness bug dressed as a feature, so serving does not, and
|
|
52
|
-
* warns when a definition ships some. `chat` runs them fully: one session, one runtime, which is
|
|
53
|
-
* exactly the shape pi is built for.
|
|
54
|
-
*
|
|
55
|
-
* Isolating them per session is mechanically possible — pi's uncached loader path builds a fresh
|
|
56
|
-
* module (jiti with `moduleCache: false`) and takes the runtime as an argument — but that function
|
|
57
|
-
* is not exported and the deep path is blocked by the package's `exports`. Reopening this needs
|
|
58
|
-
* that entry point upstream, not a workaround here.
|
|
59
|
-
*/
|
|
26
|
+
/** The definition's own extension entry points, loaded fresh for every bound session. */
|
|
60
27
|
extensionPaths?: string[];
|
|
61
28
|
/** Built-ins omitted by an explicit lower-level tool list. */
|
|
62
29
|
excludedToolNames?: readonly string[];
|
|
@@ -73,52 +40,66 @@ export interface BindPiSessionOptions {
|
|
|
73
40
|
cwd: string;
|
|
74
41
|
/** Built-ins omitted by an explicit lower-level tool list. */
|
|
75
42
|
excludedToolNames?: readonly string[];
|
|
76
|
-
/** The CALLER's session id — what a tool asking which conversation it is in hears.
|
|
77
|
-
* pi's own id, which is right where the caller has none (chat). */
|
|
43
|
+
/** The CALLER's session id — what a tool asking which conversation it is in hears. */
|
|
78
44
|
sessionId?: string;
|
|
79
|
-
/** Record each discovered activation on the session, so the next bind restores it.
|
|
80
|
-
* pi's own session has nowhere to put one, so a resumed chat re-discovers. */
|
|
45
|
+
/** Record each discovered activation on the session, so the next bind restores it. */
|
|
81
46
|
recordActivations: boolean;
|
|
82
47
|
}
|
|
83
48
|
/**
|
|
84
|
-
* Bind ONE pi session to a record: the definition's tools as pi definitions over one turn context,
|
|
85
|
-
*
|
|
86
|
-
* runtime both bind here — they differ in what they hand in (a shared vs a per-session `services`,
|
|
87
|
-
* record-resolved vs configured settings) and in whether a discovered activation has a record to
|
|
88
|
-
* land in, and in nothing else. Two copies of this drifted once (the tool adapter and the deferral
|
|
89
|
-
* narrowing each existed twice, identical but for those parameters).
|
|
49
|
+
* Bind ONE pi session to a record: the definition's tools as pi definitions over one turn context, pi's own tool
|
|
50
|
+
* copies kept off, and deferral applied.
|
|
90
51
|
*/
|
|
91
52
|
export declare function bindPiSession(options: BindPiSessionOptions): ReturnType<typeof createAgentSessionFromServices>;
|
|
92
53
|
/**
|
|
93
|
-
* Announce extensions pi failed to load. pi collects them into `LoadExtensionsResult.errors` and
|
|
94
|
-
*
|
|
95
|
-
* A definition running without the extension it ships is exactly the "quietly missing" failure this
|
|
96
|
-
* exists to remove. CHAT calls it, once per built services — serving does not load extensions at
|
|
97
|
-
* all, and announces that instead (see PiAgentSessionFactoryOptions.extensionPaths).
|
|
54
|
+
* Announce extensions pi failed to load. pi collects them into `LoadExtensionsResult.errors` and carries on with the
|
|
55
|
+
* rest.
|
|
98
56
|
*/
|
|
99
57
|
export declare function reportExtensionErrors(services: AgentSessionServices): void;
|
|
100
58
|
/** What pi is allowed to discover, minus the parts each assembly fills in itself. */
|
|
101
59
|
type DefinitionLoaderOptions = NonNullable<CreateAgentSessionServicesOptions["resourceLoaderOptions"]>;
|
|
102
|
-
/**
|
|
103
|
-
* The resource posture a fastagent definition asks pi for — ONE definition of it, for both
|
|
104
|
-
* assemblies. Serving (`piAgentSessionFactory`) and chat (`buildAgentSessionRuntime`) build
|
|
105
|
-
* different sessions on top, but what pi is allowed to DISCOVER is not one of the differences:
|
|
106
|
-
* everything comes from the definition, nothing from the machine that happens to be running it.
|
|
107
|
-
*
|
|
108
|
-
* Two copies of this drifted once already: `additionalExtensionPaths` was added to both, and only
|
|
109
|
-
* one of them also passed the resulting tool names through pi's `tools` allowlist — so extensions
|
|
110
|
-
* worked when served and vanished in chat. A difference between the two has to be visible AS a
|
|
111
|
-
* difference, which is what the parameters are for: serving reads a prompt and skills that change
|
|
112
|
-
* per turn and passes NO extension paths (it does not run them — see
|
|
113
|
-
* {@link PiAgentSessionFactoryOptions.extensionPaths}); chat reads a fixed assembly and passes its
|
|
114
|
-
* own. Both are arguments now, rather than two files that happen to disagree.
|
|
115
|
-
*/
|
|
60
|
+
/** The resource posture a fastagent definition asks pi for — ONE definition of it, for both assemblies. */
|
|
116
61
|
export declare function definitionResourceLoaderOptions(source: {
|
|
117
62
|
systemPrompt: () => string | undefined;
|
|
118
63
|
skills: () => Skill[];
|
|
119
|
-
/**
|
|
64
|
+
/** {@link readMachine} for this workspace — resolved by the caller, because this function is synchronous. */
|
|
65
|
+
machine: Machine;
|
|
120
66
|
extensionPaths?: readonly string[];
|
|
121
67
|
}): DefinitionLoaderOptions;
|
|
122
|
-
/**
|
|
68
|
+
/** Tell a waiting {@link startCompaction} that pi admitted the compaction on this record. */
|
|
69
|
+
export declare function admitCompaction(record: SessionManager): void;
|
|
70
|
+
/** What pi decided before its model call: go ahead, nothing to do, or a failure of its own (in `refused`). */
|
|
71
|
+
export type CompactAdmission = "admitted" | "nothing_to_compact" | {
|
|
72
|
+
refused: unknown;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Start pi's manual compaction on a bound session. `onAdmitted` runs INSIDE pi's admission event, so everything it
|
|
76
|
+
* publishes precedes anything pi does next (the model call, its retries). `admission` settles before the model call.
|
|
77
|
+
* pi's own pre-admission failures come back as `refused` rather than a rejection: the caller answers them to its
|
|
78
|
+
* Caller as a result. `done` is the compaction itself.
|
|
79
|
+
*/
|
|
80
|
+
export declare function startCompaction(session: AgentSession, instructions: string | undefined, onAdmitted: () => void): {
|
|
81
|
+
admission: Promise<CompactAdmission>;
|
|
82
|
+
done: Promise<CompactionResult>;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* The `/name` commands a served session dispatches, named the way pi resolves them (a name two extensions share gets
|
|
86
|
+
* a `:N` suffix). Loaded through the same {@link servingServices} a turn binds, so the menu and the dispatch cannot
|
|
87
|
+
* disagree. Loading runs the extensions' factories; no session opens, so `session_start` does not fire, and the
|
|
88
|
+
* instances are never bound (any action they call throws).
|
|
89
|
+
*/
|
|
90
|
+
export declare function servedExtensionCommands(options: {
|
|
91
|
+
cwd: string;
|
|
92
|
+
modelRuntime: ModelRuntime;
|
|
93
|
+
extensionPaths: readonly string[];
|
|
94
|
+
}): Promise<ResolvedCommand[]>;
|
|
95
|
+
/**
|
|
96
|
+
* Open-or-create the record, then bind a fresh session to it — on a fresh resource loader.
|
|
97
|
+
*
|
|
98
|
+
* ONE LOADER PER SESSION, because pi's extension runtime belongs to its loader: a loader shared across concurrent
|
|
99
|
+
* turns would let one conversation's extension act on another's session. It also makes the definition live with no
|
|
100
|
+
* bookkeeping: every bind reads the prompt and skills this invoke read. The machine's half is the process's one read
|
|
101
|
+
* (machine.ts). Extension CODE is imported once per process, so an edit to `extensions/` needs a restart, which is
|
|
102
|
+
* what `dev` does on one.
|
|
103
|
+
*/
|
|
123
104
|
export declare function piAgentSessionFactory(options: PiAgentSessionFactoryOptions): PiAgentSessionFactory;
|
|
124
105
|
export {};
|