@fastagent-sh/fastagent 0.18.0 → 0.20.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 +25 -7
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +1 -1
- package/dist/atomic-write.d.ts +23 -0
- package/dist/atomic-write.js +53 -0
- package/dist/{host/node.d.ts → channel.d.ts} +24 -28
- package/dist/channel.js +1 -0
- package/dist/channels/agentcore-limits.d.ts +9 -0
- package/dist/channels/agentcore-limits.js +9 -0
- package/dist/channels/agentcore-service.d.ts +55 -0
- package/dist/channels/agentcore-service.js +107 -0
- package/dist/channels/agentcore.d.ts +22 -20
- package/dist/channels/agentcore.js +20 -11
- package/dist/channels/busy.d.ts +1 -1
- package/dist/channels/busy.js +1 -1
- package/dist/channels/control.d.ts +55 -7
- package/dist/channels/control.js +312 -67
- package/dist/channels/discover.d.ts +59 -0
- package/dist/{engines/pi/channel.js → channels/discover.js} +19 -34
- package/dist/channels/feishu/card.js +1 -1
- package/dist/channels/feishu/context-buffer.d.ts +1 -1
- package/dist/channels/feishu/context-buffer.js +4 -4
- package/dist/channels/feishu/feishu-api.js +6 -9
- package/dist/channels/feishu/feishu.d.ts +1 -1
- package/dist/channels/feishu/feishu.js +41 -24
- package/dist/channels/feishu/invoke-turn.d.ts +1 -1
- package/dist/channels/feishu/invoke-turn.js +3 -4
- package/dist/channels/feishu/preview.d.ts +1 -1
- package/dist/channels/feishu/preview.js +7 -3
- package/dist/channels/feishu/ws-ingress.d.ts +1 -1
- package/dist/channels/github/github.d.ts +1 -1
- package/dist/channels/http.d.ts +11 -7
- package/dist/channels/http.js +1 -109
- package/dist/channels/kit/attachment-path.d.ts +12 -0
- package/dist/channels/kit/attachment-path.js +43 -0
- package/dist/channels/{context-buffer.d.ts → kit/context-buffer.d.ts} +9 -0
- package/dist/channels/{context-buffer.js → kit/context-buffer.js} +13 -2
- package/dist/channels/{invoke-turn-kit.d.ts → kit/invoke-turn-kit.d.ts} +14 -3
- package/dist/channels/{invoke-turn-kit.js → kit/invoke-turn-kit.js} +17 -6
- package/dist/channels/{preview-kit.d.ts → kit/preview-kit.d.ts} +3 -1
- package/dist/channels/{seen.js → kit/seen.js} +1 -1
- package/dist/channels/kit/signature.d.ts +12 -0
- package/dist/channels/kit/signature.js +17 -0
- package/dist/channels/{state.js → kit/state.js} +4 -7
- package/dist/channels/{stop-command.d.ts → kit/stop-command.d.ts} +1 -1
- package/dist/channels/{stop-command.js → kit/stop-command.js} +5 -5
- package/dist/channels/{tasks.d.ts → kit/tasks.d.ts} +1 -1
- package/dist/channels/{tasks.js → kit/tasks.js} +11 -5
- package/dist/channels/{thread-participants.js → kit/thread-participants.js} +1 -1
- package/dist/channels/{turn-queue.js → kit/turn-queue.js} +2 -2
- package/dist/channels/{turn-store.d.ts → kit/turn-store.d.ts} +19 -3
- package/dist/channels/{turn-store.js → kit/turn-store.js} +30 -3
- package/dist/channels/lark/lark.d.ts +1 -1
- package/dist/channels/serve.d.ts +73 -0
- package/dist/channels/serve.js +243 -0
- package/dist/channels/slack/bot-auth.js +3 -14
- package/dist/channels/slack/context-buffer.d.ts +2 -2
- package/dist/channels/slack/context-buffer.js +2 -2
- package/dist/channels/slack/invoke-turn.d.ts +2 -2
- package/dist/channels/slack/invoke-turn.js +13 -6
- package/dist/channels/slack/onboard.js +5 -5
- package/dist/channels/slack/onboarding-state.d.ts +7 -3
- package/dist/channels/slack/onboarding-state.js +13 -20
- package/dist/channels/slack/parse.js +2 -2
- package/dist/channels/slack/preview.d.ts +1 -1
- package/dist/channels/slack/preview.js +11 -3
- package/dist/channels/slack/register-webhook.js +1 -1
- package/dist/channels/slack/scaffold/slack-send.ts +2 -17
- package/dist/channels/slack/slack-api.js +23 -55
- package/dist/channels/slack/slack.d.ts +1 -1
- package/dist/channels/slack/slack.js +20 -20
- package/dist/channels/slack/welcomed.js +1 -1
- package/dist/channels/telegram/context-buffer.d.ts +2 -2
- package/dist/channels/telegram/context-buffer.js +2 -2
- package/dist/channels/telegram/invoke-turn.d.ts +1 -1
- package/dist/channels/telegram/invoke-turn.js +1 -1
- package/dist/channels/telegram/parse.d.ts +21 -1
- package/dist/channels/telegram/parse.js +67 -13
- package/dist/channels/telegram/preview.d.ts +1 -1
- package/dist/channels/telegram/preview.js +6 -2
- package/dist/channels/telegram/scaffold/channel.ts +7 -3
- package/dist/channels/telegram/telegram-api.js +5 -6
- package/dist/channels/telegram/telegram.d.ts +3 -3
- package/dist/channels/telegram/telegram.js +60 -72
- package/dist/channels/telegram/turn-store.d.ts +2 -2
- package/dist/channels/telegram/turn-store.js +2 -2
- package/dist/cli/add-slack.js +6 -5
- package/dist/cli/commands/add.js +1 -5
- package/dist/cli/commands/attach.d.ts +2 -4
- package/dist/cli/commands/attach.js +17 -15
- package/dist/cli/commands/deploy.d.ts +50 -5
- package/dist/cli/commands/deploy.js +183 -134
- package/dist/cli/commands/dev.js +25 -40
- package/dist/cli/commands/fire.js +1 -1
- package/dist/cli/commands/info.js +7 -5
- package/dist/cli/commands/init.js +1 -2
- package/dist/cli/commands/schedule.js +1 -1
- package/dist/cli/commands/start.js +80 -121
- package/dist/cli/commands/tool.js +5 -7
- package/dist/cli/program.js +1 -1
- package/dist/cli/serve.d.ts +22 -70
- package/dist/cli/serve.js +66 -257
- package/dist/cli/shared.d.ts +40 -10
- package/dist/cli/shared.js +53 -6
- package/dist/core.d.ts +3 -5
- package/dist/core.js +7 -5
- package/dist/deploy/agentcore/logs.d.ts +2 -2
- package/dist/deploy/agentcore/logs.js +2 -2
- package/dist/deploy/agentcore/plan.d.ts +12 -10
- package/dist/deploy/agentcore/plan.js +39 -31
- package/dist/deploy/agentcore/run.d.ts +5 -4
- package/dist/deploy/agentcore/run.js +13 -36
- package/dist/deploy/channel-ingress.d.ts +73 -0
- package/dist/deploy/channel-ingress.js +101 -0
- package/dist/deploy/docker/plan.d.ts +3 -7
- package/dist/deploy/docker/plan.js +4 -15
- package/dist/deploy/docker/run.d.ts +18 -1
- package/dist/deploy/docker/run.js +10 -0
- package/dist/deploy/fly/plan.d.ts +4 -5
- package/dist/deploy/fly/plan.js +7 -22
- package/dist/deploy/fly/run.d.ts +9 -23
- package/dist/deploy/fly/run.js +32 -68
- package/dist/deploy/preflight.d.ts +6 -7
- package/dist/deploy/preflight.js +27 -23
- package/dist/deploy/railway/plan.d.ts +4 -5
- package/dist/deploy/railway/plan.js +11 -26
- package/dist/deploy/railway/run.d.ts +9 -9
- package/dist/deploy/railway/run.js +40 -40
- package/dist/deploy/runner.js +22 -2
- package/dist/deploy/secrets.d.ts +18 -9
- package/dist/deploy/secrets.js +64 -12
- package/dist/dev-supervisor.js +11 -6
- package/dist/engines/pi/agent-session-factory.d.ts +104 -0
- package/dist/engines/pi/agent-session-factory.js +295 -0
- package/dist/engines/pi/auth.js +43 -43
- package/dist/engines/pi/config.d.ts +5 -5
- package/dist/engines/pi/config.js +1 -1
- package/dist/engines/pi/create.d.ts +67 -42
- package/dist/engines/pi/create.js +142 -72
- package/dist/engines/pi/definition.d.ts +42 -8
- package/dist/engines/pi/definition.js +114 -11
- package/dist/engines/pi/invoke-session.d.ts +22 -19
- package/dist/engines/pi/invoke-session.js +286 -100
- package/dist/engines/pi/login.js +39 -20
- package/dist/engines/pi/models.d.ts +14 -0
- package/dist/engines/pi/models.js +9 -1
- package/dist/engines/pi/open.d.ts +10 -8
- package/dist/engines/pi/open.js +21 -11
- package/dist/engines/pi/report.d.ts +0 -4
- package/dist/engines/pi/report.js +0 -7
- package/dist/engines/pi/search-tools.js +1 -1
- package/dist/engines/pi/service.d.ts +23 -0
- package/dist/engines/pi/service.js +27 -0
- package/dist/engines/pi/session-builder.js +87 -118
- package/dist/engines/pi/session-control.d.ts +28 -14
- package/dist/engines/pi/session-control.js +570 -438
- package/dist/engines/pi/session-inheritance.d.ts +30 -0
- package/dist/engines/pi/session-inheritance.js +261 -0
- package/dist/engines/pi/session-markers.d.ts +48 -0
- package/dist/engines/pi/session-markers.js +59 -0
- package/dist/engines/pi/session-settings.d.ts +15 -3
- package/dist/engines/pi/session-settings.js +22 -1
- package/dist/engines/pi/session-store.d.ts +140 -0
- package/dist/engines/pi/session-store.js +666 -0
- package/dist/engines/pi/tool-context.d.ts +36 -13
- package/dist/engines/pi/tool-context.js +51 -4
- package/dist/engines/pi/tool.d.ts +5 -5
- package/dist/engines/pi/tool.js +3 -3
- package/dist/engines/pi/turn-kit.d.ts +32 -6
- package/dist/engines/pi/turn-kit.js +28 -1
- package/dist/engines/pi/wake-tool.js +1 -1
- package/dist/env.js +1 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/loader.d.ts +49 -7
- package/dist/loader.js +79 -18
- package/dist/log.d.ts +3 -0
- package/dist/log.js +5 -1
- package/dist/node.d.ts +16 -0
- package/dist/node.js +20 -0
- package/dist/paths.d.ts +26 -0
- package/dist/paths.js +37 -2
- package/dist/pi.d.ts +14 -8
- package/dist/pi.js +6 -5
- package/dist/scaffold/add-channel.js +2 -2
- package/dist/scaffold/init.js +7 -2
- package/dist/scaffold/templates/persona.md +2 -2
- package/dist/scaffold/templates/tools/fetch-url.ts +0 -2
- package/dist/schedule/discover.js +3 -15
- package/dist/schedule/state.js +4 -9
- package/dist/schedule/wake-alarm.d.ts +13 -7
- package/dist/schedule/wake-alarm.js +88 -46
- package/dist/schedule/wakeups.d.ts +2 -2
- package/dist/schedule/wakeups.js +11 -8
- package/dist/service.d.ts +157 -0
- package/dist/service.js +376 -0
- package/dist/session-remote.d.ts +8 -3
- package/dist/session-remote.js +162 -92
- package/dist/session.d.ts +229 -93
- package/dist/session.js +61 -23
- package/dist/telegram.d.ts +1 -1
- package/dist/telegram.js +1 -1
- package/dist/tunnel.d.ts +18 -3
- package/dist/tunnel.js +32 -40
- package/package.json +14 -5
- package/dist/engines/pi/channel.d.ts +0 -37
- package/dist/engines/pi/harness.d.ts +0 -115
- package/dist/engines/pi/harness.js +0 -154
- package/dist/engines/pi/invoke.d.ts +0 -60
- package/dist/engines/pi/invoke.js +0 -459
- package/dist/engines/pi/read-image.d.ts +0 -4
- package/dist/engines/pi/read-image.js +0 -62
- package/dist/engines/pi/sessions.d.ts +0 -60
- package/dist/engines/pi/sessions.js +0 -464
- package/dist/host/node.js +0 -52
- /package/dist/channels/{preview-kit.js → kit/preview-kit.js} +0 -0
- /package/dist/channels/{seen.d.ts → kit/seen.d.ts} +0 -0
- /package/dist/channels/{state.d.ts → kit/state.d.ts} +0 -0
- /package/dist/channels/{text.d.ts → kit/text.d.ts} +0 -0
- /package/dist/channels/{text.js → kit/text.js} +0 -0
- /package/dist/channels/{thread-participants.d.ts → kit/thread-participants.d.ts} +0 -0
- /package/dist/channels/{turn-queue.d.ts → kit/turn-queue.d.ts} +0 -0
package/dist/engines/pi/auth.js
CHANGED
|
@@ -20,16 +20,20 @@
|
|
|
20
20
|
* Locking is vendored here on `proper-lockfile`, with the same parameters pi's file backend used
|
|
21
21
|
* before pi 0.80.8 stopped exporting it (upstream's stated migration path for SDK consumers is a
|
|
22
22
|
* custom pi-ai `CredentialStore`, which this file is). The lock guards the WRITE path only. `read`
|
|
23
|
-
* is pi-ai's per-request hot path, so it stays UNLOCKED
|
|
24
|
-
*
|
|
25
|
-
*
|
|
23
|
+
* is pi-ai's per-request hot path, so it stays UNLOCKED — safe because every write that carries a
|
|
24
|
+
* CREDENTIAL publishes by rename ({@link writeFileAtomic}): a reader sees one whole version of the
|
|
25
|
+
* file or another, never a partial one, so a rotation has no torn-read window for an unlocked read
|
|
26
|
+
* to absorb. The one in-place write left is the `{}` bootstrap below, whose window an unlocked read
|
|
27
|
+
* observes as an empty file — reported as corrupt, which for a zero-byte auth.json is the right
|
|
28
|
+
* answer either way. The write path refuses to overwrite a corrupt file (never clobbering other
|
|
29
|
+
* providers' credentials).
|
|
26
30
|
*/
|
|
27
|
-
import { chmodSync, existsSync,
|
|
31
|
+
import { chmodSync, existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
28
32
|
import { homedir } from "node:os";
|
|
29
33
|
import { dirname, join } from "node:path";
|
|
30
|
-
import { GLOBAL_HOME_DIR, SECRETS_DIRNAME } from "../../paths.js";
|
|
34
|
+
import { GLOBAL_HOME_DIR, SECRETS_DIRNAME, SECRET_FILE_MODE, ensureSecretsDir } from "../../paths.js";
|
|
35
|
+
import { writeFileAtomic } from "../../atomic-write.js";
|
|
31
36
|
import { log } from "../../log.js";
|
|
32
|
-
import { setTimeout as sleep } from "node:timers/promises";
|
|
33
37
|
import lockfile from "proper-lockfile";
|
|
34
38
|
/**
|
|
35
39
|
* The GLOBAL fastagent credentials file (distinct from pi's `~/.pi`), under the user-global machinery
|
|
@@ -46,7 +50,7 @@ function pick(creds, providerId) {
|
|
|
46
50
|
const cred = creds[providerId];
|
|
47
51
|
return cred && (cred.type === "oauth" || cred.type === "api_key") ? cred : undefined;
|
|
48
52
|
}
|
|
49
|
-
const AUTH_FILE_WRITE_OPTIONS = { encoding: "utf8", mode:
|
|
53
|
+
const AUTH_FILE_WRITE_OPTIONS = { encoding: "utf8", mode: SECRET_FILE_MODE };
|
|
50
54
|
/**
|
|
51
55
|
* Serialized cross-process read-modify-write of the credentials file: exponential-backoff retries,
|
|
52
56
|
* 30s staleness, and compromise detection (the parameters pi's `FileAuthStorageBackend` used).
|
|
@@ -56,13 +60,15 @@ const AUTH_FILE_WRITE_OPTIONS = { encoding: "utf8", mode: 0o600 };
|
|
|
56
60
|
* failed unlock after a successful operation rejects instead of leaving a stale lock silently.
|
|
57
61
|
*/
|
|
58
62
|
async function withLockedAuthFile(authPath, fn) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
63
|
+
// 0700 unconditionally, including on a directory an operator named with `--auth-path`: pointing a
|
|
64
|
+
// credential file somewhere is asking for that somewhere to hold a credential. Where the process
|
|
65
|
+
// cannot chmod (a mount it does not own), this raises — the write fails visibly instead of
|
|
66
|
+
// quietly leaving the directory readable, which is the trade this repo takes everywhere else.
|
|
67
|
+
await ensureSecretsDir(dirname(authPath));
|
|
62
68
|
if (!existsSync(authPath)) {
|
|
63
69
|
try {
|
|
64
70
|
writeFileSync(authPath, "{}", { ...AUTH_FILE_WRITE_OPTIONS, flag: "wx" });
|
|
65
|
-
chmodSync(authPath,
|
|
71
|
+
chmodSync(authPath, SECRET_FILE_MODE);
|
|
66
72
|
}
|
|
67
73
|
catch (error) {
|
|
68
74
|
// EEXIST: another process created the file between the existence check and this exclusive
|
|
@@ -89,10 +95,12 @@ async function withLockedAuthFile(authPath, fn) {
|
|
|
89
95
|
const current = existsSync(authPath) ? readFileSync(authPath, "utf8") : undefined;
|
|
90
96
|
const out = await fn(current);
|
|
91
97
|
throwIfCompromised();
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
98
|
+
// Rename, not an in-place rewrite: it is what lets `read` stay unlocked, and it is the only
|
|
99
|
+
// spelling that applies the mode before the content is reachable — `writeFileSync`'s `mode` is
|
|
100
|
+
// a no-op on an existing file, so a chmod after it leaves the new credential briefly readable
|
|
101
|
+
// at whatever mode the old file carried.
|
|
102
|
+
if (out.next !== undefined)
|
|
103
|
+
writeFileAtomic(authPath, out.next, SECRET_FILE_MODE);
|
|
96
104
|
throwIfCompromised();
|
|
97
105
|
result = out.result;
|
|
98
106
|
}
|
|
@@ -139,34 +147,26 @@ function decodeCreds(raw) {
|
|
|
139
147
|
return parsed;
|
|
140
148
|
}
|
|
141
149
|
/**
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
150
|
+
* UNLOCKED read of the whole credentials file, shared by `read` and `list`. ONE read: the write
|
|
151
|
+
* publishes by rename, so this observes one whole version or another and has nothing to absorb by
|
|
152
|
+
* re-reading. A missing file reads as undefined silently (normal not-configured); anything that
|
|
153
|
+
* does not decode is a real corruption — a hand-edit — and says so immediately, rather than after
|
|
154
|
+
* retrying a race that cannot happen.
|
|
147
155
|
*/
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
return undefined;
|
|
159
|
-
}
|
|
160
|
-
if (raw !== "") {
|
|
161
|
-
const creds = decodeCreds(raw);
|
|
162
|
-
if (creds !== undefined)
|
|
163
|
-
return creds;
|
|
164
|
-
// A partial read mid-write parses as garbage; fall through and retry. A structurally invalid
|
|
165
|
-
// root lands here too and is reported as corrupt below.
|
|
166
|
-
}
|
|
167
|
-
if (attempt < 2)
|
|
168
|
-
await sleep(2);
|
|
156
|
+
function readCreds(authPath, warn) {
|
|
157
|
+
let raw;
|
|
158
|
+
try {
|
|
159
|
+
raw = readFileSync(authPath, "utf8");
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
if (error.code === "ENOENT")
|
|
163
|
+
return undefined; // missing/deleted
|
|
164
|
+
warn(`[fastagent] cannot read ${authPath}: ${error.message}`);
|
|
165
|
+
return undefined;
|
|
169
166
|
}
|
|
167
|
+
const creds = raw === "" ? undefined : decodeCreds(raw);
|
|
168
|
+
if (creds !== undefined)
|
|
169
|
+
return creds;
|
|
170
170
|
warn(`[fastagent] corrupt auth file ${authPath}: fix or remove it`);
|
|
171
171
|
return undefined;
|
|
172
172
|
}
|
|
@@ -190,13 +190,13 @@ export function fastagentCredentialStore(authPath = GLOBAL_AUTH_PATH, options =
|
|
|
190
190
|
const warn = options.warn ?? ((message) => log.warn(message));
|
|
191
191
|
return {
|
|
192
192
|
async read(providerId) {
|
|
193
|
-
const creds =
|
|
193
|
+
const creds = readCreds(authPath, warn);
|
|
194
194
|
return creds ? pick(creds, providerId) : undefined;
|
|
195
195
|
},
|
|
196
196
|
async list() {
|
|
197
197
|
// Metadata only, never secrets (the pi-ai `list` contract). Foreign/old entries are filtered
|
|
198
198
|
// with the same validation as `read`, so both surfaces agree on what "configured" means.
|
|
199
|
-
const creds =
|
|
199
|
+
const creds = readCreds(authPath, warn);
|
|
200
200
|
if (!creds)
|
|
201
201
|
return [];
|
|
202
202
|
const infos = [];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ThinkingLevel } from "@earendil-works/pi-agent-core";
|
|
2
2
|
import type { FastagentTool } from "./tool.ts";
|
|
3
3
|
import type { Models } from "@earendil-works/pi-ai";
|
|
4
|
-
import type { AnyModel } from "./
|
|
4
|
+
import type { AnyModel } from "./models.ts";
|
|
5
5
|
export interface FastagentConfig {
|
|
6
6
|
/** "provider/modelId". Precedence: CLI --model > FASTAGENT_MODEL > config. */
|
|
7
7
|
model?: string;
|
|
@@ -9,8 +9,8 @@ export interface FastagentConfig {
|
|
|
9
9
|
* "xhigh" | "max"). Unset = pi's default. Authors tune thinking in the pi TUI while vibing — this
|
|
10
10
|
* is the serving-side counterpart (fidelity). Levels a model doesn't support are clamped by pi. */
|
|
11
11
|
thinkingLevel?: ThinkingLevel;
|
|
12
|
-
/** Extra custom tools, appended after pi
|
|
13
|
-
* plus the optional `deferred` marker (see defineTool). */
|
|
12
|
+
/** Extra custom tools, appended after the pi coding tools — never replaces them. `FastagentTool`
|
|
13
|
+
* = AgentTool plus the optional `deferred` marker (see defineTool). */
|
|
14
14
|
tools?: FastagentTool[];
|
|
15
15
|
/** `host` is the bind address: unset (or `0.0.0.0`) binds all interfaces — what containers need;
|
|
16
16
|
* `127.0.0.1` keeps the serve (including `/control/*`) off the LAN. Precedence: `--bind` > this. */
|
|
@@ -24,7 +24,7 @@ export interface FastagentConfig {
|
|
|
24
24
|
selfSchedule?: boolean;
|
|
25
25
|
/**
|
|
26
26
|
* Serve the session control plane over HTTP (`/control/*`: state/entries/events + dispatch —
|
|
27
|
-
* steer/abort/compact
|
|
27
|
+
* steer/abort/compact + session properties and lifecycle) for remote consumers: a Web panel, a desktop app, `fastagent
|
|
28
28
|
* attach`. Default off (it is a remote-control surface). When on, `dev`/`start` generate a
|
|
29
29
|
* per-boot bearer token and write `<stateRoot>/control.json` for local discovery. The serve
|
|
30
30
|
* binds all interfaces by default, so the routes are LAN-reachable with the token as the only
|
|
@@ -60,7 +60,7 @@ export declare function loadConfig(dir: string): Promise<LoadedConfig>;
|
|
|
60
60
|
* lookups then miss visibly (an unknown-provider error / a login-required hint), never a mangled id
|
|
61
61
|
* (`slice(0, indexOf("/"))` silently drops the last char when "/" is absent). */
|
|
62
62
|
export declare function providerOf(spec: string): string;
|
|
63
|
-
/** Resolve "provider/modelId" → a pi Model from `models`, so
|
|
63
|
+
/** Resolve "provider/modelId" → a pi Model from `models`, so auth resolves from the same collection. */
|
|
64
64
|
export declare function resolveModel(models: Models, spec: string): AnyModel;
|
|
65
65
|
/** All registered "provider/modelId" specs in `models`, sorted — the list behind `fastagent models`. */
|
|
66
66
|
export declare function listModels(models: Models): string[];
|
|
@@ -151,7 +151,7 @@ export function providerOf(spec) {
|
|
|
151
151
|
const slash = spec.indexOf("/");
|
|
152
152
|
return slash > 0 ? spec.slice(0, slash) : spec;
|
|
153
153
|
}
|
|
154
|
-
/** Resolve "provider/modelId" → a pi Model from `models`, so
|
|
154
|
+
/** Resolve "provider/modelId" → a pi Model from `models`, so auth resolves from the same collection. */
|
|
155
155
|
export function resolveModel(models, spec) {
|
|
156
156
|
const slash = spec.indexOf("/");
|
|
157
157
|
if (slash < 1 || slash === spec.length - 1) {
|
|
@@ -1,25 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent assembly (configuration-time): the engine assets (tools, prompt) plus the reusable ladder
|
|
3
|
+
* that puts a pi agent together.
|
|
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
|
+
*/
|
|
1
13
|
import { type ExecutionEnv, type Skill, type ThinkingLevel } from "@earendil-works/pi-agent-core";
|
|
2
|
-
import
|
|
14
|
+
import { type ModelRuntime } from "@earendil-works/pi-coding-agent";
|
|
15
|
+
import type { Provider } from "@earendil-works/pi-ai";
|
|
3
16
|
import type { Agent } from "../../agent.ts";
|
|
4
17
|
import { type FastagentConfig } from "./config.ts";
|
|
5
18
|
import { type LoadedDefinition } from "./definition.ts";
|
|
6
|
-
import { type AnyModel, piHarnessFactory } from "./harness.ts";
|
|
7
|
-
import { type PiSessionStore } from "./sessions.ts";
|
|
8
19
|
import type { ModuleLoadFailure } from "../../loader.ts";
|
|
9
20
|
import { type ToolCollision, type MountedTool } from "./tool.ts";
|
|
10
|
-
import { type
|
|
11
|
-
import { type
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export declare function piDefaultTools(): MountedTool[];
|
|
15
|
-
/** `config.tools` semantics: extra tools APPENDED after pi's defaults, never replacing them. */
|
|
16
|
-
export declare function resolveTools(config: FastagentConfig): MountedTool[];
|
|
21
|
+
import { type PiAgentSessionFactory } from "./invoke-session.ts";
|
|
22
|
+
import { type AnyModel } from "./models.ts";
|
|
23
|
+
import { type PiSessionRecordStore } from "./session-store.ts";
|
|
24
|
+
import { type Lease, type SessionObserver } from "./turn-kit.ts";
|
|
17
25
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
26
|
+
* Every pi coding tool, in canonical order, rooted at the workspace it operates in.
|
|
27
|
+
*
|
|
28
|
+
* pi ships two overlapping groupings and neither is the whole set: `createCodingTools` is the four it
|
|
29
|
+
* ACTIVATES for a terminal (read/bash/edit/write, no searching), `createReadOnlyTools` is
|
|
30
|
+
* read/grep/find/ls. `read` is in both; a directory agent mounts their union.
|
|
31
|
+
*/
|
|
32
|
+
export declare const CODING_TOOL_NAMES: readonly ["read", "grep", "find", "ls", "bash", "edit", "write"];
|
|
33
|
+
export declare function piAllCodingTools(cwd: string): MountedTool[];
|
|
34
|
+
/**
|
|
35
|
+
* The full directory-agent tool set: all pi coding tools + `config.tools` + discovered `tools/`
|
|
36
|
+
* (deduped, existing win), plus the authored names and collisions to report. One source for the
|
|
20
37
|
* dev/start openers AND `fastagent tool`, so they all mount exactly the same set.
|
|
21
38
|
*/
|
|
22
|
-
export declare function resolveAgentTools(config: FastagentConfig, agentDir: string): Promise<{
|
|
39
|
+
export declare function resolveAgentTools(config: FastagentConfig, agentDir: string, cwd: string): Promise<{
|
|
23
40
|
tools: MountedTool[];
|
|
24
41
|
toolNames: string[];
|
|
25
42
|
/** Tools registered but not initially active (defineTool `deferred: true`) — discovered/activated
|
|
@@ -57,20 +74,22 @@ export interface AssembleSystemPromptOptions {
|
|
|
57
74
|
export declare function assembleSystemPrompt(options: AssembleSystemPromptOptions): string;
|
|
58
75
|
/**
|
|
59
76
|
* INTERNAL seam (workspace ↔ assembly): hands the hub-wiring consumer the assembly's live parts —
|
|
60
|
-
* the SAME
|
|
61
|
-
* mutations (session-control.ts) contend on the real lease and validate against the real
|
|
62
|
-
* Called synchronously, exactly once, before the agent is returned. Not
|
|
77
|
+
* the SAME session factory and lease the agent runs with, plus the model registry behind a thunk —
|
|
78
|
+
* so boundary mutations (session-control.ts) contend on the real lease and validate against the real
|
|
79
|
+
* registry. Called synchronously, exactly once, before the agent is returned. Not public surface.
|
|
63
80
|
*/
|
|
64
|
-
type
|
|
65
|
-
models: Models;
|
|
66
|
-
harnessFactory: ReturnType<typeof piHarnessFactory>;
|
|
81
|
+
export type PiAssemblyParts = {
|
|
67
82
|
lease: Lease;
|
|
68
|
-
|
|
69
|
-
|
|
83
|
+
sessionFactory: PiAgentSessionFactory;
|
|
84
|
+
/** The registry and configured model, resolved on first use (a credential read is async). */
|
|
85
|
+
engine: () => Promise<{
|
|
86
|
+
modelRuntime: ModelRuntime;
|
|
70
87
|
model: AnyModel;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
88
|
+
}>;
|
|
89
|
+
/** The configured reasoning effort — the other half of the pair a session without overrides runs on. */
|
|
90
|
+
thinkingLevel: ThinkingLevel;
|
|
91
|
+
};
|
|
92
|
+
type OnAssembly = (parts: PiAssemblyParts) => void;
|
|
74
93
|
/** L1 options. Tier 1: model (spec) + instructions + tools. Tier 2: the injectable ports. */
|
|
75
94
|
export interface CreatePiAgentOptions {
|
|
76
95
|
/** Model spec "provider/modelId" (e.g. "openai-codex/gpt-5.5"), resolved against {@link models}. */
|
|
@@ -78,14 +97,18 @@ export interface CreatePiAgentOptions {
|
|
|
78
97
|
/** Reasoning effort (pi's scale). Unset = pi's default; unsupported levels are clamped per model. */
|
|
79
98
|
thinkingLevel?: ThinkingLevel;
|
|
80
99
|
/**
|
|
81
|
-
* The system prompt itself —
|
|
82
|
-
*
|
|
83
|
-
*
|
|
100
|
+
* The system prompt itself — no engine base and no wrapping (unlike the directory path, which
|
|
101
|
+
* assembles the engine base + AGENTS.md as segment ② + persona.md as segment ①). A plain string or
|
|
102
|
+
* a factory re-evaluated per invoke. When {@link skills} are mounted their listing is appended.
|
|
103
|
+
*
|
|
104
|
+
* Not byte-for-byte verbatim: pi appends its own `Current working directory:` line to whatever
|
|
105
|
+
* prompt it is given. What this rung guarantees is that no engine IDENTITY is imposed — a
|
|
106
|
+
* hand-built agent is not told it is a coding assistant.
|
|
84
107
|
*/
|
|
85
108
|
instructions?: string | (() => string);
|
|
86
109
|
/** The tool set to mount. `FastagentTool` (AgentTool plus the optional `deferred` marker, see
|
|
87
110
|
* {@link DefineToolOptions}) widens into {@link MountedTool}, which additionally admits pi's default
|
|
88
|
-
* coding tools —
|
|
111
|
+
* coding tools — those bind their workspace at construction rather than reading a turn context. */
|
|
89
112
|
tools?: MountedTool[];
|
|
90
113
|
skills?: Skill[];
|
|
91
114
|
/**
|
|
@@ -100,12 +123,15 @@ export interface CreatePiAgentOptions {
|
|
|
100
123
|
* consulted when a provider is absent from the file (resolution order is upstream-owned).
|
|
101
124
|
*/
|
|
102
125
|
authPath?: string;
|
|
103
|
-
/** Session persistence. Defaults to in-memory; inject
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
*
|
|
108
|
-
* NOT constrain
|
|
126
|
+
/** Session persistence. Defaults to in-memory; inject piSessionRecordStore for restart-surviving
|
|
127
|
+
* continuity. */
|
|
128
|
+
sessions?: PiSessionRecordStore;
|
|
129
|
+
/** Filesystem/process environment, handed to tools that read one as the turn's context. Defaults to
|
|
130
|
+
* a local NodeExecutionEnv at `process.cwd()`. At THIS rung nothing else consumes it: L1 loads no
|
|
131
|
+
* definition. It does NOT constrain the coding tools (pi's own, rooted at the workspace they were
|
|
132
|
+
* built for) or author-written `tools/`, which are code and can import anything. Not a
|
|
133
|
+
* sandbox — see {@link createPiAgentFromDefinition} for the rung where it also reads the
|
|
134
|
+
* definition. */
|
|
109
135
|
env?: ExecutionEnv;
|
|
110
136
|
/** Single-writer lease. Defaults to in-process fail-fast inProcessLease(). */
|
|
111
137
|
lease?: Lease;
|
|
@@ -127,11 +153,11 @@ export interface CreatePiAgentFromDefinitionOptions {
|
|
|
127
153
|
/** Override the engine base prompt (segment ①). Defaults to piBasePrompt({ tools, persona }) using the
|
|
128
154
|
* live-read persona.md; pass base to fully opt out of persona.md. */
|
|
129
155
|
base?: string;
|
|
130
|
-
/** Override tools. Defaults to {@link
|
|
156
|
+
/** Override tools. Defaults to {@link piAllCodingTools} (lock down with a custom list). An authored
|
|
131
157
|
* `FastagentTool[]` (AgentTool plus the optional `deferred` marker) widens into {@link MountedTool}. */
|
|
132
158
|
tools?: MountedTool[];
|
|
133
159
|
/**
|
|
134
|
-
* The agent's working directory: where the
|
|
160
|
+
* The agent's working directory: where the coding tools operate AND whose ancestors are walked for
|
|
135
161
|
* ② project context (AGENTS.md). Defaults to `dir`. Set it to the enclosing repo so a coding agent
|
|
136
162
|
* whose definition lives in `dir` operates on — and reads the AGENTS.md of — that repo (core.md
|
|
137
163
|
* scenario grid); that is what the CLI's opener does with the workspace.
|
|
@@ -145,12 +171,11 @@ export interface CreatePiAgentFromDefinitionOptions {
|
|
|
145
171
|
* dir) — unlike the dir-less {@link createPiAgent}/{@link createPiModels}, which default global.
|
|
146
172
|
*/
|
|
147
173
|
authPath?: string;
|
|
148
|
-
sessions?:
|
|
149
|
-
/** Filesystem/process environment; see {@link CreatePiAgentOptions.env}. At THIS rung it
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
* env narrows the blast radius rather than closing it. */
|
|
174
|
+
sessions?: PiSessionRecordStore;
|
|
175
|
+
/** Filesystem/process environment; see {@link CreatePiAgentOptions.env}. At THIS rung it reads
|
|
176
|
+
* persona.md and skills/. The seven coding tools, ② project context (pi's
|
|
177
|
+
* loadProjectContextFiles uses node fs directly), and author-written `tools/` stay outside it.
|
|
178
|
+
* Injecting an env narrows the blast radius rather than closing it. */
|
|
154
179
|
env?: ExecutionEnv;
|
|
155
180
|
lease?: Lease;
|
|
156
181
|
/** Observation-plane tap; see {@link CreatePiAgentOptions.observer}. */
|