@pasko70/pibo 2.4.1 → 2.4.3
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-runtime/context-build.js +100 -11
- package/dist/agent-runtime/profile-validation.js +3 -0
- package/dist/agent-runtime/resource-service.js +16 -0
- package/dist/agent-runtime/routed-session.js +180 -30
- package/dist/agent-runtime/testing/fake-adapter.js +7 -0
- package/dist/agent-runtimes/pi/adapter.js +2 -0
- package/dist/agent-runtimes/pi/routed-session.js +104 -43
- package/dist/agent-runtimes/pi/runtime.js +8 -5
- package/dist/apps/chat/web-app.js +21 -6
- package/dist/apps/chat-ui/assets/{dist-Cw9po47P.js → dist-C4JGcQjh.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-BeqHbnGN.js → dist-CF92Lv76.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-DTRjeLwO.js → dist-CJ0JS-bE.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-3YG57JXi.js → dist-DrgKyb9n.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-CrDtveZB.js → dist-VoMyV-PE.js} +1 -1
- package/dist/apps/chat-ui/assets/index-0WZI2phJ.css +1 -0
- package/dist/apps/chat-ui/assets/index-DhX1_aRM.js +228 -0
- package/dist/apps/chat-ui/index.html +2 -2
- package/dist/apps/vscode-artifacts/latest.vsix +0 -0
- package/dist/apps/vscode-artifacts/{pibo-vscode-ext-2.4.1.vsix → pibo-vscode-ext-2.4.3.vsix} +0 -0
- package/dist/cli.js +16 -6
- package/dist/core/context-build.js +66 -6
- package/dist/core/model-defaults.js +11 -3
- package/dist/core/session-router.js +285 -112
- package/dist/gateway/server.js +1 -0
- package/dist/loops/accounting.js +80 -0
- package/dist/loops/service.js +52 -13
- package/dist/loops/store.js +67 -19
- package/dist/loops/tools.js +3 -1
- package/dist/reliability/store.js +11 -6
- package/dist/runs/lifecycle.js +38 -1
- package/dist/runs/registry.js +46 -45
- package/dist/runs/tools.js +34 -24
- package/dist/subagents/context.js +48 -0
- package/dist/subagents/runtime-selection.js +28 -0
- package/dist/subagents/tool.js +28 -6
- package/dist/tools/codex-compat.js +1 -0
- package/dist/tools/contract.js +10 -0
- package/dist/tools/mcp-bridge.js +4 -2
- package/dist/tools/runtime/node-backend.js +8 -2
- package/dist/tools/runtime/python-backend.js +8 -2
- package/dist/tools/runtime/tool.js +1 -0
- package/dist/tools/session-tool-set.js +19 -12
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/dist/apps/chat-ui/assets/index-AjnP3ci-.js +0 -228
- package/dist/apps/chat-ui/assets/index-BJ56TREg.css +0 -1
|
@@ -1,5 +1,11 @@
|
|
|
1
|
+
import { createPiboRuntimeResolutionManifest, } from "../core/context-build.js";
|
|
1
2
|
import { InitialSessionContext } from "../core/profiles.js";
|
|
2
3
|
import { PIBO_AGENT_TOOL_NAMES, listAvailableAgents } from "../subagents/tool.js";
|
|
4
|
+
import { PIBO_DELEGATED_AGENT_CONTEXT_PATH } from "../subagents/context.js";
|
|
5
|
+
import { PIBO_RUN_TOOL_NAMES } from "../runs/tools.js";
|
|
6
|
+
import { PIBO_GOAL_TOOL_NAMES } from "../loops/tools.js";
|
|
7
|
+
import { CODEX_COMPAT_TOOL_NAMES } from "../tools/codex-compat.js";
|
|
8
|
+
import { isEnabledRuntimeToolProfile, materializePiboProfileTools, } from "../tools/session-tool-set.js";
|
|
3
9
|
export function profileWithRuntimeInstance(profile, runtimeInstanceId) {
|
|
4
10
|
if (profile.runtimeInstanceId === runtimeInstanceId)
|
|
5
11
|
return profile;
|
|
@@ -41,10 +47,100 @@ export function uniqueRuntimeDiagnostics(diagnostics) {
|
|
|
41
47
|
return true;
|
|
42
48
|
});
|
|
43
49
|
}
|
|
50
|
+
function uniqueNames(values) {
|
|
51
|
+
return [...new Set(values)];
|
|
52
|
+
}
|
|
44
53
|
export function buildPortableRuntimeContextSnapshot(input) {
|
|
45
54
|
const profile = input.profile;
|
|
46
55
|
const nodes = [];
|
|
47
56
|
const addNode = (node) => nodes.push({ ...node, order: nodes.length });
|
|
57
|
+
const availableAgents = listAvailableAgents(profile.subagents);
|
|
58
|
+
const delegatedSendAvailable = availableAgents.length > 0;
|
|
59
|
+
const toolContext = {
|
|
60
|
+
piboSessionId: input.piboSessionId,
|
|
61
|
+
piboRoomId: input.piboRoomId,
|
|
62
|
+
profileName: profile.profileName,
|
|
63
|
+
cwd: input.cwd,
|
|
64
|
+
};
|
|
65
|
+
const materializedProfileTools = materializePiboProfileTools(profile, toolContext);
|
|
66
|
+
const runtimeProfileTool = profile.tools.find(isEnabledRuntimeToolProfile);
|
|
67
|
+
const callableProfileTools = [
|
|
68
|
+
...materializedProfileTools.map((tool) => ({ name: tool.definition.name, yieldable: tool.profile.yieldable })),
|
|
69
|
+
...(runtimeProfileTool ? [{ name: "runtime", yieldable: runtimeProfileTool.yieldable }] : []),
|
|
70
|
+
];
|
|
71
|
+
const profileToolNames = callableProfileTools.map((tool) => tool.name);
|
|
72
|
+
const directAgentToolNames = delegatedSendAvailable
|
|
73
|
+
? PIBO_AGENT_TOOL_NAMES.filter((name) => name !== "pibo_agents_send_message")
|
|
74
|
+
: [];
|
|
75
|
+
const codexCompatToolNames = profile.toolPackages.codexCompat === true ? [...CODEX_COMPAT_TOOL_NAMES] : [];
|
|
76
|
+
const explicitYieldableToolNames = uniqueNames([
|
|
77
|
+
...callableProfileTools.filter((tool) => tool.yieldable !== false).map((tool) => tool.name),
|
|
78
|
+
...(delegatedSendAvailable ? PIBO_AGENT_TOOL_NAMES : []),
|
|
79
|
+
...codexCompatToolNames,
|
|
80
|
+
]);
|
|
81
|
+
const yieldableToolNames = profile.toolPackages.runControl === true
|
|
82
|
+
? explicitYieldableToolNames
|
|
83
|
+
: delegatedSendAvailable ? ["pibo_agents_send_message"] : [];
|
|
84
|
+
const runControlAvailable = yieldableToolNames.length > 0;
|
|
85
|
+
const activeToolNames = uniqueNames([
|
|
86
|
+
...profileToolNames,
|
|
87
|
+
...directAgentToolNames,
|
|
88
|
+
...codexCompatToolNames,
|
|
89
|
+
...(profile.toolPackages.goalControl !== false ? PIBO_GOAL_TOOL_NAMES : []),
|
|
90
|
+
...(runControlAvailable ? PIBO_RUN_TOOL_NAMES : []),
|
|
91
|
+
]);
|
|
92
|
+
const activeToolPackages = [
|
|
93
|
+
...(profile.toolPackages.goalControl !== false ? ["pibo-goal-control"] : []),
|
|
94
|
+
...(profile.toolPackages.codexCompat === true ? ["codex-compat"] : []),
|
|
95
|
+
...(runControlAvailable ? ["pibo-run-control"] : []),
|
|
96
|
+
];
|
|
97
|
+
const managedToolDisplayNames = [
|
|
98
|
+
...activeToolNames,
|
|
99
|
+
...yieldableToolNames.map((name) => `yielded-target:${name}`),
|
|
100
|
+
...availableAgents.map((agent) => `agent:${agent.name} (${agent.profile}) — ${agent.description}`),
|
|
101
|
+
...activeToolPackages.map((name) => name === "pibo-run-control" && profile.toolPackages.runControl !== true
|
|
102
|
+
? "package:pibo-run-control (automatic for delegation)"
|
|
103
|
+
: `package:${name}`),
|
|
104
|
+
];
|
|
105
|
+
const manifestContextPaths = input.resources
|
|
106
|
+
? input.resources.context.flatMap((contribution) => {
|
|
107
|
+
const path = contribution.materializedPath ?? contribution.path ?? contribution.sourcePath;
|
|
108
|
+
return path ? [path] : [];
|
|
109
|
+
})
|
|
110
|
+
: [
|
|
111
|
+
"pibo://runtime/session-context.md",
|
|
112
|
+
...profile.contextFiles.filter((file) => file.enabled !== false).map((file) => file.key ?? file.path),
|
|
113
|
+
...(delegatedSendAvailable ? [PIBO_DELEGATED_AGENT_CONTEXT_PATH] : []),
|
|
114
|
+
];
|
|
115
|
+
const runtimeManifest = createPiboRuntimeResolutionManifest({
|
|
116
|
+
profile,
|
|
117
|
+
cwd: input.cwd,
|
|
118
|
+
adapterId: input.runtime.adapterId,
|
|
119
|
+
piboSessionId: input.piboSessionId,
|
|
120
|
+
piboRoomId: input.piboRoomId,
|
|
121
|
+
activeModel: input.activeModel,
|
|
122
|
+
thinkingLevel: input.thinkingLevel,
|
|
123
|
+
toolSurface: "pibo-managed-only",
|
|
124
|
+
activeToolNames,
|
|
125
|
+
yieldableToolNames,
|
|
126
|
+
activeToolPackages,
|
|
127
|
+
contextFilePaths: manifestContextPaths,
|
|
128
|
+
skillNames: input.resources
|
|
129
|
+
? input.resources.skills.map((skill) => skill.name)
|
|
130
|
+
: profile.skills.filter((skill) => skill.enabled !== false).map((skill) => skill.name),
|
|
131
|
+
modelDefaults: input.modelDefaults,
|
|
132
|
+
subagentProfileResolver: input.subagentProfileResolver,
|
|
133
|
+
});
|
|
134
|
+
addNode({
|
|
135
|
+
id: "runtime-manifest",
|
|
136
|
+
kind: "runtime_manifest",
|
|
137
|
+
title: "Runtime Resolution Manifest",
|
|
138
|
+
source: "runtime",
|
|
139
|
+
state: "active",
|
|
140
|
+
badges: ["RESOLVED", "READ-ONLY", "PIBO-MANAGED-TOOLS"],
|
|
141
|
+
payloadJson: runtimeManifest,
|
|
142
|
+
notes: ["Resolution evidence for this inspection only. It is not a second profile configuration and is not injected into the agent prompt. Harness-native tool names may remain discoverable only at runtime."],
|
|
143
|
+
});
|
|
48
144
|
addNode({
|
|
49
145
|
id: "runtime",
|
|
50
146
|
kind: "metadata",
|
|
@@ -62,16 +158,9 @@ export function buildPortableRuntimeContextSnapshot(input) {
|
|
|
62
158
|
},
|
|
63
159
|
payloadJson: input.runtime.capabilities,
|
|
64
160
|
});
|
|
65
|
-
|
|
66
|
-
addRuntimeContributionGroup(nodes, "tools", "Pibo Tools and Delegated Agents", [
|
|
67
|
-
...profile.tools.filter((tool) => tool.enabled !== false).map((tool) => tool.name),
|
|
68
|
-
...(availableAgents.length > 0 ? PIBO_AGENT_TOOL_NAMES : []),
|
|
69
|
-
...availableAgents.map((agent) => `agent:${agent.name} (${agent.profile}) — ${agent.description}`),
|
|
70
|
-
...(profile.toolPackages.goalControl !== false ? ["package:pibo-goal-control"] : []),
|
|
71
|
-
...(profile.toolPackages.runControl === true ? ["package:pibo-run-control"] : []),
|
|
72
|
-
], input.runtime.capabilities.tools.piboManaged);
|
|
161
|
+
addRuntimeContributionGroup(nodes, "tools", "Pibo Tools and Delegated Agents", managedToolDisplayNames, input.runtime.capabilities.tools.piboManaged);
|
|
73
162
|
addNativeToolInspectionNode(nodes, input.runtime.capabilities.tools.nativeToolInspection);
|
|
74
|
-
if (
|
|
163
|
+
if (runControlAvailable) {
|
|
75
164
|
addNativeToolYieldingNode(nodes, input.runtime.capabilities.tools.nativeToolYielding);
|
|
76
165
|
}
|
|
77
166
|
if (input.resources) {
|
|
@@ -138,7 +227,7 @@ export function buildPortableRuntimeContextSnapshot(input) {
|
|
|
138
227
|
source: "profile",
|
|
139
228
|
state: "active",
|
|
140
229
|
metadata: {
|
|
141
|
-
activeModel:
|
|
230
|
+
activeModel: runtimeManifest.effectiveModel,
|
|
142
231
|
mainModel: profile.mainModel,
|
|
143
232
|
subagentModel: profile.subagentModel,
|
|
144
233
|
mainThinkingLevel: profile.mainThinkingLevel ?? profile.thinkingLevel,
|
|
@@ -187,7 +276,7 @@ export function buildPortableRuntimeContextSnapshot(input) {
|
|
|
187
276
|
piboSessionId: input.piboSessionId,
|
|
188
277
|
piboRoomId: input.piboRoomId,
|
|
189
278
|
cwd: input.cwd,
|
|
190
|
-
activeModel:
|
|
279
|
+
activeModel: runtimeManifest.effectiveModel,
|
|
191
280
|
runtime: input.runtime,
|
|
192
281
|
summary: {
|
|
193
282
|
topLevelNodes: nodes.length,
|
|
@@ -58,6 +58,9 @@ export function validateAgentRuntimeProfileCapabilities(profile, capabilities) {
|
|
|
58
58
|
if (enabledContextFiles.length > 0) {
|
|
59
59
|
pushUnsupportedDeliveryDiagnostic(diagnostics, capabilities.context, "runtime_context_unsupported", "contextFiles", `Profile "${profile.profileName}" selects managed or automatic context`);
|
|
60
60
|
}
|
|
61
|
+
if (enabledSubagents.length > 0) {
|
|
62
|
+
pushUnsupportedDeliveryDiagnostic(diagnostics, capabilities.context, "runtime_delegated_agent_context_unsupported", "subagents", `Profile "${profile.profileName}" requires delegated-agent management context`);
|
|
63
|
+
}
|
|
61
64
|
if (profile.nativeSubagents !== undefined && typeof profile.nativeSubagents !== "boolean") {
|
|
62
65
|
diagnostics.push({
|
|
63
66
|
severity: "error",
|
|
@@ -9,6 +9,7 @@ import { isHttpServer, loadConfigUnresolved, } from "../mcp/config.js";
|
|
|
9
9
|
import { redactMcpRuntimeError as redactResourceError, scopePiboMcpServerConfig, verifyPiboMcpServer, } from "../mcp/runtime-session.js";
|
|
10
10
|
import { getMcpAgentContextFileFromConfig } from "../mcp/agent-context.js";
|
|
11
11
|
import { getInstalledCliToolContextFile } from "../tools/registry.js";
|
|
12
|
+
import { getDelegatedAgentContextFile } from "../subagents/context.js";
|
|
12
13
|
import { copyAgentRuntimeSkillDirectory, createAgentRuntimeResourcePaths, } from "./resource-files.js";
|
|
13
14
|
const DEFAULT_MCP_VERIFY_TIMEOUT_MS = 15_000;
|
|
14
15
|
const DEFAULT_MAX_SKILL_FILES = 2_048;
|
|
@@ -550,6 +551,21 @@ class RuntimeResourceSession {
|
|
|
550
551
|
this.diagnostics.push({ severity: "error", code: "runtime_context_file_failed", message, contributionId: id });
|
|
551
552
|
}
|
|
552
553
|
}
|
|
554
|
+
const delegatedAgents = getDelegatedAgentContextFile(this.input.profile.subagents);
|
|
555
|
+
if (delegatedAgents) {
|
|
556
|
+
this.requiredContributionIds.add("context:delegated-agents");
|
|
557
|
+
this.context.push({
|
|
558
|
+
id: "context:delegated-agents",
|
|
559
|
+
kind: "generated",
|
|
560
|
+
source: "generated",
|
|
561
|
+
intent: "developer",
|
|
562
|
+
label: "Delegated Agent Management",
|
|
563
|
+
required: true,
|
|
564
|
+
order: 250,
|
|
565
|
+
path: delegatedAgents.path,
|
|
566
|
+
content: delegatedAgents.content,
|
|
567
|
+
});
|
|
568
|
+
}
|
|
553
569
|
const installedTools = getInstalledCliToolContextFile();
|
|
554
570
|
if (installedTools) {
|
|
555
571
|
this.context.push({
|
|
@@ -9,6 +9,20 @@ const RUN_REMINDER_CAPABILITY_TOOLS = new Set([
|
|
|
9
9
|
"pibo_run_cancel",
|
|
10
10
|
"pibo_run_ack",
|
|
11
11
|
]);
|
|
12
|
+
// Run reminders are autonomous service wakeups, so their provider/tool loop needs a deterministic boundary.
|
|
13
|
+
const RUN_REMINDER_MAX_TOOL_EXECUTIONS = 64;
|
|
14
|
+
const RUN_REMINDER_MAX_PROVIDER_ROUNDS = 64;
|
|
15
|
+
const RUN_REMINDER_MAX_TOTAL_TOKENS = 2_000_000;
|
|
16
|
+
const RUN_REMINDER_MAX_DURATION_MS = 15 * 60 * 1000;
|
|
17
|
+
const RUN_REMINDER_MAX_REPEATED_TOOL_CALLS = 12;
|
|
18
|
+
function serializedToolArgs(value) {
|
|
19
|
+
try {
|
|
20
|
+
return JSON.stringify(value) ?? String(value);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return String(value);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
12
26
|
function errorMessage(error) {
|
|
13
27
|
return error instanceof Error ? error.message : String(error);
|
|
14
28
|
}
|
|
@@ -82,9 +96,11 @@ export class RuntimeRoutedSession {
|
|
|
82
96
|
runtimeDisposePromise;
|
|
83
97
|
forceDisposalStarted = false;
|
|
84
98
|
drainPromise;
|
|
99
|
+
inFlightMessage;
|
|
85
100
|
activeMessage;
|
|
86
101
|
activeExecutionEvent;
|
|
87
102
|
activeMessageFailed = false;
|
|
103
|
+
runReminderTurnGuard;
|
|
88
104
|
activeAssistantIndex;
|
|
89
105
|
nextAssistantIndex = 0;
|
|
90
106
|
activeThinkingIndex;
|
|
@@ -409,6 +425,28 @@ export class RuntimeRoutedSession {
|
|
|
409
425
|
this.notifyState();
|
|
410
426
|
return true;
|
|
411
427
|
}
|
|
428
|
+
const inFlight = this.inFlightMessage;
|
|
429
|
+
if (inFlight?.event.id === eventId) {
|
|
430
|
+
if (!inFlight.cancellation) {
|
|
431
|
+
inFlight.cancelled = true;
|
|
432
|
+
this.notifyMessagesInterrupted([inFlight.event], "message cancelled");
|
|
433
|
+
const active = this.activeMessage?.id === eventId;
|
|
434
|
+
inFlight.cancellation = (async () => {
|
|
435
|
+
try {
|
|
436
|
+
if (active)
|
|
437
|
+
await this.runtimeSession.abort();
|
|
438
|
+
await inFlight.settled;
|
|
439
|
+
}
|
|
440
|
+
catch (error) {
|
|
441
|
+
inFlight.cancelled = false;
|
|
442
|
+
inFlight.cancellation = undefined;
|
|
443
|
+
throw error;
|
|
444
|
+
}
|
|
445
|
+
})();
|
|
446
|
+
}
|
|
447
|
+
await inFlight.cancellation;
|
|
448
|
+
return true;
|
|
449
|
+
}
|
|
412
450
|
if (this.activeMessage?.id === eventId) {
|
|
413
451
|
this.notifyMessagesInterrupted([this.activeMessage], "message cancelled");
|
|
414
452
|
await this.runtimeSession.abort();
|
|
@@ -462,6 +500,7 @@ export class RuntimeRoutedSession {
|
|
|
462
500
|
return;
|
|
463
501
|
case "tool_execution_started":
|
|
464
502
|
this.emit(this.withActiveMessage({ ...event, type: "tool_execution_started", piboSessionId: this.piboSessionId }));
|
|
503
|
+
this.trackRunReminderTurnGuard("tool_execution_started", { toolName: event.toolName, args: event.args });
|
|
465
504
|
return;
|
|
466
505
|
case "tool_execution_updated":
|
|
467
506
|
this.emit(this.withActiveMessage({ ...event, type: "tool_execution_updated", piboSessionId: this.piboSessionId }));
|
|
@@ -479,7 +518,10 @@ export class RuntimeRoutedSession {
|
|
|
479
518
|
cacheWriteTokens: event.usage.cacheWriteTokens,
|
|
480
519
|
reasoningTokens: event.usage.reasoningTokens,
|
|
481
520
|
totalTokens: event.usage.totalTokens,
|
|
521
|
+
costUsd: event.usage.costUsd,
|
|
522
|
+
provenance: this.activeMessage?.provenance,
|
|
482
523
|
}));
|
|
524
|
+
this.trackRunReminderTurnGuard("usage", { totalTokens: event.usage.totalTokens });
|
|
483
525
|
return;
|
|
484
526
|
case "compaction_start":
|
|
485
527
|
this.emit(this.withActiveMessage({
|
|
@@ -593,9 +635,10 @@ export class RuntimeRoutedSession {
|
|
|
593
635
|
}
|
|
594
636
|
}
|
|
595
637
|
async processQueuedMessage(event) {
|
|
638
|
+
const inFlight = this.beginInFlightMessage(event);
|
|
596
639
|
try {
|
|
597
640
|
const preflight = await this.options.messagePreflight?.(event);
|
|
598
|
-
if (this.disposed)
|
|
641
|
+
if (this.disposed || inFlight.cancelled)
|
|
599
642
|
return;
|
|
600
643
|
if (preflight && !preflight.allowed) {
|
|
601
644
|
this.emit({
|
|
@@ -614,6 +657,10 @@ export class RuntimeRoutedSession {
|
|
|
614
657
|
});
|
|
615
658
|
return;
|
|
616
659
|
}
|
|
660
|
+
this.activeMessage = event;
|
|
661
|
+
this.activeMessageFailed = false;
|
|
662
|
+
this.beginRunReminderTurnGuard(event);
|
|
663
|
+
this.resetContentIndices();
|
|
617
664
|
this.emit({
|
|
618
665
|
type: "message_started",
|
|
619
666
|
piboSessionId: this.piboSessionId,
|
|
@@ -622,15 +669,14 @@ export class RuntimeRoutedSession {
|
|
|
622
669
|
source: event.source,
|
|
623
670
|
provenance: event.provenance,
|
|
624
671
|
});
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
this.resetContentIndices();
|
|
672
|
+
if (inFlight.cancelled)
|
|
673
|
+
return;
|
|
628
674
|
await this.runtimeSession.prompt({
|
|
629
675
|
text: event.text,
|
|
630
676
|
source: promptSource(event.source),
|
|
631
677
|
capabilityScope: event.capabilityScope,
|
|
632
678
|
});
|
|
633
|
-
if (this.disposed)
|
|
679
|
+
if (this.disposed || inFlight.cancelled)
|
|
634
680
|
return;
|
|
635
681
|
if (!this.activeMessageFailed) {
|
|
636
682
|
this.emit({
|
|
@@ -643,7 +689,7 @@ export class RuntimeRoutedSession {
|
|
|
643
689
|
}
|
|
644
690
|
}
|
|
645
691
|
catch (error) {
|
|
646
|
-
if (this.disposed)
|
|
692
|
+
if (this.disposed || inFlight.cancelled)
|
|
647
693
|
return;
|
|
648
694
|
if (!this.activeMessageFailed) {
|
|
649
695
|
const message = errorMessage(error);
|
|
@@ -661,8 +707,103 @@ export class RuntimeRoutedSession {
|
|
|
661
707
|
this.activeMessage = undefined;
|
|
662
708
|
this.activeMessageFailed = false;
|
|
663
709
|
this.resetContentIndices();
|
|
710
|
+
this.clearRunReminderTurnGuard();
|
|
711
|
+
if (this.inFlightMessage === inFlight)
|
|
712
|
+
this.inFlightMessage = undefined;
|
|
713
|
+
inFlight.resolveSettled();
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
beginInFlightMessage(event) {
|
|
717
|
+
let resolveSettled;
|
|
718
|
+
const inFlight = {
|
|
719
|
+
event,
|
|
720
|
+
cancelled: false,
|
|
721
|
+
settled: new Promise((resolve) => { resolveSettled = resolve; }),
|
|
722
|
+
resolveSettled: () => { resolveSettled?.(); },
|
|
723
|
+
};
|
|
724
|
+
this.inFlightMessage = inFlight;
|
|
725
|
+
return inFlight;
|
|
726
|
+
}
|
|
727
|
+
beginRunReminderTurnGuard(event) {
|
|
728
|
+
this.clearRunReminderTurnGuard();
|
|
729
|
+
if (event.source !== "service" || !event.text.startsWith("<pibo_run_notification>"))
|
|
730
|
+
return;
|
|
731
|
+
const guard = {
|
|
732
|
+
eventId: event.id,
|
|
733
|
+
toolExecutions: 0,
|
|
734
|
+
providerRounds: 0,
|
|
735
|
+
totalTokens: 0,
|
|
736
|
+
toolSignatures: new Map(),
|
|
737
|
+
tripped: false,
|
|
738
|
+
};
|
|
739
|
+
guard.timer = setTimeout(() => {
|
|
740
|
+
this.tripRunReminderTurnGuard(guard, `exceeded ${RUN_REMINDER_MAX_DURATION_MS / 60_000} minutes`);
|
|
741
|
+
}, RUN_REMINDER_MAX_DURATION_MS);
|
|
742
|
+
guard.timer.unref?.();
|
|
743
|
+
this.runReminderTurnGuard = guard;
|
|
744
|
+
}
|
|
745
|
+
clearRunReminderTurnGuard() {
|
|
746
|
+
const guard = this.runReminderTurnGuard;
|
|
747
|
+
if (!guard)
|
|
748
|
+
return;
|
|
749
|
+
if (guard.timer)
|
|
750
|
+
clearTimeout(guard.timer);
|
|
751
|
+
this.runReminderTurnGuard = undefined;
|
|
752
|
+
}
|
|
753
|
+
trackRunReminderTurnGuard(type, payload) {
|
|
754
|
+
const guard = this.runReminderTurnGuard;
|
|
755
|
+
if (!guard || guard.tripped || guard.eventId !== this.activeMessage?.id)
|
|
756
|
+
return;
|
|
757
|
+
if (type === "usage") {
|
|
758
|
+
const totalTokens = payload.totalTokens ?? 0;
|
|
759
|
+
guard.totalTokens += totalTokens;
|
|
760
|
+
guard.providerRounds += 1;
|
|
761
|
+
if (guard.totalTokens > RUN_REMINDER_MAX_TOTAL_TOKENS) {
|
|
762
|
+
this.tripRunReminderTurnGuard(guard, `exceeded ${RUN_REMINDER_MAX_TOTAL_TOKENS} total tokens`);
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
if (guard.providerRounds > RUN_REMINDER_MAX_PROVIDER_ROUNDS) {
|
|
766
|
+
this.tripRunReminderTurnGuard(guard, `exceeded ${RUN_REMINDER_MAX_PROVIDER_ROUNDS} provider rounds`);
|
|
767
|
+
}
|
|
768
|
+
return;
|
|
769
|
+
}
|
|
770
|
+
const toolName = payload.toolName;
|
|
771
|
+
const args = payload.args;
|
|
772
|
+
guard.toolExecutions += 1;
|
|
773
|
+
if (guard.toolExecutions > RUN_REMINDER_MAX_TOOL_EXECUTIONS) {
|
|
774
|
+
this.tripRunReminderTurnGuard(guard, `exceeded ${RUN_REMINDER_MAX_TOOL_EXECUTIONS} tool executions`);
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
const signature = `${String(toolName ?? "unknown")}:${serializedToolArgs(args)}`;
|
|
778
|
+
const repeated = (guard.toolSignatures.get(signature) ?? 0) + 1;
|
|
779
|
+
guard.toolSignatures.set(signature, repeated);
|
|
780
|
+
if (repeated > RUN_REMINDER_MAX_REPEATED_TOOL_CALLS) {
|
|
781
|
+
this.tripRunReminderTurnGuard(guard, `repeated the same tool call more than ${RUN_REMINDER_MAX_REPEATED_TOOL_CALLS} times`);
|
|
664
782
|
}
|
|
665
783
|
}
|
|
784
|
+
tripRunReminderTurnGuard(guard, reason) {
|
|
785
|
+
if (guard.tripped || this.runReminderTurnGuard !== guard)
|
|
786
|
+
return;
|
|
787
|
+
guard.tripped = true;
|
|
788
|
+
this.activeMessageFailed = true;
|
|
789
|
+
const error = `Run-reminder turn stopped because it ${reason}.`;
|
|
790
|
+
this.emit({
|
|
791
|
+
type: "session_error",
|
|
792
|
+
piboSessionId: this.piboSessionId,
|
|
793
|
+
eventId: guard.eventId,
|
|
794
|
+
error,
|
|
795
|
+
errorDetails: {
|
|
796
|
+
category: "runtime_abort",
|
|
797
|
+
errorClass: "runtime_abort",
|
|
798
|
+
code: "run_reminder_limit_exceeded",
|
|
799
|
+
origin: "runtime",
|
|
800
|
+
retryable: false,
|
|
801
|
+
userMessage: error,
|
|
802
|
+
},
|
|
803
|
+
provenance: this.activeMessage?.provenance,
|
|
804
|
+
});
|
|
805
|
+
void Promise.resolve(this.runtimeSession.abort()).catch(() => undefined);
|
|
806
|
+
}
|
|
666
807
|
async processQueuedCompact(event) {
|
|
667
808
|
this.activeExecutionEvent = event;
|
|
668
809
|
try {
|
|
@@ -851,7 +992,10 @@ export class RuntimeRoutedSession {
|
|
|
851
992
|
}
|
|
852
993
|
activeAndQueuedMessages() {
|
|
853
994
|
const messages = this.queue.flatMap((item) => item.kind === "message" ? [item.event] : []);
|
|
854
|
-
|
|
995
|
+
const inFlight = this.inFlightMessage?.event;
|
|
996
|
+
if (this.activeMessage)
|
|
997
|
+
return [this.activeMessage, ...messages];
|
|
998
|
+
return inFlight ? [inFlight, ...messages] : messages;
|
|
855
999
|
}
|
|
856
1000
|
notifyMessagesInterrupted(messages, reason) {
|
|
857
1001
|
if (messages.length === 0)
|
|
@@ -872,53 +1016,59 @@ export class RuntimeRoutedSession {
|
|
|
872
1016
|
this.nextThinkingIndex = 0;
|
|
873
1017
|
}
|
|
874
1018
|
withActiveMessage(event) {
|
|
875
|
-
|
|
1019
|
+
const activeMessage = this.activeMessage;
|
|
1020
|
+
if (!activeMessage?.id)
|
|
1021
|
+
return event;
|
|
1022
|
+
const correlation = {
|
|
1023
|
+
eventId: activeMessage.id,
|
|
1024
|
+
...(activeMessage.provenance ? { provenance: activeMessage.provenance } : {}),
|
|
1025
|
+
};
|
|
1026
|
+
if (event.type === "assistant_delta") {
|
|
876
1027
|
const assistantIndex = this.activeAssistantIndex ?? this.nextAssistantIndex;
|
|
877
1028
|
if (this.activeAssistantIndex === undefined) {
|
|
878
1029
|
this.nextAssistantIndex += 1;
|
|
879
1030
|
this.activeAssistantIndex = assistantIndex;
|
|
880
1031
|
}
|
|
881
|
-
return { ...event,
|
|
1032
|
+
return { ...event, ...correlation, assistantIndex };
|
|
882
1033
|
}
|
|
883
|
-
if (
|
|
1034
|
+
if (event.type === "assistant_message") {
|
|
884
1035
|
const assistantIndex = this.activeAssistantIndex ?? this.nextAssistantIndex;
|
|
885
1036
|
if (this.activeAssistantIndex === undefined)
|
|
886
1037
|
this.nextAssistantIndex += 1;
|
|
887
1038
|
this.activeAssistantIndex = undefined;
|
|
888
|
-
return { ...event,
|
|
1039
|
+
return { ...event, ...correlation, assistantIndex };
|
|
889
1040
|
}
|
|
890
|
-
if (
|
|
1041
|
+
if (event.type === "thinking_started") {
|
|
891
1042
|
const thinkingIndex = this.nextThinkingIndex;
|
|
892
1043
|
this.nextThinkingIndex += 1;
|
|
893
1044
|
this.activeThinkingIndex = thinkingIndex;
|
|
894
|
-
return { ...event,
|
|
1045
|
+
return { ...event, ...correlation, thinkingIndex };
|
|
895
1046
|
}
|
|
896
|
-
if (
|
|
1047
|
+
if (event.type === "thinking_delta" || event.type === "thinking_finished") {
|
|
897
1048
|
const thinkingIndex = this.activeThinkingIndex ?? this.nextThinkingIndex;
|
|
898
1049
|
if (this.activeThinkingIndex === undefined) {
|
|
899
1050
|
this.nextThinkingIndex += 1;
|
|
900
1051
|
this.activeThinkingIndex = thinkingIndex;
|
|
901
1052
|
}
|
|
902
|
-
const output = { ...event,
|
|
1053
|
+
const output = { ...event, ...correlation, thinkingIndex };
|
|
903
1054
|
if (event.type === "thinking_finished")
|
|
904
1055
|
this.activeThinkingIndex = undefined;
|
|
905
1056
|
return output;
|
|
906
1057
|
}
|
|
907
|
-
if (
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
return { ...event, eventId: this.activeMessage.id };
|
|
1058
|
+
if (event.type === "assistant_usage"
|
|
1059
|
+
|| event.type === "compaction_start"
|
|
1060
|
+
|| event.type === "compaction_end"
|
|
1061
|
+
|| event.type === "tool_call"
|
|
1062
|
+
|| event.type === "tool_execution_started"
|
|
1063
|
+
|| event.type === "tool_execution_updated"
|
|
1064
|
+
|| event.type === "tool_execution_finished"
|
|
1065
|
+
|| event.type === "approval_requested"
|
|
1066
|
+
|| event.type === "approval_resolved"
|
|
1067
|
+
|| event.type === "user_input_requested"
|
|
1068
|
+
|| event.type === "user_input_resolved"
|
|
1069
|
+
|| event.type === "session_error"
|
|
1070
|
+
|| event.type === "execution_result") {
|
|
1071
|
+
return { ...event, ...correlation };
|
|
922
1072
|
}
|
|
923
1073
|
return event;
|
|
924
1074
|
}
|
|
@@ -12,6 +12,7 @@ export class FakeAgentRuntimeSession {
|
|
|
12
12
|
disposed = false;
|
|
13
13
|
aborted = false;
|
|
14
14
|
promptIndex = 0;
|
|
15
|
+
activeScript;
|
|
15
16
|
abortWaiters = [];
|
|
16
17
|
prompts = [];
|
|
17
18
|
disposeCalls = 0;
|
|
@@ -47,6 +48,7 @@ export class FakeAgentRuntimeSession {
|
|
|
47
48
|
this.aborted = false;
|
|
48
49
|
const turnId = `fake-turn-${this.promptIndex}`;
|
|
49
50
|
const script = typeof this.script === "function" ? this.script(input, this.promptIndex) : this.script ?? {};
|
|
51
|
+
this.activeScript = script;
|
|
50
52
|
this.emit({ type: "turn_started", turnId });
|
|
51
53
|
try {
|
|
52
54
|
if (script.waitForAbort) {
|
|
@@ -72,6 +74,7 @@ export class FakeAgentRuntimeSession {
|
|
|
72
74
|
this.emit({ type: "turn_completed", turnId, status: "completed" });
|
|
73
75
|
}
|
|
74
76
|
finally {
|
|
77
|
+
this.activeScript = undefined;
|
|
75
78
|
this.streaming = false;
|
|
76
79
|
}
|
|
77
80
|
}
|
|
@@ -84,6 +87,10 @@ export class FakeAgentRuntimeSession {
|
|
|
84
87
|
}
|
|
85
88
|
async abort() {
|
|
86
89
|
this.abortCalls += 1;
|
|
90
|
+
if (this.activeScript?.abortFailWith)
|
|
91
|
+
throw new Error(this.activeScript.abortFailWith);
|
|
92
|
+
if (this.activeScript?.abortNeverSettles)
|
|
93
|
+
return;
|
|
87
94
|
const wasStreaming = this.streaming;
|
|
88
95
|
this.aborted = true;
|
|
89
96
|
const waiters = this.abortWaiters;
|
|
@@ -210,7 +210,9 @@ export function semanticEventFromPibo(event) {
|
|
|
210
210
|
outputTokens: event.outputTokens,
|
|
211
211
|
cacheReadTokens: event.cacheReadTokens,
|
|
212
212
|
cacheWriteTokens: event.cacheWriteTokens,
|
|
213
|
+
reasoningTokens: event.reasoningTokens,
|
|
213
214
|
totalTokens: event.totalTokens,
|
|
215
|
+
costUsd: event.costUsd,
|
|
214
216
|
},
|
|
215
217
|
};
|
|
216
218
|
case "compaction_start":
|