@fastagent-sh/fastagent 0.22.1 → 0.24.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/dist/agent.d.ts +10 -0
- package/dist/channels/agentcore-protocol.d.ts +2 -1
- package/dist/channels/agentcore-service.js +10 -18
- package/dist/channels/agentcore.js +6 -3
- package/dist/channels/control.js +23 -0
- package/dist/channels/kit/preview-kit.d.ts +6 -1
- package/dist/channels/kit/preview-kit.js +21 -4
- package/dist/channels/slack/config-api.d.ts +2 -2
- package/dist/channels/slack/config-api.js +2 -2
- package/dist/channels/slack/onboard.js +2 -2
- package/dist/channels/slack/preview.js +2 -1
- package/dist/channels/slack/register-webhook.js +2 -2
- package/dist/channels/slack/slack-api.js +4 -4
- package/dist/cli/add-feishu.js +4 -2
- package/dist/cli/auth-view.d.ts +15 -6
- package/dist/cli/auth-view.js +24 -8
- package/dist/cli/box-login.d.ts +33 -0
- package/dist/cli/box-login.js +162 -0
- package/dist/cli/commands/deploy/agentcore.js +48 -11
- package/dist/cli/commands/deploy/docker.js +24 -13
- package/dist/cli/commands/deploy/fly.js +30 -7
- package/dist/cli/commands/deploy/railway.js +21 -7
- package/dist/cli/commands/deploy/shared.d.ts +18 -17
- package/dist/cli/commands/deploy/shared.js +20 -21
- package/dist/cli/commands/destroy.js +2 -2
- package/dist/cli/commands/info.js +15 -12
- package/dist/cli/commands/invoke.js +2 -2
- package/dist/cli/commands/login.d.ts +7 -1
- package/dist/cli/commands/login.js +123 -10
- package/dist/cli/commands/logs.js +2 -2
- package/dist/cli/commands/models.d.ts +4 -1
- package/dist/cli/commands/models.js +37 -4
- package/dist/cli/commands/routine-run.js +2 -2
- package/dist/cli/commands/start.d.ts +0 -5
- package/dist/cli/commands/start.js +3 -13
- package/dist/cli/invoke-stream.js +14 -0
- package/dist/cli/kernel.d.ts +2 -0
- package/dist/cli/kernel.js +1 -1
- package/dist/cli/login-relay.d.ts +38 -0
- package/dist/cli/login-relay.js +121 -0
- package/dist/cli/program.js +46 -8
- package/dist/cli/shared.d.ts +6 -5
- package/dist/cli/shared.js +29 -36
- package/dist/deploy/agentcore/plan.d.ts +10 -11
- package/dist/deploy/agentcore/plan.js +8 -14
- package/dist/deploy/agentcore/run.d.ts +8 -1
- package/dist/deploy/agentcore/run.js +20 -14
- package/dist/deploy/agentcore/shell.d.ts +25 -0
- package/dist/deploy/agentcore/shell.js +202 -0
- package/dist/deploy/box-shell.d.ts +43 -0
- package/dist/deploy/box-shell.js +28 -0
- package/dist/deploy/build-context.js +16 -7
- package/dist/deploy/channel-ingress.d.ts +20 -1
- package/dist/deploy/channel-ingress.js +34 -7
- package/dist/deploy/container.d.ts +14 -0
- package/dist/deploy/container.js +45 -1
- package/dist/deploy/docker/plan.d.ts +7 -3
- package/dist/deploy/docker/plan.js +9 -14
- package/dist/deploy/docker/run.d.ts +14 -7
- package/dist/deploy/docker/run.js +58 -35
- package/dist/deploy/fly/plan.d.ts +6 -3
- package/dist/deploy/fly/plan.js +6 -8
- package/dist/deploy/fly/run.d.ts +8 -2
- package/dist/deploy/fly/run.js +15 -25
- package/dist/deploy/preflight.d.ts +9 -7
- package/dist/deploy/preflight.js +92 -20
- package/dist/deploy/railway/plan.d.ts +6 -3
- package/dist/deploy/railway/plan.js +7 -9
- package/dist/deploy/railway/run.d.ts +10 -6
- package/dist/deploy/railway/run.js +29 -13
- package/dist/deploy/runner.d.ts +16 -0
- package/dist/deploy/runner.js +31 -0
- package/dist/deploy/secrets.d.ts +4 -13
- package/dist/deploy/secrets.js +8 -27
- package/dist/dev-supervisor.js +7 -4
- package/dist/engines/pi/agent-models.d.ts +83 -0
- package/dist/engines/pi/agent-models.js +120 -0
- package/dist/engines/pi/agent-session-factory.d.ts +13 -13
- package/dist/engines/pi/agent-session-factory.js +132 -159
- package/dist/engines/pi/auth.d.ts +56 -3
- package/dist/engines/pi/auth.js +68 -109
- package/dist/engines/pi/config.d.ts +0 -25
- package/dist/engines/pi/config.js +3 -37
- package/dist/engines/pi/create.d.ts +34 -21
- package/dist/engines/pi/create.js +90 -57
- package/dist/engines/pi/entry-images.d.ts +14 -0
- package/dist/engines/pi/entry-images.js +23 -0
- package/dist/engines/pi/invoke-session.js +88 -20
- package/dist/engines/pi/locked-file.d.ts +9 -0
- package/dist/engines/pi/locked-file.js +102 -0
- package/dist/engines/pi/login.d.ts +27 -14
- package/dist/engines/pi/login.js +41 -18
- package/dist/engines/pi/machine.d.ts +23 -0
- package/dist/engines/pi/machine.js +24 -2
- package/dist/engines/pi/models.d.ts +120 -36
- package/dist/engines/pi/models.js +316 -66
- package/dist/engines/pi/open.d.ts +65 -20
- package/dist/engines/pi/open.js +88 -34
- package/dist/engines/pi/report.d.ts +3 -0
- package/dist/engines/pi/report.js +11 -0
- package/dist/engines/pi/service.d.ts +2 -2
- package/dist/engines/pi/service.js +1 -0
- package/dist/engines/pi/session-builder.d.ts +3 -2
- package/dist/engines/pi/session-builder.js +30 -76
- package/dist/engines/pi/session-control.d.ts +4 -4
- package/dist/engines/pi/session-control.js +86 -43
- package/dist/engines/pi/session-settings.d.ts +9 -0
- package/dist/engines/pi/session-settings.js +17 -0
- package/dist/engines/pi/session-store.d.ts +2 -2
- package/dist/engines/pi/tool-context.d.ts +3 -5
- package/dist/engines/pi/tool-context.js +4 -16
- package/dist/engines/pi/tool.d.ts +32 -21
- package/dist/engines/pi/tool.js +21 -25
- package/dist/engines/pi/turn-kit.d.ts +18 -9
- package/dist/engines/pi/turn-kit.js +115 -32
- package/dist/open-url.d.ts +15 -1
- package/dist/open-url.js +35 -3
- package/dist/paths.d.ts +4 -2
- package/dist/paths.js +6 -2
- package/dist/pi.d.ts +5 -3
- package/dist/pi.js +3 -2
- package/dist/service.d.ts +5 -8
- package/dist/session-remote.js +21 -0
- package/dist/session.d.ts +88 -15
- package/dist/session.js +5 -1
- package/package.json +6 -5
- package/dist/engines/pi/search-tools.d.ts +0 -4
- package/dist/engines/pi/search-tools.js +0 -109
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
/** The turn mechanism's ENGINE-agnostic half: the parts that describe a turn rather than pi. */
|
|
2
|
+
import { stripVTControlCharacters } from "node:util";
|
|
3
|
+
import { contentText } from "@earendil-works/pi-ai";
|
|
1
4
|
import { ABORTED_CODE } from "../../agent.js";
|
|
5
|
+
import { log } from "../../log.js";
|
|
2
6
|
export function inProcessLease() {
|
|
3
7
|
const busy = new Set();
|
|
4
8
|
return {
|
|
@@ -70,19 +74,38 @@ function messageSignal(message) {
|
|
|
70
74
|
return {};
|
|
71
75
|
}
|
|
72
76
|
/**
|
|
73
|
-
*
|
|
77
|
+
* How an answer ended, read off the stopReason pi records on the message. The ONE reading: `message_finished`,
|
|
78
|
+
* the `assistant` entry `entries()` publishes, and the invoke terminal all derive from it, so the live outcome and
|
|
79
|
+
* the recorded one cannot disagree.
|
|
80
|
+
*/
|
|
81
|
+
export function answerOutcome(message) {
|
|
82
|
+
const error = message.errorMessage ? { error: { message: message.errorMessage } } : {};
|
|
83
|
+
switch (message.stopReason) {
|
|
84
|
+
case "error":
|
|
85
|
+
return { status: "failed", ...error };
|
|
86
|
+
case "aborted":
|
|
87
|
+
return { status: "aborted", ...error };
|
|
88
|
+
case "length":
|
|
89
|
+
return { status: "truncated" };
|
|
90
|
+
default:
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Terminal mapping, decided by the resolved message's outcome: pi's `prompt()` RESOLVES a message with stopReason
|
|
74
96
|
* "error"/"aborted" rather than throwing, so relying on catch alone would miss that whole failure class and violate
|
|
75
|
-
* SPEC MUST 1.
|
|
97
|
+
* SPEC MUST 1. A truncated final answer still completes the run.
|
|
76
98
|
*/
|
|
77
99
|
export function toTerminal(message) {
|
|
78
|
-
|
|
100
|
+
const outcome = answerOutcome(message);
|
|
101
|
+
if (outcome?.status === "aborted") {
|
|
79
102
|
// A deliberate stop (a control-plane or consumer abort), not an error — see {@link ABORTED_CODE} for the consumer
|
|
80
103
|
// contract (design §6).
|
|
81
|
-
const details = message
|
|
104
|
+
const details = outcome.error?.message ?? "run aborted";
|
|
82
105
|
return { type: "failed", details, retryable: false, code: ABORTED_CODE };
|
|
83
106
|
}
|
|
84
|
-
if (
|
|
85
|
-
const details = message
|
|
107
|
+
if (outcome?.status === "failed") {
|
|
108
|
+
const details = outcome.error?.message ?? "model stopped: error";
|
|
86
109
|
return { type: "failed", details, retryable: classifyRetryable(details, messageSignal(message)) };
|
|
87
110
|
}
|
|
88
111
|
return { type: "completed" };
|
|
@@ -105,35 +128,95 @@ export async function toPiPromptOptions(prompt, delivery) {
|
|
|
105
128
|
return { images: prompt.images.map((img) => ({ type: "image", data: img.data, mimeType: img.mimeType })) };
|
|
106
129
|
}
|
|
107
130
|
const { resizeImage } = await import("@earendil-works/pi-coding-agent");
|
|
108
|
-
const images = await Promise.all(prompt.images.map(async (img) => {
|
|
109
|
-
const resized = await resizeImage(Buffer.from(img.data, "base64"), img.mimeType)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
131
|
+
const images = await Promise.all(prompt.images.map(async (img, i) => {
|
|
132
|
+
const resized = await resizeImage(Buffer.from(img.data, "base64"), img.mimeType);
|
|
133
|
+
if (resized)
|
|
134
|
+
return { type: "image", data: resized.data, mimeType: resized.mimeType };
|
|
135
|
+
// `null` covers an image it cannot decode or shrink under the limit AND an image backend that did not load,
|
|
136
|
+
// and does not say which. pi's own tool-result path keeps the original in that case rather than drop what the
|
|
137
|
+
// sender attached, and so does this; a provider that refuses it fails the turn with its own message.
|
|
138
|
+
log.warn(`[fastagent] queued image ${i + 1} (${img.mimeType}) could not be resized; sending it as given — ` +
|
|
139
|
+
"the provider may refuse it");
|
|
140
|
+
return { type: "image", data: img.data, mimeType: img.mimeType };
|
|
113
141
|
}));
|
|
114
142
|
return { images };
|
|
115
143
|
}
|
|
116
|
-
/**
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const d = se.data;
|
|
129
|
-
return { type: "tool_ended", id: d.id, isError: d.isError, content: d.content };
|
|
130
|
-
}
|
|
131
|
-
case "retry_scheduled": {
|
|
132
|
-
// `operation` (compaction | branch_summary) stays session-plane vocabulary.
|
|
133
|
-
const d = se.data;
|
|
134
|
-
return { type: "retrying", attempt: d.attempt, maxAttempts: d.maxAttempts, delayMs: d.delayMs, reason: d.error };
|
|
135
|
-
}
|
|
136
|
-
default:
|
|
144
|
+
/**
|
|
145
|
+
* The SPEC projection of ONE run's rich stream. Stateful only for `tool_progress`, the one event that is a status
|
|
146
|
+
* rather than a fact: an outer call's status line is sent when it changes, and a call that call makes, at any depth,
|
|
147
|
+
* is its status. Nested calls are otherwise the observation plane's alone.
|
|
148
|
+
*/
|
|
149
|
+
export function agentEventProjection() {
|
|
150
|
+
/** Each nested call's outer call, the one the stream announced with `tool_started`. */
|
|
151
|
+
const outerOf = new Map();
|
|
152
|
+
/** The status line each outer call last reported. */
|
|
153
|
+
const shown = new Map();
|
|
154
|
+
const progress = (id, text) => {
|
|
155
|
+
if (text === undefined || shown.get(id) === text)
|
|
137
156
|
return null;
|
|
157
|
+
shown.set(id, text);
|
|
158
|
+
return { type: "tool_progress", id, text };
|
|
159
|
+
};
|
|
160
|
+
return (se) => {
|
|
161
|
+
switch (se.type) {
|
|
162
|
+
case "message_delta": {
|
|
163
|
+
const d = se.data;
|
|
164
|
+
return d.channel === "text" ? { type: "text", delta: d.delta } : { type: "thinking", delta: d.delta };
|
|
165
|
+
}
|
|
166
|
+
case "tool_started": {
|
|
167
|
+
const d = se.data;
|
|
168
|
+
if (!d.parentToolCallId)
|
|
169
|
+
return { type: "tool_started", id: d.id, name: d.name, args: d.args };
|
|
170
|
+
const outer = outerOf.get(d.parentToolCallId) ?? d.parentToolCallId;
|
|
171
|
+
outerOf.set(d.id, outer);
|
|
172
|
+
return progress(outer, callLine(d.name, d.args));
|
|
173
|
+
}
|
|
174
|
+
case "tool_progress": {
|
|
175
|
+
const d = se.data;
|
|
176
|
+
// A nested call's own output is not its caller's status; the nested call starting is (above).
|
|
177
|
+
if (d.parentToolCallId || !Array.isArray(d.partialResult.content))
|
|
178
|
+
return null;
|
|
179
|
+
return progress(d.id, lastLine(contentText(d.partialResult.content, "\n")));
|
|
180
|
+
}
|
|
181
|
+
case "tool_finished": {
|
|
182
|
+
const d = se.data;
|
|
183
|
+
if (d.parentToolCallId)
|
|
184
|
+
return null;
|
|
185
|
+
return { type: "tool_ended", id: d.id, isError: d.isError, content: d.content };
|
|
186
|
+
}
|
|
187
|
+
case "retry_scheduled": {
|
|
188
|
+
// `operation` (compaction | branch_summary) stays session-plane vocabulary.
|
|
189
|
+
const d = se.data;
|
|
190
|
+
return {
|
|
191
|
+
type: "retrying",
|
|
192
|
+
attempt: d.attempt,
|
|
193
|
+
maxAttempts: d.maxAttempts,
|
|
194
|
+
delayMs: d.delayMs,
|
|
195
|
+
reason: d.error,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
default:
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* The line a terminal shows last: control sequences removed, and a bare `\r`, a progress bar redrawing in place, ends a
|
|
205
|
+
* line like `\n` does. Undefined when there is no visible text yet (a shell that has printed nothing).
|
|
206
|
+
*/
|
|
207
|
+
function lastLine(text) {
|
|
208
|
+
const lines = stripVTControlCharacters(text).split(/\r\n|\r|\n/);
|
|
209
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
210
|
+
const line = lines[i]?.trim();
|
|
211
|
+
if (line)
|
|
212
|
+
return line;
|
|
138
213
|
}
|
|
214
|
+
return undefined;
|
|
215
|
+
}
|
|
216
|
+
/** A nested call as its caller's status: the tool and its first plain argument, on one line (`weather London`). */
|
|
217
|
+
function callLine(name, args) {
|
|
218
|
+
const first = args !== null && typeof args === "object" && !Array.isArray(args)
|
|
219
|
+
? Object.values(args).find((value) => typeof value === "string" || typeof value === "number")
|
|
220
|
+
: undefined;
|
|
221
|
+
return first === undefined ? name : `${name} ${String(first).replace(/\s+/g, " ").trim()}`.trim();
|
|
139
222
|
}
|
package/dist/open-url.d.ts
CHANGED
|
@@ -1,2 +1,16 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* How to hand `url` to the default browser on `platform`, or undefined when it must not be handed over at all.
|
|
3
|
+
*
|
|
4
|
+
* Only a web page: `https:`, or `http:` on a loopback host. Some callers pass URLs they did not build — a deployed box's
|
|
5
|
+
* login relays its own (`cli/login-relay.ts`), and that box runs code its agent can rewrite — and the platform openers
|
|
6
|
+
* open anything: a local path, a `file:`/`smb:` URL, an argument that starts with `-`. Parsed and re-serialized, so
|
|
7
|
+
* what reaches the opener is what was checked. No shell anywhere: on Windows `start` needs one, and cmd reads the `&`
|
|
8
|
+
* every OAuth URL carries as a command separator, so `rundll32 url.dll,FileProtocolHandler` takes the URL as one
|
|
9
|
+
* argument instead.
|
|
10
|
+
*/
|
|
11
|
+
export declare function browserCommand(url: string, platform: NodeJS.Platform): {
|
|
12
|
+
cmd: string;
|
|
13
|
+
args: string[];
|
|
14
|
+
} | undefined;
|
|
15
|
+
/** Best-effort open a URL in the default browser (callers print it too). A URL that is not a web page is refused, visibly. */
|
|
2
16
|
export declare function openExternalUrl(url: string): void;
|
package/dist/open-url.js
CHANGED
|
@@ -1,6 +1,38 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* How to hand `url` to the default browser on `platform`, or undefined when it must not be handed over at all.
|
|
4
|
+
*
|
|
5
|
+
* Only a web page: `https:`, or `http:` on a loopback host. Some callers pass URLs they did not build — a deployed box's
|
|
6
|
+
* login relays its own (`cli/login-relay.ts`), and that box runs code its agent can rewrite — and the platform openers
|
|
7
|
+
* open anything: a local path, a `file:`/`smb:` URL, an argument that starts with `-`. Parsed and re-serialized, so
|
|
8
|
+
* what reaches the opener is what was checked. No shell anywhere: on Windows `start` needs one, and cmd reads the `&`
|
|
9
|
+
* every OAuth URL carries as a command separator, so `rundll32 url.dll,FileProtocolHandler` takes the URL as one
|
|
10
|
+
* argument instead.
|
|
11
|
+
*/
|
|
12
|
+
export function browserCommand(url, platform) {
|
|
13
|
+
let parsed;
|
|
14
|
+
try {
|
|
15
|
+
parsed = new URL(url);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return undefined; // not a URL: nothing to open
|
|
19
|
+
}
|
|
20
|
+
const loopback = ["localhost", "127.0.0.1", "[::1]"].includes(parsed.hostname);
|
|
21
|
+
if (!(parsed.protocol === "https:" || (parsed.protocol === "http:" && loopback)))
|
|
22
|
+
return undefined;
|
|
23
|
+
const href = parsed.href;
|
|
24
|
+
if (platform === "darwin")
|
|
25
|
+
return { cmd: "open", args: [href] };
|
|
26
|
+
if (platform === "win32")
|
|
27
|
+
return { cmd: "rundll32", args: ["url.dll,FileProtocolHandler", href] };
|
|
28
|
+
return { cmd: "xdg-open", args: [href] };
|
|
29
|
+
}
|
|
30
|
+
/** Best-effort open a URL in the default browser (callers print it too). A URL that is not a web page is refused, visibly. */
|
|
3
31
|
export function openExternalUrl(url) {
|
|
4
|
-
const
|
|
5
|
-
|
|
32
|
+
const command = browserCommand(url, process.platform);
|
|
33
|
+
if (!command) {
|
|
34
|
+
console.error(`[fastagent] not opening ${JSON.stringify(url)}: only an https URL, or http on this machine, opens`);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
spawn(command.cmd, command.args, { stdio: "ignore", detached: true }).on("error", () => { });
|
|
6
38
|
}
|
package/dist/paths.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** The directory name `init` gives an agent (`<workspace>/fastagent/`) unless `--agent-dir` names another. */
|
|
2
2
|
export declare const DEFAULT_AGENT_DIRNAME = "fastagent";
|
|
3
|
-
/** The user-global machinery home
|
|
4
|
-
export declare
|
|
3
|
+
/** The user-global machinery home, `~/.fastagent`: the machine's credentials, models.json and model catalog. */
|
|
4
|
+
export declare function globalHome(): string;
|
|
5
5
|
/**
|
|
6
6
|
* The secrets segment inside an agent dir (or the global home). Every path fastagent resolves — `.env`,
|
|
7
7
|
* `.env.example`, auth.json, the scaffold's write — derives from it, so they cannot drift apart.
|
|
@@ -19,6 +19,8 @@ export declare const STATE_DIRNAME = ".state";
|
|
|
19
19
|
export declare const AGENT_CONFIG_FILE = "fastagent.config.ts";
|
|
20
20
|
/** The optional custom-model-endpoint file inside an agent dir (pi's models.json schema). */
|
|
21
21
|
export declare const AGENT_MODELS_FILE = "models.json";
|
|
22
|
+
/** The agent's model catalog: pi.dev's models newer than pi's bundled catalog, fetched by `models --refresh`. */
|
|
23
|
+
export declare const AGENT_MODEL_CATALOG_FILE = "models-store.json";
|
|
22
24
|
export interface ResolvedPlacement {
|
|
23
25
|
/**
|
|
24
26
|
* The AGENT directory — where the definition (persona.md/skills/tools/channels/routines), the config, and the
|
package/dist/paths.js
CHANGED
|
@@ -8,8 +8,10 @@ import { homedir } from "node:os";
|
|
|
8
8
|
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
9
9
|
/** The directory name `init` gives an agent (`<workspace>/fastagent/`) unless `--agent-dir` names another. */
|
|
10
10
|
export const DEFAULT_AGENT_DIRNAME = "fastagent";
|
|
11
|
-
/** The user-global machinery home
|
|
12
|
-
export
|
|
11
|
+
/** The user-global machinery home, `~/.fastagent`: the machine's credentials, models.json and model catalog. */
|
|
12
|
+
export function globalHome() {
|
|
13
|
+
return join(homedir(), ".fastagent");
|
|
14
|
+
}
|
|
13
15
|
/**
|
|
14
16
|
* The secrets segment inside an agent dir (or the global home). Every path fastagent resolves — `.env`,
|
|
15
17
|
* `.env.example`, auth.json, the scaffold's write — derives from it, so they cannot drift apart.
|
|
@@ -27,6 +29,8 @@ export const STATE_DIRNAME = ".state";
|
|
|
27
29
|
export const AGENT_CONFIG_FILE = "fastagent.config.ts";
|
|
28
30
|
/** The optional custom-model-endpoint file inside an agent dir (pi's models.json schema). */
|
|
29
31
|
export const AGENT_MODELS_FILE = "models.json";
|
|
32
|
+
/** The agent's model catalog: pi.dev's models newer than pi's bundled catalog, fetched by `models --refresh`. */
|
|
33
|
+
export const AGENT_MODEL_CATALOG_FILE = "models-store.json";
|
|
30
34
|
/**
|
|
31
35
|
* The definition paths an agent LOADS content from — the surface a second agent must not be scaffolded inside
|
|
32
36
|
* ({@link agentDefinitionOwner}), because the outer agent would read it as its own skills/tools.
|
package/dist/pi.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { z } from "zod";
|
|
|
5
5
|
export type { AgentTool, ExecutionEnv, Skill, SkillDiagnostic } from "@earendil-works/pi-agent-core";
|
|
6
6
|
/** A conversation record, as the tool runtime and the control plane hold it. */
|
|
7
7
|
export type { SessionManager, SessionEntry as PiSessionEntry } from "@earendil-works/pi-coding-agent";
|
|
8
|
-
export { availableModelsFromDir, createPiAgentFromDir, type CreatePiAgentFromDirOptions, } from "./engines/pi/open.ts";
|
|
8
|
+
export { availableModelsFromDir, createPiAgentFromDir, type CreatePiAgentFromDirOptions, refreshMachineModelCatalog, refreshModelCatalog, } from "./engines/pi/open.ts";
|
|
9
9
|
export type { LoadedDefinition, SkillCollision } from "./engines/pi/definition.ts";
|
|
10
10
|
export { defineConfig, listModels, resolveModel, type FastagentConfig, } from "./engines/pi/config.ts";
|
|
11
11
|
export type { SessionObserver } from "./engines/pi/turn-kit.ts";
|
|
@@ -14,9 +14,11 @@ export { createPiSessionControl, type CreatePiSessionControlOptions, } from "./e
|
|
|
14
14
|
export { piInMemorySessionRecordStore, piSessionRecordStore, type PiSessionRecordStore, } from "./engines/pi/session-store.ts";
|
|
15
15
|
export type { SessionInheritance } from "./engines/pi/session-inheritance.ts";
|
|
16
16
|
export { GLOBAL_AUTH_PATH, fastagentCredentialStore, type FastagentAuthOptions } from "./engines/pi/auth.ts";
|
|
17
|
-
export { createPiModels,
|
|
17
|
+
export { createPiModels, type CreatePiModelsOptions } from "./engines/pi/agent-models.ts";
|
|
18
|
+
export { probeAuthSource } from "./engines/pi/models.ts";
|
|
18
19
|
export { login, loginOptions, LoginCancelled, type LoginMethod, type LoginOption, type LoginRequest, type LoginResult, } from "./engines/pi/login.ts";
|
|
19
|
-
|
|
20
|
+
/** pi-ai's sign-in types, and the `CredentialStore` a caller supplies as `credentialStore` (with what it holds). */
|
|
21
|
+
export type { AuthEvent, AuthInteraction, AuthPrompt, Credential, CredentialStore } from "@earendil-works/pi-ai";
|
|
20
22
|
export type { Models } from "@earendil-works/pi-ai";
|
|
21
23
|
export type { Provider, ProviderAuth } from "@earendil-works/pi-ai";
|
|
22
24
|
export type { Model } from "@earendil-works/pi-ai";
|
package/dist/pi.js
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
export { createPiAgent, createPiAgentFromDefinition, } from "./engines/pi/create.js";
|
|
3
3
|
export { defineTool, } from "./engines/pi/tool.js";
|
|
4
4
|
export { z } from "zod";
|
|
5
|
-
export { availableModelsFromDir, createPiAgentFromDir, } from "./engines/pi/open.js";
|
|
5
|
+
export { availableModelsFromDir, createPiAgentFromDir, refreshMachineModelCatalog, refreshModelCatalog, } from "./engines/pi/open.js";
|
|
6
6
|
export { defineConfig, listModels, resolveModel, } from "./engines/pi/config.js";
|
|
7
7
|
export { inProcessLease } from "./engines/pi/turn-kit.js";
|
|
8
8
|
export { createPiSessionControl, } from "./engines/pi/session-control.js";
|
|
9
9
|
export { piInMemorySessionRecordStore, piSessionRecordStore, } from "./engines/pi/session-store.js";
|
|
10
10
|
export { GLOBAL_AUTH_PATH, fastagentCredentialStore } from "./engines/pi/auth.js";
|
|
11
|
-
export { createPiModels
|
|
11
|
+
export { createPiModels } from "./engines/pi/agent-models.js";
|
|
12
|
+
export { probeAuthSource } from "./engines/pi/models.js";
|
|
12
13
|
export { login, loginOptions, LoginCancelled, } from "./engines/pi/login.js";
|
|
13
14
|
// The product's one-call assembly: a directory becomes a live service.
|
|
14
15
|
export { createAgentService } from "./engines/pi/service.js";
|
package/dist/service.d.ts
CHANGED
|
@@ -7,9 +7,9 @@ import type { LoadedRoutine } from "./schedule/routine.ts";
|
|
|
7
7
|
export interface ServingSurface {
|
|
8
8
|
/**
|
|
9
9
|
* The routes that AUTHENTICATE NOBODY — `GET /health`, `POST /invoke`, and `POST /run` where the definition
|
|
10
|
-
* declares routines, minus what a channel took over or `http.invoke: false` withheld. Kept APART from the
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* declares routines, minus what a channel took over or `http.invoke: false` withheld. Kept APART from the
|
|
11
|
+
* channels' table rather than derived from it, because three decisions read it (browser reachability, the JSON
|
|
12
|
+
* body gate, what the startup line calls unauthenticated) and must give the same answer.
|
|
13
13
|
*/
|
|
14
14
|
unverified: Routes;
|
|
15
15
|
/**
|
|
@@ -133,11 +133,8 @@ export interface AgentService {
|
|
|
133
133
|
longConnections: string[];
|
|
134
134
|
};
|
|
135
135
|
/**
|
|
136
|
-
* The
|
|
137
|
-
*
|
|
138
|
-
* `routes` instead answers a different question, since a channel may serve one of those paths with a protocol of
|
|
139
|
-
* its own. That mistake ran in both directions here — a try-it curl for a route that 404s, and a warning about an
|
|
140
|
-
* unauthenticated `/invoke` that was really a signature-checked channel.
|
|
136
|
+
* The keys of {@link ServingSurface.unverified}: what a caller reads to describe this surface. Not derivable from
|
|
137
|
+
* `routes`, where a channel may serve one of those paths behind its own signature check.
|
|
141
138
|
*/
|
|
142
139
|
unverifiedRoutes: readonly string[];
|
|
143
140
|
/**
|
package/dist/session-remote.js
CHANGED
|
@@ -271,6 +271,19 @@ export async function connectSessionControl(options) {
|
|
|
271
271
|
id: session,
|
|
272
272
|
state: () => get(`/control/sessions/${id(session)}`),
|
|
273
273
|
entries: (options) => get(`/control/sessions/${id(session)}/entries${options?.since !== undefined ? `?since=${encodeURIComponent(options.since)}` : ""}`, PAYLOAD_TIMEOUT_MS),
|
|
274
|
+
image: async (ref) => {
|
|
275
|
+
const res = await fetchFn(`${base}/control/sessions/${id(session)}/image?ref=${encodeURIComponent(ref)}`, {
|
|
276
|
+
signal: AbortSignal.timeout(PAYLOAD_TIMEOUT_MS),
|
|
277
|
+
});
|
|
278
|
+
if (!res.ok)
|
|
279
|
+
throw await controlError(res);
|
|
280
|
+
if (res.status === 204)
|
|
281
|
+
return undefined;
|
|
282
|
+
return {
|
|
283
|
+
data: toBase64(new Uint8Array(await res.arrayBuffer())),
|
|
284
|
+
mimeType: res.headers.get("content-type") ?? "application/octet-stream",
|
|
285
|
+
};
|
|
286
|
+
},
|
|
274
287
|
events: () => eventsOf(session),
|
|
275
288
|
update: (patch) => write(`/control/sessions/${id(session)}`, "PATCH", patch),
|
|
276
289
|
steer: (prompt) => write(`/control/sessions/${id(session)}/actions`, "POST", { type: "steer", prompt }),
|
|
@@ -404,6 +417,14 @@ export function connectAgent(options) {
|
|
|
404
417
|
},
|
|
405
418
|
};
|
|
406
419
|
}
|
|
420
|
+
/** Base64 without `Buffer` (this module runs in any Fetch runtime), in chunks: spreading megabytes of bytes into one
|
|
421
|
+
* `String.fromCharCode` call overflows the argument limit. */
|
|
422
|
+
function toBase64(bytes) {
|
|
423
|
+
let binary = "";
|
|
424
|
+
for (let i = 0; i < bytes.length; i += 0x8000)
|
|
425
|
+
binary += String.fromCharCode(...bytes.subarray(i, i + 0x8000));
|
|
426
|
+
return btoa(binary);
|
|
427
|
+
}
|
|
407
428
|
/** Minimal SSE reader: yields each `data:` payload; ignores comments (heartbeats) and other fields. */
|
|
408
429
|
async function* sseData(body, watch) {
|
|
409
430
|
const decoder = new TextDecoder();
|
package/dist/session.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Session control plane — the engine-neutral serving extension beside Agent Handler (docs/design/session-control.md).
|
|
3
3
|
*/
|
|
4
|
-
import type { Json, Prompt } from "./agent.ts";
|
|
4
|
+
import type { ImageRef, Json, Prompt } from "./agent.ts";
|
|
5
5
|
export interface SessionControl {
|
|
6
6
|
capabilities(): SessionCapabilities;
|
|
7
7
|
/** The names this agent exposes — what a composer's `/` completion LISTS. */
|
|
@@ -42,15 +42,34 @@ export interface Session {
|
|
|
42
42
|
entries(options?: {
|
|
43
43
|
since?: string;
|
|
44
44
|
}): Promise<SessionEntries>;
|
|
45
|
+
/**
|
|
46
|
+
* The bytes behind an {@link EntryImage.ref} this session published; `undefined` when this session holds no such
|
|
47
|
+
* image. Total, like every read but `list()`.
|
|
48
|
+
*
|
|
49
|
+
* Over the wire, a `mimeType` other than `image/png`, `image/jpeg`, `image/gif` or `image/webp` reads back as
|
|
50
|
+
* `application/octet-stream`: the transport will not serve a sender-declared type it cannot trust (the entry still
|
|
51
|
+
* lists the declared one). pi normalizes an invoke's opening prompt images to those four; a `steer`/`followUp`
|
|
52
|
+
* image and a tool result keep whatever type the sender declared, so `image/jpg`, a type with parameters, or
|
|
53
|
+
* `image/svg+xml` sent that way reads back as `application/octet-stream` remotely.
|
|
54
|
+
*/
|
|
55
|
+
image(ref: string): Promise<ImageRef | undefined>;
|
|
45
56
|
events(): SessionEventStream;
|
|
46
|
-
/**
|
|
57
|
+
/**
|
|
58
|
+
* Set durable session properties, applied by the session's next turn. An id with no record (nothing has written it
|
|
59
|
+
* yet) takes them too: the write creates its record, and the session's first turn runs on them. Refused there:
|
|
60
|
+
* `leafEntryId` (no entries to point at) and an id no client could address ({@link isAddressableSession}).
|
|
61
|
+
*/
|
|
47
62
|
update(patch: SessionUpdate): Promise<SessionResult>;
|
|
48
63
|
/**
|
|
49
64
|
* Join the active run: delivered after the current turn's tool calls, before the next model call. `prompt.text`
|
|
50
|
-
* must not be empty (`invalid_command`): a queued prompt is reported by its text ({@link PendingPrompts}).
|
|
65
|
+
* must not be empty (`invalid_command`): a queued prompt is reported by its text ({@link PendingPrompts}). An
|
|
66
|
+
* accepted result carries its {@link PromptDisposition}.
|
|
51
67
|
*/
|
|
52
68
|
steer(prompt: Prompt): Promise<SessionResult>;
|
|
53
|
-
/**
|
|
69
|
+
/**
|
|
70
|
+
* Queue for the active run, FIFO, delivered when it is otherwise idle. Same non-empty `text` rule and
|
|
71
|
+
* {@link PromptDisposition} as `steer`.
|
|
72
|
+
*/
|
|
54
73
|
followUp(prompt: Prompt): Promise<SessionResult>;
|
|
55
74
|
/** Stop the active run — its queues, its retry delay, its cancellable tool work. */
|
|
56
75
|
abort(): Promise<SessionResult>;
|
|
@@ -110,11 +129,22 @@ export interface SessionCapabilities {
|
|
|
110
129
|
delete: boolean;
|
|
111
130
|
/** Which {@link SessionUpdate} fields this deployment accepts. */
|
|
112
131
|
updatable: SessionUpdateField[];
|
|
113
|
-
/** The
|
|
114
|
-
allowedModels?:
|
|
132
|
+
/** The models `update({ model })` accepts, by `spec` — present iff `model` is updatable. */
|
|
133
|
+
allowedModels?: ModelDescriptor[];
|
|
115
134
|
toolProgress: boolean;
|
|
116
135
|
usage: boolean;
|
|
117
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* A model as a picker shows it, before any session runs on it. `thinkingLevels` is what `update({ thinkingLevel })`
|
|
139
|
+
* accepts for a session on this model; `name` and `contextWindow` are absent when the model does not declare them.
|
|
140
|
+
*/
|
|
141
|
+
export interface ModelDescriptor {
|
|
142
|
+
/** What `update({ model })` takes. */
|
|
143
|
+
spec: string;
|
|
144
|
+
name?: string;
|
|
145
|
+
thinkingLevels: string[];
|
|
146
|
+
contextWindow?: number;
|
|
147
|
+
}
|
|
118
148
|
/** One name a client can offer the user. */
|
|
119
149
|
export interface AgentCommand {
|
|
120
150
|
name: string;
|
|
@@ -133,7 +163,11 @@ export declare const UNSUPPORTED_CAPABILITY_CODE = "unsupported_capability";
|
|
|
133
163
|
export declare const NO_ACTIVE_RUN_CODE = "no_active_run";
|
|
134
164
|
/** Stable `SessionResult.error.code` for a PAYLOAD that is invalid for this runtime. */
|
|
135
165
|
export declare const INVALID_COMMAND_CODE = "invalid_command";
|
|
136
|
-
/**
|
|
166
|
+
/**
|
|
167
|
+
* Stable `SessionResult.error.code` for a write that needs a record (fork's source, compact, delete) against an id
|
|
168
|
+
* that has none, because nothing has written it yet. `update()` creates the record instead, and answers this code only
|
|
169
|
+
* when a concurrent `delete()` removes the record between its read and its write.
|
|
170
|
+
*/
|
|
137
171
|
export declare const NO_SUCH_SESSION_CODE = "no_such_session";
|
|
138
172
|
/** Stable `SessionResult.error.code` for a write rejected BEFORE acceptance with nothing durable landed. */
|
|
139
173
|
export declare const BOUNDARY_COMMAND_FAILED_CODE = "boundary_command_failed";
|
|
@@ -169,6 +203,7 @@ export declare const PARTIAL_UPDATE_CODE = "partial_update";
|
|
|
169
203
|
export type SessionResult = {
|
|
170
204
|
ok: true;
|
|
171
205
|
runId?: string;
|
|
206
|
+
disposition?: PromptDisposition;
|
|
172
207
|
} | {
|
|
173
208
|
ok: false;
|
|
174
209
|
error: {
|
|
@@ -177,6 +212,13 @@ export type SessionResult = {
|
|
|
177
212
|
retryable: boolean;
|
|
178
213
|
};
|
|
179
214
|
};
|
|
215
|
+
/**
|
|
216
|
+
* What became of an accepted `steer`/`followUp` prompt — present on exactly those results. `queued`: it waits in
|
|
217
|
+
* {@link PendingPrompts} until the run takes it in. `handled`: the engine consumed it before the queue (in pi, a
|
|
218
|
+
* definition extension's `input` handler), so it never enters the conversation, and no `queue_changed` or
|
|
219
|
+
* `user_message` reports it.
|
|
220
|
+
*/
|
|
221
|
+
export type PromptDisposition = "queued" | "handled";
|
|
180
222
|
/** One session in {@link SessionControl.sessions} — a conversation-list row, not a session's contents. */
|
|
181
223
|
export interface SessionSummary {
|
|
182
224
|
session: string;
|
|
@@ -194,7 +236,10 @@ export interface SessionState {
|
|
|
194
236
|
/** `compacting` refers to MANUAL compaction (`compact`) at a session boundary. */
|
|
195
237
|
status: "idle" | "running" | "compacting";
|
|
196
238
|
activeRunId?: string;
|
|
197
|
-
/**
|
|
239
|
+
/**
|
|
240
|
+
* What this session will RUN with, not what was recorded. An id with no record reports what its first turn would run
|
|
241
|
+
* on: the defaults, the level clamped to the model.
|
|
242
|
+
*/
|
|
198
243
|
model?: string;
|
|
199
244
|
thinkingLevel?: string;
|
|
200
245
|
/** What `update({ thinkingLevel })` accepts for THIS session — re-read after a model change. */
|
|
@@ -232,6 +277,15 @@ export interface SessionEntry {
|
|
|
232
277
|
kind: string;
|
|
233
278
|
data: Json;
|
|
234
279
|
}
|
|
280
|
+
/**
|
|
281
|
+
* One image a message carried, as `data.images` lists it on a `user` or `tool` entry and on `user_message` (absent
|
|
282
|
+
* when there are none). Bytes stay out: `entries()` is read on every open and reconnect, and one screenshot is
|
|
283
|
+
* megabytes. `ref` is opaque; {@link Session.image} of the same session reads the bytes.
|
|
284
|
+
*/
|
|
285
|
+
export type EntryImage = {
|
|
286
|
+
ref: string;
|
|
287
|
+
mimeType: string;
|
|
288
|
+
};
|
|
235
289
|
/**
|
|
236
290
|
* A live event subscription, plus the ONE thing a reconnecting client cannot infer: when it started.
|
|
237
291
|
*
|
|
@@ -283,12 +337,13 @@ export type MessageStartedEvent = SessionEvent<"message_started", Record<never,
|
|
|
283
337
|
/**
|
|
284
338
|
* A user message entered the conversation: the run's opening prompt, a steer or follow-up leaving `pending`, or one an
|
|
285
339
|
* extension sent. It reports after the message is recorded, so `entries()` already holds `entryId` with the same
|
|
286
|
-
* `text` (a slash command expanded
|
|
287
|
-
*
|
|
340
|
+
* `text` (a slash command expanded) and `images`, and before the answer to it starts. The one live event a backfill
|
|
341
|
+
* can be deduplicated against exactly.
|
|
288
342
|
*/
|
|
289
343
|
export type UserMessageEvent = SessionEvent<"user_message", {
|
|
290
344
|
entryId: string;
|
|
291
345
|
text: string;
|
|
346
|
+
images?: EntryImage[];
|
|
292
347
|
}> & {
|
|
293
348
|
runId: string;
|
|
294
349
|
};
|
|
@@ -298,13 +353,29 @@ export type MessageDeltaEvent = SessionEvent<"message_delta", {
|
|
|
298
353
|
}> & {
|
|
299
354
|
runId: string;
|
|
300
355
|
};
|
|
301
|
-
|
|
356
|
+
/**
|
|
357
|
+
* How an answer ended, when it did not end normally: absent on an answer that did. One value, carried live by its
|
|
358
|
+
* `message_finished` and durably by its `assistant` entry, so a reopened conversation reads what a watcher saw.
|
|
359
|
+
* `truncated` is an answer cut off at the output limit — a property of the answer, not of its run, which may still
|
|
360
|
+
* complete. An answer whose entry a `context_edit { omitted }` targets (`failed` or `truncated`) is an attempt the
|
|
361
|
+
* engine abandoned; a retry usually, but not always, follows it.
|
|
362
|
+
*/
|
|
363
|
+
export type AnswerOutcome = {
|
|
364
|
+
status: "failed" | "aborted" | "truncated";
|
|
365
|
+
error?: {
|
|
366
|
+
message: string;
|
|
367
|
+
};
|
|
368
|
+
};
|
|
369
|
+
export type MessageFinishedEvent = SessionEvent<"message_finished", {
|
|
370
|
+
outcome?: AnswerOutcome;
|
|
371
|
+
}> & {
|
|
302
372
|
runId: string;
|
|
303
373
|
};
|
|
304
374
|
export type ToolStartedEvent = SessionEvent<"tool_started", {
|
|
305
375
|
id: string;
|
|
306
376
|
name: string;
|
|
307
377
|
args: Json;
|
|
378
|
+
parentToolCallId?: string;
|
|
308
379
|
}> & {
|
|
309
380
|
runId: string;
|
|
310
381
|
};
|
|
@@ -313,6 +384,7 @@ export type ToolProgressEvent = SessionEvent<"tool_progress", {
|
|
|
313
384
|
id: string;
|
|
314
385
|
name: string;
|
|
315
386
|
partialResult: Json;
|
|
387
|
+
parentToolCallId?: string;
|
|
316
388
|
}> & {
|
|
317
389
|
runId: string;
|
|
318
390
|
};
|
|
@@ -320,15 +392,16 @@ export type ToolFinishedEvent = SessionEvent<"tool_finished", {
|
|
|
320
392
|
id: string;
|
|
321
393
|
isError: boolean;
|
|
322
394
|
content: Json;
|
|
395
|
+
parentToolCallId?: string;
|
|
323
396
|
}> & {
|
|
324
397
|
runId: string;
|
|
325
398
|
};
|
|
326
399
|
/**
|
|
327
400
|
* The prompts queued on the active run, oldest first, as the engine queued them: plain text as sent, a slash command
|
|
328
|
-
* already expanded (a `/skill:…` becomes the skill's text),
|
|
329
|
-
* enters the conversation as a user message: from then on it is in the record and in
|
|
330
|
-
* can still end the run before the model answers it). Whatever is still listed when
|
|
331
|
-
* the conversation and is dropped with the run.
|
|
401
|
+
* already expanded (a `/skill:…` becomes the skill's text), without its images (its `user_message` carries them). A
|
|
402
|
+
* prompt LEAVES its list when it enters the conversation as a user message: from then on it is in the record and in
|
|
403
|
+
* every later model call (an abort can still end the run before the model answers it). Whatever is still listed when
|
|
404
|
+
* the run settles never entered the conversation and is dropped with the run.
|
|
332
405
|
*/
|
|
333
406
|
export type PendingPrompts = {
|
|
334
407
|
steering: string[];
|
package/dist/session.js
CHANGED
|
@@ -28,7 +28,11 @@ export const UNSUPPORTED_CAPABILITY_CODE = "unsupported_capability";
|
|
|
28
28
|
export const NO_ACTIVE_RUN_CODE = "no_active_run";
|
|
29
29
|
/** Stable `SessionResult.error.code` for a PAYLOAD that is invalid for this runtime. */
|
|
30
30
|
export const INVALID_COMMAND_CODE = "invalid_command";
|
|
31
|
-
/**
|
|
31
|
+
/**
|
|
32
|
+
* Stable `SessionResult.error.code` for a write that needs a record (fork's source, compact, delete) against an id
|
|
33
|
+
* that has none, because nothing has written it yet. `update()` creates the record instead, and answers this code only
|
|
34
|
+
* when a concurrent `delete()` removes the record between its read and its write.
|
|
35
|
+
*/
|
|
32
36
|
export const NO_SUCH_SESSION_CODE = "no_such_session";
|
|
33
37
|
/** Stable `SessionResult.error.code` for a write rejected BEFORE acceptance with nothing durable landed. */
|
|
34
38
|
export const BOUNDARY_COMMAND_FAILED_CODE = "boundary_command_failed";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fastagent-sh/fastagent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"description": "Vibe first. Then FastAgent: turn a local agent directory into a live service in your app, on Telegram, Slack, Feishu, or behind any channel.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -101,15 +101,16 @@
|
|
|
101
101
|
},
|
|
102
102
|
"dependencies": {
|
|
103
103
|
"@clack/prompts": "^1.6.0",
|
|
104
|
-
"@earendil-works/pi-agent-core": "^0.
|
|
105
|
-
"@earendil-works/pi-ai": "^0.
|
|
106
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
104
|
+
"@earendil-works/pi-agent-core": "^0.99.2",
|
|
105
|
+
"@earendil-works/pi-ai": "^0.99.2",
|
|
106
|
+
"@earendil-works/pi-coding-agent": "^0.99.2",
|
|
107
107
|
"@hono/node-server": "^2.1.1",
|
|
108
108
|
"@larksuiteoapi/node-sdk": "^1.71.1",
|
|
109
|
+
"@smithy/signature-v4": "^5.7.4",
|
|
109
110
|
"chokidar": "^5.0.0",
|
|
110
111
|
"commander": "^15.0.0",
|
|
111
112
|
"croner": "^10.0.1",
|
|
112
|
-
"effect": "4.0.0-rc.
|
|
113
|
+
"effect": "4.0.0-rc.118",
|
|
113
114
|
"giget": "^3.3.0",
|
|
114
115
|
"ignore": "^7.0.5",
|
|
115
116
|
"proper-lockfile": "^4.1.2",
|