@pasko70/pibo 2.2.4 → 2.3.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 (61) hide show
  1. package/dist/agent-runtime/capabilities.js +9 -1
  2. package/dist/agent-runtime/context-build.js +5 -2
  3. package/dist/agent-runtimes/codex-native/adapter.js +5 -0
  4. package/dist/agent-runtimes/omp/adapter.js +5 -0
  5. package/dist/agent-runtimes/omp/turn.js +2 -0
  6. package/dist/agent-runtimes/pi/adapter.js +28 -7
  7. package/dist/agent-runtimes/pi/intent-tracing.js +120 -0
  8. package/dist/agent-runtimes/pi/routed-session.js +25 -8
  9. package/dist/agent-runtimes/pi/runtime.js +28 -16
  10. package/dist/apps/chat/chat-settings-routes.js +44 -3
  11. package/dist/apps/chat/chat-transcription.js +85 -0
  12. package/dist/apps/chat/data/chat-data-mappers.js +4 -4
  13. package/dist/apps/chat/stream.js +23 -9
  14. package/dist/apps/chat/trace-v2.js +1 -0
  15. package/dist/apps/chat/web-app.js +49 -0
  16. package/dist/apps/chat-ui/assets/{dist-luJVFsmq.js → dist-Byygd1lH.js} +1 -1
  17. package/dist/apps/chat-ui/assets/{dist-ltfz1vFX.js → dist-C9BrS7sL.js} +1 -1
  18. package/dist/apps/chat-ui/assets/{dist-rf4HYdoa.js → dist-CUcAofmV.js} +1 -1
  19. package/dist/apps/chat-ui/assets/{dist-CImWCF2M.js → dist-D4RU6xu3.js} +1 -1
  20. package/dist/apps/chat-ui/assets/{dist-BFwTuvyi.js → dist-DusFwy0L.js} +1 -1
  21. package/dist/apps/chat-ui/assets/{index-nZQXUpxE.css → index-BJ56TREg.css} +1 -1
  22. package/dist/apps/chat-ui/assets/index-Bifi_kjN.js +228 -0
  23. package/dist/apps/chat-ui/index.html +2 -2
  24. package/dist/apps/chat-vscode-web/assets/index-WsLm1mo3.js +43 -0
  25. package/dist/apps/chat-vscode-web/index.html +1 -1
  26. package/dist/apps/vscode-artifacts/latest.vsix +0 -0
  27. package/dist/apps/vscode-artifacts/pibo-vscode-ext-2.3.0.vsix +0 -0
  28. package/dist/core/codex-compat.js +1 -3
  29. package/dist/core/context-build.js +16 -7
  30. package/dist/core/gateway-resource-guard.js +35 -14
  31. package/dist/core/gateway-settings.js +64 -0
  32. package/dist/core/session-router.js +226 -46
  33. package/dist/core/user-settings.js +20 -0
  34. package/dist/data/ingest-service.js +14 -2
  35. package/dist/debug/agents.js +391 -0
  36. package/dist/debug/index.js +14 -2
  37. package/dist/gateway/server.js +2 -0
  38. package/dist/index.js +6 -1
  39. package/dist/plugins/builtin.js +4 -2
  40. package/dist/plugins/openai-chatgpt-transcription.js +12 -0
  41. package/dist/plugins/openai-transcription.js +12 -0
  42. package/dist/plugins/registry.js +23 -0
  43. package/dist/session-ui/delegation.js +4 -2
  44. package/dist/session-ui/terminalRows.js +51 -1
  45. package/dist/shared/trace-async-agent-runs.js +4 -2
  46. package/dist/shared/trace-event-projection.js +12 -2
  47. package/dist/shared/trace-live-reducer.js +4 -0
  48. package/dist/shared/trace-patch-nodes.js +1 -0
  49. package/dist/shared/trace-subagent-links.js +19 -6
  50. package/dist/subagents/observations.js +149 -0
  51. package/dist/subagents/tool.js +177 -46
  52. package/dist/tools/session-service.js +1 -0
  53. package/dist/tools/session-tool-set.js +9 -5
  54. package/dist/transcription/openai-chatgpt.js +148 -0
  55. package/dist/transcription/openai.js +72 -0
  56. package/dist/transcription/types.js +8 -0
  57. package/npm-shrinkwrap.json +2 -2
  58. package/package.json +1 -1
  59. package/dist/apps/chat-ui/assets/index-D2Maa2v1.js +0 -226
  60. package/dist/apps/chat-vscode-web/assets/index-BpurWVnX.js +0 -41
  61. package/dist/apps/vscode-artifacts/pibo-vscode-ext-2.2.4.vsix +0 -0
@@ -27,6 +27,9 @@ const BOOLEAN_CAPABILITY_PATHS = [
27
27
  "nativeSubagents.supported",
28
28
  "nativeSubagents.configurable",
29
29
  "nativeSubagents.enabledByDefault",
30
+ "tools.intentTracing.supported",
31
+ "tools.intentTracing.configurable",
32
+ "tools.intentTracing.enabledByDefault",
30
33
  "historyImport",
31
34
  "auth.status",
32
35
  "auth.cancel",
@@ -121,7 +124,7 @@ export function validateAgentRuntimeCapabilities(value) {
121
124
  if (reasoningSupported === false && Array.isArray(reasoningValues) && reasoningValues.length > 0) {
122
125
  errors.push("reasoning.values must be omitted or empty when reasoning is unsupported");
123
126
  }
124
- for (const feature of ["contextDiscovery", "nativeSubagents"]) {
127
+ for (const feature of ["contextDiscovery", "nativeSubagents", "tools.intentTracing"]) {
125
128
  const supported = readPath(value, `${feature}.supported`);
126
129
  const configurable = readPath(value, `${feature}.configurable`);
127
130
  const enabledByDefault = readPath(value, `${feature}.enabledByDefault`);
@@ -243,6 +246,11 @@ export function createMinimalAgentRuntimeCapabilities() {
243
246
  piboManaged: unavailable,
244
247
  nativeToolInspection: unavailable,
245
248
  nativeToolYielding: unavailable,
249
+ intentTracing: {
250
+ supported: false,
251
+ configurable: false,
252
+ enabledByDefault: false,
253
+ },
246
254
  },
247
255
  mcp: {
248
256
  externalServers: unavailable,
@@ -1,4 +1,5 @@
1
1
  import { InitialSessionContext } from "../core/profiles.js";
2
+ import { PIBO_AGENT_TOOL_NAMES, listAvailableAgents } from "../subagents/tool.js";
2
3
  export function profileWithRuntimeInstance(profile, runtimeInstanceId) {
3
4
  if (profile.runtimeInstanceId === runtimeInstanceId)
4
5
  return profile;
@@ -61,9 +62,11 @@ export function buildPortableRuntimeContextSnapshot(input) {
61
62
  },
62
63
  payloadJson: input.runtime.capabilities,
63
64
  });
64
- addRuntimeContributionGroup(nodes, "tools", "Pibo Tools and Subagents", [
65
+ const availableAgents = listAvailableAgents(profile.subagents);
66
+ addRuntimeContributionGroup(nodes, "tools", "Pibo Tools and Delegated Agents", [
65
67
  ...profile.tools.filter((tool) => tool.enabled !== false).map((tool) => tool.name),
66
- ...profile.subagents.filter((subagent) => subagent.enabled !== false).map((subagent) => `subagent:${subagent.name} -> ${subagent.targetProfile}`),
68
+ ...(availableAgents.length > 0 ? PIBO_AGENT_TOOL_NAMES : []),
69
+ ...availableAgents.map((agent) => `agent:${agent.name} (${agent.profile}) — ${agent.description}`),
67
70
  ...(profile.toolPackages.goalControl !== false ? ["package:pibo-goal-control"] : []),
68
71
  ...(profile.toolPackages.runControl === true ? ["package:pibo-run-control"] : []),
69
72
  ], input.runtime.capabilities.tools.piboManaged);
@@ -51,6 +51,11 @@ function codexNativeCapabilities(structuredUserInput) {
51
51
  reason: "Stable Codex App Server 0.147.0 does not expose a complete pre-turn native-tool inventory; Pibo reports selected MCP tools immediately and harness-native tools after stable item notifications prove they are active.",
52
52
  },
53
53
  nativeToolYielding: unsupportedAgentRuntimeCapability("Codex native tools remain harness-owned and are not wrapped as Pibo yielded tools."),
54
+ intentTracing: {
55
+ supported: false,
56
+ configurable: false,
57
+ enabledByDefault: false,
58
+ },
54
59
  },
55
60
  mcp: {
56
61
  externalServers: { support: "mcp", transports: ["streamable-http", "stdio"] },
@@ -50,6 +50,11 @@ function ompCapabilities() {
50
50
  reason: "OMP exposes its native tool inventory via get_state.dumpTools and runtime tool_execution items; a complete pre-turn inventory is only partially exposed through RPC.",
51
51
  },
52
52
  nativeToolYielding: unsupportedAgentRuntimeCapability("OMP native tools remain harness-owned and are not wrapped as Pibo yielded tools."),
53
+ intentTracing: {
54
+ supported: true,
55
+ configurable: false,
56
+ enabledByDefault: true,
57
+ },
53
58
  },
54
59
  mcp: {
55
60
  externalServers: { support: "unsupported", reason: "OMP manages its own MCP; external MCP delivery is not wired in the initial OMP adapter." },
@@ -238,11 +238,13 @@ export class OmpRpcTurnController {
238
238
  return;
239
239
  }
240
240
  if (frame.type === "tool_execution_start") {
241
+ const intent = typeof frame.intent === "string" ? frame.intent.trim() : "";
241
242
  this.emit({
242
243
  type: "tool_execution_started",
243
244
  toolCallId: frame.toolCallId,
244
245
  toolName: frame.toolName,
245
246
  args: frame.args,
247
+ ...(intent ? { intent } : {}),
246
248
  });
247
249
  return;
248
250
  }
@@ -10,6 +10,7 @@ import { loadModelCatalog as loadPiModelCatalog, piAgentRuntimeModelCatalog, } f
10
10
  import { inspectPiAgentRuntimeHistory, readPiAgentRuntimeHistory, } from "./history.js";
11
11
  import { PiAgentRuntimeAuthController } from "./auth.js";
12
12
  import { importPortableHistoryIntoPi } from "./portable-history.js";
13
+ import { piIntentTracingEnabled } from "./intent-tracing.js";
13
14
  const PI_ADAPTER_ID = "pi";
14
15
  export const PI_PROTOCOL_VERSION = "0.84.2";
15
16
  export const PI_AGENT_RUNTIME_CAPABILITIES = {
@@ -43,6 +44,11 @@ export const PI_AGENT_RUNTIME_CAPABILITIES = {
43
44
  piboManaged: { support: "direct" },
44
45
  nativeToolInspection: { support: "native" },
45
46
  nativeToolYielding: { support: "native" },
47
+ intentTracing: {
48
+ supported: true,
49
+ configurable: true,
50
+ enabledByDefault: false,
51
+ },
46
52
  },
47
53
  mcp: {
48
54
  externalServers: { support: "materialized", modes: ["isolated-pibo-mcp-config"] },
@@ -165,7 +171,7 @@ function nativeSessionInfoFromPi(runtimeInstanceId, info) {
165
171
  firstMessage: info.firstMessage,
166
172
  };
167
173
  }
168
- function semanticEventFromPibo(event) {
174
+ export function semanticEventFromPibo(event) {
169
175
  switch (event.type) {
170
176
  case "message_started":
171
177
  return { type: "turn_started", turnId: event.eventId };
@@ -188,6 +194,7 @@ function semanticEventFromPibo(event) {
188
194
  toolName: event.toolName,
189
195
  args: event.args,
190
196
  argsComplete: event.argsComplete,
197
+ ...(event.intent ? { intent: event.intent } : {}),
191
198
  };
192
199
  case "tool_execution_started":
193
200
  return { ...event, type: "tool_execution_started" };
@@ -519,12 +526,23 @@ class PiAgentRuntimeAdapter {
519
526
  message: `Profile "${input.profile.profileName}" selects runtime instance "${input.profile.runtimeInstanceId}", not "${this.instanceId}".`,
520
527
  });
521
528
  }
522
- if (Object.keys(input.profile.runtimeOptions).length > 0) {
529
+ const runtimeOptionKeys = Object.keys(input.profile.runtimeOptions);
530
+ for (const key of runtimeOptionKeys) {
531
+ if (key === "intentTracing")
532
+ continue;
533
+ diagnostics.push({
534
+ severity: "error",
535
+ code: "pi_runtime_option_unsupported",
536
+ message: `The Pi runtime does not accept profile option "${key}".`,
537
+ path: `runtimeOptions.${key}`,
538
+ });
539
+ }
540
+ if ("intentTracing" in input.profile.runtimeOptions && typeof input.profile.runtimeOptions["intentTracing"] !== "boolean") {
523
541
  diagnostics.push({
524
542
  severity: "error",
525
- code: "pi_runtime_options_unsupported",
526
- message: "The Pi runtime does not accept adapter-specific profile options.",
527
- path: "runtimeOptions",
543
+ code: "pi_intent_tracing_invalid",
544
+ message: "Pi intentTracing must be a boolean.",
545
+ path: "runtimeOptions.intentTracing",
528
546
  });
529
547
  }
530
548
  const profileProvidesBash = input.profile.toolPackages.runControl === true
@@ -582,14 +600,16 @@ class PiAgentRuntimeAdapter {
582
600
  throw new Error("Pi portable history import requires a new native session.");
583
601
  }
584
602
  const compatibility = input.services?.compatibility;
603
+ const profile = cloneProfileForPiSession(input);
604
+ const intentTracing = piIntentTracingEnabled(profile.runtimeOptions);
585
605
  const runtime = await createPiboRuntime({
586
606
  cwd: input.workspace,
587
607
  persistSession: compatibility?.persistSession,
588
- profile: cloneProfileForPiSession(input),
608
+ profile,
589
609
  thinkingLevel: compatibility?.thinkingLevel,
590
610
  retryDefaults: compatibility?.retryDefaults,
591
611
  extensionFactories: compatibility?.extensionFactories,
592
- subagentRunner: input.services?.subagentRunner,
612
+ agentsController: input.services?.agentsController,
593
613
  runToolController: input.services?.runToolController,
594
614
  runtimeToolController: input.services?.codeRuntimeToolController,
595
615
  portableTools: input.services?.portableTools,
@@ -631,6 +651,7 @@ class PiAgentRuntimeAdapter {
631
651
  metadata: {
632
652
  ...(input.binding?.metadata ?? {}),
633
653
  persistent: compatibility?.persistSession !== false,
654
+ intentTracing,
634
655
  nativePresenceExpected: compatibility?.persistSession !== false
635
656
  && runtime.session.sessionManager.buildSessionContext().messages.length > 0,
636
657
  },
@@ -0,0 +1,120 @@
1
+ export const PI_TOOL_INTENT_FIELD = "i";
2
+ const PI_TOOL_INTENT_FALLBACK_FIELD = "__pibo_intent";
3
+ const intentTracingSessions = new WeakMap();
4
+ const PI_TOOL_INTENT_SCHEMA = {
5
+ type: "string",
6
+ minLength: 1,
7
+ description: "Capitalized 2–6-word present-participle intent describing why this tool is being called; no period.",
8
+ };
9
+ export function piIntentTracingEnabled(runtimeOptions) {
10
+ return runtimeOptions["intentTracing"] === true;
11
+ }
12
+ export function splitPiToolIntentArguments(value, intentField = PI_TOOL_INTENT_FIELD) {
13
+ if (!value || typeof value !== "object" || Array.isArray(value))
14
+ return { args: value };
15
+ const record = value;
16
+ const intentValue = record[intentField];
17
+ const intent = typeof intentValue === "string" && intentValue.trim() ? intentValue.trim() : undefined;
18
+ const { [intentField]: _intent, ...args } = record;
19
+ return intent ? { args, intent } : { args };
20
+ }
21
+ export function piToolIntentFieldForSchema(schema) {
22
+ if (!schema || typeof schema !== "object" || Array.isArray(schema))
23
+ return PI_TOOL_INTENT_FIELD;
24
+ const record = schema;
25
+ if (record.type !== "object")
26
+ return PI_TOOL_INTENT_FIELD;
27
+ const properties = record.properties && typeof record.properties === "object" && !Array.isArray(record.properties)
28
+ ? record.properties
29
+ : {};
30
+ const required = new Set(Array.isArray(record.required)
31
+ ? record.required.filter((name) => typeof name === "string")
32
+ : []);
33
+ const fieldIsUsed = (field) => Object.prototype.hasOwnProperty.call(properties, field) || required.has(field);
34
+ if (!fieldIsUsed(PI_TOOL_INTENT_FIELD))
35
+ return PI_TOOL_INTENT_FIELD;
36
+ let candidate = PI_TOOL_INTENT_FALLBACK_FIELD;
37
+ let suffix = 2;
38
+ while (fieldIsUsed(candidate))
39
+ candidate = `${PI_TOOL_INTENT_FALLBACK_FIELD}_${suffix++}`;
40
+ return candidate;
41
+ }
42
+ export function injectPiToolIntentSchema(schema) {
43
+ if (!schema || typeof schema !== "object" || Array.isArray(schema))
44
+ return schema;
45
+ const record = schema;
46
+ if (record.type !== "object")
47
+ return schema;
48
+ const properties = record.properties && typeof record.properties === "object" && !Array.isArray(record.properties)
49
+ ? record.properties
50
+ : {};
51
+ const intentField = piToolIntentFieldForSchema(schema);
52
+ const required = Array.isArray(record.required)
53
+ ? record.required.filter((name) => typeof name === "string" && name !== intentField)
54
+ : [];
55
+ return {
56
+ ...record,
57
+ properties: {
58
+ [intentField]: PI_TOOL_INTENT_SCHEMA,
59
+ ...properties,
60
+ },
61
+ required: [intentField, ...required],
62
+ };
63
+ }
64
+ export function piIntentTracingInstalled(session) {
65
+ return intentTracingSessions.has(session);
66
+ }
67
+ export function piToolIntentField(session, toolName) {
68
+ return intentTracingSessions.get(session)?.get(toolName);
69
+ }
70
+ export function installPiIntentTracing(session) {
71
+ if (intentTracingSessions.has(session))
72
+ return;
73
+ const intentFields = new Map();
74
+ const wrappedTools = new WeakMap();
75
+ const wrapActiveTools = () => {
76
+ session.agent.state.tools = session.agent.state.tools.map((tool) => {
77
+ const existing = wrappedTools.get(tool);
78
+ if (existing) {
79
+ intentFields.set(tool.name, existing.intentField);
80
+ return existing.tool;
81
+ }
82
+ const wrapped = wrapPiToolWithIntent(tool);
83
+ wrappedTools.set(tool, wrapped);
84
+ intentFields.set(tool.name, wrapped.intentField);
85
+ return wrapped.tool;
86
+ });
87
+ };
88
+ const setActiveToolsByName = session.setActiveToolsByName.bind(session);
89
+ session.setActiveToolsByName = (toolNames) => {
90
+ setActiveToolsByName(toolNames);
91
+ wrapActiveTools();
92
+ };
93
+ intentTracingSessions.set(session, intentFields);
94
+ wrapActiveTools();
95
+ }
96
+ function wrapPiToolWithIntent(tool) {
97
+ const prepareArguments = tool.prepareArguments;
98
+ const intentField = piToolIntentFieldForSchema(tool.parameters);
99
+ return {
100
+ intentField,
101
+ tool: {
102
+ ...tool,
103
+ parameters: injectPiToolIntentSchema(tool.parameters),
104
+ prepareArguments: (rawArgs) => {
105
+ const { args, intent } = splitPiToolIntentArguments(rawArgs, intentField);
106
+ const prepared = prepareArguments ? prepareArguments(args) : args;
107
+ if (!prepared || typeof prepared !== "object" || Array.isArray(prepared))
108
+ return prepared;
109
+ return {
110
+ ...prepared,
111
+ ...(intent ? { [intentField]: intent } : {}),
112
+ };
113
+ },
114
+ execute: async (toolCallId, params, signal, onUpdate) => {
115
+ const { args } = splitPiToolIntentArguments(params, intentField);
116
+ return await tool.execute(toolCallId, args, signal, onUpdate);
117
+ },
118
+ },
119
+ };
120
+ }
@@ -6,6 +6,7 @@ import { expandInlineSkills } from "../../core/skill-expansion.js";
6
6
  import { PIBO_CONTEXT_GUARD_RESUME_MESSAGE_TYPE, PIBO_CONTEXT_GUARD_RESUME_PROMPT, cancelPiboAssistantContextGuardRecovery, claimPiboAssistantContextGuardRecovery, waitForPiboAssistantContextGuardRecovery, } from "../../core/context-guard.js";
7
7
  import { PIBO_PROVIDER_RECOVERY_MESSAGE_TYPE, PIBO_PROVIDER_RECOVERY_PROMPT, PiboProviderRecoveryCancelledError, isRetryablePiboAssistantError, isRetryablePiboProviderError, resolvePiboProviderRecoverySettings, waitForPiboProviderRecovery, } from "../../core/provider-recovery.js";
8
8
  import { PiAgentRuntimeAuthController } from "./auth.js";
9
+ import { piIntentTracingInstalled, piToolIntentField, splitPiToolIntentArguments } from "./intent-tracing.js";
9
10
  import { loadModelCatalog as loadPiModelCatalog } from "./model-catalog.js";
10
11
  import { PIBO_TRANSCRIPT_INTEGRITY_RESUME_MESSAGE_TYPE, PIBO_TRANSCRIPT_INTEGRITY_RESUME_PROMPT, PiboTranscriptIntegrityError, claimPiboTranscriptIntegrityContinuation, settlePiboTranscriptIntegrityContinuation, } from "../../core/transcript-integrity.js";
11
12
  const FAST_SERVICE_TIER = "priority";
@@ -175,45 +176,57 @@ function toolCallFromAssistantEvent(candidate) {
175
176
  }
176
177
  return toolCallFromMessage(candidate.message, candidate.assistantMessageEvent?.contentIndex);
177
178
  }
178
- function normalizeToolCallEvent(piboSessionId, candidate) {
179
+ function normalizeToolCallEvent(piboSessionId, candidate, context) {
179
180
  if (candidate.type === "message_update" &&
180
181
  (candidate.assistantMessageEvent?.type === "toolcall_start" ||
181
182
  candidate.assistantMessageEvent?.type === "toolcall_end")) {
182
183
  const toolCall = toolCallFromAssistantEvent(candidate);
183
184
  if (!toolCall)
184
185
  return undefined;
186
+ const { args, intent } = context?.intentTracing
187
+ ? splitPiToolIntentArguments(toolCall.args, context.intentFieldForTool?.(toolCall.name))
188
+ : { args: toolCall.args };
185
189
  return {
186
190
  type: "tool_call",
187
191
  piboSessionId,
188
192
  toolCallId: toolCall.id,
189
193
  toolName: toolCall.name,
190
- args: toolCall.args,
194
+ args,
191
195
  argsComplete: candidate.assistantMessageEvent.type === "toolcall_end",
196
+ ...(intent ? { intent } : {}),
192
197
  };
193
198
  }
194
199
  return undefined;
195
200
  }
196
- function normalizeToolExecutionEvent(piboSessionId, candidate) {
201
+ function normalizeToolExecutionEvent(piboSessionId, candidate, context) {
197
202
  if (typeof candidate.toolCallId !== "string" || typeof candidate.toolName !== "string") {
198
203
  return undefined;
199
204
  }
200
205
  if (candidate.type === "tool_execution_start") {
206
+ const { args, intent } = context?.intentTracing
207
+ ? splitPiToolIntentArguments(candidate.args, context.intentFieldForTool?.(candidate.toolName))
208
+ : { args: candidate.args };
201
209
  return {
202
210
  type: "tool_execution_started",
203
211
  piboSessionId,
204
212
  toolCallId: candidate.toolCallId,
205
213
  toolName: candidate.toolName,
206
- args: candidate.args,
214
+ args,
215
+ ...(intent ? { intent } : {}),
207
216
  };
208
217
  }
209
218
  if (candidate.type === "tool_execution_update") {
219
+ const { args, intent } = context?.intentTracing
220
+ ? splitPiToolIntentArguments(candidate.args, context.intentFieldForTool?.(candidate.toolName))
221
+ : { args: candidate.args };
210
222
  return {
211
223
  type: "tool_execution_updated",
212
224
  piboSessionId,
213
225
  toolCallId: candidate.toolCallId,
214
226
  toolName: candidate.toolName,
215
- args: candidate.args,
227
+ args,
216
228
  partialResult: candidate.partialResult,
229
+ ...(intent ? { intent } : {}),
217
230
  };
218
231
  }
219
232
  if (candidate.type === "tool_execution_end") {
@@ -332,10 +345,10 @@ export function normalizePiEvent(piboSessionId, event, context) {
332
345
  ? { type: "thinking_finished", piboSessionId, contentIndex: messageContentIndex(candidate) }
333
346
  : { type: "thinking_finished", piboSessionId, contentIndex: messageContentIndex(candidate), text };
334
347
  }
335
- const toolCallEvent = normalizeToolCallEvent(piboSessionId, candidate);
348
+ const toolCallEvent = normalizeToolCallEvent(piboSessionId, candidate, context);
336
349
  if (toolCallEvent)
337
350
  return toolCallEvent;
338
- const toolExecutionEvent = normalizeToolExecutionEvent(piboSessionId, candidate);
351
+ const toolExecutionEvent = normalizeToolExecutionEvent(piboSessionId, candidate, context);
339
352
  if (toolExecutionEvent)
340
353
  return toolExecutionEvent;
341
354
  if (candidate.type === "message_end") {
@@ -553,7 +566,11 @@ export class RoutedSession {
553
566
  this.unsubscribe = session.subscribe((event) => {
554
567
  this.onPiEventTelemetry?.(this.piboSessionId, event, { status: this.getStatus(), activeEventId: this.activeMessage?.id ?? this.activeExecutionEvent?.id });
555
568
  const model = this.runtime.session.model;
556
- const normalized = normalizePiEvent(this.piboSessionId, event, { contextWindow: numberValue(model?.contextWindow) });
569
+ const normalized = normalizePiEvent(this.piboSessionId, event, {
570
+ contextWindow: numberValue(model?.contextWindow),
571
+ intentTracing: piIntentTracingInstalled(session),
572
+ intentFieldForTool: (toolName) => piToolIntentField(session, toolName),
573
+ });
557
574
  const candidate = event && typeof event === "object" ? event : undefined;
558
575
  const assistantMessageEnded = candidate?.type === "message_end" && isAssistantMessage(candidate.message);
559
576
  const usageEvent = assistantMessageEnded ? normalizeAssistantUsageEvent(this.piboSessionId, candidate?.message) : undefined;
@@ -5,7 +5,7 @@ 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 { createSubagentToolName, } from "../../subagents/tool.js";
8
+ import { PIBO_AGENT_TOOL_NAMES, } from "../../subagents/tool.js";
9
9
  import { getInstalledCliToolContextFile } from "../../tools/registry.js";
10
10
  import { createCodexCompatExtension } from "../../core/codex-compat.js";
11
11
  import { createWebSearchProviderExtension, isWebSearchProviderTool } from "../../tools/web-search.js";
@@ -28,6 +28,7 @@ import { compactValidationToolResultForContext } from "../../core/test-output-co
28
28
  import { installPiboTranscriptIntegrity } from "../../core/transcript-integrity.js";
29
29
  import { normalizePiboToolDefinition, } from "../../tools/contract.js";
30
30
  import { compilePiboToolForPi } from "./tool-compiler.js";
31
+ import { installPiIntentTracing, piIntentTracingEnabled } from "./intent-tracing.js";
31
32
  import { createPiboSessionToolDefinitions, isCodexBrowserToolProfile as isCodexBrowserTool, isEnabledCodexBrowserToolProfile as isEnabledCodexBrowserTool, isEnabledRuntimeToolProfile as isEnabledRuntimeTool, isGeneratedPiboTool, isRuntimeToolProfile as isRuntimeTool, } from "../../tools/session-tool-set.js";
32
33
  function hasOwnRetrySetting(settings, key) {
33
34
  return settings !== undefined && settings !== null && Object.prototype.hasOwnProperty.call(settings, key);
@@ -154,11 +155,20 @@ function getProfileExtensionFactories(profile, extensionFactories, contextGuardR
154
155
  ...(extensionFactories ?? []),
155
156
  ];
156
157
  }
157
- function createInspectionSubagentRunner() {
158
+ function createInspectionAgentsController() {
159
+ const fail = () => {
160
+ throw new Error("Profile inspection cannot execute delegated-agent tools");
161
+ };
158
162
  return {
159
- async runSubagent() {
160
- throw new Error("Profile inspection cannot execute subagents");
161
- },
163
+ sendMessage: fail,
164
+ listAgents: () => [],
165
+ observe: (input) => ({
166
+ filters: input,
167
+ observations: [],
168
+ nextAfterSequence: input.afterSequence ?? 0,
169
+ truncated: false,
170
+ }),
171
+ killAgent: fail,
162
172
  };
163
173
  }
164
174
  function createInspectionRunToolController() {
@@ -190,6 +200,9 @@ async function createSessionManager(cwd, profile, persistSession) {
190
200
  export async function createPiboRuntime(options = {}) {
191
201
  const cwd = options.cwd ?? getDefaultPiboWorkspace();
192
202
  const profile = options.profile ?? createDefaultPiboProfile();
203
+ if (profile.subagents.some((subagent) => subagent.enabled !== false) && options.subagentRunner && !options.agentsController && !options.portableTools) {
204
+ throw new Error("PiboRuntimeOptions.subagentRunner is retired. Provide agentsController so the runtime can expose the four pibo_agents_* management tools. The deprecated createSubagentToolDefinitions export remains available only for external legacy tool assembly.");
205
+ }
193
206
  const agentDir = getAgentDir();
194
207
  const sessionManager = await createSessionManager(cwd, profile, options.persistSession !== false);
195
208
  const createRuntime = async ({ cwd: runtimeCwd, agentDir: runtimeAgentDir, sessionManager: runtimeSessionManager, sessionStartEvent, }) => {
@@ -284,7 +297,7 @@ export async function createPiboRuntime(options = {}) {
284
297
  : createPiboSessionToolDefinitions({
285
298
  profile,
286
299
  toolContext,
287
- subagentRunner: options.subagentRunner,
300
+ agentsController: options.agentsController,
288
301
  runToolController: options.runToolController,
289
302
  runtimeToolController,
290
303
  codexBrowserController,
@@ -306,6 +319,8 @@ export async function createPiboRuntime(options = {}) {
306
319
  noTools: profile.builtinTools === "disabled" ? "builtin" : undefined,
307
320
  tools: getBuiltinToolAllowlist(profile, piboToolDefinitions),
308
321
  });
322
+ if (piIntentTracingEnabled(profile.runtimeOptions))
323
+ installPiIntentTracing(created.session);
309
324
  installPiboTranscriptIntegrity(created.session);
310
325
  installValidationOutputCompaction(created.session.agent);
311
326
  registerPiboAssistantContextGuardRecovery(created.session, contextGuardRecovery);
@@ -414,7 +429,7 @@ export async function inspectPiboProfile(options = {}) {
414
429
  persistSession: false,
415
430
  modelDefaults: {},
416
431
  activeModel: undefined,
417
- subagentRunner: options.subagentRunner ?? (hasEnabledSubagents ? createInspectionSubagentRunner() : undefined),
432
+ agentsController: options.agentsController ?? (hasEnabledSubagents ? createInspectionAgentsController() : undefined),
418
433
  runToolController: options.runToolController ?? (hasYieldableTools ? createInspectionRunToolController() : undefined),
419
434
  });
420
435
  try {
@@ -459,14 +474,11 @@ export async function inspectPiboProfile(options = {}) {
459
474
  registered: registeredToolNames.has(tool.name) || tool.providerTool !== undefined || isRuntimeTool(tool) || isCodexBrowserTool(tool),
460
475
  active: activeToolNames.has(tool.name) || tool.providerTool !== undefined,
461
476
  })).concat(generatedTools),
462
- subagents: profile.subagents.map((subagent) => {
463
- const toolName = createSubagentToolName(subagent.name);
464
- return {
465
- name: subagent.name,
466
- targetProfile: subagent.targetProfile,
467
- active: activeToolNames.has(toolName),
468
- };
469
- }),
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
+ })),
470
482
  mcpServers: [...profile.mcpServers],
471
483
  mcpStatus: options.resources?.getInspection().mcpServers.map((server) => structuredClone(server)) ?? [],
472
484
  resourceDelivery: options.resources?.getInspection().delivery.map((report) => ({ ...report })) ?? [],
@@ -521,7 +533,7 @@ function installPiboContextGuardTuiQueueOrdering(session) {
521
533
  export async function runPiboTui(options = {}) {
522
534
  const profile = options.profile ?? createDefaultPiboProfile();
523
535
  const hasEnabledSubagents = profile.subagents.some((subagent) => subagent.enabled !== false);
524
- if (hasEnabledSubagents && (!options.subagentRunner || !options.runToolController)) {
536
+ if (hasEnabledSubagents && (!options.agentsController || !options.runToolController)) {
525
537
  console.error(`Error: Profile "${profile.profileName}" uses subagents and requires the routed pibo runtime. ` +
526
538
  `Use "npm run tui:routed -- ${profile.profileName}" for local TUI QA.`);
527
539
  process.exitCode = 1;
@@ -1,7 +1,8 @@
1
1
  import { readPiboBasePrompt, savePiboCustomBasePrompt, setPiboBasePromptMode } from "../../core/base-prompt.js";
2
2
  import { readPiboCompactionPrompt, savePiboCustomCompactionPrompt, setPiboCompactionPromptMode } from "../../core/compaction-prompt.js";
3
+ import { loadPiboGatewaySettings, sanitizeConcurrentYieldedRuns, updatePiboGatewaySettings, } from "../../core/gateway-settings.js";
3
4
  import { sanitizeTelemetryRetentionDays, sanitizeTelemetryRetentionSettings } from "../../core/telemetry-retention-settings.js";
4
- import { loadPiboUserSettings, sanitizeShortcutSettings, sanitizeTimezone, updatePiboUserSettings, updateTelemetryRetentionLastPrunedAt } from "../../core/user-settings.js";
5
+ import { loadPiboUserSettings, sanitizeShortcutSettings, sanitizeTimezone, sanitizeTranscriptionProviderId, updatePiboUserSettings, updateTelemetryRetentionLastPrunedAt } from "../../core/user-settings.js";
5
6
  import { PiboWebHttpError, readJsonBody, responseJson } from "../../web/http.js";
6
7
  import { CHAT_WEB_API_PREFIX } from "./chat-api-routes.js";
7
8
  import { normalizeBasePromptMarkdown, normalizeBasePromptMode, normalizeCompactionPromptMarkdown, normalizeCompactionPromptMode, updateChatModelDefaults, } from "./chat-request-normalizers.js";
@@ -13,6 +14,10 @@ export function chatSettingsRoute(pathname, method) {
13
14
  return { kind: "user-settings", action: "read" };
14
15
  if (pathname === `${CHAT_WEB_API_PREFIX}/user-settings` && method === "PATCH")
15
16
  return { kind: "user-settings", action: "update" };
17
+ if (pathname === `${CHAT_WEB_API_PREFIX}/gateway-settings` && method === "GET")
18
+ return { kind: "gateway-settings", action: "read" };
19
+ if (pathname === `${CHAT_WEB_API_PREFIX}/gateway-settings` && method === "PATCH")
20
+ return { kind: "gateway-settings", action: "update" };
16
21
  if (pathname === `${CHAT_WEB_API_PREFIX}/telemetry-retention/prune` && method === "POST")
17
22
  return { kind: "telemetry-retention", action: "prune" };
18
23
  if (pathname === `${CHAT_WEB_API_PREFIX}/base-prompt` && method === "GET")
@@ -46,7 +51,13 @@ export async function handleChatSettingsRoute(input) {
46
51
  if (route.action === "read")
47
52
  return responseJson({ userSettings: loadPiboUserSettings() });
48
53
  const body = await readJsonBody(request);
49
- return responseJson({ userSettings: updatePiboUserSettings(userSettingsPatch(body)) });
54
+ return responseJson({ userSettings: updatePiboUserSettings(userSettingsPatch(body, input.transcriptionProviderIds)) });
55
+ }
56
+ if (route.kind === "gateway-settings") {
57
+ if (route.action === "read")
58
+ return responseJson({ gatewaySettings: loadPiboGatewaySettings() });
59
+ const body = await readJsonBody(request);
60
+ return responseJson({ gatewaySettings: updatePiboGatewaySettings(gatewaySettingsPatch(body)) });
50
61
  }
51
62
  if (route.kind === "telemetry-retention") {
52
63
  if (!input.dataStore)
@@ -77,7 +88,25 @@ export async function handleChatSettingsRoute(input) {
77
88
  }
78
89
  return responseJson({ compactionPrompt: await savePiboCustomCompactionPrompt(normalizeCompactionPromptMarkdown(body.markdown), cwd) });
79
90
  }
80
- function userSettingsPatch(body) {
91
+ function gatewaySettingsPatch(body) {
92
+ const patch = {};
93
+ if (body.maxConcurrentYieldedRuns !== undefined) {
94
+ const value = sanitizeConcurrentYieldedRuns(body.maxConcurrentYieldedRuns);
95
+ if (!value)
96
+ throw new PiboWebHttpError("Invalid gateway yielded-run concurrency", 400);
97
+ patch.maxConcurrentYieldedRuns = value;
98
+ }
99
+ if (body.sessionConcurrentYieldedRuns !== undefined) {
100
+ const value = sanitizeConcurrentYieldedRuns(body.sessionConcurrentYieldedRuns);
101
+ if (!value)
102
+ throw new PiboWebHttpError("Invalid session yielded-run concurrency", 400);
103
+ patch.sessionConcurrentYieldedRuns = value;
104
+ }
105
+ if (Object.keys(patch).length === 0)
106
+ throw new PiboWebHttpError("No gateway settings provided", 400);
107
+ return patch;
108
+ }
109
+ function userSettingsPatch(body, transcriptionProviderIds) {
81
110
  const patch = {};
82
111
  if (body.timezone !== undefined) {
83
112
  const timezone = sanitizeTimezone(body.timezone);
@@ -87,6 +116,18 @@ function userSettingsPatch(body) {
87
116
  }
88
117
  if (body.shortcuts !== undefined)
89
118
  patch.shortcuts = sanitizeShortcutSettings(body.shortcuts);
119
+ if (body.transcription !== undefined) {
120
+ const raw = body.transcription && typeof body.transcription === "object" && !Array.isArray(body.transcription)
121
+ ? body.transcription
122
+ : {};
123
+ const providerId = sanitizeTranscriptionProviderId(raw.providerId);
124
+ if (!providerId)
125
+ throw new PiboWebHttpError("Invalid transcription provider", 400);
126
+ if (transcriptionProviderIds && !transcriptionProviderIds.includes(providerId)) {
127
+ throw new PiboWebHttpError(`Unknown transcription provider "${providerId}"`, 400);
128
+ }
129
+ patch.transcription = { providerId };
130
+ }
90
131
  if (body.telemetryRetention !== undefined) {
91
132
  const current = loadPiboUserSettings().telemetryRetention;
92
133
  patch.telemetryRetention = {