pi-outpost 0.27.1 → 0.28.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.
|
@@ -12370,7 +12370,7 @@ function rulePatterns(profile, rules, sources) {
|
|
|
12370
12370
|
}
|
|
12371
12371
|
|
|
12372
12372
|
// shared/bin/validate-structured-exchange.mjs
|
|
12373
|
-
var VERSION = `validate-structured-exchange ${false ? "development" : "0.
|
|
12373
|
+
var VERSION = `validate-structured-exchange ${false ? "development" : "0.28.0"}`;
|
|
12374
12374
|
var USAGE = `validate-structured-exchange [file]
|
|
12375
12375
|
validate-structured-exchange --profile <profile.json> [file]
|
|
12376
12376
|
validate-structured-exchange --check-profile <profile.json>
|
package/dist/pi-outpost.mjs
CHANGED
|
@@ -132364,6 +132364,12 @@ var WORST_LISTED = 8;
|
|
|
132364
132364
|
function isStackExhaustion(message) {
|
|
132365
132365
|
return /maximum call stack size exceeded|call stack size exceeded|stack overflow/i.test(message);
|
|
132366
132366
|
}
|
|
132367
|
+
var PROVIDER_STACK_ENV = "PI_OUTPOST_PROVIDER_STACK";
|
|
132368
|
+
var PROVIDER_STACK_OFF = /* @__PURE__ */ new Set(["", "0", "false", "no", "off"]);
|
|
132369
|
+
function providerStackProbeArmed(env2 = process.env) {
|
|
132370
|
+
return !PROVIDER_STACK_OFF.has((env2[PROVIDER_STACK_ENV] ?? "").trim().toLowerCase());
|
|
132371
|
+
}
|
|
132372
|
+
var PROVIDER_STACK_HINT = `[pi-outpost] no stack accompanies this \u2014 the provider's catch drops it. Set ${PROVIDER_STACK_ENV}=1 and the next occurrence will print one.`;
|
|
132367
132373
|
function inspectShape(root) {
|
|
132368
132374
|
let depth = 0;
|
|
132369
132375
|
let cyclic = false;
|
|
@@ -132508,6 +132514,7 @@ function writeRecord(agentDir, report) {
|
|
|
132508
132514
|
context?.cyclic?.length ? ` SELF-REFERENCE in ${context.cyclic.length} entr${context.cyclic.length === 1 ? "y" : "ies"}` : ""
|
|
132509
132515
|
].join("");
|
|
132510
132516
|
console.error(headline);
|
|
132517
|
+
if (!providerStackProbeArmed()) console.error(PROVIDER_STACK_HINT);
|
|
132511
132518
|
const file = path23.join(agentDir, "turn-failures.jsonl");
|
|
132512
132519
|
try {
|
|
132513
132520
|
fs21.mkdirSync(agentDir, { recursive: true });
|
|
@@ -143476,7 +143483,7 @@ function cacheControlFor(url) {
|
|
|
143476
143483
|
}
|
|
143477
143484
|
|
|
143478
143485
|
// ../server/src/index.ts
|
|
143479
|
-
var VERSION2 = true ? "0.
|
|
143486
|
+
var VERSION2 = true ? "0.28.0" : "dev";
|
|
143480
143487
|
var PI_SDK_VERSION = true ? "0.86.1" : readInstalledPiSdkVersion();
|
|
143481
143488
|
var LAUNCH_DIR = process.env.INIT_CWD ?? process.cwd();
|
|
143482
143489
|
function complain(error) {
|
|
@@ -144212,8 +144219,8 @@ for (const root of config.openProjects) {
|
|
|
144212
144219
|
}
|
|
144213
144220
|
workspace.workPlan = await loadWorkPlan(workspace.agent.snapshot().sessionFile);
|
|
144214
144221
|
workspace.workPlanSessionFile = workspace.agent.snapshot().sessionFile;
|
|
144215
|
-
publishWorkPlanTools(workspace, workspace.workPlan);
|
|
144216
144222
|
withholdDocumentTools(workspace);
|
|
144223
|
+
publishWorkPlanTools(workspace, workspace.workPlan);
|
|
144217
144224
|
function withholdDocumentTools(workspace2) {
|
|
144218
144225
|
for (const tool of [...DOCUMENT_TOOLS, PROJECT_MODEL_TOOL]) workspace2.agent.setToolPublished(tool, false);
|
|
144219
144226
|
workspace2.documentToolIdleTurns.clear();
|
|
@@ -144241,11 +144248,12 @@ function unpublishDocumentTools(workspace2, tools) {
|
|
|
144241
144248
|
}
|
|
144242
144249
|
}
|
|
144243
144250
|
var DOCUMENT_TOOL_IDLE_LIMIT = { unused: 1, used: 5 };
|
|
144251
|
+
var WORK_PLAN_EXTENDED_IDLE_LIMIT = 5;
|
|
144244
144252
|
function ageDocumentTools(workspace2) {
|
|
144245
144253
|
const used = workspace2.documentToolsUsedThisTurn;
|
|
144246
144254
|
for (const [tool, idle] of workspace2.documentToolIdleTurns) {
|
|
144247
144255
|
if (used.has(tool)) continue;
|
|
144248
|
-
const limit = workspace2.documentToolsEverUsed.has(tool) ? DOCUMENT_TOOL_IDLE_LIMIT.used : DOCUMENT_TOOL_IDLE_LIMIT.unused;
|
|
144256
|
+
const limit = tool === WORK_PLAN_EXTENDED_TOOL ? WORK_PLAN_EXTENDED_IDLE_LIMIT : workspace2.documentToolsEverUsed.has(tool) ? DOCUMENT_TOOL_IDLE_LIMIT.used : DOCUMENT_TOOL_IDLE_LIMIT.unused;
|
|
144249
144257
|
if (idle + 1 < limit) {
|
|
144250
144258
|
workspace2.documentToolIdleTurns.set(tool, idle + 1);
|
|
144251
144259
|
continue;
|
|
@@ -144256,7 +144264,10 @@ function ageDocumentTools(workspace2) {
|
|
|
144256
144264
|
used.clear();
|
|
144257
144265
|
}
|
|
144258
144266
|
function publishWorkPlanTools(workspace2, plan) {
|
|
144259
|
-
|
|
144267
|
+
const published = plan !== null;
|
|
144268
|
+
if (!workspace2.agent.setToolPublished(WORK_PLAN_EXTENDED_TOOL, published)) return;
|
|
144269
|
+
if (published) workspace2.documentToolIdleTurns.set(WORK_PLAN_EXTENDED_TOOL, 0);
|
|
144270
|
+
else workspace2.documentToolIdleTurns.delete(WORK_PLAN_EXTENDED_TOOL);
|
|
144260
144271
|
}
|
|
144261
144272
|
function queueWorkPlanSessionSync(workspace2, after) {
|
|
144262
144273
|
const sessionFile = workspace2.agent.snapshot().sessionFile;
|
|
@@ -144276,8 +144287,8 @@ function queueWorkPlanSessionSync(workspace2, after) {
|
|
|
144276
144287
|
if (!sameSessionFile(workspace2.agent.snapshot().sessionFile, sessionFile)) return;
|
|
144277
144288
|
workspace2.workPlan = plan;
|
|
144278
144289
|
workspace2.workPlanSessionFile = sessionFile;
|
|
144279
|
-
publishWorkPlanTools(workspace2, plan);
|
|
144280
144290
|
withholdDocumentTools(workspace2);
|
|
144291
|
+
publishWorkPlanTools(workspace2, plan);
|
|
144281
144292
|
broadcast(workspace2, { type: "session_replaced", ...snapshot(workspace2) });
|
|
144282
144293
|
if (inherited) broadcast(workspace2, { type: "work_plan_changed", workPlan: plan });
|
|
144283
144294
|
announceWorkspaceActivity();
|
|
@@ -145251,8 +145262,8 @@ async function ensureStarted(target) {
|
|
|
145251
145262
|
refreshExtensionRender(target);
|
|
145252
145263
|
target.workPlan = await loadWorkPlan(runtime.snapshot().sessionFile);
|
|
145253
145264
|
target.workPlanSessionFile = runtime.snapshot().sessionFile;
|
|
145254
|
-
publishWorkPlanTools(target, target.workPlan);
|
|
145255
145265
|
withholdDocumentTools(target);
|
|
145266
|
+
publishWorkPlanTools(target, target.workPlan);
|
|
145256
145267
|
target.lastUsedAt = Date.now();
|
|
145257
145268
|
void refreshPiPackages(target);
|
|
145258
145269
|
})();
|
package/dist/pi-outpost.sea.mjs
CHANGED
|
@@ -468768,6 +468768,12 @@ var WORST_LISTED = 8;
|
|
|
468768
468768
|
function isStackExhaustion(message) {
|
|
468769
468769
|
return /maximum call stack size exceeded|call stack size exceeded|stack overflow/i.test(message);
|
|
468770
468770
|
}
|
|
468771
|
+
var PROVIDER_STACK_ENV = "PI_OUTPOST_PROVIDER_STACK";
|
|
468772
|
+
var PROVIDER_STACK_OFF = /* @__PURE__ */ new Set(["", "0", "false", "no", "off"]);
|
|
468773
|
+
function providerStackProbeArmed(env4 = process.env) {
|
|
468774
|
+
return !PROVIDER_STACK_OFF.has((env4[PROVIDER_STACK_ENV] ?? "").trim().toLowerCase());
|
|
468775
|
+
}
|
|
468776
|
+
var PROVIDER_STACK_HINT = `[pi-outpost] no stack accompanies this \u2014 the provider's catch drops it. Set ${PROVIDER_STACK_ENV}=1 and the next occurrence will print one.`;
|
|
468771
468777
|
function inspectShape(root) {
|
|
468772
468778
|
let depth = 0;
|
|
468773
468779
|
let cyclic = false;
|
|
@@ -468912,6 +468918,7 @@ function writeRecord(agentDir, report) {
|
|
|
468912
468918
|
context?.cyclic?.length ? ` SELF-REFERENCE in ${context.cyclic.length} entr${context.cyclic.length === 1 ? "y" : "ies"}` : ""
|
|
468913
468919
|
].join("");
|
|
468914
468920
|
console.error(headline);
|
|
468921
|
+
if (!providerStackProbeArmed()) console.error(PROVIDER_STACK_HINT);
|
|
468915
468922
|
const file = path41.join(agentDir, "turn-failures.jsonl");
|
|
468916
468923
|
try {
|
|
468917
468924
|
fs35.mkdirSync(agentDir, { recursive: true });
|
|
@@ -471379,7 +471386,7 @@ function cacheControlFor(url) {
|
|
|
471379
471386
|
}
|
|
471380
471387
|
|
|
471381
471388
|
// ../server/src/index.ts
|
|
471382
|
-
var VERSION4 = true ? "0.
|
|
471389
|
+
var VERSION4 = true ? "0.28.0" : "dev";
|
|
471383
471390
|
var PI_SDK_VERSION = true ? "0.86.1" : readInstalledPiSdkVersion();
|
|
471384
471391
|
var LAUNCH_DIR = process.env.INIT_CWD ?? process.cwd();
|
|
471385
471392
|
function complain(error) {
|
|
@@ -472115,8 +472122,8 @@ for (const root of config.openProjects) {
|
|
|
472115
472122
|
}
|
|
472116
472123
|
workspace.workPlan = await loadWorkPlan(workspace.agent.snapshot().sessionFile);
|
|
472117
472124
|
workspace.workPlanSessionFile = workspace.agent.snapshot().sessionFile;
|
|
472118
|
-
publishWorkPlanTools(workspace, workspace.workPlan);
|
|
472119
472125
|
withholdDocumentTools(workspace);
|
|
472126
|
+
publishWorkPlanTools(workspace, workspace.workPlan);
|
|
472120
472127
|
function withholdDocumentTools(workspace2) {
|
|
472121
472128
|
for (const tool of [...DOCUMENT_TOOLS, PROJECT_MODEL_TOOL]) workspace2.agent.setToolPublished(tool, false);
|
|
472122
472129
|
workspace2.documentToolIdleTurns.clear();
|
|
@@ -472144,11 +472151,12 @@ function unpublishDocumentTools(workspace2, tools) {
|
|
|
472144
472151
|
}
|
|
472145
472152
|
}
|
|
472146
472153
|
var DOCUMENT_TOOL_IDLE_LIMIT = { unused: 1, used: 5 };
|
|
472154
|
+
var WORK_PLAN_EXTENDED_IDLE_LIMIT = 5;
|
|
472147
472155
|
function ageDocumentTools(workspace2) {
|
|
472148
472156
|
const used = workspace2.documentToolsUsedThisTurn;
|
|
472149
472157
|
for (const [tool, idle] of workspace2.documentToolIdleTurns) {
|
|
472150
472158
|
if (used.has(tool)) continue;
|
|
472151
|
-
const limit3 = workspace2.documentToolsEverUsed.has(tool) ? DOCUMENT_TOOL_IDLE_LIMIT.used : DOCUMENT_TOOL_IDLE_LIMIT.unused;
|
|
472159
|
+
const limit3 = tool === WORK_PLAN_EXTENDED_TOOL ? WORK_PLAN_EXTENDED_IDLE_LIMIT : workspace2.documentToolsEverUsed.has(tool) ? DOCUMENT_TOOL_IDLE_LIMIT.used : DOCUMENT_TOOL_IDLE_LIMIT.unused;
|
|
472152
472160
|
if (idle + 1 < limit3) {
|
|
472153
472161
|
workspace2.documentToolIdleTurns.set(tool, idle + 1);
|
|
472154
472162
|
continue;
|
|
@@ -472159,7 +472167,10 @@ function ageDocumentTools(workspace2) {
|
|
|
472159
472167
|
used.clear();
|
|
472160
472168
|
}
|
|
472161
472169
|
function publishWorkPlanTools(workspace2, plan) {
|
|
472162
|
-
|
|
472170
|
+
const published = plan !== null;
|
|
472171
|
+
if (!workspace2.agent.setToolPublished(WORK_PLAN_EXTENDED_TOOL, published)) return;
|
|
472172
|
+
if (published) workspace2.documentToolIdleTurns.set(WORK_PLAN_EXTENDED_TOOL, 0);
|
|
472173
|
+
else workspace2.documentToolIdleTurns.delete(WORK_PLAN_EXTENDED_TOOL);
|
|
472163
472174
|
}
|
|
472164
472175
|
function queueWorkPlanSessionSync(workspace2, after) {
|
|
472165
472176
|
const sessionFile = workspace2.agent.snapshot().sessionFile;
|
|
@@ -472179,8 +472190,8 @@ function queueWorkPlanSessionSync(workspace2, after) {
|
|
|
472179
472190
|
if (!sameSessionFile(workspace2.agent.snapshot().sessionFile, sessionFile)) return;
|
|
472180
472191
|
workspace2.workPlan = plan;
|
|
472181
472192
|
workspace2.workPlanSessionFile = sessionFile;
|
|
472182
|
-
publishWorkPlanTools(workspace2, plan);
|
|
472183
472193
|
withholdDocumentTools(workspace2);
|
|
472194
|
+
publishWorkPlanTools(workspace2, plan);
|
|
472184
472195
|
broadcast(workspace2, { type: "session_replaced", ...snapshot(workspace2) });
|
|
472185
472196
|
if (inherited) broadcast(workspace2, { type: "work_plan_changed", workPlan: plan });
|
|
472186
472197
|
announceWorkspaceActivity();
|
|
@@ -473154,8 +473165,8 @@ async function ensureStarted(target) {
|
|
|
473154
473165
|
refreshExtensionRender(target);
|
|
473155
473166
|
target.workPlan = await loadWorkPlan(runtime.snapshot().sessionFile);
|
|
473156
473167
|
target.workPlanSessionFile = runtime.snapshot().sessionFile;
|
|
473157
|
-
publishWorkPlanTools(target, target.workPlan);
|
|
473158
473168
|
withholdDocumentTools(target);
|
|
473169
|
+
publishWorkPlanTools(target, target.workPlan);
|
|
473159
473170
|
target.lastUsedAt = Date.now();
|
|
473160
473171
|
void refreshPiPackages(target);
|
|
473161
473172
|
})();
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Arm the provider stack probe, or do nothing at all.
|
|
3
|
+
*
|
|
4
|
+
* Passed with `--import`, because the whole module graph is loaded before any of
|
|
5
|
+
* pi-outpost's own code evaluates: a `register()` call from inside `index.ts` would run
|
|
6
|
+
* after the SDK was already parsed, and rewrite nothing. This is the only slot early
|
|
7
|
+
* enough, which is why it is a module of its own rather than a few lines somewhere.
|
|
8
|
+
*
|
|
9
|
+
* Inert unless `PI_OUTPOST_PROVIDER_STACK` is set to something meaning yes. Off, this
|
|
10
|
+
* file costs one environment read and returns; nothing is registered, no module is
|
|
11
|
+
* rewritten, and the process runs exactly as it did before. That is the point of the
|
|
12
|
+
* flag: a diagnostic nobody asked for should not be in the path of everybody's turns.
|
|
13
|
+
*
|
|
14
|
+
* On, it also raises `Error.stackTraceLimit`. V8's default of 10 frames is nothing on a
|
|
15
|
+
* recursion — the repeated frame is the answer, and ten of it says only that something
|
|
16
|
+
* repeated.
|
|
17
|
+
*/
|
|
18
|
+
import { register } from "node:module";
|
|
19
|
+
import { MessageChannel } from "node:worker_threads";
|
|
20
|
+
|
|
21
|
+
export const ENV_VAR = "PI_OUTPOST_PROVIDER_STACK";
|
|
22
|
+
|
|
23
|
+
/** How many frames are worth keeping. A recursion shows its cycle long before this. */
|
|
24
|
+
export const STACK_TRACE_LIMIT = 200;
|
|
25
|
+
|
|
26
|
+
/** Whether the flag's value means yes. Unset, empty, `0`, `false` and `no` mean no. */
|
|
27
|
+
export function isEnabled(value) {
|
|
28
|
+
if (typeof value !== "string") return false;
|
|
29
|
+
const normalized = value.trim().toLowerCase();
|
|
30
|
+
if (normalized.length === 0) return false;
|
|
31
|
+
return normalized !== "0" && normalized !== "false" && normalized !== "no" && normalized !== "off";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Registers the load hook and returns the port arming announcements arrive on.
|
|
36
|
+
*
|
|
37
|
+
* Exported so a test can drive it without a second process, and so the caller decides
|
|
38
|
+
* what to do with the announcements — this module only prints them.
|
|
39
|
+
*/
|
|
40
|
+
export function armProviderStackProbe(env = process.env) {
|
|
41
|
+
if (!isEnabled(env[ENV_VAR])) return undefined;
|
|
42
|
+
Error.stackTraceLimit = STACK_TRACE_LIMIT;
|
|
43
|
+
const { port1, port2 } = new MessageChannel();
|
|
44
|
+
port1.on("message", (url) => {
|
|
45
|
+
console.error(`[pi-outpost] provider stack probe armed on ${url}`);
|
|
46
|
+
});
|
|
47
|
+
// Nothing should wait on this port: an armed probe must not hold the event loop open.
|
|
48
|
+
port1.unref();
|
|
49
|
+
register("./providerStackRewrite.mjs", {
|
|
50
|
+
parentURL: import.meta.url,
|
|
51
|
+
data: port2,
|
|
52
|
+
transferList: [port2],
|
|
53
|
+
});
|
|
54
|
+
console.error(
|
|
55
|
+
`[pi-outpost] provider stack probe on (${ENV_VAR}). If no probe reports in by the first` +
|
|
56
|
+
" model call, the SDK's catch has moved and there was nothing to read.",
|
|
57
|
+
);
|
|
58
|
+
return port1;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
armProviderStackProbe();
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The module-load hook that puts a provider's lost stack back on stderr.
|
|
3
|
+
*
|
|
4
|
+
* Every pi-ai provider's stream loop ends in the same catch:
|
|
5
|
+
*
|
|
6
|
+
* catch (error) { output.errorMessage = formatProviderError(normalizeProviderError(error)); … }
|
|
7
|
+
*
|
|
8
|
+
* The message is kept and the `Error` is dropped, so by the time `assistant_end`
|
|
9
|
+
* crosses the runtime seam there is no `.stack` left anywhere in the process — which is
|
|
10
|
+
* the gap `turnFailureLog.ts` was written around, and why it records a census of the
|
|
11
|
+
* *input* rather than a trace. `normalizeProviderError` returns a flat
|
|
12
|
+
* `{ status, body, message, messageCarriesBody }`; it never carries the stack either.
|
|
13
|
+
* No extension hook reaches this: `after_provider_response` fires before the stream is
|
|
14
|
+
* consumed, and V8 offers no hook at an `Error`'s construction — `prepareStackTrace`
|
|
15
|
+
* runs on the first read of `.stack`, which never happens.
|
|
16
|
+
*
|
|
17
|
+
* So the stack is read here, at module load, before the catch can drop it. The source
|
|
18
|
+
* is rewritten **in memory**: nothing under `node_modules` is touched, `npm ci` has
|
|
19
|
+
* nothing to undo, and a machine running without the flag runs the bytes it installed.
|
|
20
|
+
*
|
|
21
|
+
* Matched on the catch's own line rather than on a filename, so it arms every provider
|
|
22
|
+
* that shares it — and arms none if a future SDK rewrites that line. That silence is
|
|
23
|
+
* reported rather than left to be discovered: each arming is announced through the
|
|
24
|
+
* port, and a run that announces nothing is a hook that found nothing.
|
|
25
|
+
*
|
|
26
|
+
* Hooks run off-thread, so `console.error` from here would not interleave with the
|
|
27
|
+
* server's own output; the port is how this side talks back. The injected probe itself
|
|
28
|
+
* runs in the module's own context on the main thread, where stderr is the real one.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/** The assignment that drops the error, verbatim from every pi-ai provider. */
|
|
32
|
+
const NEEDLE = "output.errorMessage = formatProviderError(normalizeProviderError(error));";
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Only stack exhaustion. Deliberately the same test as `isStackExhaustion` in
|
|
36
|
+
* `turnFailureLog.ts`: every other provider failure is already legible in the red
|
|
37
|
+
* bubble, and dumping 200 frames for a rate limit would bury the rare event in the
|
|
38
|
+
* common ones.
|
|
39
|
+
*/
|
|
40
|
+
const PROBE = [
|
|
41
|
+
"try { if (/maximum call stack size exceeded|call stack size exceeded|stack overflow/i.test(String(error && error.message)))",
|
|
42
|
+
' console.error("[pi-outpost] provider stack:\\n" + ((error && error.stack) || String(error)));',
|
|
43
|
+
" } catch { }",
|
|
44
|
+
].join("");
|
|
45
|
+
|
|
46
|
+
/** Set by `initialize`, which `module.register` calls with the port it was given. */
|
|
47
|
+
let port;
|
|
48
|
+
|
|
49
|
+
export function initialize(data) {
|
|
50
|
+
port = data;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function load(url, context, nextLoad) {
|
|
54
|
+
const result = await nextLoad(url, context);
|
|
55
|
+
if (result.source === undefined || result.source === null) return result;
|
|
56
|
+
const source = result.source.toString();
|
|
57
|
+
if (!source.includes(NEEDLE)) return result;
|
|
58
|
+
port?.postMessage(url);
|
|
59
|
+
// Prepended, not replacing: the assignment still runs and the turn still fails the
|
|
60
|
+
// way it did. This hook observes, it does not change what the agent sees.
|
|
61
|
+
return { ...result, source: source.replaceAll(NEEDLE, `${PROBE} ${NEEDLE}`) };
|
|
62
|
+
}
|
package/dist/sea-prep.blob
CHANGED
|
Binary file
|