@pasko70/pibo 1.12.0 → 1.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/apps/chat/chat-trace-helpers.js +59 -2
- package/dist/apps/chat/data/timeline-query-service.js +1 -1
- package/dist/apps/chat/web-app.js +16 -8
- package/dist/apps/chat-ui/assets/{dist-DiPvo4rq.js → dist-3bD-92Wo.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-DxJWicji.js → dist-BFjy5Y59.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-D1U9ck8z.js → dist-BKwQlbhS.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-B2Pozq2c.js → dist-Cp68y_h5.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-DYdgxFZX.js → dist-DE0y_EI7.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-Ci4lft6y.js → dist-DPb0yDi4.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-CkLit_da.js → dist-D_dQ5GaA.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-Bgv5Fm3v.js → dist-Daq2KRpq.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-D4qbF8wy.js → dist-aZnuCezL.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-la7ZfDGk.js → dist-q6Vpm5yH.js} +1 -1
- package/dist/apps/chat-ui/assets/index-DXPKuGfs.js +237 -0
- package/dist/apps/chat-ui/index.html +1 -1
- package/dist/apps/chat-vscode-web/assets/index-B3dSrp-L.js +41 -0
- package/dist/apps/chat-vscode-web/index.html +1 -1
- package/dist/apps/vscode-artifacts/latest.vsix +0 -0
- package/dist/apps/vscode-artifacts/pibo-vscode-ext-1.12.1.vsix +0 -0
- package/dist/core/gateway-resource-guard.js +46 -15
- package/dist/core/routed-session.js +40 -1
- package/dist/core/runtime.js +2 -0
- package/dist/core/session-errors.js +3 -0
- package/dist/core/session-router.js +25 -2
- package/dist/core/transcript-integrity.js +431 -0
- package/dist/data/pibo-store.js +2 -0
- package/dist/data/telemetry.js +148 -0
- package/dist/debug/index.js +11 -0
- package/dist/gateway/server.js +1 -0
- package/dist/reliability/store.js +11 -6
- package/dist/runs/registry.js +38 -1
- package/dist/runs/resource-isolation.js +437 -0
- package/dist/runs/tools.js +6 -3
- package/dist/sessions/pibo-data-store.js +114 -0
- package/dist/shared/trace-engine.js +3 -3
- package/dist/shared/trace-event-projection.js +165 -36
- package/dist/shared/trace-nodes.js +6 -4
- package/dist/shared/trace-page-merge.js +106 -2
- package/dist/shared/trace-transcript.js +194 -36
- package/package.json +1 -1
- package/dist/apps/chat-ui/assets/index-CYxPvrxL.js +0 -237
- package/dist/apps/chat-vscode-web/assets/index-CFSHKXsQ.js +0 -41
- package/dist/apps/vscode-artifacts/pibo-vscode-ext-1.12.0.vsix +0 -0
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<meta name="theme-color" content="#101d22" />
|
|
7
7
|
<title>Pibo</title>
|
|
8
|
-
<script type="module" crossorigin src="/apps/chat-vscode/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/apps/chat-vscode/assets/index-B3dSrp-L.js"></script>
|
|
9
9
|
<link rel="stylesheet" crossorigin href="/apps/chat-vscode/assets/index-Dupu1DzQ.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
Binary file
|
|
Binary file
|
|
@@ -2,6 +2,7 @@ import { execFile } from "node:child_process";
|
|
|
2
2
|
import { freemem, totalmem } from "node:os";
|
|
3
3
|
import { promisify } from "node:util";
|
|
4
4
|
import { getHeapStatistics } from "node:v8";
|
|
5
|
+
import { collectYieldedRunHostResourceSnapshot } from "../runs/resource-isolation.js";
|
|
5
6
|
const execFileAsync = promisify(execFile);
|
|
6
7
|
const DEFAULT_POLICY = Object.freeze({
|
|
7
8
|
mode: "block",
|
|
@@ -40,7 +41,8 @@ export function collectGatewayProcessMemory() {
|
|
|
40
41
|
export function buildGatewayResourceSnapshot(options = {}) {
|
|
41
42
|
const policy = resolveGatewayResourceGuardPolicy(options.env);
|
|
42
43
|
const gateway = collectGatewayProcessMemory();
|
|
43
|
-
const
|
|
44
|
+
const hostResources = options.hostResourceSnapshot ?? collectYieldedRunHostResourceSnapshot({ now: options.now });
|
|
45
|
+
const host = { freeBytes: hostResources.memoryFreeBytes || freemem(), availableBytes: hostResources.memoryAvailableBytes || freemem(), totalBytes: totalmem() };
|
|
44
46
|
const processResult = processResultFromOptions(gateway.pid, options, policy);
|
|
45
47
|
const checks = evaluateGatewayResourceChecks({ gateway, host, policy, knownDaemons: processResult.knownDaemons });
|
|
46
48
|
const severity = maxSeverity(checks.map((check) => check.severity));
|
|
@@ -52,6 +54,7 @@ export function buildGatewayResourceSnapshot(options = {}) {
|
|
|
52
54
|
host,
|
|
53
55
|
checks,
|
|
54
56
|
processes: processResult,
|
|
57
|
+
yieldedRunUnits: yieldedUnitResultFromOptions(options),
|
|
55
58
|
severity,
|
|
56
59
|
guardAction: guardAction(policy, severity),
|
|
57
60
|
nextCommands: [
|
|
@@ -63,16 +66,22 @@ export function buildGatewayResourceSnapshot(options = {}) {
|
|
|
63
66
|
};
|
|
64
67
|
}
|
|
65
68
|
export async function collectGatewayResourceSnapshot(options = {}) {
|
|
66
|
-
if (options.includeProcesses === false
|
|
69
|
+
if (options.includeProcesses === false
|
|
70
|
+
|| options.processListOutput !== undefined
|
|
71
|
+
|| options.processListError !== undefined
|
|
72
|
+
|| options.yieldedUnitListOutput !== undefined
|
|
73
|
+
|| options.yieldedUnitListError !== undefined) {
|
|
67
74
|
return buildGatewayResourceSnapshot(options);
|
|
68
75
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
+
const [processes, yieldedUnits] = await Promise.allSettled([
|
|
77
|
+
execFileAsync("ps", ["-eo", "pid=,ppid=,rss=,comm=,args="], { maxBuffer: 10 * 1024 * 1024 }),
|
|
78
|
+
execFileAsync("systemctl", ["list-units", "--all", "--plain", "--no-legend", "--no-pager", "pibo-yielded-*.service"], { maxBuffer: 1024 * 1024 }),
|
|
79
|
+
]);
|
|
80
|
+
return buildGatewayResourceSnapshot({
|
|
81
|
+
...options,
|
|
82
|
+
...(processes.status === "fulfilled" ? { processListOutput: processes.value.stdout } : { processListError: errorText(processes.reason) }),
|
|
83
|
+
...(yieldedUnits.status === "fulfilled" ? { yieldedUnitListOutput: yieldedUnits.value.stdout } : { yieldedUnitListError: errorText(yieldedUnits.reason) }),
|
|
84
|
+
});
|
|
76
85
|
}
|
|
77
86
|
export function assertGatewayResourceAvailableForWork(workLabel, env = process.env) {
|
|
78
87
|
const snapshot = buildGatewayResourceSnapshot({ env, includeProcesses: false });
|
|
@@ -94,15 +103,16 @@ export class GatewayWorkAdmissionController {
|
|
|
94
103
|
]);
|
|
95
104
|
}
|
|
96
105
|
if (policy.mode === "block" &&
|
|
97
|
-
snapshot.host.
|
|
106
|
+
snapshot.host.availableBytes < policy.minFreeMemoryBytes + policy.yieldedRunMemoryReservationBytes) {
|
|
98
107
|
throwGatewayResourceBlock(workLabel, [
|
|
99
|
-
`Host
|
|
108
|
+
`Host available memory ${snapshot.host.availableBytes} cannot preserve reserve ${policy.minFreeMemoryBytes} after the yielded-run reservation ${policy.yieldedRunMemoryReservationBytes}.`,
|
|
100
109
|
]);
|
|
101
110
|
}
|
|
102
111
|
const reservation = Symbol(workLabel);
|
|
103
112
|
this.activeReservations.add(reservation);
|
|
104
113
|
let released = false;
|
|
105
114
|
return {
|
|
115
|
+
admission: collectYieldedRunHostResourceSnapshot(),
|
|
106
116
|
release: () => {
|
|
107
117
|
if (released)
|
|
108
118
|
return;
|
|
@@ -135,16 +145,27 @@ export function parseHostProcessResourceList(output, gatewayPid, policy = DEFAUL
|
|
|
135
145
|
.filter((row) => row.kind === "gateway" || row.kind === "child" || row.kind === "known-daemon")
|
|
136
146
|
.sort((a, b) => resourceProcessRank(a, policy) - resourceProcessRank(b, policy) || b.rssBytes - a.rssBytes);
|
|
137
147
|
}
|
|
148
|
+
export function parseYieldedRunSystemdUnits(output) {
|
|
149
|
+
return output.split("\n").flatMap((line) => {
|
|
150
|
+
const match = line.trim().match(/^(pibo-yielded-[^\s]+\.service)\s+(\S+)\s+(\S+)\s+(\S+)\s*(.*)$/);
|
|
151
|
+
return match ? [{ unitName: match[1], loadState: match[2], activeState: match[3], subState: match[4], description: match[5] ?? "" }] : [];
|
|
152
|
+
});
|
|
153
|
+
}
|
|
138
154
|
export function renderGatewayResourceSnapshotText(snapshot) {
|
|
139
155
|
const lines = [`Gateway resource health: ${snapshot.severity} (guard=${snapshot.policy.mode}, action=${snapshot.guardAction})`];
|
|
140
156
|
lines.push(`Generated at: ${snapshot.generatedAt}`);
|
|
141
157
|
lines.push(`Gateway PID: ${snapshot.gateway.pid}`);
|
|
142
158
|
lines.push(`Gateway memory: rss=${snapshot.gateway.rssBytes} heapUsed=${snapshot.gateway.heapUsedBytes} heapAvailable=${snapshot.gateway.heapAvailableBytes} heapLimit=${snapshot.gateway.heapLimitBytes}`);
|
|
143
|
-
lines.push(`Host memory: free=${snapshot.host.freeBytes} total=${snapshot.host.totalBytes}`);
|
|
159
|
+
lines.push(`Host memory: free=${snapshot.host.freeBytes} available=${snapshot.host.availableBytes} total=${snapshot.host.totalBytes}`);
|
|
144
160
|
lines.push(`Thresholds: minFree=${snapshot.policy.minFreeMemoryBytes} minHeapAvailable=${snapshot.policy.minHeapAvailableBytes} maxRss=${snapshot.policy.maxRssBytes} daemonWarnRss=${snapshot.policy.knownDaemonWarningRssBytes} maxYieldedRuns=${snapshot.policy.maxConcurrentYieldedRuns} yieldedRunReservation=${snapshot.policy.yieldedRunMemoryReservationBytes}`);
|
|
145
161
|
lines.push(`Related processes: children=${snapshot.processes.children.length} knownDaemons=${snapshot.processes.knownDaemons.length} processList=${snapshot.processes.available ? "available" : "unavailable"}`);
|
|
162
|
+
lines.push(`Yielded-run cgroups: units=${snapshot.yieldedRunUnits.units.length} systemdList=${snapshot.yieldedRunUnits.available ? "available" : "unavailable"}`);
|
|
146
163
|
if (snapshot.processes.error)
|
|
147
164
|
lines.push(`Process list error: ${snapshot.processes.error}`);
|
|
165
|
+
if (snapshot.yieldedRunUnits.error)
|
|
166
|
+
lines.push(`Yielded-run unit list error: ${snapshot.yieldedRunUnits.error}`);
|
|
167
|
+
for (const unit of snapshot.yieldedRunUnits.units)
|
|
168
|
+
lines.push(`- ${unit.unitName}: ${unit.activeState}/${unit.subState}`);
|
|
148
169
|
const visibleProcesses = [...snapshot.processes.children, ...snapshot.processes.knownDaemons].slice(0, 10);
|
|
149
170
|
if (visibleProcesses.length > 0) {
|
|
150
171
|
lines.push("PID\tPPID\tRSS_BYTES\tKIND\tLABEL\tCOMMAND");
|
|
@@ -166,9 +187,9 @@ function evaluateGatewayResourceChecks(input) {
|
|
|
166
187
|
checks.push({ id: "guard-disabled", severity: "ok", message: "Gateway resource guard is disabled." });
|
|
167
188
|
return checks;
|
|
168
189
|
}
|
|
169
|
-
checks.push(input.host.
|
|
170
|
-
? { id: "host-memory-reserve", severity: "critical", message: `Host
|
|
171
|
-
: { id: "host-memory-reserve", severity: "ok", message: `Host
|
|
190
|
+
checks.push(input.host.availableBytes < input.policy.minFreeMemoryBytes
|
|
191
|
+
? { id: "host-memory-reserve", severity: "critical", message: `Host available memory ${input.host.availableBytes} is below reserve ${input.policy.minFreeMemoryBytes}.` }
|
|
192
|
+
: { id: "host-memory-reserve", severity: "ok", message: `Host available memory ${input.host.availableBytes} satisfies reserve ${input.policy.minFreeMemoryBytes}.` });
|
|
172
193
|
checks.push(input.gateway.heapAvailableBytes < input.policy.minHeapAvailableBytes
|
|
173
194
|
? { id: "gateway-heap-reserve", severity: "critical", message: `Gateway heap availability ${input.gateway.heapAvailableBytes} is below reserve ${input.policy.minHeapAvailableBytes}.` }
|
|
174
195
|
: { id: "gateway-heap-reserve", severity: "ok", message: `Gateway heap availability ${input.gateway.heapAvailableBytes} satisfies reserve ${input.policy.minHeapAvailableBytes}.` });
|
|
@@ -193,6 +214,16 @@ function processResultFromOptions(gatewayPid, options, policy) {
|
|
|
193
214
|
knownDaemons: rows.filter((row) => row.kind === "known-daemon"),
|
|
194
215
|
};
|
|
195
216
|
}
|
|
217
|
+
function yieldedUnitResultFromOptions(options) {
|
|
218
|
+
if (options.yieldedUnitListError)
|
|
219
|
+
return { available: false, error: options.yieldedUnitListError, units: [] };
|
|
220
|
+
if (options.yieldedUnitListOutput === undefined)
|
|
221
|
+
return { available: false, units: [] };
|
|
222
|
+
return { available: true, units: parseYieldedRunSystemdUnits(options.yieldedUnitListOutput) };
|
|
223
|
+
}
|
|
224
|
+
function errorText(error) {
|
|
225
|
+
return error instanceof Error ? error.message : String(error);
|
|
226
|
+
}
|
|
196
227
|
function parseMode(value, fallback) {
|
|
197
228
|
const normalized = value?.trim().toLowerCase();
|
|
198
229
|
if (normalized === undefined || normalized === "")
|
|
@@ -5,6 +5,7 @@ import { normalizeSessionErrorDetails, runtimeSessionErrorDetails } from "./sess
|
|
|
5
5
|
import { expandInlineSkills } from "./skill-expansion.js";
|
|
6
6
|
import { PIBO_CONTEXT_GUARD_RESUME_MESSAGE_TYPE, PIBO_CONTEXT_GUARD_RESUME_PROMPT, cancelPiboAssistantContextGuardRecovery, claimPiboAssistantContextGuardRecovery, waitForPiboAssistantContextGuardRecovery, } from "./context-guard.js";
|
|
7
7
|
import { PIBO_PROVIDER_RECOVERY_MESSAGE_TYPE, PIBO_PROVIDER_RECOVERY_PROMPT, PiboProviderRecoveryCancelledError, isRetryablePiboAssistantError, isRetryablePiboProviderError, resolvePiboProviderRecoverySettings, waitForPiboProviderRecovery, } from "./provider-recovery.js";
|
|
8
|
+
import { PIBO_TRANSCRIPT_INTEGRITY_RESUME_MESSAGE_TYPE, PIBO_TRANSCRIPT_INTEGRITY_RESUME_PROMPT, PiboTranscriptIntegrityError, claimPiboTranscriptIntegrityContinuation, settlePiboTranscriptIntegrityContinuation, } from "./transcript-integrity.js";
|
|
8
9
|
const FAST_SERVICE_TIER = "priority";
|
|
9
10
|
const RUN_REMINDER_CAPABILITY_TOOLS = new Set([
|
|
10
11
|
"pibo_run_status",
|
|
@@ -583,6 +584,12 @@ export class RoutedSession {
|
|
|
583
584
|
this.pendingAssistantError = undefined;
|
|
584
585
|
this.pendingAssistantErrorRetryable = false;
|
|
585
586
|
}
|
|
587
|
+
takePendingAssistantError() {
|
|
588
|
+
const pending = this.pendingAssistantError;
|
|
589
|
+
this.pendingAssistantError = undefined;
|
|
590
|
+
this.pendingAssistantErrorRetryable = false;
|
|
591
|
+
return pending;
|
|
592
|
+
}
|
|
586
593
|
cancelProviderRecovery() {
|
|
587
594
|
this.providerRecoveryCancelled = true;
|
|
588
595
|
this.providerRecoveryAbortController?.abort();
|
|
@@ -593,6 +600,34 @@ export class RoutedSession {
|
|
|
593
600
|
if (waitForIdle)
|
|
594
601
|
await waitForIdle.call(session);
|
|
595
602
|
}
|
|
603
|
+
async resumeTranscriptIntegrityRecovery(session) {
|
|
604
|
+
const reports = claimPiboTranscriptIntegrityContinuation(session);
|
|
605
|
+
if (reports.length === 0)
|
|
606
|
+
return;
|
|
607
|
+
try {
|
|
608
|
+
this.pendingAssistantError = undefined;
|
|
609
|
+
this.pendingAssistantErrorRetryable = false;
|
|
610
|
+
await session.sendCustomMessage({
|
|
611
|
+
customType: PIBO_TRANSCRIPT_INTEGRITY_RESUME_MESSAGE_TYPE,
|
|
612
|
+
content: [{ type: "text", text: PIBO_TRANSCRIPT_INTEGRITY_RESUME_PROMPT }],
|
|
613
|
+
display: false,
|
|
614
|
+
details: { repairIds: reports.map((report) => report.repairId) },
|
|
615
|
+
}, { triggerTurn: true });
|
|
616
|
+
await this.waitForPiAgentSettlement(session);
|
|
617
|
+
await this.resumeContextGuardRecovery(session);
|
|
618
|
+
const pendingError = this.takePendingAssistantError();
|
|
619
|
+
if (pendingError) {
|
|
620
|
+
throw new PiboTranscriptIntegrityError(`Transcript integrity continuation failed: ${pendingError.error}`);
|
|
621
|
+
}
|
|
622
|
+
settlePiboTranscriptIntegrityContinuation(session, "completed");
|
|
623
|
+
}
|
|
624
|
+
catch (error) {
|
|
625
|
+
settlePiboTranscriptIntegrityContinuation(session, "failed", error);
|
|
626
|
+
throw error instanceof PiboTranscriptIntegrityError
|
|
627
|
+
? error
|
|
628
|
+
: new PiboTranscriptIntegrityError(`Transcript integrity continuation failed: ${errorMessage(error)}`);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
596
631
|
async resumeContextGuardRecovery(session) {
|
|
597
632
|
while (await waitForPiboAssistantContextGuardRecovery(session)) {
|
|
598
633
|
try {
|
|
@@ -1092,6 +1127,10 @@ export class RoutedSession {
|
|
|
1092
1127
|
});
|
|
1093
1128
|
return;
|
|
1094
1129
|
}
|
|
1130
|
+
const session = this.runtime.session;
|
|
1131
|
+
await this.resumeTranscriptIntegrityRecovery(session);
|
|
1132
|
+
if (this.disposed)
|
|
1133
|
+
return;
|
|
1095
1134
|
this.emit({
|
|
1096
1135
|
type: "message_started",
|
|
1097
1136
|
piboSessionId: this.piboSessionId,
|
|
@@ -1109,7 +1148,6 @@ export class RoutedSession {
|
|
|
1109
1148
|
this.nextAssistantIndex = 0;
|
|
1110
1149
|
this.activeThinkingIndex = undefined;
|
|
1111
1150
|
this.nextThinkingIndex = 0;
|
|
1112
|
-
const session = this.runtime.session;
|
|
1113
1151
|
this.applyMessageCapabilityScope(event, session);
|
|
1114
1152
|
const expandedText = expandInlineSkills(event.text, session.resourceLoader.getSkills().skills);
|
|
1115
1153
|
await session.prompt(expandedText, { source: promptSource(event.source) });
|
|
@@ -1172,6 +1210,7 @@ export class RoutedSession {
|
|
|
1172
1210
|
async processQueuedCompact(event) {
|
|
1173
1211
|
this.activeExecutionEvent = event;
|
|
1174
1212
|
try {
|
|
1213
|
+
await this.resumeTranscriptIntegrityRecovery(this.runtime.session);
|
|
1175
1214
|
const result = await this.runAction(event);
|
|
1176
1215
|
if (this.disposed)
|
|
1177
1216
|
return;
|
package/dist/core/runtime.js
CHANGED
|
@@ -26,6 +26,7 @@ import { PIBO_APP_CONTEXT } from "../app-context.js";
|
|
|
26
26
|
import { createRuntimeToolDefinition } from "../tools/runtime/tool.js";
|
|
27
27
|
import { RuntimeSessionRegistry } from "../tools/runtime/registry.js";
|
|
28
28
|
import { compactValidationToolResultForContext } from "./test-output-compaction.js";
|
|
29
|
+
import { installPiboTranscriptIntegrity } from "./transcript-integrity.js";
|
|
29
30
|
function hasOwnRetrySetting(settings, key) {
|
|
30
31
|
return settings !== undefined && settings !== null && Object.prototype.hasOwnProperty.call(settings, key);
|
|
31
32
|
}
|
|
@@ -301,6 +302,7 @@ export async function createPiboRuntime(options = {}) {
|
|
|
301
302
|
noTools: profile.builtinTools === "disabled" ? "builtin" : undefined,
|
|
302
303
|
tools: getBuiltinToolAllowlist(profile, customTools),
|
|
303
304
|
});
|
|
305
|
+
installPiboTranscriptIntegrity(created.session);
|
|
304
306
|
installValidationOutputCompaction(created.session.agent);
|
|
305
307
|
registerPiboAssistantContextGuardRecovery(created.session, contextGuardRecovery);
|
|
306
308
|
if (options.contextGuardTuiQueueOrdering === true) {
|
|
@@ -18,6 +18,9 @@ const PROVIDER_NETWORK_ERROR_MARKERS = [
|
|
|
18
18
|
];
|
|
19
19
|
export function classifySessionErrorMessage(message, options = {}) {
|
|
20
20
|
const normalized = message.toLowerCase();
|
|
21
|
+
if (normalized.includes("transcript integrity") || normalized.includes("no tool call found for function call output")) {
|
|
22
|
+
return { category: "transcript_integrity", errorClass: "transcript_integrity", code: "invalid_tool_transcript", origin: "runtime", retryable: false, userMessage: "The persisted tool transcript was invalid and could not be repaired automatically." };
|
|
23
|
+
}
|
|
21
24
|
if (normalized.includes("context_length_exceeded") || normalized.includes("context window")) {
|
|
22
25
|
return { category: "context_overflow", errorClass: "provider_context", code: "context_length_exceeded", origin: "provider", retryable: false, userMessage: "The model context window was exceeded." };
|
|
23
26
|
}
|
|
@@ -7,6 +7,7 @@ import { runtimeSessionErrorDetails } from "./session-errors.js";
|
|
|
7
7
|
import { createSubagentToolName } from "../subagents/tool.js";
|
|
8
8
|
import { PiboRunRegistry } from "../runs/registry.js";
|
|
9
9
|
import { PiboRunExecutionTimeoutError } from "../runs/lifecycle.js";
|
|
10
|
+
import { PiboRunResourceLimitError } from "../runs/resource-isolation.js";
|
|
10
11
|
import { createPiboSignalRegistry } from "../signals/registry.js";
|
|
11
12
|
import { createDefaultPiboReliabilityStore } from "../reliability/store.js";
|
|
12
13
|
import { InMemoryPiboSessionStore, } from "../sessions/store.js";
|
|
@@ -86,6 +87,8 @@ function formatRunReminderMessage(notification) {
|
|
|
86
87
|
status: run.status,
|
|
87
88
|
toolName: run.toolName,
|
|
88
89
|
summary: run.summary,
|
|
90
|
+
resourceLimitReason: run.resources?.limitReason,
|
|
91
|
+
resourceUnit: run.resources?.unitName,
|
|
89
92
|
})),
|
|
90
93
|
timedOut: notification.timedOut.map((run) => ({
|
|
91
94
|
runId: run.runId,
|
|
@@ -202,6 +205,17 @@ export class PiboSessionRouter {
|
|
|
202
205
|
this.runtimeRegistry = new RuntimeSessionRegistry({ cwd: options.cwd ?? getDefaultPiboWorkspace() });
|
|
203
206
|
this.runRegistry = new PiboRunRegistry({ store: this.reliabilityStore });
|
|
204
207
|
this.runRegistry.subscribe((event) => this.projectRunRegistryEvent(event));
|
|
208
|
+
const recoveredRuntimeState = options.recoverInterruptedRuntimeState
|
|
209
|
+
? this.sessionStore.recoverInterruptedRuntimeState?.({
|
|
210
|
+
recoveredRuns: this.runRegistry.listRecoveredRuns(),
|
|
211
|
+
}) ?? []
|
|
212
|
+
: [];
|
|
213
|
+
for (const recovery of recoveredRuntimeState) {
|
|
214
|
+
const session = this.sessionStore.get(recovery.event.piboSessionId);
|
|
215
|
+
if (session)
|
|
216
|
+
this.signalRegistry.project({ type: "session_created", session });
|
|
217
|
+
this.signalRegistry.project({ type: "pibo_output", event: recovery.event });
|
|
218
|
+
}
|
|
205
219
|
for (const run of this.runRegistry.listAll({ includeConsumed: true, includeDetached: true })) {
|
|
206
220
|
this.signalRegistry.project({ type: "run_changed", run, reason: "recovered" });
|
|
207
221
|
}
|
|
@@ -863,8 +877,10 @@ export class PiboSessionRouter {
|
|
|
863
877
|
}
|
|
864
878
|
createRunToolController(parentPiboSessionId) {
|
|
865
879
|
return {
|
|
866
|
-
startToolRun: ({ toolName, params, completionPolicy, retryable, maxAttempts, timeoutMs, serviceWarning, execute }) => {
|
|
880
|
+
startToolRun: ({ toolName, params, completionPolicy, retryable, maxAttempts, timeoutMs, serviceWarning, resources, execute }) => {
|
|
867
881
|
const admission = this.gatewayWorkAdmission.reserve(`yielded run ${toolName}`);
|
|
882
|
+
if (resources)
|
|
883
|
+
resources.admission = admission.admission;
|
|
868
884
|
const reminderGeneration = this.runReminderGeneration(parentPiboSessionId);
|
|
869
885
|
let run;
|
|
870
886
|
try {
|
|
@@ -877,6 +893,7 @@ export class PiboSessionRouter {
|
|
|
877
893
|
maxAttempts,
|
|
878
894
|
timeoutMs,
|
|
879
895
|
serviceWarning,
|
|
896
|
+
resources,
|
|
880
897
|
});
|
|
881
898
|
}
|
|
882
899
|
catch (error) {
|
|
@@ -886,15 +903,21 @@ export class PiboSessionRouter {
|
|
|
886
903
|
void (async () => {
|
|
887
904
|
try {
|
|
888
905
|
const result = await execute();
|
|
906
|
+
if (resources)
|
|
907
|
+
this.runRegistry.updateResources(run.runId, resources);
|
|
889
908
|
const completed = this.runRegistry.complete(run.runId, result);
|
|
890
909
|
if (completed)
|
|
891
910
|
this.handleTerminalRunReminder(parentPiboSessionId, completed.runId, reminderGeneration);
|
|
892
911
|
}
|
|
893
912
|
catch (error) {
|
|
894
913
|
const message = error instanceof Error ? error.message : String(error);
|
|
914
|
+
if (resources)
|
|
915
|
+
this.runRegistry.updateResources(run.runId, resources);
|
|
895
916
|
const terminalRun = error instanceof PiboRunExecutionTimeoutError
|
|
896
917
|
? this.runRegistry.timeOut(run.runId, message, error.timeoutPhase)
|
|
897
|
-
:
|
|
918
|
+
: error instanceof PiboRunResourceLimitError
|
|
919
|
+
? this.runRegistry.resourceLimit(run.runId, message, error.resources)
|
|
920
|
+
: this.runRegistry.fail(run.runId, message);
|
|
898
921
|
if (terminalRun)
|
|
899
922
|
this.handleTerminalRunReminder(parentPiboSessionId, terminalRun.runId, reminderGeneration);
|
|
900
923
|
}
|