@pasko70/pibo 3.0.1 → 3.1.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 +20 -6
- package/compute-image/Dockerfile +47 -0
- package/compute-image/Dockerfile.dockerignore +5 -0
- package/dist/agent-runtime/context-build.js +26 -2
- package/dist/agent-runtime/contract.js +78 -28
- package/dist/agent-runtime/portable-history.js +19 -9
- package/dist/agent-runtime/registry.js +8 -2
- package/dist/agent-runtime/routed-session.js +120 -15
- package/dist/agent-runtimes/codex-native/adapter.js +12 -0
- package/dist/agent-runtimes/codex-native/resource-delivery.js +35 -7
- package/dist/agent-runtimes/omp/adapter.js +3 -7
- package/dist/agent-runtimes/pi/adapter.js +5 -3
- package/dist/agent-runtimes/pi/routed-session.js +59 -12
- package/dist/agent-runtimes/pi/runtime.js +6 -0
- package/dist/apps/chat/agent-profiles.js +31 -2
- package/dist/apps/chat/agent-store.js +98 -6
- package/dist/apps/chat/chat-request-normalizers.js +31 -0
- package/dist/apps/chat/data/chat-data-mappers.js +61 -11
- package/dist/apps/chat/data/project-service.js +119 -15
- package/dist/apps/chat/data/room-service.js +21 -0
- package/dist/apps/chat/data/session-query-service.js +33 -10
- package/dist/apps/chat/data/timeline-query-service.js +60 -35
- package/dist/apps/chat/loop-api.js +10 -2
- package/dist/apps/chat/output-compactor.js +144 -21
- package/dist/apps/chat/output-event-policy.js +179 -2
- package/dist/apps/chat/stream.js +16 -7
- package/dist/apps/chat/trace-v2.js +1 -0
- package/dist/apps/chat/web-app.js +317 -86
- package/dist/apps/chat-ui/assets/{dist-BDIATCQt.js → dist-CUQJqggN.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-mqCviI-c.js → dist-ClUlQWYN.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-JnW4v8UE.js → dist-Djul9BmZ.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-lRiLP9rr.js → dist-GD0JGdCi.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-BBDMeU5-.js → dist-W5HOqHym.js} +1 -1
- package/dist/apps/chat-ui/assets/index-BcjkX-iP.js +228 -0
- package/dist/apps/chat-ui/assets/index-CmqRSbBU.css +1 -0
- package/dist/apps/chat-ui/index.html +2 -2
- package/dist/apps/chat-vscode-web/assets/index-JvrPUGvI.js +43 -0
- package/dist/apps/chat-vscode-web/index.html +1 -1
- package/dist/apps/cli-ui/InkSessionApp.js +111 -12
- package/dist/apps/cli-ui/cliSessionsCommand.js +34 -8
- package/dist/cli-session/localSessionSource.js +153 -161
- package/dist/cli.js +7 -11
- package/dist/compute/cli.js +35 -16
- package/dist/compute/docker.js +341 -94
- package/dist/config/config.js +3 -0
- package/dist/core/context-build.js +7 -16
- package/dist/core/output-persistence-retry.js +484 -0
- package/dist/core/output-render-sequence.js +331 -0
- package/dist/core/profiles.js +24 -0
- package/dist/core/provider-recovery.js +7 -1
- package/dist/core/session-model.js +37 -1
- package/dist/core/session-router.js +78 -110
- package/dist/data/ingest-service.js +91 -9
- package/dist/data/navigation-store.js +5 -5
- package/dist/data/pibo-store.js +8 -1
- package/dist/data/schema.js +243 -3
- package/dist/data/session-store.js +3 -3
- package/dist/debug/agents.js +91 -89
- package/dist/debug/index.js +46 -2
- package/dist/debug/pty.js +127 -48
- package/dist/gateway/cli.js +4 -0
- package/dist/gateway/web.js +8 -8
- package/dist/local/client.js +3 -2
- package/dist/loops/channel.js +3 -1
- package/dist/loops/cli.js +2 -1
- package/dist/loops/service.js +90 -11
- package/dist/loops/store.js +100 -74
- package/dist/mcp/agent-context.js +13 -26
- package/dist/mcp/commands/info.js +3 -1
- package/dist/mcp/config-command.js +46 -2
- package/dist/mcp/config.js +18 -4
- package/dist/plugins/context-files-store.js +36 -6
- package/dist/plugins/context-files.js +52 -1
- package/dist/plugins/registry.js +2 -0
- package/dist/plugins/user-profile-resources.js +22 -0
- package/dist/previews/base-url.js +34 -0
- package/dist/previews/config.js +2 -32
- package/dist/ralph/store.js +5 -0
- package/dist/reliability/store.js +378 -106
- package/dist/session-ui/terminalRows.js +8 -4
- package/dist/sessions/pibo-data-store.js +145 -0
- package/dist/sessions/store.js +42 -0
- package/dist/setup/cli.js +422 -6
- package/dist/setup/installation-profiles.js +464 -0
- package/dist/shared/deterministic-digest.js +94 -0
- package/dist/shared/trace-engine.js +54 -0
- package/dist/shared/trace-event-projection.js +124 -67
- package/dist/shared/trace-history.js +47 -12
- package/dist/shared/trace-live-reducer.js +23 -4
- package/dist/shared/trace-nodes.js +17 -28
- package/dist/shared/trace-order.js +41 -5
- package/dist/shared/trace-page-merge.js +44 -14
- package/dist/shared/trace-patch-nodes.js +2 -0
- package/dist/shared/trace-subagent-links.js +4 -1
- package/dist/shared/trace-tool-identity.js +15 -8
- package/dist/signals/projector.js +28 -6
- package/dist/subagents/observation-query.js +121 -0
- package/dist/subagents/tool.js +7 -3
- package/dist/tools/agent-browser-leases.js +58 -23
- package/dist/tools/agent-browser-wrapper.js +1 -1
- package/dist/tools/browser-use-leases.js +129 -16
- package/dist/tools/browser-use-wrapper.js +1 -1
- package/dist/tools/index.js +27 -11
- package/dist/tools/python-runtime.js +10 -3
- package/dist/tools/registry.js +1 -1
- package/dist/tools/runtime/node-backend.js +16 -5
- package/dist/tools/runtime/node-worker-source.js +112 -33
- package/dist/tools/runtime/python-backend.js +16 -5
- package/dist/tools/runtime/python-worker-source.js +167 -16
- package/dist/tools/runtime/registry.js +23 -10
- package/dist/user-skills/store.js +0 -1
- package/docs/ops/vscode-extension-release.md +9 -1
- package/npm-shrinkwrap.json +9 -2
- package/package.json +9 -2
- package/scripts/docker-entrypoint.sh +46 -0
- package/scripts/prepare-agent-browser-wrapper.sh +70 -0
- package/scripts/prepare-browser-use-wrapper.sh +255 -0
- package/dist/apps/chat-ui/assets/index-0XOOVxLP.js +0 -228
- package/dist/apps/chat-ui/assets/index-DV7_CgsC.css +0 -1
- package/dist/apps/chat-vscode-web/assets/index-Dtw2Z7jz.js +0 -43
- package/dist/apps/vscode-artifacts/latest.vsix +0 -0
- package/dist/apps/vscode-artifacts/pibo-vscode-ext-3.0.1.vsix +0 -0
|
@@ -290,6 +290,7 @@ export class CodexNativeThreadSession {
|
|
|
290
290
|
recycleProcessAfterInterruptedTurn = false;
|
|
291
291
|
selectedToolNames = new Set();
|
|
292
292
|
observedToolNames = new Set();
|
|
293
|
+
emittedResourceWarnings = new Set();
|
|
293
294
|
toolInventoryWarning;
|
|
294
295
|
constructor(runtimeInstanceId, process, threads, settings, resourceDelivery, binding, structuredUserInput, reloadProcess, productContext, bindingPersistence, firstUseTestFailpoints) {
|
|
295
296
|
this.runtimeInstanceId = runtimeInstanceId;
|
|
@@ -390,6 +391,7 @@ export class CodexNativeThreadSession {
|
|
|
390
391
|
this.assertActive();
|
|
391
392
|
await this.ensureFreshResourcesForTurn();
|
|
392
393
|
this.assertIdle();
|
|
394
|
+
this.emitPendingResourceWarnings();
|
|
393
395
|
this.operationInFlight = true;
|
|
394
396
|
let ownedFirstUseAttempt;
|
|
395
397
|
try {
|
|
@@ -473,6 +475,7 @@ export class CodexNativeThreadSession {
|
|
|
473
475
|
contextUsage: this.settings.currentContextUsage,
|
|
474
476
|
warnings: [
|
|
475
477
|
...diagnostics.filter((entry) => entry.level === "warning").map((entry) => entry.message),
|
|
478
|
+
...this.resourceDelivery.warnings.map((entry) => entry.message),
|
|
476
479
|
...(this.resourceWarning ? [this.resourceWarning] : []),
|
|
477
480
|
...(this.toolInventoryWarning ? [this.toolInventoryWarning] : []),
|
|
478
481
|
],
|
|
@@ -659,6 +662,15 @@ export class CodexNativeThreadSession {
|
|
|
659
662
|
throw new Error(`Native Codex portable-resource credential refresh failed while ${phase}; Pibo will retry while the session remains idle.`);
|
|
660
663
|
}
|
|
661
664
|
}
|
|
665
|
+
emitPendingResourceWarnings() {
|
|
666
|
+
for (const warning of this.resourceDelivery.warnings) {
|
|
667
|
+
const key = `${warning.code}\0${warning.message}`;
|
|
668
|
+
if (this.emittedResourceWarnings.has(key))
|
|
669
|
+
continue;
|
|
670
|
+
this.emittedResourceWarnings.add(key);
|
|
671
|
+
this.emit({ type: "warning", message: warning.message, details: { code: warning.code } });
|
|
672
|
+
}
|
|
673
|
+
}
|
|
662
674
|
updateSelectedToolNames(resourceDelivery) {
|
|
663
675
|
const names = [...new Set(resourceDelivery.enabledToolNames)].sort();
|
|
664
676
|
this.selectedToolNames = new Set(names.slice(0, MAX_INSPECTED_SELECTED_TOOL_NAMES));
|
|
@@ -256,21 +256,25 @@ export class CodexNativeResourceDelivery {
|
|
|
256
256
|
skillRoots;
|
|
257
257
|
selectedSkills;
|
|
258
258
|
expectedMcpServers;
|
|
259
|
+
resources;
|
|
259
260
|
portableTools;
|
|
260
261
|
mcpAccess;
|
|
261
262
|
credentialIssuedAtMs;
|
|
262
263
|
credentialExpiresAtMs;
|
|
263
|
-
|
|
264
|
+
resourceWarnings;
|
|
265
|
+
constructor(environment, threadConfig, developerInstructions, skillRoots, selectedSkills, expectedMcpServers, resources, portableTools, mcpAccess, credentialIssuedAtMs, credentialExpiresAtMs, resourceWarnings = []) {
|
|
264
266
|
this.environment = environment;
|
|
265
267
|
this.threadConfig = threadConfig;
|
|
266
268
|
this.developerInstructions = developerInstructions;
|
|
267
269
|
this.skillRoots = skillRoots;
|
|
268
270
|
this.selectedSkills = selectedSkills;
|
|
269
271
|
this.expectedMcpServers = expectedMcpServers;
|
|
272
|
+
this.resources = resources;
|
|
270
273
|
this.portableTools = portableTools;
|
|
271
274
|
this.mcpAccess = mcpAccess;
|
|
272
275
|
this.credentialIssuedAtMs = credentialIssuedAtMs;
|
|
273
276
|
this.credentialExpiresAtMs = credentialExpiresAtMs;
|
|
277
|
+
this.resourceWarnings = resourceWarnings;
|
|
274
278
|
}
|
|
275
279
|
static async prepare(input) {
|
|
276
280
|
const resourceEnvironment = { ...(input.resources?.getAdapterEnvironment() ?? {}) };
|
|
@@ -323,7 +327,7 @@ export class CodexNativeResourceDelivery {
|
|
|
323
327
|
const selectedSkills = input.resources
|
|
324
328
|
? await Promise.all(input.resources.getInspection().skills.flatMap((skill) => {
|
|
325
329
|
const path = skill.materializedPath;
|
|
326
|
-
return path ? [{ name: skill.name, path }] : [];
|
|
330
|
+
return path ? [{ contributionId: skill.contributionId, name: skill.name, path }] : [];
|
|
327
331
|
}).map(async (skill) => ({ ...skill, path: await realpath(skill.path) })))
|
|
328
332
|
: [];
|
|
329
333
|
const materializedSkillsRoot = input.resources?.getInspection().paths?.skills;
|
|
@@ -339,7 +343,7 @@ export class CodexNativeResourceDelivery {
|
|
|
339
343
|
: { multi_agent: false, multi_agent_v2: false };
|
|
340
344
|
threadConfig.agents = { enabled: input.nativeSubagentsEnabled };
|
|
341
345
|
}
|
|
342
|
-
return new CodexNativeResourceDelivery(resourceEnvironment, Object.keys(threadConfig).length > 0 ? threadConfig : undefined, buildDeveloperInstructions(input.resources), skillRoots, selectedSkills, expectedMcpServers, input.portableTools, mcpAccess, credentialIssuedAtMs, credentialExpiresAtMs);
|
|
346
|
+
return new CodexNativeResourceDelivery(resourceEnvironment, Object.keys(threadConfig).length > 0 ? threadConfig : undefined, buildDeveloperInstructions(input.resources), skillRoots, selectedSkills, expectedMcpServers, input.resources, input.portableTools, mcpAccess, credentialIssuedAtMs, credentialExpiresAtMs);
|
|
343
347
|
}
|
|
344
348
|
catch (error) {
|
|
345
349
|
if (mcpAccess && input.portableTools)
|
|
@@ -350,6 +354,9 @@ export class CodexNativeResourceDelivery {
|
|
|
350
354
|
get hasMcpServers() {
|
|
351
355
|
return this.expectedMcpServers.length > 0;
|
|
352
356
|
}
|
|
357
|
+
get warnings() {
|
|
358
|
+
return this.resourceWarnings;
|
|
359
|
+
}
|
|
353
360
|
get enabledToolNames() {
|
|
354
361
|
return this.expectedMcpServers
|
|
355
362
|
.flatMap((server) => server.toolNames.map((toolName) => `${server.name}/${toolName}`))
|
|
@@ -379,6 +386,7 @@ export class CodexNativeResourceDelivery {
|
|
|
379
386
|
this.credentialExpiresAtMs = expiresAt;
|
|
380
387
|
}
|
|
381
388
|
async configureProcess(client, workspace) {
|
|
389
|
+
this.resourceWarnings = [];
|
|
382
390
|
if (this.skillRoots.length === 0)
|
|
383
391
|
return;
|
|
384
392
|
let response;
|
|
@@ -411,15 +419,35 @@ export class CodexNativeResourceDelivery {
|
|
|
411
419
|
}
|
|
412
420
|
}
|
|
413
421
|
}
|
|
422
|
+
const collisions = new Set();
|
|
414
423
|
for (const skill of this.selectedSkills) {
|
|
415
424
|
const sameNamePaths = loadedSkills.get(skill.name) ?? new Set();
|
|
416
425
|
const conflictingPath = [...sameNamePaths].find((path) => path !== skill.path);
|
|
417
|
-
if (conflictingPath)
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
if (!loadedPaths.has(skill.path))
|
|
426
|
+
if (conflictingPath)
|
|
427
|
+
collisions.add(skill.name);
|
|
428
|
+
if (!loadedPaths.has(skill.path) && !conflictingPath)
|
|
421
429
|
throw new Error(`Codex did not load selected Pibo skill "${skill.name}".`);
|
|
422
430
|
}
|
|
431
|
+
let collisionMessage;
|
|
432
|
+
if (collisions.size > 0) {
|
|
433
|
+
const names = [...collisions].sort().map((name) => `"${name}"`).join(", ");
|
|
434
|
+
collisionMessage = `Codex native skill name collision for ${names}: the selected Pibo skill remains materialized, but precedence is ambiguous. Rename or disable one source to remove the collision.`;
|
|
435
|
+
this.resourceWarnings = [{
|
|
436
|
+
code: "codex_native_skill_name_collision",
|
|
437
|
+
message: collisionMessage,
|
|
438
|
+
}];
|
|
439
|
+
}
|
|
440
|
+
this.resources?.recordAdapterDelivery?.(this.selectedSkills.map((skill) => {
|
|
441
|
+
const collided = collisions.has(skill.name);
|
|
442
|
+
return {
|
|
443
|
+
contributionId: skill.contributionId,
|
|
444
|
+
status: collided ? "degraded" : "delivered",
|
|
445
|
+
mode: "codex-extra-roots",
|
|
446
|
+
fidelity: collided ? "lossy" : "exact",
|
|
447
|
+
target: skill.path,
|
|
448
|
+
...(collided && collisionMessage ? { diagnostic: collisionMessage } : {}),
|
|
449
|
+
};
|
|
450
|
+
}));
|
|
423
451
|
}
|
|
424
452
|
async verifyThread(client, threadId) {
|
|
425
453
|
if (this.expectedMcpServers.length === 0)
|
|
@@ -631,13 +631,9 @@ class OmpAgentRuntimeAdapter {
|
|
|
631
631
|
}
|
|
632
632
|
return emptyOmpHistoryPage(this.instanceId);
|
|
633
633
|
}
|
|
634
|
-
async resolveBinding() {
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
runtimeInstanceId: this.instanceId,
|
|
638
|
-
adapterId: OMP_ADAPTER_ID,
|
|
639
|
-
state: "unbound",
|
|
640
|
-
};
|
|
634
|
+
async resolveBinding(input) {
|
|
635
|
+
// OMP can verify and resume the transcript only after startup via switch_session.
|
|
636
|
+
return structuredClone(input.binding);
|
|
641
637
|
}
|
|
642
638
|
}
|
|
643
639
|
export const OMP_AGENT_RUNTIME_DRIVER = {
|
|
@@ -135,6 +135,7 @@ function cloneProfileForPiSession(input) {
|
|
|
135
135
|
parentSessionId: profile.parentSessionId,
|
|
136
136
|
model: profile.model,
|
|
137
137
|
mainModel: profile.mainModel,
|
|
138
|
+
mainModelFallbacks: profile.mainModelFallbacks,
|
|
138
139
|
subagentModel: profile.subagentModel,
|
|
139
140
|
thinkingLevel: profile.thinkingLevel,
|
|
140
141
|
mainThinkingLevel: profile.mainThinkingLevel,
|
|
@@ -148,6 +149,7 @@ function cloneProfileForPiSession(input) {
|
|
|
148
149
|
mcpServers: profile.mcpServers,
|
|
149
150
|
piPackages: profile.piPackages,
|
|
150
151
|
contextFiles: profile.contextFiles,
|
|
152
|
+
diagnostics: profile.diagnostics,
|
|
151
153
|
builtinTools: profile.builtinTools,
|
|
152
154
|
builtinToolNames: profile.builtinToolNames,
|
|
153
155
|
autoContextFiles: profile.autoContextFiles,
|
|
@@ -276,7 +278,7 @@ class PiAgentRuntimeSession {
|
|
|
276
278
|
bindingNativeSessionId;
|
|
277
279
|
nativePresenceExpected;
|
|
278
280
|
disposed = false;
|
|
279
|
-
constructor(runtimeInstanceId, piboSessionId, runtime, binding, initialFastMode, providerWebSearchEnabled) {
|
|
281
|
+
constructor(runtimeInstanceId, piboSessionId, runtime, binding, initialFastMode, providerWebSearchEnabled, providerFallbacksEnabled) {
|
|
280
282
|
this.runtimeInstanceId = runtimeInstanceId;
|
|
281
283
|
this.piboSessionId = piboSessionId;
|
|
282
284
|
this.runtime = runtime;
|
|
@@ -284,7 +286,7 @@ class PiAgentRuntimeSession {
|
|
|
284
286
|
this.cwd = runtime.cwd;
|
|
285
287
|
this.bindingNativeSessionId = runtime.session.sessionId;
|
|
286
288
|
this.nativePresenceExpected = runtime.session.sessionManager.buildSessionContext().messages.length > 0;
|
|
287
|
-
this.routed = new PiRoutedSession(piboSessionId, runtime, (event) => this.handlePiboEvent(event), PiboPluginRegistry.create(), true, undefined, initialFastMode, undefined, undefined, (state) => this.handleEngineState(state));
|
|
289
|
+
this.routed = new PiRoutedSession(piboSessionId, runtime, (event) => this.handlePiboEvent(event), PiboPluginRegistry.create(), true, undefined, initialFastMode, undefined, undefined, (state) => this.handleEngineState(state), undefined, undefined, providerFallbacksEnabled);
|
|
288
290
|
if (providerWebSearchEnabled)
|
|
289
291
|
this.routed.enableProviderWebSearchObservation();
|
|
290
292
|
this.controls = this.createControls();
|
|
@@ -685,7 +687,7 @@ class PiAgentRuntimeAdapter {
|
|
|
685
687
|
&& runtime.session.sessionManager.buildSessionContext().messages.length > 0,
|
|
686
688
|
},
|
|
687
689
|
};
|
|
688
|
-
return new PiAgentRuntimeSession(this.instanceId, input.piboSession.id, runtime, binding, compatibility?.initialFastMode ?? false, profile.tools.some((tool) => tool.enabled !== false && isWebSearchProviderTool(tool)));
|
|
690
|
+
return new PiAgentRuntimeSession(this.instanceId, input.piboSession.id, runtime, binding, compatibility?.initialFastMode ?? false, profile.tools.some((tool) => tool.enabled !== false && isWebSearchProviderTool(tool)), compatibility?.providerFallbacksEnabled ?? false);
|
|
689
691
|
}
|
|
690
692
|
loadModelCatalog() {
|
|
691
693
|
const now = Date.now();
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname } from "node:path";
|
|
1
3
|
import { SessionManager, shouldCompact } from "@earendil-works/pi-coding-agent";
|
|
2
4
|
import { PiboSteeringUnavailableError } from "../../core/events.js";
|
|
3
5
|
import { getOpenAiCodexProviderUsageForActiveModel } from "../../auth/openai-codex-usage.js";
|
|
@@ -18,6 +20,16 @@ const RUN_REMINDER_CAPABILITY_TOOLS = new Set([
|
|
|
18
20
|
"pibo_run_cancel",
|
|
19
21
|
"pibo_run_ack",
|
|
20
22
|
]);
|
|
23
|
+
function materializeForkedSession(sessionManager) {
|
|
24
|
+
const sessionFile = sessionManager.getSessionFile();
|
|
25
|
+
const header = sessionManager.getHeader();
|
|
26
|
+
if (!sessionManager.isPersisted() || !sessionFile || !header || existsSync(sessionFile))
|
|
27
|
+
return;
|
|
28
|
+
mkdirSync(dirname(sessionFile), { recursive: true });
|
|
29
|
+
writeFileSync(sessionFile, `${[header, ...sessionManager.getEntries()].map((entry) => JSON.stringify(entry)).join("\n")}\n`, { encoding: "utf8", flag: "wx" });
|
|
30
|
+
// Reload through the public API so Pi also records that the file is flushed.
|
|
31
|
+
sessionManager.setSessionFile(sessionFile);
|
|
32
|
+
}
|
|
21
33
|
function modelSupportsFastServiceTier(model) {
|
|
22
34
|
if (!model)
|
|
23
35
|
return false;
|
|
@@ -587,6 +599,7 @@ export class RoutedSession {
|
|
|
587
599
|
onStateChange;
|
|
588
600
|
onMessagesInterrupted;
|
|
589
601
|
messagePreflight;
|
|
602
|
+
providerFallbacksEnabled;
|
|
590
603
|
queue = [];
|
|
591
604
|
processing = false;
|
|
592
605
|
disposed = false;
|
|
@@ -605,6 +618,9 @@ export class RoutedSession {
|
|
|
605
618
|
nextAssistantIndex = 0;
|
|
606
619
|
activeThinkingIndex;
|
|
607
620
|
nextThinkingIndex = 0;
|
|
621
|
+
nextUsageIndex = 0;
|
|
622
|
+
activeCompactionIndex;
|
|
623
|
+
nextCompactionIndex = 0;
|
|
608
624
|
sessionIdentityOperationInFlight = false;
|
|
609
625
|
pendingAssistantError;
|
|
610
626
|
pendingAssistantErrorRetryable = false;
|
|
@@ -616,7 +632,7 @@ export class RoutedSession {
|
|
|
616
632
|
recoverySession;
|
|
617
633
|
isContinuePatched = false;
|
|
618
634
|
compatibilityAuthController;
|
|
619
|
-
constructor(piboSessionId, runtime, emit, pluginRegistry, forwardPiEvents, onPiEventTelemetry, initialFastMode, onSessionOperation, onKillChildren, onStateChange, onMessagesInterrupted, messagePreflight) {
|
|
635
|
+
constructor(piboSessionId, runtime, emit, pluginRegistry, forwardPiEvents, onPiEventTelemetry, initialFastMode, onSessionOperation, onKillChildren, onStateChange, onMessagesInterrupted, messagePreflight, providerFallbacksEnabled = false) {
|
|
620
636
|
this.piboSessionId = piboSessionId;
|
|
621
637
|
this.runtime = runtime;
|
|
622
638
|
this.emit = emit;
|
|
@@ -628,6 +644,7 @@ export class RoutedSession {
|
|
|
628
644
|
this.onStateChange = onStateChange;
|
|
629
645
|
this.onMessagesInterrupted = onMessagesInterrupted;
|
|
630
646
|
this.messagePreflight = messagePreflight;
|
|
647
|
+
this.providerFallbacksEnabled = providerFallbacksEnabled;
|
|
631
648
|
this.fastMode = initialFastMode && this.fastModeSupported();
|
|
632
649
|
this.bindRuntimeSession();
|
|
633
650
|
this.patchProviderRequest();
|
|
@@ -1005,26 +1022,34 @@ export class RoutedSession {
|
|
|
1005
1022
|
const candidate = event;
|
|
1006
1023
|
const eventId = this.activeMessage?.id ?? this.activeExecutionEvent?.id;
|
|
1007
1024
|
if (candidate.type === "compaction_start") {
|
|
1025
|
+
const compactionIndex = this.activeCompactionIndex ?? this.nextCompactionIndex;
|
|
1026
|
+
if (this.activeCompactionIndex === undefined)
|
|
1027
|
+
this.nextCompactionIndex += 1;
|
|
1028
|
+
this.activeCompactionIndex = compactionIndex;
|
|
1008
1029
|
this.emit(this.withActiveMessage({
|
|
1009
1030
|
type: "compaction_start",
|
|
1010
1031
|
piboSessionId: this.piboSessionId,
|
|
1011
1032
|
eventId,
|
|
1033
|
+
compactionIndex,
|
|
1012
1034
|
reason: typeof candidate.reason === "string" ? candidate.reason : "unknown",
|
|
1013
1035
|
}));
|
|
1014
1036
|
}
|
|
1015
1037
|
if (candidate.type === "compaction_end") {
|
|
1038
|
+
const compactionIndex = this.activeCompactionIndex ?? this.nextCompactionIndex;
|
|
1039
|
+
if (this.activeCompactionIndex === undefined)
|
|
1040
|
+
this.nextCompactionIndex += 1;
|
|
1041
|
+
this.activeCompactionIndex = undefined;
|
|
1016
1042
|
if (candidate.result && candidate.aborted !== true) {
|
|
1017
|
-
//
|
|
1018
|
-
//
|
|
1043
|
+
// End any open output block, but keep durable part indices monotonic for
|
|
1044
|
+
// the lifetime of the routed event across context-guard continuation.
|
|
1019
1045
|
this.activeAssistantIndex = undefined;
|
|
1020
|
-
this.nextAssistantIndex = 0;
|
|
1021
1046
|
this.activeThinkingIndex = undefined;
|
|
1022
|
-
this.nextThinkingIndex = 0;
|
|
1023
1047
|
}
|
|
1024
1048
|
this.emit(this.withActiveMessage({
|
|
1025
1049
|
type: "compaction_end",
|
|
1026
1050
|
piboSessionId: this.piboSessionId,
|
|
1027
1051
|
eventId,
|
|
1052
|
+
compactionIndex,
|
|
1028
1053
|
reason: typeof candidate.reason === "string" ? candidate.reason : "unknown",
|
|
1029
1054
|
result: candidate.result,
|
|
1030
1055
|
aborted: candidate.aborted === true,
|
|
@@ -1082,9 +1107,15 @@ export class RoutedSession {
|
|
|
1082
1107
|
if (event.action === "compact") {
|
|
1083
1108
|
return this.enqueueCompactAction(event);
|
|
1084
1109
|
}
|
|
1085
|
-
const
|
|
1086
|
-
|
|
1087
|
-
|
|
1110
|
+
const sessionIdentityOperation = event.action === "session.fork"
|
|
1111
|
+
? "fork"
|
|
1112
|
+
: event.action === "session.clone"
|
|
1113
|
+
? "clone"
|
|
1114
|
+
: event.action === "session.switch"
|
|
1115
|
+
? "switch"
|
|
1116
|
+
: undefined;
|
|
1117
|
+
if (sessionIdentityOperation) {
|
|
1118
|
+
this.assertSessionIdentityOperationIdle(sessionIdentityOperation);
|
|
1088
1119
|
this.sessionIdentityOperationInFlight = true;
|
|
1089
1120
|
}
|
|
1090
1121
|
try {
|
|
@@ -1102,7 +1133,7 @@ export class RoutedSession {
|
|
|
1102
1133
|
return output;
|
|
1103
1134
|
}
|
|
1104
1135
|
finally {
|
|
1105
|
-
if (
|
|
1136
|
+
if (sessionIdentityOperation)
|
|
1106
1137
|
this.sessionIdentityOperationInFlight = false;
|
|
1107
1138
|
}
|
|
1108
1139
|
}
|
|
@@ -1213,6 +1244,11 @@ export class RoutedSession {
|
|
|
1213
1244
|
this.assertSessionWorkIdle("fork");
|
|
1214
1245
|
const previous = this.createSessionSnapshot();
|
|
1215
1246
|
const result = await this.runtime.fork(entryId);
|
|
1247
|
+
if (!result.cancelled) {
|
|
1248
|
+
// Pi defers persistence until an assistant message. Materialize an empty
|
|
1249
|
+
// first-message branch so history readers can use its advertised path.
|
|
1250
|
+
materializeForkedSession(this.runtime.session.sessionManager);
|
|
1251
|
+
}
|
|
1216
1252
|
return {
|
|
1217
1253
|
piboSessionId: this.piboSessionId,
|
|
1218
1254
|
previous,
|
|
@@ -1518,6 +1554,9 @@ export class RoutedSession {
|
|
|
1518
1554
|
this.nextAssistantIndex = 0;
|
|
1519
1555
|
this.activeThinkingIndex = undefined;
|
|
1520
1556
|
this.nextThinkingIndex = 0;
|
|
1557
|
+
this.nextUsageIndex = 0;
|
|
1558
|
+
this.activeCompactionIndex = undefined;
|
|
1559
|
+
this.nextCompactionIndex = 0;
|
|
1521
1560
|
this.emit({
|
|
1522
1561
|
type: "message_started",
|
|
1523
1562
|
piboSessionId: this.piboSessionId,
|
|
@@ -1539,7 +1578,8 @@ export class RoutedSession {
|
|
|
1539
1578
|
await this.resumeContextGuardRecovery(session);
|
|
1540
1579
|
if (this.disposed || inFlight.cancelled)
|
|
1541
1580
|
return;
|
|
1542
|
-
|
|
1581
|
+
if (!this.providerFallbacksEnabled)
|
|
1582
|
+
await this.recoverTransientProviderErrors(session);
|
|
1543
1583
|
if (this.disposed || inFlight.cancelled)
|
|
1544
1584
|
return;
|
|
1545
1585
|
this.flushPendingAssistantError();
|
|
@@ -1578,6 +1618,9 @@ export class RoutedSession {
|
|
|
1578
1618
|
this.nextAssistantIndex = 0;
|
|
1579
1619
|
this.activeThinkingIndex = undefined;
|
|
1580
1620
|
this.nextThinkingIndex = 0;
|
|
1621
|
+
this.nextUsageIndex = 0;
|
|
1622
|
+
this.activeCompactionIndex = undefined;
|
|
1623
|
+
this.nextCompactionIndex = 0;
|
|
1581
1624
|
this.providerWebSearchLifecycle.clear();
|
|
1582
1625
|
if (this.inFlightMessage === inFlight)
|
|
1583
1626
|
this.inFlightMessage = undefined;
|
|
@@ -1817,8 +1860,12 @@ export class RoutedSession {
|
|
|
1817
1860
|
this.activeThinkingIndex = undefined;
|
|
1818
1861
|
return output;
|
|
1819
1862
|
}
|
|
1820
|
-
if (event.type === "assistant_usage"
|
|
1821
|
-
|
|
1863
|
+
if (event.type === "assistant_usage") {
|
|
1864
|
+
const usageIndex = this.nextUsageIndex;
|
|
1865
|
+
this.nextUsageIndex += 1;
|
|
1866
|
+
return { ...event, ...correlation, usageIndex };
|
|
1867
|
+
}
|
|
1868
|
+
if (event.type === "compaction_start" ||
|
|
1822
1869
|
event.type === "compaction_end" ||
|
|
1823
1870
|
event.type === "tool_call" ||
|
|
1824
1871
|
event.type === "tool_execution_started" ||
|
|
@@ -332,6 +332,10 @@ export async function createPiboRuntime(options = {}) {
|
|
|
332
332
|
}
|
|
333
333
|
const resourceLoader = services.resourceLoader;
|
|
334
334
|
const diagnostics = [
|
|
335
|
+
...profile.diagnostics.map((diagnostic) => ({
|
|
336
|
+
type: diagnostic.severity,
|
|
337
|
+
message: `[${diagnostic.code}] ${diagnostic.message}`,
|
|
338
|
+
})),
|
|
335
339
|
...piPackageOptions.diagnostics,
|
|
336
340
|
...services.diagnostics,
|
|
337
341
|
...collectResourceDiagnostics(resourceLoader.getSkills().diagnostics),
|
|
@@ -416,6 +420,7 @@ export async function inspectPiboProfile(options = {}) {
|
|
|
416
420
|
mcpServers: profile.mcpServers,
|
|
417
421
|
piPackages: profile.piPackages,
|
|
418
422
|
contextFiles: profile.contextFiles,
|
|
423
|
+
diagnostics: profile.diagnostics,
|
|
419
424
|
builtinTools: profile.builtinTools,
|
|
420
425
|
builtinToolNames: profile.builtinToolNames,
|
|
421
426
|
autoContextFiles: profile.autoContextFiles,
|
|
@@ -456,6 +461,7 @@ export async function inspectPiboProfile(options = {}) {
|
|
|
456
461
|
runtimeOptions: structuredClone(profile.runtimeOptions),
|
|
457
462
|
...(profile.model ? { model: { ...profile.model } } : {}),
|
|
458
463
|
...(profile.mainModel ? { mainModel: { ...profile.mainModel } } : {}),
|
|
464
|
+
mainModelFallbacks: profile.mainModelFallbacks.map((model) => ({ ...model })),
|
|
459
465
|
...(profile.subagentModel ? { subagentModel: { ...profile.subagentModel } } : {}),
|
|
460
466
|
...(profile.thinkingLevel ? { thinkingLevel: profile.thinkingLevel } : {}),
|
|
461
467
|
...(profile.mainThinkingLevel ? { mainThinkingLevel: profile.mainThinkingLevel } : {}),
|
|
@@ -14,6 +14,14 @@ export function createCustomAgentProfileDefinition(agent, options = {}) {
|
|
|
14
14
|
catch (error) {
|
|
15
15
|
if (!isUnknownSkillError(error, skillName))
|
|
16
16
|
throw error;
|
|
17
|
+
const message = `Unknown skill "${skillName}" referenced by custom agent "${agent.profileName}"`;
|
|
18
|
+
builder.addDiagnostic({
|
|
19
|
+
severity: "warning",
|
|
20
|
+
code: "custom_agent_unknown_skill",
|
|
21
|
+
message,
|
|
22
|
+
resourceKind: "skill",
|
|
23
|
+
resourceName: skillName,
|
|
24
|
+
});
|
|
17
25
|
if (shouldWarnMissingReferences)
|
|
18
26
|
console.warn(`Skipping unknown skill "${skillName}" for custom agent "${agent.profileName}"`);
|
|
19
27
|
}
|
|
@@ -25,12 +33,29 @@ export function createCustomAgentProfileDefinition(agent, options = {}) {
|
|
|
25
33
|
catch (error) {
|
|
26
34
|
if (!isUnknownContextFileError(error, contextFileKey))
|
|
27
35
|
throw error;
|
|
36
|
+
const message = `Unknown context file "${contextFileKey}" referenced by custom agent "${agent.profileName}"`;
|
|
37
|
+
builder.addDiagnostic({
|
|
38
|
+
severity: "warning",
|
|
39
|
+
code: "custom_agent_unknown_context_file",
|
|
40
|
+
message,
|
|
41
|
+
resourceKind: "context-file",
|
|
42
|
+
resourceName: contextFileKey,
|
|
43
|
+
});
|
|
28
44
|
if (shouldWarnMissingReferences)
|
|
29
45
|
console.warn(`Skipping unknown context file "${contextFileKey}" for custom agent "${agent.profileName}"`);
|
|
30
46
|
}
|
|
31
47
|
}
|
|
32
|
-
for (const toolName of agent.nativeTools)
|
|
33
|
-
|
|
48
|
+
for (const toolName of agent.nativeTools) {
|
|
49
|
+
try {
|
|
50
|
+
builder.addTool(context.getTool(toolName));
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
if (!isUnknownToolError(error, toolName))
|
|
54
|
+
throw error;
|
|
55
|
+
if (shouldWarnMissingReferences)
|
|
56
|
+
console.warn(`Skipping unknown tool "${toolName}" for custom agent "${agent.profileName}"`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
34
59
|
for (const subagent of agent.subagents)
|
|
35
60
|
builder.addSubagent(subagent);
|
|
36
61
|
return builder.createSession();
|
|
@@ -61,6 +86,7 @@ function createCustomAgentBuilder(agent) {
|
|
|
61
86
|
.withToolPackages({ runControl: agent.runControl, goalControl: agent.goalControl ?? true });
|
|
62
87
|
if (agent.mainModel)
|
|
63
88
|
builder.withMainModel(agent.mainModel);
|
|
89
|
+
builder.withMainModelFallbacks(agent.mainModelFallbacks ?? []);
|
|
64
90
|
if (agent.subagentModel)
|
|
65
91
|
builder.withSubagentModel(agent.subagentModel);
|
|
66
92
|
if (agent.thinkingLevel)
|
|
@@ -80,6 +106,9 @@ function createCustomAgentBuilder(agent) {
|
|
|
80
106
|
function uniqueAliases(aliases, profileName) {
|
|
81
107
|
return [...new Set(aliases.filter((alias) => alias && alias !== profileName))];
|
|
82
108
|
}
|
|
109
|
+
function isUnknownToolError(error, toolName) {
|
|
110
|
+
return error instanceof Error && error.message === `Unknown tool "${toolName}"`;
|
|
111
|
+
}
|
|
83
112
|
function isUnknownContextFileError(error, contextFileKey) {
|
|
84
113
|
return error instanceof Error && error.message === `Unknown context file "${contextFileKey}"`;
|
|
85
114
|
}
|