@fastagent-sh/fastagent 0.21.1 → 0.22.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 +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 +209 -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 +153 -228
- 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
|
@@ -1,28 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Agent assembly (configuration-time): the engine assets (tools, prompt) plus the reusable ladder
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* L2 createPiAgentFromDefinition(dir, options) — load a definition directory, assemble, then L1.
|
|
6
|
-
* L1 createPiAgent(options) — assemble from typed parts (the canonical ctor).
|
|
7
|
-
* L0 createPiAgentFromSession({ sessionFactory }) — in invoke-session.ts (the turn mechanism).
|
|
8
|
-
*
|
|
9
|
-
* Above L2 sits the agent opener createPiAgentFromDir (open.ts), which both `dev` and
|
|
10
|
-
* `start` drive. Each rung calls the one below; options narrow as you go up (L2 owns systemPrompt/skills —
|
|
11
|
-
* they come from the definition; the openers own model/tools — from config resolution).
|
|
12
|
-
*
|
|
13
|
-
* Every rung assembles the same VALUE first — a {@link PiAssembly}: the lease, the session factory
|
|
14
|
-
* and the engine thunk — and the agent is that value under the L0. The opener needs the value
|
|
15
|
-
* itself (the control plane contends on the same lease and validates against the same registry), so
|
|
16
|
-
* `assemblePiFromDefinition` hands it out and `createPiAgentFromDefinition` is it plus the L0.
|
|
2
|
+
* Agent assembly (configuration-time): the engine assets (tools, prompt) plus the reusable ladder that puts a pi agent
|
|
3
|
+
* together.
|
|
17
4
|
*/
|
|
18
5
|
import { toUSVString } from "node:util";
|
|
19
6
|
import { NodeExecutionEnv } from "@earendil-works/pi-agent-core/node";
|
|
20
7
|
import { createCodingTools, createPowerShellTool, createReadOnlyTools, } from "@earendil-works/pi-coding-agent";
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
8
|
+
import { resolveAuthLayers, resolveModel } from "./config.js";
|
|
9
|
+
import { isAgentcoreRuntime, isDeployedWorkspace } from "../../paths.js";
|
|
23
10
|
import { loadAgentDefinition, loadExtensionPaths } from "./definition.js";
|
|
24
11
|
import { reportFindingsIfChanged } from "./report.js";
|
|
25
|
-
import { isDeferredTool, loadTools, mergeDiscoveredTools } from "./tool.js";
|
|
12
|
+
import { isDeferredTool, loadTools, mergeDiscoveredTools, } from "./tool.js";
|
|
13
|
+
import { readSecretDeclaration } from "../../declared-secrets.js";
|
|
26
14
|
import { withSearchTool } from "./search-tools.js";
|
|
27
15
|
import { createPiAgentFromSession } from "./invoke-session.js";
|
|
28
16
|
import { piAgentSessionFactory } from "./agent-session-factory.js";
|
|
@@ -31,27 +19,10 @@ import { piInMemorySessionRecordStore } from "./session-store.js";
|
|
|
31
19
|
import { inProcessLease } from "./turn-kit.js";
|
|
32
20
|
// ── §1 tools ─────────────────────────────────────────────────────────────────
|
|
33
21
|
//
|
|
34
|
-
// A directory agent gets every pi coding tool.
|
|
35
|
-
// sandbox boundary, not in an allowlist that leaves authored tools unrestricted. L1/L2 library callers
|
|
36
|
-
// can still replace the coding defaults through `tools`; deferred tools may add `search_tools`.
|
|
37
|
-
//
|
|
38
|
-
// This is not a security boundary and no default here could be one: the built-in POST /invoke has no
|
|
39
|
-
// authentication, author-written `tools/` import whatever they like, and a WebSocket or Socket-Mode
|
|
40
|
-
// channel dials OUT, so no bind address constrains who can message the agent. Whoever can reach an
|
|
41
|
-
// agent can use everything it mounts — put it behind something that decides who may.
|
|
42
|
-
//
|
|
43
|
-
// All seven come from pi-coding-agent and reach the machine through `node:fs`, bypassing the per-turn
|
|
44
|
-
// {@link ExecutionEnv}. pi-agent-core ships env-routed look-alikes, but that seam narrows a blast
|
|
45
|
-
// radius rather than closing one (authored `tools/` ignore it), so a real sandbox must wrap the
|
|
46
|
-
// process instead.
|
|
47
|
-
//
|
|
48
|
-
// Chat receives the same tool objects through pi's `customTools` path; pi's builtin copies stay off.
|
|
22
|
+
// A directory agent gets every pi coding tool.
|
|
49
23
|
/**
|
|
50
|
-
* Every pi coding tool, in canonical order, rooted at the workspace it operates in.
|
|
51
|
-
*
|
|
52
|
-
* pi ships two overlapping groupings and neither is the whole set: `createCodingTools` is the four it
|
|
53
|
-
* ACTIVATES for a terminal (read/bash/edit/write, no searching), `createReadOnlyTools` is
|
|
54
|
-
* read/grep/find/ls. `read` is in both; a directory agent mounts their union.
|
|
24
|
+
* Every pi coding tool, in canonical order, rooted at the workspace it operates in. pi ships two overlapping groupings
|
|
25
|
+
* and neither is the whole set.
|
|
55
26
|
*/
|
|
56
27
|
export const CODING_TOOL_NAMES = ["read", "grep", "find", "ls", "bash", "edit", "write"];
|
|
57
28
|
export function piAllCodingTools(cwd) {
|
|
@@ -72,14 +43,7 @@ export function piAllCodingTools(cwd) {
|
|
|
72
43
|
}).filter((tool) => tool.name !== "read");
|
|
73
44
|
return [...createReadOnlyTools(cwd), ...mutating];
|
|
74
45
|
}
|
|
75
|
-
/**
|
|
76
|
-
* Every tool an `AgentSession` registers on its own, whether or not a directory agent mounts it.
|
|
77
|
-
*
|
|
78
|
-
* Wider than {@link CODING_TOOL_NAMES} on purpose: pi 0.84.3 added `powershell`, which the session
|
|
79
|
-
* registers regardless of the tools we pass. A name absent from THIS list is a name never excluded,
|
|
80
|
-
* and an excluded name is the only thing that cannot be activated — so leaving it out would let
|
|
81
|
-
* `tools: [read]` keep a reachable shell.
|
|
82
|
-
*/
|
|
46
|
+
/** Every tool an `AgentSession` registers on its own, whether or not a directory agent mounts it. */
|
|
83
47
|
function piRegisteredToolNames(cwd) {
|
|
84
48
|
return [
|
|
85
49
|
...createReadOnlyTools(cwd).map((tool) => tool.name),
|
|
@@ -87,24 +51,26 @@ function piRegisteredToolNames(cwd) {
|
|
|
87
51
|
createPowerShellTool(cwd).name,
|
|
88
52
|
];
|
|
89
53
|
}
|
|
90
|
-
/** Built-ins omitted by an explicit lower-level tool list.
|
|
54
|
+
/** Built-ins omitted by an explicit lower-level tool list. */
|
|
91
55
|
function omittedBuiltinNames(mounted, cwd) {
|
|
92
56
|
const mountedNames = new Set(mounted.map((tool) => tool.name));
|
|
93
57
|
return [...new Set(piRegisteredToolNames(cwd))].filter((name) => !mountedNames.has(name));
|
|
94
58
|
}
|
|
95
59
|
/**
|
|
96
|
-
* The full directory-agent tool set: all pi coding tools + `config.tools` + discovered `tools/`
|
|
97
|
-
*
|
|
98
|
-
* dev/start openers AND `fastagent tool`, so they all mount exactly the same set.
|
|
60
|
+
* The full directory-agent tool set: all pi coding tools + `config.tools` + discovered `tools/` (deduped, existing
|
|
61
|
+
* win), plus the authored names and collisions to report.
|
|
99
62
|
*/
|
|
100
63
|
export async function resolveAgentTools(config, agentDir, cwd) {
|
|
101
|
-
// Discovered `tools/` come from `agentDir` (the agent's own surface); the coding tools are
|
|
102
|
-
//
|
|
103
|
-
// `read`/`bash` to land, and which is not always the definition directory.
|
|
64
|
+
// Discovered `tools/` come from `agentDir` (the agent's own surface); the coding tools are rooted at `cwd`, the
|
|
65
|
+
// WORKSPACE.
|
|
104
66
|
const discovered = await loadTools(agentDir);
|
|
105
67
|
const configured = piAllCodingTools(cwd);
|
|
106
68
|
const configuredNames = new Set(configured.map((tool) => tool.name));
|
|
107
69
|
const configuredCollisions = [];
|
|
70
|
+
// The config.tools that actually MOUNT — collected here rather than re-derived from `config.tools`
|
|
71
|
+
// afterwards, so a tool dropped for sharing a coding tool's name cannot contribute a declaration
|
|
72
|
+
// (its body never runs, and gating a start on its secret would refuse to serve for nothing).
|
|
73
|
+
const mountedConfigTools = [];
|
|
108
74
|
for (const tool of config.tools ?? []) {
|
|
109
75
|
if (configuredNames.has(tool.name)) {
|
|
110
76
|
configuredCollisions.push({ name: tool.name, source: "config.tools" });
|
|
@@ -112,20 +78,19 @@ export async function resolveAgentTools(config, agentDir, cwd) {
|
|
|
112
78
|
}
|
|
113
79
|
configuredNames.add(tool.name);
|
|
114
80
|
configured.push(tool);
|
|
81
|
+
mountedConfigTools.push(tool);
|
|
115
82
|
}
|
|
116
83
|
const merged = mergeDiscoveredTools(configured, discovered.tools);
|
|
117
|
-
// The built-in `search_tools` loader mounts here
|
|
118
|
-
// computed — so `dev`/`start`/`info`/`fastagent tool` all see the same surface (idempotent; an
|
|
119
|
-
// agent-defined search_tools wins).
|
|
84
|
+
// The built-in `search_tools` loader mounts here.
|
|
120
85
|
const tools = withSearchTool(merged.tools);
|
|
121
|
-
// Builtin = a search_tools that was ABSENT before withSearchTool (a reference compare would misfire
|
|
122
|
-
//
|
|
86
|
+
// Builtin = a search_tools that was ABSENT before withSearchTool (a reference compare would misfire on the
|
|
87
|
+
// deferred-authored-loader case, where withSearchTool returns a new array without adding one).
|
|
123
88
|
const builtinLoaderMounted = !merged.tools.some((t) => t.name === "search_tools") && tools.some((t) => t.name === "search_tools");
|
|
124
89
|
const toolCollisions = [...discovered.collisions, ...configuredCollisions, ...merged.collisions];
|
|
125
|
-
// `toolNames` is the AUTHOR's active-by-default surface (config.tools + tools/)
|
|
126
|
-
// tools
|
|
127
|
-
// the
|
|
128
|
-
|
|
90
|
+
// `toolNames` is the AUTHOR's active-by-default surface (config.tools + tools/).
|
|
91
|
+
// The discovered tools that were DROPPED (a coding tool or config.tools already owns the name):
|
|
92
|
+
// asking the mounted set instead would read the winner's name as proof the loser is mounted.
|
|
93
|
+
const shadowed = new Set(merged.collisions.map((c) => c.name));
|
|
129
94
|
const defaultNames = new Set(CODING_TOOL_NAMES);
|
|
130
95
|
const toolNames = tools
|
|
131
96
|
.filter((t) => !defaultNames.has(t.name) && !isDeferredTool(t) && !(builtinLoaderMounted && t.name === "search_tools"))
|
|
@@ -136,29 +101,35 @@ export async function resolveAgentTools(config, agentDir, cwd) {
|
|
|
136
101
|
deferredToolNames: tools.filter(isDeferredTool).map((t) => t.name),
|
|
137
102
|
toolCollisions,
|
|
138
103
|
toolFailures: discovered.failures,
|
|
104
|
+
// Mounted only, and config.tools are FastagentTools too, so a programmatic tool declares the
|
|
105
|
+
// same way a file does.
|
|
106
|
+
toolSecrets: new Map([
|
|
107
|
+
...[...discovered.secrets].filter(([name]) => !shadowed.has(name)),
|
|
108
|
+
// A programmatic tool declares the same way a file does. The source names the ENTRY, not just
|
|
109
|
+
// the list: `source` has to point at something the author can find, and "config.tools" alone
|
|
110
|
+
// locates nothing when the list has several tools. The shape was already refused by config
|
|
111
|
+
// validation (config.ts), so a throw here means a FastagentConfig assembled in code bypassed
|
|
112
|
+
// it — still the caller's own object, so it fails loudly rather than being isolated.
|
|
113
|
+
...mountedConfigTools.map((tool) => {
|
|
114
|
+
const declaration = readSecretDeclaration(tool, `config.tools "${tool.name}"`);
|
|
115
|
+
if (declaration.error !== undefined)
|
|
116
|
+
throw new Error(declaration.error);
|
|
117
|
+
return [tool.name, declaration.secrets];
|
|
118
|
+
}),
|
|
119
|
+
]),
|
|
139
120
|
};
|
|
140
121
|
}
|
|
141
122
|
// Fastagent owns identity and project context; Pi appends skills and cwd for both serving and chat.
|
|
142
|
-
/**
|
|
143
|
-
* The pi engine's base prompt (segment ①), mirroring pi-coding-agent's default path with two
|
|
144
|
-
* deviations: the pi-TUI docs section is dropped (those paths don't exist in deployments), and the
|
|
145
|
-
* tool list is generated from the actually-mounted tools (base and toolset must agree). An authored
|
|
146
|
-
* `persona` (from persona.md) replaces the default identity line, keeping the tools list + guidelines.
|
|
147
|
-
*/
|
|
123
|
+
/** The pi engine's base prompt (segment ①), mirroring pi-coding-agent's default path with two deviations. */
|
|
148
124
|
export function piBasePrompt(options = {}) {
|
|
149
125
|
const mounted = options.tools ?? [];
|
|
150
|
-
// Deferred tools stay OUT of the list: their schemas are not in the request until activated, so
|
|
151
|
-
//
|
|
152
|
-
// (which IS listed — it's active). Computed from the static mounted set, so the prompt — the cached
|
|
153
|
-
// context prefix — does not change when a tool is activated mid-session.
|
|
126
|
+
// Deferred tools stay OUT of the list: their schemas are not in the request until activated, so naming them here
|
|
127
|
+
// would invite calls to tools that don't exist yet.
|
|
154
128
|
const tools = mounted.filter((t) => !isDeferredTool(t));
|
|
155
129
|
const deferredCount = mounted.length - tools.length;
|
|
156
130
|
const toolsList = tools.length > 0 ? tools.map((t) => `- ${t.name}: ${(t.description ?? "").split("\n")[0]}`).join("\n") : "(none)";
|
|
157
|
-
// Segment ① identity: an authored persona (persona.md) replaces the default engine identity line
|
|
158
|
-
//
|
|
159
|
-
// the full coding surface; a partial/empty surface must not claim machine capabilities it lacks.
|
|
160
|
-
// The four this sentence NAMES — reading, executing, editing, writing. Searching is not part of the
|
|
161
|
-
// claim, so requiring it would demote an agent that can do everything the identity says it can.
|
|
131
|
+
// Segment ① identity: an authored persona (persona.md) replaces the default engine identity line (core.md §2),
|
|
132
|
+
// keeping the tools list + guidelines below.
|
|
162
133
|
const mountedNames = new Set(mounted.map((tool) => tool.name));
|
|
163
134
|
const fullCodingSurface = ["read", "bash", "edit", "write"].every((name) => mountedNames.has(name));
|
|
164
135
|
const identity = options.persona?.trim() ||
|
|
@@ -168,6 +139,23 @@ export function piBasePrompt(options = {}) {
|
|
|
168
139
|
const deferredNote = deferredCount > 0
|
|
169
140
|
? `\n\n${deferredCount} additional tool(s) are registered but inactive — use search_tools to discover and activate them before concluding a capability is missing.`
|
|
170
141
|
: "";
|
|
142
|
+
// What takes effect when, and the agent's own path to a new capability, are the same on every host; only how long
|
|
143
|
+
// the storage lives differs, below. The skill it writes lives in the definition directory, which the next
|
|
144
|
+
// deployment replaces (or, on AgentCore, erases with everything else) — so the sentence says so, and where a skill
|
|
145
|
+
// that should outlast it has to go. A skill outside the definition would survive, but it is machine state, read
|
|
146
|
+
// once per process (machine.ts), so it would not be live.
|
|
147
|
+
const RUNTIME_CHANGES = ` Markdown definition files are read each turn; changes to tools, channels or configuration take effect when the service restarts. To give yourself a new capability now, write a skill — a SKILL.md in your definition's skills/ directory, with any script it needs run through bash. It lasts until the next deployment replaces that directory, so a capability that should outlast it belongs in the author's release: propose it to them.${
|
|
148
|
+
// Named only when mounted (a serve; not a one-shot invoke), like the deferred tools above: naming a tool the model does not
|
|
149
|
+
// have invites calls to it.
|
|
150
|
+
mountedNames.has("wake") ? " To schedule your own follow-up work, use the wake tool." : ""}`;
|
|
151
|
+
// How long the storage lives is the HOST's answer, not a deployment-wide one: AgentCore's managed
|
|
152
|
+
// mount is reset by every deploy, so telling that agent to keep work "outside the definition" would
|
|
153
|
+
// name a location its next deploy erases.
|
|
154
|
+
const deploymentNote = !isDeployedWorkspace()
|
|
155
|
+
? ""
|
|
156
|
+
: isAgentcoreRuntime()
|
|
157
|
+
? `\n\nYour workspace survives restarts, including uncommitted work; /tmp does not. Every deployment of a new version resets this host's storage entirely, so anything that must outlive a deployment belongs in an external system (a git remote, an issue tracker, a database).${RUNTIME_CHANGES}`
|
|
158
|
+
: `\n\nYour workspace survives restarts and deployments, including uncommitted work; /tmp does not. A new deployment replaces your definition directory with the author's release, so keep ongoing project work outside it.${RUNTIME_CHANGES}`;
|
|
171
159
|
return `${identity}
|
|
172
160
|
|
|
173
161
|
Available tools:
|
|
@@ -177,7 +165,7 @@ In addition to the tools above, you may have access to other custom tools depend
|
|
|
177
165
|
|
|
178
166
|
Guidelines:
|
|
179
167
|
- Be concise in your responses
|
|
180
|
-
- Show file paths clearly when working with files`;
|
|
168
|
+
- Show file paths clearly when working with files${deploymentNote}`;
|
|
181
169
|
}
|
|
182
170
|
export function assembleSystemPrompt(options) {
|
|
183
171
|
let prompt = options.base;
|
|
@@ -192,29 +180,22 @@ export function assembleSystemPrompt(options) {
|
|
|
192
180
|
}
|
|
193
181
|
return prompt;
|
|
194
182
|
}
|
|
195
|
-
/**
|
|
196
|
-
* Shared low-level wiring: resolve the model spec against the collection, default the K ports, build
|
|
197
|
-
* the parts. Internal — the public rungs decide the systemPrompt (L1 from instructions, L2 from the
|
|
198
|
-
* directory) and route through here.
|
|
199
|
-
*/
|
|
183
|
+
/** Shared low-level wiring: resolve the model spec against the collection, default the K ports, build the parts. */
|
|
200
184
|
function assemblePi(opts) {
|
|
201
185
|
const cwd = opts.cwd ?? opts.env?.cwd ?? process.cwd();
|
|
202
|
-
// Materialized here (not defaulted inside the L0) so the value carries the SAME lease instance the
|
|
203
|
-
//
|
|
186
|
+
// Materialized here (not defaulted inside the L0) so the value carries the SAME lease instance the agent runs under
|
|
187
|
+
// — boundary mutations must contend on it.
|
|
204
188
|
const lease = opts.lease ?? inProcessLease();
|
|
205
189
|
const sessions = opts.sessions ?? piInMemorySessionRecordStore({ cwd });
|
|
206
|
-
// The model and its runtime resolve on FIRST USE
|
|
207
|
-
// assembling an agent is not, so the credential read belongs on the first turn rather than in the
|
|
208
|
-
// caller's constructor. Memoized, and shared with the control plane so a boundary mutation
|
|
209
|
-
// validates against the registry the runs actually use.
|
|
190
|
+
// The model and its runtime resolve on FIRST USE.
|
|
210
191
|
let engine;
|
|
211
192
|
const resolveEngine = () => {
|
|
212
193
|
engine ??= (async () => {
|
|
213
|
-
// The caller's registry when there is one — the directory rung builds it from the agent's own
|
|
214
|
-
//
|
|
215
|
-
const modelRuntime = opts.models ?? (await createPiModelRuntime({
|
|
216
|
-
// ModelRuntime registers providers by config record, so an injected Provider INSTANCE (a
|
|
217
|
-
//
|
|
194
|
+
// The caller's registry when there is one — the directory rung builds it from the agent's own models.json, so a
|
|
195
|
+
// custom endpoint declared there is the one a turn resolves against.
|
|
196
|
+
const modelRuntime = opts.models ?? (await createPiModelRuntime({ auth: opts.auth }));
|
|
197
|
+
// ModelRuntime registers providers by config record, so an injected Provider INSTANCE (a gateway, a self-hosted
|
|
198
|
+
// endpoint, a test fake) goes in through its native seam.
|
|
218
199
|
for (const provider of opts.providers ?? [])
|
|
219
200
|
modelRuntime.registerNativeProvider(provider);
|
|
220
201
|
return { modelRuntime, model: resolveModel(modelRuntime, opts.model) };
|
|
@@ -228,10 +209,9 @@ function assemblePi(opts) {
|
|
|
228
209
|
tools: opts.tools,
|
|
229
210
|
readDefinition: opts.readDefinition,
|
|
230
211
|
cwd,
|
|
231
|
-
...(opts.agentDir ? { agentDir: opts.agentDir } : {}),
|
|
232
212
|
...(opts.extensionPaths ? { extensionPaths: opts.extensionPaths } : {}),
|
|
233
|
-
// `noTools: "builtin"` leaves pi's built-ins in the registry; a lower-level replacement must also
|
|
234
|
-
//
|
|
213
|
+
// `noTools: "builtin"` leaves pi's built-ins in the registry; a lower-level replacement must also deny every
|
|
214
|
+
// omitted coding name so a loader cannot reactivate one later.
|
|
235
215
|
excludedToolNames: omittedBuiltinNames(opts.tools ?? [], cwd),
|
|
236
216
|
});
|
|
237
217
|
return {
|
|
@@ -239,6 +219,7 @@ function assemblePi(opts) {
|
|
|
239
219
|
sessionFactory,
|
|
240
220
|
engine: resolveEngine,
|
|
241
221
|
thinkingLevel: opts.thinkingLevel ?? DEFAULT_THINKING_LEVEL,
|
|
222
|
+
extensionPaths: opts.extensionPaths ?? [],
|
|
242
223
|
};
|
|
243
224
|
}
|
|
244
225
|
/** The agent an assembly runs as: the L0 over its lease and session factory. */
|
|
@@ -252,7 +233,7 @@ export function createPiAgent(options) {
|
|
|
252
233
|
model: options.model,
|
|
253
234
|
thinkingLevel: options.thinkingLevel,
|
|
254
235
|
providers: options.providers,
|
|
255
|
-
authPath: options.authPath,
|
|
236
|
+
...(options.authPath !== undefined ? { auth: { path: options.authPath } } : {}),
|
|
256
237
|
readDefinition: () => ({
|
|
257
238
|
systemPrompt: typeof instructions === "function" ? instructions() : instructions,
|
|
258
239
|
skills,
|
|
@@ -265,60 +246,49 @@ export function createPiAgent(options) {
|
|
|
265
246
|
}), options.observer);
|
|
266
247
|
}
|
|
267
248
|
/**
|
|
268
|
-
*
|
|
269
|
-
* definition
|
|
270
|
-
*
|
|
249
|
+
* THE model registry an agent directory runs on: pi's built-ins, the directory's own `models.json` (custom endpoints
|
|
250
|
+
* are definition data and travel with the artifact) layered over the machine's `~/.fastagent/models.json` (environment,
|
|
251
|
+
* which does not travel), and any injected Provider instance, over the given credentials.
|
|
252
|
+
* The directory rung assembles from it and `availableModelsFromDir` lists from it, so a layer added here reaches both.
|
|
271
253
|
*/
|
|
272
|
-
export
|
|
273
|
-
|
|
274
|
-
|
|
254
|
+
export function definitionModelRuntime(dir, options) {
|
|
255
|
+
return createPiModelRuntime({ agentDir: dir, ...options });
|
|
256
|
+
}
|
|
257
|
+
/** L2, as the value: load the directory (base + AGENTS.md + skills + env) and assemble. */
|
|
258
|
+
export async function assemblePiFromDefinition(dir,
|
|
259
|
+
/** `auth` is the opener's already-resolved layers, which take the place of `authPath`. */
|
|
260
|
+
options) {
|
|
261
|
+
// `dir` = the agent-definition dir (persona.md/skills/); `cwd` (default = dir) is the run root where tools operate
|
|
262
|
+
// and whose ancestors are walked for ② context.
|
|
275
263
|
const cwd = options.cwd ?? dir;
|
|
276
264
|
const env = options.env ?? new NodeExecutionEnv({ cwd });
|
|
277
|
-
// Boot-time load: fail-visibly at startup on a broken directory, and give callers the snapshot to
|
|
278
|
-
//
|
|
279
|
-
// `cwd`, not `env.cwd`, for the same reason as the tools below: `cwd` is the run root whose
|
|
280
|
-
// ancestors carry ② project context. Reading it off the env pointed the AGENTS.md walk at the
|
|
281
|
-
// loader's directory whenever a caller supplied both.
|
|
265
|
+
// Boot-time load: fail-visibly at startup on a broken directory, and give callers the snapshot to report
|
|
266
|
+
// (skills/diagnostics/collisions).
|
|
282
267
|
const definition = await loadAgentDefinition(dir, { cwd, env });
|
|
283
|
-
// Deferred tools need their loader on every rung (idempotent — the workspace opener already applied
|
|
284
|
-
//
|
|
285
|
-
// `cwd`, not `env.cwd`: the workspace is what this option MEANS, and a caller may hand a custom env
|
|
286
|
-
// for definition loading whose root is a different directory. Taking it off the env would silently
|
|
287
|
-
// point the coding tools at the loader's directory.
|
|
268
|
+
// Deferred tools need their loader on every rung (idempotent — the workspace opener already applied it; a caller's
|
|
269
|
+
// own search_tools wins).
|
|
288
270
|
const tools = withSearchTool(options.tools ?? piAllCodingTools(cwd));
|
|
289
|
-
// Boot findings go through the SAME memoized reporter every later reader uses (report.ts, keyed by
|
|
290
|
-
//
|
|
291
|
-
// command list only when the set CHANGES — a runtime-written bad skill surfaces the moment it
|
|
292
|
-
// appears, a static one does not spam. Log dedup, not session state (stateless invoke holds).
|
|
271
|
+
// Boot findings go through the SAME memoized reporter every later reader uses (report.ts, keyed by the resolved
|
|
272
|
+
// dir).
|
|
293
273
|
reportFindingsIfChanged(definition.dir, definition);
|
|
294
|
-
|
|
295
|
-
// passes an explicit authPath, so this only affects direct L2 callers).
|
|
296
|
-
const authPath = options.authPath ?? defaultAuthPath(resolveSecretsDir(dir));
|
|
274
|
+
const auth = options.auth ?? (options.authPath === undefined ? resolveAuthLayers(dir) : { path: options.authPath });
|
|
297
275
|
const assembly = assemblePi({
|
|
298
276
|
model: options.model,
|
|
299
277
|
thinkingLevel: options.thinkingLevel,
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
//
|
|
306
|
-
//
|
|
307
|
-
// no process restart — restarts are reserved for code (tools/channels/config, module cache).
|
|
308
|
-
// One read yields prompt AND skills (they can never diverge), and the
|
|
309
|
-
// fs cost is a few reads against a model call. Broken edits stay visible: a throw-class problem
|
|
310
|
-
// (unreadable AGENTS.md) fails that turn's invoke, and the loader's NON-fatal findings (bad
|
|
311
|
-
// SKILL.md frontmatter, name collisions — returned as data, not thrown) are warned the moment
|
|
312
|
-
// the finding set changes (boot findings are the baseline) — a runtime-written bad skill must
|
|
313
|
-
// not silently vanish from the agent, and a static one must not spam every turn's log. The
|
|
314
|
-
// next good edit heals both.
|
|
278
|
+
models: await definitionModelRuntime(dir, {
|
|
279
|
+
auth,
|
|
280
|
+
...(options.providers ? { providers: options.providers } : {}),
|
|
281
|
+
}),
|
|
282
|
+
// The directory is the agent, LIVE: re-read the definition on every invoke, so AGENTS.md/skills edits (the
|
|
283
|
+
// author's, or the agent's own self-modification) take effect on the next turn with no process restart — restarts
|
|
284
|
+
// are reserved for code (tools/channels/config, module cache).
|
|
315
285
|
readDefinition: async () => {
|
|
316
286
|
const def = await loadAgentDefinition(dir, { cwd, env });
|
|
317
287
|
reportFindingsIfChanged(def.dir, def);
|
|
318
288
|
return {
|
|
319
289
|
systemPrompt: assembleSystemPrompt({
|
|
320
|
-
// Segment ①: an authored persona (persona.md, def.persona) overrides the engine identity,
|
|
321
|
-
//
|
|
290
|
+
// Segment ①: an authored persona (persona.md, def.persona) overrides the engine identity, re-read per turn
|
|
291
|
+
// like AGENTS.md so edits go live.
|
|
322
292
|
base: options.base ?? piBasePrompt({ tools, persona: def.persona }),
|
|
323
293
|
// ② project context: AGENTS.md files (agentDir + cwd-ancestor walk) via loadProjectContextFiles.
|
|
324
294
|
contextFiles: def.contextFiles,
|
|
@@ -328,9 +298,6 @@ export async function assemblePiFromDefinition(dir, options) {
|
|
|
328
298
|
},
|
|
329
299
|
tools,
|
|
330
300
|
sessions: options.sessions,
|
|
331
|
-
// Discovered so the serving assembly can WARN that it does not run them (and so the refusals
|
|
332
|
-
// apply to the artifact either way) — `chat` is where they load. Boot-resolved: the set cannot
|
|
333
|
-
// change without a restart, which is why this sits outside readDefinition above.
|
|
334
301
|
extensionPaths: await loadExtensionPaths(dir, { cwd, env }),
|
|
335
302
|
cwd,
|
|
336
303
|
env,
|
|
@@ -1,25 +1,21 @@
|
|
|
1
1
|
import { type ExecutionEnv, type Skill, type SkillDiagnostic } from "@earendil-works/pi-agent-core";
|
|
2
|
-
/** A same-name skill collision (the discarded side).
|
|
2
|
+
/** A same-name skill collision (the discarded side). */
|
|
3
3
|
export interface SkillCollision {
|
|
4
4
|
name: string;
|
|
5
5
|
winnerPath: string;
|
|
6
6
|
loserPath: string;
|
|
7
7
|
}
|
|
8
|
-
/** Result of loading a definition directory.
|
|
8
|
+
/** Result of loading a definition directory. */
|
|
9
9
|
export interface LoadedDefinition {
|
|
10
|
-
/**
|
|
11
|
-
* Project-context files feeding segment ② `<project_context>`, sourced via pi's `loadProjectContextFiles`:
|
|
12
|
-
* the agentDir's own AGENTS.md/CLAUDE.md FIRST, then every AGENTS.md from root down to `cwd` (so the
|
|
13
|
-
* file nearest `cwd` comes LAST — pi's array order). Empty when none exist. This WALKS cwd's ancestors (pi's coding-agent behaviour) — see core.md §6.
|
|
14
|
-
*/
|
|
10
|
+
/** Project-context files feeding segment ② `<project_context>`, sourced via pi's `loadProjectContextFiles`. */
|
|
15
11
|
contextFiles: Array<{
|
|
16
12
|
path: string;
|
|
17
13
|
content: string;
|
|
18
14
|
}>;
|
|
19
15
|
/**
|
|
20
|
-
* Verbatim `persona.md` content — the authored persona that OVERRIDES segment ①'s identity line
|
|
21
|
-
*
|
|
22
|
-
*
|
|
16
|
+
* Verbatim `persona.md` content — the authored persona that OVERRIDES segment ①'s identity line (piBasePrompt keeps
|
|
17
|
+
* the tool list + guidelines; NOT a full system-prompt replacement — that is L1 createPiAgent's `instructions`).
|
|
18
|
+
* undefined when absent → segment ① is the default engine identity.
|
|
23
19
|
*/
|
|
24
20
|
persona?: string;
|
|
25
21
|
skills: Skill[];
|
|
@@ -31,62 +27,23 @@ export interface LoadedDefinition {
|
|
|
31
27
|
dir: string;
|
|
32
28
|
}
|
|
33
29
|
export interface LoadAgentDefinitionOptions {
|
|
34
|
-
/**
|
|
35
|
-
* Working directory whose ancestors are walked for context files (segment ②). Default = `agentDir`.
|
|
36
|
-
* The opener passes the workspace instead, so an agent that lives in `agentDir` picks up the
|
|
37
|
-
* project's AGENTS.md up the tree (core.md scenario grid).
|
|
38
|
-
*/
|
|
30
|
+
/** Working directory whose ancestors are walked for context files (segment ②). */
|
|
39
31
|
cwd?: string;
|
|
40
32
|
env?: ExecutionEnv;
|
|
41
33
|
}
|
|
42
|
-
/** Read an agent definition. persona.md/skills come from `agentDir`; ② context = pi's loadProjectContextFiles({ cwd, agentDir }). */
|
|
43
|
-
export declare function loadAgentDefinition(agentDir: string, options?: LoadAgentDefinitionOptions): Promise<LoadedDefinition>;
|
|
44
34
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* Paths, not loaded objects — unlike skills (data: content inline, serializable), an extension is
|
|
48
|
-
* CODE that pi loads with jiti and binds to its own eventBus/runtime, so loading it here would
|
|
49
|
-
* reimplement pi's loader. The engine binding hands these to pi as `additionalExtensionPaths`, which
|
|
50
|
-
* survives `noExtensions: true` — that flag suppresses MACHINE-GLOBAL discovery (`~/.pi`), and the
|
|
51
|
-
* definition's own extensions were only ever collateral to it. FILES, not the directory: pi's paths
|
|
52
|
-
* are module specifiers, and a directory fails as `Cannot find module` into a
|
|
53
|
-
* `LoadExtensionsResult.errors` entry nothing reads.
|
|
54
|
-
*
|
|
55
|
-
* SEPARATE from {@link loadAgentDefinition} on purpose. Prompt and skills are re-read every invoke
|
|
56
|
-
* ("the directory is the agent, LIVE"); scanning for extension entry points is not, since the set
|
|
57
|
-
* cannot change without a restart. Called once per assembly, like `tools/`.
|
|
58
|
-
*
|
|
59
|
-
* Discovery runs on BOTH paths; loading does not. `chat` hands these to pi and runs them fully.
|
|
60
|
-
* Serving only announces them — pi's extension runtime is shared across sessions, and serving has
|
|
61
|
-
* concurrent turns for unrelated conversations (see `PiAgentSessionFactoryOptions.extensionPaths`).
|
|
62
|
-
* The refusals below are therefore about what the ARTIFACT may contain, and hold for both.
|
|
63
|
-
*
|
|
64
|
-
* Discovery follows pi's own rules, so an extension that works in pi works here:
|
|
65
|
-
*
|
|
66
|
-
* 1. a direct `*.ts` / `*.js` file;
|
|
67
|
-
* 2. a subdirectory with `index.ts` / `index.js`.
|
|
68
|
-
*
|
|
69
|
-
* pi has a third rule — a subdirectory whose `package.json` declares a `pi` field — which is NOT
|
|
70
|
-
* implemented here. That shape is reported rather than skipped: a definition whose extension silently
|
|
71
|
-
* fails to load is the failure mode this whole path exists to remove.
|
|
72
|
-
*
|
|
73
|
-
* Containment matches skills/tools/channels/schedules (the fifth of five surfaces): a symlinked
|
|
74
|
-
* `extensions/` escaping the agent dir is refused, and — like `loadModuleDir`, whose `entry.isFile()`
|
|
75
|
-
* excludes them — a symlinked ENTRY is not loaded either. pi's own discovery does follow those, but
|
|
76
|
-
* an extension reached through a link out of the definition is code the artifact does not carry: it
|
|
77
|
-
* resolves on the authoring machine and is missing in the container. Refused loudly, never silently.
|
|
78
|
-
*
|
|
79
|
-
* Absent is normal and silent; a FILE at that path is not — that is an author who meant something.
|
|
35
|
+
* Read an agent definition. persona.md/skills come from `agentDir`; ② context = pi's loadProjectContextFiles({ cwd,
|
|
36
|
+
* agentDir }).
|
|
80
37
|
*/
|
|
38
|
+
export declare function loadAgentDefinition(agentDir: string, options?: LoadAgentDefinitionOptions): Promise<LoadedDefinition>;
|
|
39
|
+
/** Extension entry-point FILES under `<agentDir>/extensions/`, empty when there are none. */
|
|
81
40
|
export declare function loadExtensionPaths(agentDir: string, options?: {
|
|
82
41
|
cwd?: string;
|
|
83
42
|
env?: ExecutionEnv;
|
|
84
43
|
}): Promise<string[]>;
|
|
85
44
|
/**
|
|
86
|
-
* The definition's skills ALONE, resolved the same way `loadAgentDefinition` resolves them (same
|
|
87
|
-
*
|
|
88
|
-
* names and must not pay the full load's ② context walk (every AGENTS.md from cwd to root) for them.
|
|
89
|
-
* The control plane's `commands()` is that reader, called when a composer opens its completion list.
|
|
45
|
+
* The definition's skills ALONE, resolved the same way `loadAgentDefinition` resolves them (same loader, same
|
|
46
|
+
* containment guard, same first-wins collision rule).
|
|
90
47
|
*/
|
|
91
48
|
export declare function loadAgentSkills(agentDir: string, options?: {
|
|
92
49
|
cwd?: string;
|
|
@@ -97,6 +54,5 @@ export declare function loadAgentSkills(agentDir: string, options?: {
|
|
|
97
54
|
collisions: SkillCollision[];
|
|
98
55
|
dir: string;
|
|
99
56
|
}>;
|
|
100
|
-
/** Resolve to a canonical (symlink-free) absolute path so comparisons match `process.cwd()`'s realpath.
|
|
101
|
-
* A non-existent path can't be realpath'd, so it stays as the plain absolute resolve. */
|
|
57
|
+
/** Resolve to a canonical (symlink-free) absolute path so comparisons match `process.cwd()`'s realpath. */
|
|
102
58
|
export declare function canonicalPath(p: string): string;
|