@pasko70/pibo 1.14.0 → 1.16.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 (52) hide show
  1. package/context/pibo-native-tooling.md +1 -1
  2. package/dist/apps/chat/web-app.js +11 -0
  3. package/dist/apps/chat-ui/assets/{dist-1eQpSfYj.js → dist-4-l8R83g.js} +1 -1
  4. package/dist/apps/{context-files-ui/assets/dist-CHdx1Jri.js → chat-ui/assets/dist-B9-pH_ss.js} +1 -1
  5. package/dist/apps/chat-ui/assets/{dist-hoDORUlL.js → dist-BKc5qFOn.js} +1 -1
  6. package/dist/apps/{context-files-ui/assets/dist-CntqFySz.js → chat-ui/assets/dist-CfT2OdUN.js} +1 -1
  7. package/dist/apps/chat-ui/assets/{dist-ur4yXrlj.js → dist-ClTBuMxL.js} +1 -1
  8. package/dist/apps/{context-files-ui/assets/dist-Cjq6RWEt.js → chat-ui/assets/dist-D4pAJPG3.js} +1 -1
  9. package/dist/apps/{context-files-ui/assets/dist-kPuQud7t.js → chat-ui/assets/dist-DCr1bDLp.js} +1 -1
  10. package/dist/apps/{context-files-ui/assets/dist-B7gXtTZC.js → chat-ui/assets/dist-D_inCXoq.js} +1 -1
  11. package/dist/apps/{context-files-ui/assets/dist-C-Jm45P4.js → chat-ui/assets/dist-DbW63bQx.js} +1 -1
  12. package/dist/apps/chat-ui/assets/{dist-BIwXuAMQ.js → dist-DyeQntkx.js} +1 -1
  13. package/dist/apps/chat-ui/assets/index-CMTOlTY9.js +473 -0
  14. package/dist/apps/chat-ui/assets/index-E0RmuCkY.css +1 -0
  15. package/dist/apps/chat-ui/index.html +2 -2
  16. package/dist/apps/chat-vscode-web/assets/index-BeTXIfmQ.js +275 -0
  17. package/dist/apps/chat-vscode-web/index.html +1 -1
  18. package/dist/apps/context-files-ui/assets/{dist-DxEGebCR.js → dist-4oHMVqMd.js} +1 -1
  19. package/dist/apps/{chat-ui/assets/dist-LWXXqiGT.js → context-files-ui/assets/dist-B8GCRy-W.js} +1 -1
  20. package/dist/apps/{chat-ui/assets/dist-CtsdsIpj.js → context-files-ui/assets/dist-BZscbUy_.js} +1 -1
  21. package/dist/apps/context-files-ui/assets/{dist-BKuGdcnX.js → dist-C3bTw5ib.js} +1 -1
  22. package/dist/apps/{chat-ui/assets/dist-BG1J2hGI.js → context-files-ui/assets/dist-CFbqQ7A8.js} +1 -1
  23. package/dist/apps/context-files-ui/assets/{dist-BD262Ouw.js → dist-CZOCrCg8.js} +1 -1
  24. package/dist/apps/{chat-ui/assets/dist-DmqwP_tM.js → context-files-ui/assets/dist-D9wOh84K.js} +1 -1
  25. package/dist/apps/{chat-ui/assets/dist-BeCHnL7P.js → context-files-ui/assets/dist-D_65A0Jm.js} +1 -1
  26. package/dist/apps/{chat-ui/assets/dist-DfdQQObC.js → context-files-ui/assets/dist-DsVkw0QH.js} +1 -1
  27. package/dist/apps/context-files-ui/assets/{dist-CULMH-fB.js → dist-dXgL1mFo.js} +1 -1
  28. package/dist/apps/context-files-ui/assets/index-DiJwk6ni.js +438 -0
  29. package/dist/apps/context-files-ui/index.html +1 -1
  30. package/dist/apps/vscode-artifacts/latest.vsix +0 -0
  31. package/dist/apps/vscode-artifacts/pibo-vscode-ext-1.16.0.vsix +0 -0
  32. package/dist/core/routed-session.js +17 -0
  33. package/dist/core/runtime.js +27 -5
  34. package/dist/core/session-router.js +20 -6
  35. package/dist/debug/web-streaming-benchmark-analysis.js +23 -0
  36. package/dist/debug/web-streaming-browser-library.js +0 -1
  37. package/dist/debug/web.js +4 -2
  38. package/dist/gateway/server.js +1 -0
  39. package/dist/plugins/builtin.js +10 -9
  40. package/dist/session-ui/terminalRows.js +12 -2
  41. package/dist/shared/trace-event-projection.js +15 -15
  42. package/dist/shared/trace-live-reducer.js +1 -0
  43. package/dist/tools/browser-use-leases.js +16 -0
  44. package/dist/tools/codex-browser-node-repl.js +224 -0
  45. package/dist/tools/codex-browser-node-worker-source.js +403 -0
  46. package/dist/tools/codex-browser.js +461 -0
  47. package/package.json +3 -1
  48. package/dist/apps/chat-ui/assets/index-CoCl8FG8.css +0 -1
  49. package/dist/apps/chat-ui/assets/index-DLNTzhdh.js +0 -237
  50. package/dist/apps/chat-vscode-web/assets/index-R_7kgvvD.js +0 -41
  51. package/dist/apps/context-files-ui/assets/index-DZWsbuvg.js +0 -202
  52. package/dist/apps/vscode-artifacts/pibo-vscode-ext-1.14.0.vsix +0 -0
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Pibo Context Files</title>
7
- <script type="module" crossorigin src="/apps/context-files/assets/index-DZWsbuvg.js"></script>
7
+ <script type="module" crossorigin src="/apps/context-files/assets/index-DiJwk6ni.js"></script>
8
8
  <link rel="modulepreload" crossorigin href="/apps/context-files/assets/dist-D1KyNDg5.js">
9
9
  <link rel="stylesheet" crossorigin href="/apps/context-files/assets/index-Cs4XQITe.css">
10
10
  </head>
@@ -818,6 +818,22 @@ export class RoutedSession {
818
818
  } : {}),
819
819
  };
820
820
  }
821
+ async getStatusSnapshot() {
822
+ const contextUsage = this.getContextUsage();
823
+ const providerUsage = await this.getProviderUsage();
824
+ return {
825
+ ...this.getStatus(),
826
+ activeModel: this.getActiveModel(),
827
+ contextUsage: contextUsage
828
+ ? {
829
+ tokens: contextUsage.tokens ?? undefined,
830
+ contextWindow: contextUsage.contextWindow ?? undefined,
831
+ percent: contextUsage.percent ?? undefined,
832
+ }
833
+ : contextUsage,
834
+ ...(providerUsage ? { providerUsage } : {}),
835
+ };
836
+ }
821
837
  getContextUsage() {
822
838
  return this.runtime.session.getContextUsage();
823
839
  }
@@ -1261,6 +1277,7 @@ export class RoutedSession {
1261
1277
  return await gatewayAction.execute({
1262
1278
  piboSessionId: this.piboSessionId,
1263
1279
  getStatus: () => this.getStatus(),
1280
+ getStatusSnapshot: () => this.getStatusSnapshot(),
1264
1281
  getContextUsage: () => this.getContextUsage(),
1265
1282
  getActiveModel: () => this.getActiveModel(),
1266
1283
  getProviderUsage: () => this.getProviderUsage(),
@@ -25,6 +25,7 @@ import { registerOpenAiGpt56Models } from "../providers/openai-gpt56.js";
25
25
  import { PIBO_APP_CONTEXT } from "../app-context.js";
26
26
  import { createRuntimeToolDefinition } from "../tools/runtime/tool.js";
27
27
  import { RuntimeSessionRegistry } from "../tools/runtime/registry.js";
28
+ import { CODEX_BROWSER_TOOL_NAMES, CodexBrowserSessionController, createCodexBrowserToolDefinitions, } from "../tools/codex-browser.js";
28
29
  import { compactValidationToolResultForContext } from "./test-output-compaction.js";
29
30
  import { installPiboTranscriptIntegrity } from "./transcript-integrity.js";
30
31
  function hasOwnRetrySetting(settings, key) {
@@ -102,12 +103,18 @@ function getEnabledSkillPaths(cwd, profile) {
102
103
  .filter((skill) => skill.enabled !== false)
103
104
  .map((skill) => resolveProfilePath(cwd, skill.path));
104
105
  }
105
- function getEnabledToolDefinitions(profile, options, subagentRunner, runToolController, runtimeToolController) {
106
+ function getEnabledToolDefinitions(profile, options, subagentRunner, runToolController, runtimeToolController, codexBrowserController) {
106
107
  const runtimeProfileTool = profile.tools.find(isEnabledRuntimeTool);
107
108
  const runtimeTool = runtimeProfileTool && runtimeToolController
108
109
  ? createRuntimeToolDefinition(runtimeToolController)
109
110
  : undefined;
110
- const profileTools = profile.tools.filter((tool) => !isRuntimeTool(tool)).filter(hasEnabledToolDefinition);
111
+ const selectedCodexBrowserToolNames = profile.tools
112
+ .filter(isEnabledCodexBrowserTool)
113
+ .map((tool) => tool.name);
114
+ const codexBrowserTools = codexBrowserController
115
+ ? createCodexBrowserToolDefinitions(codexBrowserController, selectedCodexBrowserToolNames)
116
+ : [];
117
+ const profileTools = profile.tools.filter((tool) => !isRuntimeTool(tool) && !isCodexBrowserTool(tool)).filter(hasEnabledToolDefinition);
111
118
  const profileToolDefinitions = profileTools.map((tool) => getToolDefinition(tool, options.toolContext));
112
119
  const codexCompatEnabled = profile.toolPackages.codexCompat === true;
113
120
  const runControlEnabled = profile.toolPackages.runControl === true;
@@ -129,6 +136,7 @@ function getEnabledToolDefinitions(profile, options, subagentRunner, runToolCont
129
136
  ...(runControlBashTool ? [runControlBashTool] : []),
130
137
  ...profileTools.filter((tool) => tool.yieldable !== false).map((tool) => getToolDefinition(tool, options.toolContext)),
131
138
  ...(runtimeTool && runtimeProfileTool?.yieldable !== false ? [runtimeTool] : []),
139
+ ...codexBrowserTools.filter((definition) => profile.tools.find((tool) => tool.name === definition.name)?.yieldable !== false),
132
140
  ...subagentTools,
133
141
  ...codexCompatTools,
134
142
  ];
@@ -139,6 +147,7 @@ function getEnabledToolDefinitions(profile, options, subagentRunner, runToolCont
139
147
  ...(runControlBashTool ? [runControlBashTool] : []),
140
148
  ...profileToolDefinitions,
141
149
  ...(runtimeTool ? [runtimeTool] : []),
150
+ ...codexBrowserTools,
142
151
  ...subagentTools,
143
152
  ...codexCompatTools,
144
153
  ...goalTools,
@@ -159,6 +168,12 @@ function isRuntimeTool(tool) {
159
168
  function isEnabledRuntimeTool(tool) {
160
169
  return tool.enabled !== false && isRuntimeTool(tool);
161
170
  }
171
+ function isCodexBrowserTool(tool) {
172
+ return tool.builtInPiboTool === "codex_browser" || CODEX_BROWSER_TOOL_NAMES.includes(tool.name);
173
+ }
174
+ function isEnabledCodexBrowserTool(tool) {
175
+ return tool.enabled !== false && isCodexBrowserTool(tool);
176
+ }
162
177
  function isGeneratedPiboTool(name) {
163
178
  return name === "runtime" || name.startsWith("pibo_subagent_") || name.startsWith("pibo_run_") || PIBO_GOAL_TOOL_NAMES.includes(name);
164
179
  }
@@ -280,6 +295,12 @@ export async function createPiboRuntime(options = {}) {
280
295
  const localRuntimeRegistry = ownsLocalRuntimeRegistry ? new RuntimeSessionRegistry({ cwd: runtimeCwd }) : undefined;
281
296
  const runtimeToolController = options.runtimeToolController
282
297
  ?? localRuntimeRegistry?.createController(profile.sessionId ?? "local");
298
+ const codexBrowserController = profile.tools.some(isEnabledCodexBrowserTool)
299
+ ? new CodexBrowserSessionController({
300
+ cwd: runtimeCwd,
301
+ piboSessionId: options.sessionContext?.piboSessionId ?? profile.sessionId ?? runtimeSessionManager.getSessionId(),
302
+ })
303
+ : undefined;
283
304
  const customTools = getEnabledToolDefinitions(profile, {
284
305
  runtimeCwd,
285
306
  shellCommandPrefix: services.settingsManager.getShellCommandPrefix(),
@@ -290,7 +311,7 @@ export async function createPiboRuntime(options = {}) {
290
311
  profileName: profile.profileName,
291
312
  getActiveMessage: options.sessionContext?.getActiveMessage,
292
313
  },
293
- }, options.subagentRunner, options.runToolController, runtimeToolController);
314
+ }, options.subagentRunner, options.runToolController, runtimeToolController, codexBrowserController);
294
315
  const modelDefaults = options.modelDefaults ?? loadPiboModelDefaults(runtimeCwd);
295
316
  const created = await createAgentSessionFromServices({
296
317
  services,
@@ -324,6 +345,7 @@ export async function createPiboRuntime(options = {}) {
324
345
  if (localRuntimeRegistry) {
325
346
  void localRuntimeRegistry.closeControllerSessions(profile.sessionId ?? "local", { force: true });
326
347
  }
348
+ void codexBrowserController?.dispose();
327
349
  originalDispose();
328
350
  };
329
351
  return {
@@ -444,8 +466,8 @@ export async function inspectPiboProfile(options = {}) {
444
466
  })),
445
467
  tools: profile.tools.map((tool) => ({
446
468
  name: tool.name,
447
- hasDefinition: Boolean(tool.definition) || Boolean(tool.createDefinition) || isRuntimeTool(tool),
448
- registered: registeredToolNames.has(tool.name) || tool.providerTool !== undefined || isRuntimeTool(tool),
469
+ hasDefinition: Boolean(tool.definition) || Boolean(tool.createDefinition) || isRuntimeTool(tool) || isCodexBrowserTool(tool),
470
+ registered: registeredToolNames.has(tool.name) || tool.providerTool !== undefined || isRuntimeTool(tool) || isCodexBrowserTool(tool),
449
471
  active: activeToolNames.has(tool.name) || tool.providerTool !== undefined,
450
472
  })).concat(generatedTools),
451
473
  subagents: profile.subagents.map((subagent) => {
@@ -23,6 +23,7 @@ import { PiboRuntimeTelemetryRecorder } from "./runtime-telemetry.js";
23
23
  import { createPiboProviderTelemetryExtension } from "./provider-telemetry.js";
24
24
  import { AsyncTelemetryWriter } from "../data/telemetry-writer.js";
25
25
  const DEFAULT_SUBAGENT_REPLY_TIMEOUT_MS = 10 * 60 * 1000;
26
+ const DEFAULT_SUBAGENT_MAX_DEPTH = 3;
26
27
  const DEFAULT_ROUTED_SESSION_IDLE_TIMEOUT_MS = 30 * 60 * 1000;
27
28
  const DEFAULT_ROUTED_SESSION_DISPOSE_TIMEOUT_MS = 30 * 1000;
28
29
  export const LOOP_RUNTIME_RETRY_DEFAULTS = {
@@ -43,7 +44,10 @@ export function resolvePiboSessionInitialFastMode(session) {
43
44
  const value = session.metadata?.initialFastMode;
44
45
  return typeof value === "boolean" ? value : undefined;
45
46
  }
46
- function profileForSession(baseProfile, piSessionId, parentPiSessionId) {
47
+ function hasReachedSubagentMaxDepth(subagent, depth) {
48
+ return depth >= (subagent.maxDepth ?? DEFAULT_SUBAGENT_MAX_DEPTH);
49
+ }
50
+ function profileForSession(baseProfile, piSessionId, parentPiSessionId, subagentDepth) {
47
51
  const options = {
48
52
  profileName: baseProfile.profileName,
49
53
  sessionId: piSessionId,
@@ -59,7 +63,7 @@ function profileForSession(baseProfile, piSessionId, parentPiSessionId) {
59
63
  subagentFast: baseProfile.subagentFast,
60
64
  skills: baseProfile.skills,
61
65
  tools: baseProfile.tools,
62
- subagents: baseProfile.subagents,
66
+ subagents: baseProfile.subagents.filter((subagent) => !hasReachedSubagentMaxDepth(subagent, subagentDepth)),
63
67
  mcpServers: baseProfile.mcpServers,
64
68
  contextFiles: baseProfile.contextFiles,
65
69
  piPackages: baseProfile.piPackages,
@@ -479,6 +483,15 @@ export class PiboSessionRouter {
479
483
  getSessionRuntimeStatus(piboSessionId) {
480
484
  return this.sessions.get(piboSessionId)?.getStatus();
481
485
  }
486
+ async getSessionStatusSnapshot(piboSessionId) {
487
+ const session = await this.getOrCreateSession(piboSessionId);
488
+ try {
489
+ return await session.getStatusSnapshot();
490
+ }
491
+ finally {
492
+ this.scheduleIdleSessionEvictionIfIdle(piboSessionId);
493
+ }
494
+ }
482
495
  async setLiveSessionActiveModel(piboSessionId, model) {
483
496
  const session = this.sessions.get(piboSessionId);
484
497
  if (!session)
@@ -700,6 +713,7 @@ export class PiboSessionRouter {
700
713
  const modelDefaults = this.resolveModelDefaults();
701
714
  const activeModel = this.ensureSessionActiveModel(piboSession, profile, parentPiSessionId, modelDefaults);
702
715
  const initialThinkingLevel = resolvePiboSessionInitialThinkingLevel(piboSession);
716
+ const sessionProfile = profileForSession(profile, piboSession.piSessionId, parentPiSessionId, this.getSubagentDepth(piboSession.id));
703
717
  const userSettings = loadPiboUserSettings();
704
718
  const telemetryExtension = this.telemetryStore
705
719
  ? createPiboProviderTelemetryExtension({ store: this.telemetryStore, writer: this.telemetryWriter, session: piboSession, model: activeModel })
@@ -709,7 +723,7 @@ export class PiboSessionRouter {
709
723
  persistSession: this.options.persistSession,
710
724
  thinkingLevel: initialThinkingLevel ?? this.options.thinkingLevel,
711
725
  retryDefaults: resolvePiboSessionRetryDefaults(piboSession.kind, this.options.retryDefaults),
712
- profile: profileForSession(profile, piboSession.piSessionId, parentPiSessionId),
726
+ profile: sessionProfile,
713
727
  extensionFactories: [
714
728
  ...(telemetryExtension ? [telemetryExtension] : []),
715
729
  ...(this.options.extensionFactories ?? []),
@@ -726,7 +740,7 @@ export class PiboSessionRouter {
726
740
  getActiveMessage: () => session?.getActiveMessage(),
727
741
  },
728
742
  });
729
- const initialFastMode = resolvePiboSessionInitialFastMode(piboSession) ?? selectRequestedFastMode(profileForSession(profile, piboSession.piSessionId, parentPiSessionId), modelDefaults) ?? false;
743
+ const initialFastMode = resolvePiboSessionInitialFastMode(piboSession) ?? selectRequestedFastMode(sessionProfile, modelDefaults) ?? false;
730
744
  session = new RoutedSession(piboSession.id, runtime, this.emitOutput, this.pluginRegistry, this.options.forwardPiEvents ?? false, this.telemetryRecorder
731
745
  ? (id, event, context) => this.telemetryRecorder?.recordPiEvent(id, event, { session: this.sessionStore.get(id), status: context.status, activeEventId: context.activeEventId })
732
746
  : undefined, initialFastMode, (result, event) => this.handleSessionOperation(result, event), (id, opts) => this.killChildSessions(id, opts), (state) => {
@@ -952,8 +966,8 @@ export class PiboSessionRouter {
952
966
  };
953
967
  }
954
968
  assertSubagentDepth(parentPiboSessionId, subagent) {
955
- const maxDepth = subagent.maxDepth ?? 3;
956
- if (this.getSubagentDepth(parentPiboSessionId) >= maxDepth) {
969
+ const maxDepth = subagent.maxDepth ?? DEFAULT_SUBAGENT_MAX_DEPTH;
970
+ if (hasReachedSubagentMaxDepth(subagent, this.getSubagentDepth(parentPiboSessionId))) {
957
971
  throw new Error(`Subagent "${subagent.name}" exceeded max depth ${maxDepth} from Pibo session "${parentPiboSessionId}"`);
958
972
  }
959
973
  }
@@ -12,6 +12,29 @@ const URL_COMPARISON_MAX_FIRST_LIVE_LATENCY_DELTA_MS = 250;
12
12
  const URL_COMPARISON_MAX_FIRST_VISIBLE_LATENCY_DELTA_MS = 300;
13
13
  const PROVIDER_MIN_TEXT_PRESERVATION_RATIO = 0.95;
14
14
  const PROVIDER_MIN_REASONING_PRESERVATION_RATIO = 0.95;
15
+ const X_ACCEL_BUFFERING_REGRESSION = "SSE X-Accel-Buffering header is not no";
16
+ export function evaluateStreamingSseHeaderRegressions(benchmark, url) {
17
+ if (!benchmark.sse?.requested)
18
+ return [];
19
+ const visibleValue = benchmark.sse.headers?.["x-accel-buffering"]?.trim().toLowerCase();
20
+ if (visibleValue)
21
+ return visibleValue === "no" ? [] : [X_ACCEL_BUFFERING_REGRESSION];
22
+ return isDirectStreamingBenchmarkUrl(url) ? [X_ACCEL_BUFFERING_REGRESSION] : [];
23
+ }
24
+ function isDirectStreamingBenchmarkUrl(value) {
25
+ try {
26
+ const hostname = new URL(value).hostname.toLowerCase();
27
+ return hostname === "localhost"
28
+ || hostname.endsWith(".localhost")
29
+ || hostname === "0.0.0.0"
30
+ || hostname === "::1"
31
+ || hostname === "[::1]"
32
+ || /^127(?:\.\d{1,3}){3}$/.test(hostname);
33
+ }
34
+ catch {
35
+ return false;
36
+ }
37
+ }
15
38
  export function scoreStreamingBenchmark(benchmark) {
16
39
  const debugDelta = benchmark.debug.delta ?? {};
17
40
  const textDeltaCount = numberField(debugDelta, "textDeltaCount");
@@ -645,7 +645,6 @@ function streamingBenchmarkRegressions(result) {
645
645
  if (result.sse && result.sse.requested) {
646
646
  if (!result.sse.installed) failures.push('SSE fetch probe unavailable');
647
647
  if (result.sse.status && result.sse.status !== 200) failures.push('SSE fetch status ' + result.sse.status);
648
- if (result.sse.headers && String(result.sse.headers['x-accel-buffering'] || '').toLowerCase() !== 'no') failures.push('SSE X-Accel-Buffering header is not no');
649
648
  if (result.sse.errors && result.sse.errors.length) failures.push('SSE fetch errors: ' + result.sse.errors.slice(0, 2).join('; '));
650
649
  if (!traceCatchupRequested && expectedDeltas !== undefined && result.sse.textEventCount < expectedDeltas) failures.push('SSE text events ' + result.sse.textEventCount + ' < fixture deltas ' + expectedDeltas);
651
650
  if (!traceCatchupRequested && expectedReasoningDeltas !== undefined && result.sse.reasoningEventCount < expectedReasoningDeltas) failures.push('SSE reasoning events ' + result.sse.reasoningEventCount + ' < fixture reasoning deltas ' + expectedReasoningDeltas);
package/dist/debug/web.js CHANGED
@@ -3,7 +3,7 @@ import { listBrowserUseCdpTargets, selectBestChatTarget, formatBrowserUseTargets
3
3
  import { CdpClient } from "../tools/cdp-client.js";
4
4
  import { diffSnapshots, formatSnapshot, formatSnapshotDiff, formatWatch } from "./web-render-analysis.js";
5
5
  import { formatStreamingBenchmarkAssertionError, formatStreamingBenchmarkCompactReport, formatStreamingBenchmarkResult, streamingBenchmarkReportRows, } from "./web-streaming-report.js";
6
- import { applyExpectedStreamingRegressions, attachStreamingProviderTelemetryToBenchmarks, evaluateStreamingLivePipelineRegressions, evaluateStreamingProviderRegressions, readStreamingBenchmarkArtifact, readStreamingBenchmarkRuns, scoreStreamingBenchmark, streamingBenchmarkReportTarget, summarizeStreamingBenchmarkGroup, summarizeStreamingBenchmarkUrlComparison, summarizeStreamingCadence, summarizeStreamingLivePipeline, summarizeStreamingProviderPreservation, } from "./web-streaming-benchmark-analysis.js";
6
+ import { applyExpectedStreamingRegressions, attachStreamingProviderTelemetryToBenchmarks, evaluateStreamingLivePipelineRegressions, evaluateStreamingProviderRegressions, evaluateStreamingSseHeaderRegressions, readStreamingBenchmarkArtifact, readStreamingBenchmarkRuns, scoreStreamingBenchmark, streamingBenchmarkReportTarget, summarizeStreamingBenchmarkGroup, summarizeStreamingBenchmarkUrlComparison, summarizeStreamingCadence, summarizeStreamingLivePipeline, summarizeStreamingProviderPreservation, } from "./web-streaming-benchmark-analysis.js";
7
7
  import { collectStreamingProviderTelemetry, collectStreamingProviderTelemetryFromSelectedBrowserSession, collectStreamingProviderTelemetryFromSession, collectStreamingProviderTelemetryFromTurn, } from "./web-streaming-provider-telemetry.js";
8
8
  import { buildStreamingBenchmarkExpression, streamingBenchmarkEventSourceProbeScript, streamingBenchmarkFixtureHtml } from "./web-streaming-browser-scripts.js";
9
9
  import { buildSnapshotExpression, buildWatchExpression } from "./web-snapshot-browser-scripts.js";
@@ -12,7 +12,7 @@ import { compactTarget, limitStdout, readBaselineSnapshot, writeArtifact, writeL
12
12
  import { applyNegativeStreamingProfile, DEFAULT_DEPTH_LIMIT, DEFAULT_EVENT_LIMIT, DEFAULT_NODE_LIMIT, DEFAULT_TEXT_LIMIT, parseDuration, parseFixtureMix, parseFixturePreludeMessages, parseFixtureProfile, parseNegativeProfile, parseOptions, parseRuns, presetScope, resolveScope, resolveStreamingBenchmarkCompareUrl, resolveStreamingBenchmarkHostedCompareUrl } from "./web-options.js";
13
13
  export { formatStreamingBenchmarkAssertionSummary, formatStreamingBenchmarkUrlComparison, summarizeStreamingSelectedLiveEventSource } from "./web-streaming-report.js";
14
14
  export { resolveStreamingBenchmarkHostedCompareUrlFromValues } from "./web-options.js";
15
- export { attachStreamingProviderTelemetryToBenchmark, evaluateStreamingBenchmarkAssertion, evaluateStreamingBenchmarkUrlComparisonRegressions, evaluateStreamingLivePipelineRegressions, evaluateStreamingProviderRegressions, summarizeStreamingBenchmarkUrlComparison, summarizeStreamingBenchmarks, summarizeStreamingLivePipeline, summarizeStreamingProviderPreservation } from "./web-streaming-benchmark-analysis.js";
15
+ export { attachStreamingProviderTelemetryToBenchmark, evaluateStreamingBenchmarkAssertion, evaluateStreamingBenchmarkUrlComparisonRegressions, evaluateStreamingLivePipelineRegressions, evaluateStreamingProviderRegressions, evaluateStreamingSseHeaderRegressions, summarizeStreamingBenchmarkUrlComparison, summarizeStreamingBenchmarks, summarizeStreamingLivePipeline, summarizeStreamingProviderPreservation } from "./web-streaming-benchmark-analysis.js";
16
16
  export { collectStreamingProviderTelemetryFromSelectedBrowserSession, collectStreamingProviderTelemetryFromSession, collectStreamingProviderTelemetryFromTurn, summarizeStreamingProviderTelemetry } from "./web-streaming-provider-telemetry.js";
17
17
  export { formatWatch, inferWatchFlickers } from "./web-render-analysis.js";
18
18
  export { analyzeStreamingRenderOrderCapture } from "./web-render-order-analysis.js";
@@ -485,6 +485,7 @@ async function runStreamingBenchmarkSeries(client, runs, durationMs, options) {
485
485
  }
486
486
  async function runStreamingBenchmark(client, durationMs, options = {}) {
487
487
  await client.send("Page.bringToFront").catch(() => undefined);
488
+ const targetUrl = await currentBrowserUrl(client);
488
489
  const benchmarkTimeoutMs = durationMs + (options.startBackendFixture ? 20_000 : 10_000);
489
490
  const benchmark = await client.evaluateJson(buildStreamingBenchmarkExpression(durationMs, options), benchmarkTimeoutMs);
490
491
  const withRenderOrder = { ...benchmark, renderOrder: analyzeStreamingRenderOrderCapture(benchmark.renderOrder) };
@@ -496,6 +497,7 @@ async function runStreamingBenchmark(client, durationMs, options = {}) {
496
497
  ...withCadence,
497
498
  regressions: [
498
499
  ...withCadence.regressions,
500
+ ...evaluateStreamingSseHeaderRegressions(withCadence, targetUrl),
499
501
  ...(withCadence.renderOrder?.analysis?.regressions ?? []),
500
502
  ...evaluateStreamingLivePipelineRegressions(withCadence),
501
503
  ...evaluateStreamingProviderRegressions(withCadence),
@@ -330,6 +330,7 @@ export class PiboGatewayServer {
330
330
  findSessions: (input) => this.requireSessionStore().find(input),
331
331
  listSessions: () => this.requireSessionStore().list?.() ?? [],
332
332
  getSessionRuntimeStatus: (piboSessionId) => this.requireRouter().getSessionRuntimeStatus(piboSessionId),
333
+ getSessionStatusSnapshot: (piboSessionId) => this.requireRouter().getSessionStatusSnapshot(piboSessionId),
333
334
  listSessionRuntimeStatuses: () => this.requireRouter().listSessionRuntimeStatuses(),
334
335
  listRuns: (options) => this.requireRouter().listRuns(options),
335
336
  snapshotSignalSession: (piboSessionId) => this.requireRouter().snapshotSignalSession(piboSessionId),
@@ -4,6 +4,7 @@ import { createPiboGatewayToolProfiles } from "../gateway/tool.js";
4
4
  import { InitialSessionContextBuilder } from "../core/profiles.js";
5
5
  import { parsePiboThinkingLevel } from "../core/thinking.js";
6
6
  import { createWebSearchToolProfile } from "../tools/web-search.js";
7
+ import { CODEX_BROWSER_TOOL_NAMES, createCodexBrowserToolProfiles } from "../tools/codex-browser.js";
7
8
  import { createRuntimeToolProfile } from "../tools/runtime/tool.js";
8
9
  import { completeLogin, getLoginStatus, removeLogin, setApiKey, startLogin } from "../auth/login-actions.js";
9
10
  import { loadModelCatalog } from "../apps/chat/model-catalog.js";
@@ -166,6 +167,12 @@ export const piboCorePlugin = definePiboPlugin({
166
167
  });
167
168
  api.registerTool(createWebSearchToolProfile());
168
169
  api.registerTool(createRuntimeToolProfile());
170
+ api.registerTools(createCodexBrowserToolProfiles());
171
+ api.registerCapabilityPackage({
172
+ name: "codex-browser-interface",
173
+ description: "Expose Browser Use and its persistent browser-bound Node REPL through a Codex-familiar structured tool surface.",
174
+ toolNames: [...CODEX_BROWSER_TOOL_NAMES],
175
+ });
169
176
  registerPiboNativeTooling(api);
170
177
  api.registerProfile({
171
178
  name: DEFAULT_PIBO_PROFILE_NAME,
@@ -181,14 +188,8 @@ export const piboCorePlugin = definePiboPlugin({
181
188
  name: "status",
182
189
  description: "Return current session status with context usage quota.",
183
190
  slashCommands: ["status"],
184
- async execute(context) {
185
- const providerUsage = await context.getProviderUsage();
186
- return {
187
- ...context.getStatus(),
188
- activeModel: context.getActiveModel(),
189
- contextUsage: context.getContextUsage(),
190
- ...(providerUsage ? { providerUsage } : {}),
191
- };
191
+ execute(context) {
192
+ return context.getStatusSnapshot();
192
193
  },
193
194
  });
194
195
  api.registerGatewayAction({
@@ -361,7 +362,7 @@ export const piboCorePlugin = definePiboPlugin({
361
362
  api.registerGatewayAction({
362
363
  name: "model",
363
364
  description: "Open the interactive model selector for authenticated providers.",
364
- slashCommands: ["model", "models"],
365
+ slashCommands: ["model"],
365
366
  async execute() {
366
367
  const catalog = await loadModelCatalog(process.cwd());
367
368
  return {
@@ -2,6 +2,13 @@ import { compareTraceNodes } from "../shared/trace-engine.js";
2
2
  import { terminalTextValue } from "./terminalValue.js";
3
3
  export const COMPACT_TERMINAL_OUTPUT_PREVIEW_LINES = 5;
4
4
  export const COMPACT_TERMINAL_EXPLORING_PREVIEW_LINES = 6;
5
+ const CODEX_COMPATIBLE_TOOL_LABELS = {
6
+ browser_use_open_tabs: "browser_use.open_tabs",
7
+ browser_use_take_screenshot: "browser_use.take_screenshot",
8
+ browser_use_browser_use: "browser_use.browser_use",
9
+ node_repl_js: "node_repl.js",
10
+ node_repl_js_reset: "node_repl.js_reset",
11
+ };
5
12
  export function buildCompactTerminalRows(traceView, options) {
6
13
  if (!traceView)
7
14
  return [];
@@ -270,7 +277,7 @@ function createToolRowCandidate(node, turnId) {
270
277
  token(toolVerb(node.status), toneForStatus(node.status), "semibold"),
271
278
  token(" "),
272
279
  ],
273
- functionCall: { name: node.title, input: node.input },
280
+ functionCall: { name: displayToolName(node.title), input: node.input },
274
281
  },
275
282
  ...preview.lines,
276
283
  ],
@@ -359,7 +366,7 @@ function createToolResultRow(node) {
359
366
  lines: [
360
367
  {
361
368
  prefix: "bullet",
362
- tokens: [token(node.status === "error" ? "Tool failed" : "Returned", toneForStatus(node.status), "semibold"), token(` ${node.title}`)],
369
+ tokens: [token(node.status === "error" ? "Tool failed" : "Returned", toneForStatus(node.status), "semibold"), token(` ${displayToolName(node.title)}`)],
363
370
  },
364
371
  ...preview.lines,
365
372
  ],
@@ -1030,6 +1037,9 @@ function classifyExploringTool(node) {
1030
1037
  }
1031
1038
  return undefined;
1032
1039
  }
1040
+ function displayToolName(name) {
1041
+ return CODEX_COMPATIBLE_TOOL_LABELS[name] ?? name;
1042
+ }
1033
1043
  function matchesTool(name, terms) {
1034
1044
  return terms.some((term) => name === term || name.startsWith(`${term}_`) || name.endsWith(`_${term}`) || name.includes(term));
1035
1045
  }
@@ -21,15 +21,15 @@ export function applySingleEventToNodes(nodes, byId, piboSessionId, storedEvent,
21
21
  return;
22
22
  }
23
23
  if (payload.type === "assistant_delta") {
24
- mergeAssistantDeltaEvent(nodes, byId, payload, sessionStatus, storedEvent.createdAt, storedEvent.eventSequence, storedEvent.streamId, storedEvent.streamFrameIndex);
24
+ mergeAssistantDeltaEvent(nodes, byId, payload, sessionStatus, storedEvent.createdAt, storedEvent.eventSequence, storedEvent.streamId, storedEvent.streamFrameIndex, storedEvent.traceSource);
25
25
  return;
26
26
  }
27
27
  if (payload.type === "thinking_delta") {
28
- mergeThinkingDeltaEvent(nodes, byId, payload, sessionStatus, storedEvent.createdAt, storedEvent.eventSequence, storedEvent.streamId, storedEvent.streamFrameIndex);
28
+ mergeThinkingDeltaEvent(nodes, byId, payload, sessionStatus, storedEvent.createdAt, storedEvent.eventSequence, storedEvent.streamId, storedEvent.streamFrameIndex, storedEvent.traceSource);
29
29
  return;
30
30
  }
31
31
  if (payload.type === "assistant_message") {
32
- const node = assistantMessageNodeFromEvent(piboSessionId, payload, storedEvent.createdAt, storedEvent.eventSequence, storedEvent.streamId, storedEvent.streamFrameIndex);
32
+ const node = assistantMessageNodeFromEvent(piboSessionId, payload, storedEvent.createdAt, storedEvent.eventSequence, storedEvent.streamId, storedEvent.streamFrameIndex, storedEvent.traceSource);
33
33
  const existing = byId.get(node.id) ?? findMatchingContentNode(byId, node);
34
34
  if (existing) {
35
35
  mergeAssistantMessageEvent(existing, node);
@@ -39,7 +39,7 @@ export function applySingleEventToNodes(nodes, byId, piboSessionId, storedEvent,
39
39
  byId.set(node.id, node);
40
40
  return;
41
41
  }
42
- const node = traceNodeFromEvent(piboSessionId, payload, childByParent, linkedChildByToolCallId, sessionStatus, storedEvent.createdAt, storedEvent.eventSequence, storedEvent.streamId, storedEvent.streamFrameIndex);
42
+ const node = traceNodeFromEvent(piboSessionId, payload, childByParent, linkedChildByToolCallId, sessionStatus, storedEvent.createdAt, storedEvent.eventSequence, storedEvent.streamId, storedEvent.streamFrameIndex, storedEvent.traceSource);
43
43
  if (!node)
44
44
  return;
45
45
  if (node.type === "user.message" &&
@@ -117,7 +117,7 @@ export function applySingleEventToNodes(nodes, byId, piboSessionId, storedEvent,
117
117
  for (const indexed of flattenTraceNodes([node]))
118
118
  byId.set(indexed.id, indexed);
119
119
  }
120
- function assistantMessageNodeFromEvent(piboSessionId, event, createdAt, eventSequence, streamId, streamFrameIndex) {
120
+ function assistantMessageNodeFromEvent(piboSessionId, event, createdAt, eventSequence, streamId, streamFrameIndex, traceSource) {
121
121
  const eventId = typeof event.eventId === "string" ? event.eventId : undefined;
122
122
  const assistantId = assistantEventNodeId(event);
123
123
  const id = assistantId ? assistantMessageNodeId(assistantId) : `event:${event.type}:${cryptoSafeId(event)}`;
@@ -135,7 +135,7 @@ function assistantMessageNodeFromEvent(piboSessionId, event, createdAt, eventSeq
135
135
  output: event.text,
136
136
  source: "event-log",
137
137
  stableKey: assistantId ? `assistant:${assistantId}` : eventStableKey(event),
138
- orderKey: eventTraceNodeOrder(eventSequence, event.type, streamId, streamFrameIndex),
138
+ orderKey: eventTraceNodeOrder(eventSequence, event.type, streamId, streamFrameIndex, traceSource),
139
139
  children: [],
140
140
  };
141
141
  }
@@ -356,7 +356,7 @@ export function latestTraceStreamId(events, initial) {
356
356
  return latest;
357
357
  }
358
358
  // ── event → node helpers ─────────────────────────────────────────
359
- function traceNodeFromEvent(piboSessionId, event, childByParent, linkedChildByToolCallId, sessionStatus, createdAt, eventSequence, streamId, streamFrameIndex) {
359
+ function traceNodeFromEvent(piboSessionId, event, childByParent, linkedChildByToolCallId, sessionStatus, createdAt, eventSequence, streamId, streamFrameIndex, traceSource) {
360
360
  const eventId = "eventId" in event && typeof event.eventId === "string" ? event.eventId : undefined;
361
361
  const id = `event:${event.type}:${eventId ?? cryptoSafeId(event)}`;
362
362
  const turnParentId = eventId ? messageTurnNodeId(eventId) : undefined;
@@ -367,7 +367,7 @@ function traceNodeFromEvent(piboSessionId, event, childByParent, linkedChildByTo
367
367
  startedAt: createdAt,
368
368
  source: "event-log",
369
369
  stableKey: eventStableKey(event),
370
- orderKey: eventTraceNodeOrder(eventSequence, event.type, streamId, streamFrameIndex),
370
+ orderKey: eventTraceNodeOrder(eventSequence, event.type, streamId, streamFrameIndex, traceSource),
371
371
  children: [],
372
372
  };
373
373
  switch (event.type) {
@@ -382,7 +382,7 @@ function traceNodeFromEvent(piboSessionId, event, childByParent, linkedChildByTo
382
382
  startedAt: createdAt,
383
383
  source: "event-log",
384
384
  stableKey: eventId ? `run-notification:${eventId}` : id,
385
- orderKey: eventTraceNodeOrder(eventSequence, event.type, streamId, streamFrameIndex),
385
+ orderKey: eventTraceNodeOrder(eventSequence, event.type, streamId, streamFrameIndex, traceSource),
386
386
  notification,
387
387
  });
388
388
  }
@@ -555,7 +555,7 @@ function traceNodeFromEvent(piboSessionId, event, childByParent, linkedChildByTo
555
555
  return undefined;
556
556
  }
557
557
  }
558
- function mergeAssistantDeltaEvent(nodes, byId, event, sessionStatus, createdAt, eventSequence, streamId, streamFrameIndex) {
558
+ function mergeAssistantDeltaEvent(nodes, byId, event, sessionStatus, createdAt, eventSequence, streamId, streamFrameIndex, traceSource) {
559
559
  if (typeof event.text !== "string" || event.text.length === 0)
560
560
  return;
561
561
  const assistantId = assistantEventNodeId(event);
@@ -581,7 +581,7 @@ function mergeAssistantDeltaEvent(nodes, byId, event, sessionStatus, createdAt,
581
581
  output: event.text,
582
582
  source: "event-log",
583
583
  stableKey: assistantId ? `assistant:${assistantId}` : id,
584
- orderKey: eventTraceNodeOrder(eventSequence, event.type, streamId, streamFrameIndex),
584
+ orderKey: eventTraceNodeOrder(eventSequence, event.type, streamId, streamFrameIndex, traceSource),
585
585
  children: [],
586
586
  };
587
587
  nodes.push(node);
@@ -599,7 +599,7 @@ function mergeAssistantMessageEvent(target, update) {
599
599
  target.error = update.error ?? target.error;
600
600
  target.completedAt = update.completedAt ?? target.completedAt;
601
601
  }
602
- function mergeThinkingDeltaEvent(nodes, byId, event, sessionStatus, createdAt, eventSequence, streamId, streamFrameIndex) {
602
+ function mergeThinkingDeltaEvent(nodes, byId, event, sessionStatus, createdAt, eventSequence, streamId, streamFrameIndex, traceSource) {
603
603
  if (typeof event.text !== "string" || event.text.length === 0)
604
604
  return;
605
605
  const thinkingId = thinkingEventNodeId(event);
@@ -626,7 +626,7 @@ function mergeThinkingDeltaEvent(nodes, byId, event, sessionStatus, createdAt, e
626
626
  output: event.text,
627
627
  source: "event-log",
628
628
  stableKey,
629
- orderKey: eventTraceNodeOrder(eventSequence, event.type, streamId, streamFrameIndex),
629
+ orderKey: eventTraceNodeOrder(eventSequence, event.type, streamId, streamFrameIndex, traceSource),
630
630
  children: [],
631
631
  };
632
632
  nodes.push(node);
@@ -806,8 +806,8 @@ function isOpenTranscriptEvent(event) {
806
806
  event.type === "thinking_delta" ||
807
807
  event.type === "thinking_finished");
808
808
  }
809
- function eventTraceNodeOrder(eventSequence, type, streamId, streamFrameIndex) {
810
- if (eventSequence === undefined && (streamId !== undefined || streamFrameIndex !== undefined)) {
809
+ function eventTraceNodeOrder(eventSequence, type, streamId, streamFrameIndex, traceSource) {
810
+ if (traceSource === "live") {
811
811
  return liveTraceOrder(streamId, streamFrameIndex, eventNodeKind(type));
812
812
  }
813
813
  return eventTraceOrder(eventSequence, eventNodeKind(type));
@@ -148,6 +148,7 @@ function makeStored(streamEvent, piboSessionId, type, payload, nextSequence, now
148
148
  eventSequence: sequence,
149
149
  streamId: typeof streamEvent.streamId === "number" ? streamEvent.streamId : undefined,
150
150
  streamFrameIndex,
151
+ traceSource: "live",
151
152
  eventId: typeof payload.eventId === "string" ? payload.eventId : undefined,
152
153
  type,
153
154
  createdAt: streamEventCreatedAt(streamEvent) ?? now(),
@@ -73,6 +73,22 @@ function defaultTemplateDir(status) {
73
73
  // Create an empty template directory so leases get clean profiles.
74
74
  return preferred;
75
75
  }
76
+ export function findActiveBrowserUseLeaseForHolder(status, holder, app, now = new Date()) {
77
+ return readRegistry(status).leases.find((lease) => lease.holder === holder &&
78
+ lease.status === 'active' &&
79
+ !isExpired(lease, now) &&
80
+ (app === undefined || lease.app === app));
81
+ }
82
+ export function browserUseLeaseEnvironment(status, lease) {
83
+ return {
84
+ BROWSER_USE_HOME: browserUseHome(status),
85
+ PIBO_BROWSER_USE_LEASE_ID: lease.id,
86
+ PIBO_BROWSER_USE_SESSION: lease.sessionName,
87
+ PIBO_BROWSER_USE_CHROME_USER_DATA_DIR: lease.userDataDir,
88
+ PIBO_BROWSER_USE_DEFAULT_PROFILE: lease.profileName,
89
+ ...(lease.browserPoolLeaseId ? { PIBO_BROWSER_POOL_LEASE_ID: lease.browserPoolLeaseId } : {}),
90
+ };
91
+ }
76
92
  export function readRegistry(status) {
77
93
  const path = registryPath(status);
78
94
  if (!existsSync(path))