@pasko70/pibo 2.4.2 → 2.5.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.
Files changed (44) hide show
  1. package/dist/agent-runtime/context-build.js +100 -11
  2. package/dist/agent-runtime/profile-validation.js +3 -0
  3. package/dist/agent-runtime/resource-service.js +16 -0
  4. package/dist/agent-runtime/routed-session.js +30 -23
  5. package/dist/agent-runtime/testing/fake-adapter.js +7 -0
  6. package/dist/agent-runtimes/pi/adapter.js +2 -0
  7. package/dist/agent-runtimes/pi/routed-session.js +42 -27
  8. package/dist/agent-runtimes/pi/runtime.js +8 -5
  9. package/dist/apps/chat/web-app.js +21 -6
  10. package/dist/apps/chat-ui/assets/{dist-CrDtveZB.js → dist-BxJuOpXP.js} +1 -1
  11. package/dist/apps/chat-ui/assets/{dist-3YG57JXi.js → dist-CvA-WTQT.js} +1 -1
  12. package/dist/apps/chat-ui/assets/{dist-Cw9po47P.js → dist-DPzsIE8h.js} +1 -1
  13. package/dist/apps/chat-ui/assets/{dist-DTRjeLwO.js → dist-Dj5P89Wy.js} +1 -1
  14. package/dist/apps/chat-ui/assets/{dist-BeqHbnGN.js → dist-Sll26U24.js} +1 -1
  15. package/dist/apps/chat-ui/assets/index-0WZI2phJ.css +1 -0
  16. package/dist/apps/chat-ui/assets/index-BW5XFgYP.js +228 -0
  17. package/dist/apps/chat-ui/index.html +2 -2
  18. package/dist/apps/vscode-artifacts/latest.vsix +0 -0
  19. package/dist/apps/vscode-artifacts/{pibo-vscode-ext-2.4.2.vsix → pibo-vscode-ext-2.5.0.vsix} +0 -0
  20. package/dist/cli.js +16 -6
  21. package/dist/core/context-build.js +66 -6
  22. package/dist/core/model-defaults.js +11 -3
  23. package/dist/core/session-router.js +152 -69
  24. package/dist/gateway/server.js +1 -0
  25. package/dist/loops/accounting.js +80 -0
  26. package/dist/loops/service.js +51 -16
  27. package/dist/loops/store.js +50 -14
  28. package/dist/runs/lifecycle.js +26 -1
  29. package/dist/runs/registry.js +29 -47
  30. package/dist/runs/tools.js +23 -22
  31. package/dist/subagents/context.js +48 -0
  32. package/dist/subagents/runtime-selection.js +28 -0
  33. package/dist/subagents/tool.js +28 -6
  34. package/dist/tools/codex-compat.js +1 -0
  35. package/dist/tools/contract.js +10 -0
  36. package/dist/tools/mcp-bridge.js +4 -2
  37. package/dist/tools/runtime/node-backend.js +8 -2
  38. package/dist/tools/runtime/python-backend.js +8 -2
  39. package/dist/tools/runtime/tool.js +1 -0
  40. package/dist/tools/session-tool-set.js +19 -12
  41. package/npm-shrinkwrap.json +2 -2
  42. package/package.json +1 -1
  43. package/dist/apps/chat-ui/assets/index-AjnP3ci-.js +0 -228
  44. 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
- const availableAgents = listAvailableAgents(profile.subagents);
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 (profile.toolPackages.runControl === true) {
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: input.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: input.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({
@@ -518,6 +518,7 @@ export class RuntimeRoutedSession {
518
518
  cacheWriteTokens: event.usage.cacheWriteTokens,
519
519
  reasoningTokens: event.usage.reasoningTokens,
520
520
  totalTokens: event.usage.totalTokens,
521
+ costUsd: event.usage.costUsd,
521
522
  provenance: this.activeMessage?.provenance,
522
523
  }));
523
524
  this.trackRunReminderTurnGuard("usage", { totalTokens: event.usage.totalTokens });
@@ -1015,53 +1016,59 @@ export class RuntimeRoutedSession {
1015
1016
  this.nextThinkingIndex = 0;
1016
1017
  }
1017
1018
  withActiveMessage(event) {
1018
- if (this.activeMessage?.id && event.type === "assistant_delta") {
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") {
1019
1027
  const assistantIndex = this.activeAssistantIndex ?? this.nextAssistantIndex;
1020
1028
  if (this.activeAssistantIndex === undefined) {
1021
1029
  this.nextAssistantIndex += 1;
1022
1030
  this.activeAssistantIndex = assistantIndex;
1023
1031
  }
1024
- return { ...event, eventId: this.activeMessage.id, assistantIndex };
1032
+ return { ...event, ...correlation, assistantIndex };
1025
1033
  }
1026
- if (this.activeMessage?.id && event.type === "assistant_message") {
1034
+ if (event.type === "assistant_message") {
1027
1035
  const assistantIndex = this.activeAssistantIndex ?? this.nextAssistantIndex;
1028
1036
  if (this.activeAssistantIndex === undefined)
1029
1037
  this.nextAssistantIndex += 1;
1030
1038
  this.activeAssistantIndex = undefined;
1031
- return { ...event, eventId: this.activeMessage.id, assistantIndex };
1039
+ return { ...event, ...correlation, assistantIndex };
1032
1040
  }
1033
- if (this.activeMessage?.id && event.type === "thinking_started") {
1041
+ if (event.type === "thinking_started") {
1034
1042
  const thinkingIndex = this.nextThinkingIndex;
1035
1043
  this.nextThinkingIndex += 1;
1036
1044
  this.activeThinkingIndex = thinkingIndex;
1037
- return { ...event, eventId: this.activeMessage.id, thinkingIndex };
1045
+ return { ...event, ...correlation, thinkingIndex };
1038
1046
  }
1039
- if (this.activeMessage?.id && (event.type === "thinking_delta" || event.type === "thinking_finished")) {
1047
+ if (event.type === "thinking_delta" || event.type === "thinking_finished") {
1040
1048
  const thinkingIndex = this.activeThinkingIndex ?? this.nextThinkingIndex;
1041
1049
  if (this.activeThinkingIndex === undefined) {
1042
1050
  this.nextThinkingIndex += 1;
1043
1051
  this.activeThinkingIndex = thinkingIndex;
1044
1052
  }
1045
- const output = { ...event, eventId: this.activeMessage.id, thinkingIndex };
1053
+ const output = { ...event, ...correlation, thinkingIndex };
1046
1054
  if (event.type === "thinking_finished")
1047
1055
  this.activeThinkingIndex = undefined;
1048
1056
  return output;
1049
1057
  }
1050
- if (this.activeMessage?.id
1051
- && (event.type === "assistant_usage"
1052
- || event.type === "compaction_start"
1053
- || event.type === "compaction_end"
1054
- || event.type === "tool_call"
1055
- || event.type === "tool_execution_started"
1056
- || event.type === "tool_execution_updated"
1057
- || event.type === "tool_execution_finished"
1058
- || event.type === "approval_requested"
1059
- || event.type === "approval_resolved"
1060
- || event.type === "user_input_requested"
1061
- || event.type === "user_input_resolved"
1062
- || event.type === "session_error"
1063
- || event.type === "execution_result")) {
1064
- 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 };
1065
1072
  }
1066
1073
  return event;
1067
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":
@@ -50,6 +50,9 @@ export function normalizeAssistantUsageEvent(piboSessionId, message) {
50
50
  const outputTokens = numberValue(usage.outputTokens) ?? numberValue(usage.output);
51
51
  const cacheReadTokens = numberValue(usage.cacheRead);
52
52
  const cacheWriteTokens = numberValue(usage.cacheWrite);
53
+ const reasoningTokens = numberValue(usage.reasoningTokens) ?? numberValue(usage.reasoning);
54
+ const cost = usage.cost && typeof usage.cost === "object" ? usage.cost : undefined;
55
+ const costUsd = numberValue(cost?.total) ?? numberValue(usage.cost);
53
56
  const reportedTotal = numberValue(usage.totalTokens);
54
57
  const normalizedTotal = reportedTotal ?? [inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens]
55
58
  .filter((value) => value !== undefined)
@@ -63,7 +66,9 @@ export function normalizeAssistantUsageEvent(piboSessionId, message) {
63
66
  ...(outputTokens !== undefined ? { outputTokens } : {}),
64
67
  ...(cacheReadTokens !== undefined ? { cacheReadTokens } : {}),
65
68
  ...(cacheWriteTokens !== undefined ? { cacheWriteTokens } : {}),
69
+ ...(reasoningTokens !== undefined ? { reasoningTokens } : {}),
66
70
  totalTokens: Math.max(0, normalizedTotal),
71
+ ...(costUsd !== undefined ? { costUsd } : {}),
67
72
  };
68
73
  }
69
74
  function stringValue(value) {
@@ -137,22 +142,26 @@ function messageContentIndex(candidate) {
137
142
  function promptSource(source) {
138
143
  return source === "user" || source === "ui" ? "interactive" : "rpc";
139
144
  }
140
- function lastTextPartFromMessage(message) {
145
+ function textFromMessage(message) {
141
146
  if (!message || typeof message !== "object")
142
147
  return undefined;
143
148
  const content = message.content;
144
149
  if (!Array.isArray(content))
145
150
  return undefined;
146
- for (let index = content.length - 1; index >= 0; index -= 1) {
151
+ const textParts = [];
152
+ for (let index = 0; index < content.length; index += 1) {
147
153
  const part = content[index];
148
154
  if (!part || typeof part !== "object")
149
155
  continue;
150
156
  const candidate = part;
151
157
  if (candidate.type === "text" && typeof candidate.text === "string" && candidate.text.length > 0) {
152
- return { text: candidate.text, contentIndex: index };
158
+ textParts.push({ text: candidate.text, contentIndex: index });
153
159
  }
154
160
  }
155
- return undefined;
161
+ const finalPart = textParts.at(-1);
162
+ if (!finalPart)
163
+ return undefined;
164
+ return { text: textParts.map((part) => part.text).join("\n"), contentIndex: finalPart.contentIndex };
156
165
  }
157
166
  function toolCallFromMessage(message, contentIndex) {
158
167
  if (!message || typeof message !== "object" || typeof contentIndex !== "number")
@@ -363,13 +372,13 @@ export function normalizePiEvent(piboSessionId, event, context) {
363
372
  errorDetails: assistantErrorDetails(message, context),
364
373
  };
365
374
  }
366
- const textPart = lastTextPartFromMessage(candidate.message);
367
- if (textPart) {
375
+ const messageText = textFromMessage(candidate.message);
376
+ if (messageText) {
368
377
  return {
369
378
  type: "assistant_message",
370
379
  piboSessionId,
371
- contentIndex: textPart.contentIndex,
372
- text: textPart.text,
380
+ contentIndex: messageText.contentIndex,
381
+ text: messageText.text,
373
382
  };
374
383
  }
375
384
  }
@@ -1461,50 +1470,56 @@ export class RoutedSession {
1461
1470
  };
1462
1471
  }
1463
1472
  withActiveMessage(event) {
1464
- if (this.activeMessage?.id && event.type === "assistant_delta") {
1473
+ const activeMessage = this.activeMessage;
1474
+ if (!activeMessage?.id)
1475
+ return event;
1476
+ const correlation = {
1477
+ eventId: activeMessage.id,
1478
+ ...(activeMessage.provenance ? { provenance: activeMessage.provenance } : {}),
1479
+ };
1480
+ if (event.type === "assistant_delta") {
1465
1481
  const assistantIndex = this.activeAssistantIndex ?? this.nextAssistantIndex;
1466
1482
  if (this.activeAssistantIndex === undefined) {
1467
1483
  this.nextAssistantIndex += 1;
1468
1484
  this.activeAssistantIndex = assistantIndex;
1469
1485
  }
1470
- return { ...event, eventId: this.activeMessage.id, assistantIndex };
1486
+ return { ...event, ...correlation, assistantIndex };
1471
1487
  }
1472
- if (this.activeMessage?.id && event.type === "assistant_message") {
1488
+ if (event.type === "assistant_message") {
1473
1489
  const assistantIndex = this.activeAssistantIndex ?? this.nextAssistantIndex;
1474
1490
  if (this.activeAssistantIndex === undefined) {
1475
1491
  this.nextAssistantIndex += 1;
1476
1492
  }
1477
1493
  this.activeAssistantIndex = undefined;
1478
- return { ...event, eventId: this.activeMessage.id, assistantIndex };
1494
+ return { ...event, ...correlation, assistantIndex };
1479
1495
  }
1480
- if (this.activeMessage?.id && event.type === "thinking_started") {
1496
+ if (event.type === "thinking_started") {
1481
1497
  const thinkingIndex = this.nextThinkingIndex;
1482
1498
  this.nextThinkingIndex += 1;
1483
1499
  this.activeThinkingIndex = thinkingIndex;
1484
- return { ...event, eventId: this.activeMessage.id, thinkingIndex };
1500
+ return { ...event, ...correlation, thinkingIndex };
1485
1501
  }
1486
- if (this.activeMessage?.id && (event.type === "thinking_delta" || event.type === "thinking_finished")) {
1502
+ if (event.type === "thinking_delta" || event.type === "thinking_finished") {
1487
1503
  const thinkingIndex = this.activeThinkingIndex ?? this.nextThinkingIndex;
1488
1504
  if (this.activeThinkingIndex === undefined) {
1489
1505
  this.nextThinkingIndex += 1;
1490
1506
  this.activeThinkingIndex = thinkingIndex;
1491
1507
  }
1492
- const output = { ...event, eventId: this.activeMessage.id, thinkingIndex };
1508
+ const output = { ...event, ...correlation, thinkingIndex };
1493
1509
  if (event.type === "thinking_finished")
1494
1510
  this.activeThinkingIndex = undefined;
1495
1511
  return output;
1496
1512
  }
1497
- if (this.activeMessage?.id &&
1498
- (event.type === "assistant_usage" ||
1499
- event.type === "compaction_start" ||
1500
- event.type === "compaction_end" ||
1501
- event.type === "tool_call" ||
1502
- event.type === "tool_execution_started" ||
1503
- event.type === "tool_execution_updated" ||
1504
- event.type === "tool_execution_finished" ||
1505
- event.type === "session_error" ||
1506
- event.type === "execution_result")) {
1507
- return { ...event, eventId: this.activeMessage.id };
1513
+ if (event.type === "assistant_usage" ||
1514
+ event.type === "compaction_start" ||
1515
+ event.type === "compaction_end" ||
1516
+ event.type === "tool_call" ||
1517
+ event.type === "tool_execution_started" ||
1518
+ event.type === "tool_execution_updated" ||
1519
+ event.type === "tool_execution_finished" ||
1520
+ event.type === "session_error" ||
1521
+ event.type === "execution_result") {
1522
+ return { ...event, ...correlation };
1508
1523
  }
1509
1524
  return event;
1510
1525
  }
@@ -5,7 +5,8 @@ import { createAgentSessionFromServices, createAgentSessionRuntime, createAgentS
5
5
  import { DEFAULT_BUILTIN_TOOL_NAMES, InitialSessionContext, } from "../../core/profiles.js";
6
6
  import { loadPiboModelDefaults, selectRequestedModelProfile, selectRequestedThinkingLevel } from "../../core/model-defaults.js";
7
7
  import { createDefaultPiboProfile } from "../../core/default-profile.js";
8
- import { PIBO_AGENT_TOOL_NAMES, } from "../../subagents/tool.js";
8
+ import { getDelegatedAgentContextFile } from "../../subagents/context.js";
9
+ import { resolvePiboSubagentRuntimeSelections } from "../../subagents/runtime-selection.js";
9
10
  import { getInstalledCliToolContextFile } from "../../tools/registry.js";
10
11
  import { createCodexCompatExtension } from "../../core/codex-compat.js";
11
12
  import { createWebSearchProviderExtension, isWebSearchProviderTool } from "../../tools/web-search.js";
@@ -218,6 +219,7 @@ export async function createPiboRuntime(options = {}) {
218
219
  : createSessionContextFile({ piboSessionId: profile.sessionId, ...options.sessionContext });
219
220
  const installedToolContextFile = options.resources ? undefined : getInstalledCliToolContextFile();
220
221
  const mcpAgentContextFile = options.resources ? undefined : await getMcpAgentContextFile(profile.mcpServers);
222
+ const delegatedAgentContextFile = options.resources ? undefined : getDelegatedAgentContextFile(profile.subagents);
221
223
  const skillPaths = options.resources
222
224
  ? [...options.resources.getSkillPaths("source")]
223
225
  : getEnabledSkillPaths(runtimeCwd, profile);
@@ -241,6 +243,7 @@ export async function createPiboRuntime(options = {}) {
241
243
  agentsFiles: mergeContextFiles(base.agentsFiles, [
242
244
  ...(sessionContextFile ? [sessionContextFile] : []),
243
245
  ...contextFiles,
246
+ ...(delegatedAgentContextFile ? [delegatedAgentContextFile] : []),
244
247
  ...(installedToolContextFile ? [installedToolContextFile] : []),
245
248
  ...(mcpAgentContextFile ? [mcpAgentContextFile] : []),
246
249
  ]),
@@ -400,6 +403,7 @@ function resolveProfileModel(profile, modelRegistry, cwd, modelDefaults, activeM
400
403
  export async function inspectPiboProfile(options = {}) {
401
404
  const cwd = options.cwd ?? process.cwd();
402
405
  const profile = options.profile ?? createDefaultPiboProfile();
406
+ const inspectionModelDefaults = options.modelDefaults ?? loadPiboModelDefaults(cwd);
403
407
  const runtimeProfile = new InitialSessionContext({
404
408
  profileName: profile.profileName,
405
409
  runtimeInstanceId: profile.runtimeInstanceId,
@@ -474,10 +478,9 @@ export async function inspectPiboProfile(options = {}) {
474
478
  registered: registeredToolNames.has(tool.name) || tool.providerTool !== undefined || isRuntimeTool(tool) || isCodexBrowserTool(tool),
475
479
  active: activeToolNames.has(tool.name) || tool.providerTool !== undefined,
476
480
  })).concat(generatedTools),
477
- subagents: profile.subagents.map((subagent) => ({
478
- name: subagent.name,
479
- targetProfile: subagent.targetProfile,
480
- active: subagent.enabled !== false && activeToolNames.has(PIBO_AGENT_TOOL_NAMES[0]),
481
+ subagents: resolvePiboSubagentRuntimeSelections(profile.subagents, options.subagentProfileResolver, inspectionModelDefaults).map(({ enabled, ...subagent }) => ({
482
+ ...subagent,
483
+ active: enabled && activeToolNames.has("pibo_run_start"),
481
484
  })),
482
485
  mcpServers: [...profile.mcpServers],
483
486
  mcpStatus: options.resources?.getInspection().mcpServers.map((server) => structuredClone(server)) ?? [],
@@ -20,6 +20,7 @@ import { withWorkflowSessionKind } from "../../sessions/workflow-session-kind.js
20
20
  import { CustomAgentStore, createDefaultCustomAgentStore, previewCustomAgentCreate, previewCustomAgentUpdate, } from "./agent-store.js";
21
21
  import { loadPiboModelDefaults, } from "../../core/model-defaults.js";
22
22
  import { inspectPiboContextBuild } from "../../core/context-build.js";
23
+ import { isPiboThinkingLevel } from "../../core/thinking.js";
23
24
  import { loadPiboUserSettings, updateTelemetryRetentionLastPrunedAt } from "../../core/user-settings.js";
24
25
  import { isTelemetryRetentionMaintenanceDue, maybeRunTelemetryRetentionMaintenance } from "./telemetry-retention-service.js";
25
26
  import { loadModelCatalog } from "./model-catalog.js";
@@ -2346,19 +2347,22 @@ async function buildContextBuildSnapshotForRequest(input) {
2346
2347
  if (!input.piboSessionId)
2347
2348
  throw new PiboWebHttpError("piboSessionId is required", 400);
2348
2349
  const selectedSession = requireSharedSession(input.context, input.piboSessionId);
2349
- const configuredProfile = createProfile(selectedSession.profile);
2350
- const runtimeInstanceId = selectedSession.runtimeBinding?.runtimeInstanceId ?? configuredProfile.runtimeInstanceId;
2351
- const profile = profileWithRuntimeInstance(configuredProfile, runtimeInstanceId);
2350
+ const runtimeBinding = input.context.channelContext.getSessionRuntimeBinding?.(selectedSession.id) ?? selectedSession.runtimeBinding;
2351
+ const configuredProfile = input.context.channelContext.getSessionRuntimeProfile?.(selectedSession.id) ?? createProfile(selectedSession.profile);
2352
+ const runtimeInstanceId = runtimeBinding?.runtimeInstanceId ?? configuredProfile.runtimeInstanceId;
2353
+ const profile = configuredProfile.runtimeInstanceId === runtimeInstanceId
2354
+ ? configuredProfile
2355
+ : profileWithRuntimeInstance(configuredProfile, runtimeInstanceId);
2352
2356
  const cwd = selectedSession.workspace ?? getDefaultPiboWorkspace();
2353
2357
  const runtime = await resolveContextBuildRuntime(input.context, runtimeInstanceId);
2354
2358
  const validationDiagnostics = input.context.channelContext.validateAgentRuntimeProfile
2355
2359
  ? await input.context.channelContext.validateAgentRuntimeProfile(profile, cwd)
2356
2360
  : [];
2357
- const bindingMismatchDiagnostic = selectedSession.runtimeBinding && selectedSession.runtimeBinding.adapterId !== runtime.adapterId
2361
+ const bindingMismatchDiagnostic = runtimeBinding && runtimeBinding.adapterId !== runtime.adapterId
2358
2362
  ? [{
2359
2363
  severity: "error",
2360
2364
  code: "runtime_binding_adapter_mismatch",
2361
- message: `Session binding expects adapter "${selectedSession.runtimeBinding.adapterId}", but runtime instance "${runtime.id}" uses "${runtime.adapterId}".`,
2365
+ message: `Session binding expects adapter "${runtimeBinding.adapterId}", but runtime instance "${runtime.id}" uses "${runtime.adapterId}".`,
2362
2366
  }]
2363
2367
  : [];
2364
2368
  const diagnostics = uniqueRuntimeDiagnostics([
@@ -2371,12 +2375,17 @@ async function buildContextBuildSnapshotForRequest(input) {
2371
2375
  adapterId: runtime.adapterId,
2372
2376
  available: runtime.available && !diagnostics.some((diagnostic) => diagnostic.severity === "error"),
2373
2377
  transport: runtime.transport,
2374
- bindingState: selectedSession.runtimeBinding?.state,
2378
+ bindingState: runtimeBinding?.state,
2375
2379
  protocol: runtime.protocol,
2376
2380
  capabilities: runtime.capabilities,
2377
2381
  diagnostics,
2378
2382
  };
2379
2383
  const userSettings = loadPiboUserSettings();
2384
+ const modelDefaults = loadPiboModelDefaults(cwd);
2385
+ const storedInitialThinkingLevel = selectedSession.metadata?.initialThinkingLevel;
2386
+ const initialThinkingLevel = typeof storedInitialThinkingLevel === "string" && isPiboThinkingLevel(storedInitialThinkingLevel)
2387
+ ? storedInitialThinkingLevel
2388
+ : undefined;
2380
2389
  const resourceService = new PiboRuntimeResourceService();
2381
2390
  const resources = await resourceService.createSession({
2382
2391
  piboSessionId: selectedSession.id,
@@ -2396,6 +2405,9 @@ async function buildContextBuildSnapshotForRequest(input) {
2396
2405
  cwd,
2397
2406
  profile,
2398
2407
  activeModel: selectedSession.activeModel,
2408
+ thinkingLevel: initialThinkingLevel,
2409
+ modelDefaults,
2410
+ subagentProfileResolver: createProfile,
2399
2411
  persistSession: false,
2400
2412
  resources,
2401
2413
  sessionContext: {
@@ -2426,6 +2438,9 @@ async function buildContextBuildSnapshotForRequest(input) {
2426
2438
  piboSessionId: selectedSession.id,
2427
2439
  piboRoomId: chatRoomIdFromMetadata(selectedSession.metadata),
2428
2440
  activeModel: selectedSession.activeModel,
2441
+ thinkingLevel: initialThinkingLevel,
2442
+ modelDefaults,
2443
+ subagentProfileResolver: createProfile,
2429
2444
  resources: resources.getInspection(),
2430
2445
  });
2431
2446
  }