@pasko70/pibo 1.9.13 → 1.10.1

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 (163) hide show
  1. package/README.md +183 -183
  2. package/context/codex-base-prompt.md +148 -148
  3. package/context/compute-worker.md +23 -23
  4. package/context/pibo-compaction-prompt.md +100 -100
  5. package/context/pibo-native-tooling.md +18 -18
  6. package/context/pibo-system-prompt.md +77 -77
  7. package/dist/apps/chat/agent-profiles.js +2 -2
  8. package/dist/apps/chat/agent-store.js +263 -250
  9. package/dist/apps/chat/chat-request-normalizers.js +17 -0
  10. package/dist/apps/chat/data/chat-data-mappers.js +2 -0
  11. package/dist/apps/chat/data/project-service.js +168 -168
  12. package/dist/apps/chat/data/read-state-service.js +18 -18
  13. package/dist/apps/chat/data/session-query-service.js +25 -25
  14. package/dist/apps/chat/data/timeline-query-service.js +19 -19
  15. package/dist/apps/chat/loop-api.js +181 -0
  16. package/dist/apps/chat/static-assets.js +854 -854
  17. package/dist/apps/chat/web-app.js +36 -16
  18. package/dist/apps/chat/workflow-manual-trigger-runtime.js +149 -46
  19. package/dist/apps/chat/workflow-persistence.js +255 -255
  20. package/dist/apps/chat-ui/assets/{dist-BZ2eTC4f.js → dist-3Sts0Afa.js} +1 -1
  21. package/dist/apps/chat-ui/assets/{dist-BHa-kcGl.js → dist-4NlLjLs7.js} +1 -1
  22. package/dist/apps/chat-ui/assets/{dist-yCYNNb5d.js → dist-BA6mhAec.js} +1 -1
  23. package/dist/apps/chat-ui/assets/{dist-D811wJeV.js → dist-BPl-fzRB.js} +1 -1
  24. package/dist/apps/chat-ui/assets/{dist-Dq4GxJi3.js → dist-BPnn9e2B.js} +1 -1
  25. package/dist/apps/chat-ui/assets/{dist-CzE6k3F3.js → dist-BpfBSMzK.js} +1 -1
  26. package/dist/apps/chat-ui/assets/{dist-CnVsqwSG.js → dist-Cvx5M97R.js} +1 -1
  27. package/dist/apps/chat-ui/assets/{dist-WyXdYl-w.js → dist-DnXWNQRm.js} +1 -1
  28. package/dist/apps/chat-ui/assets/{dist-BNMu92bb.js → dist-hU-2oAb6.js} +1 -1
  29. package/dist/apps/chat-ui/assets/{dist-BCB6zezO.js → dist-r31x5Fcc.js} +1 -1
  30. package/dist/apps/chat-ui/assets/{dist-HqTN67dc.js → dist-uF6UXzI7.js} +1 -1
  31. package/dist/apps/chat-ui/assets/index-CaTGYBOS.js +173 -0
  32. package/dist/apps/chat-ui/assets/{index-C0x9nEcf.css → index-al8DeEjA.css} +1 -1
  33. package/dist/apps/chat-ui/index.html +18 -18
  34. package/dist/apps/chat-ui/manifest.webmanifest +25 -25
  35. package/dist/apps/chat-ui/sw.js +47 -47
  36. package/dist/apps/chat-vscode-web/assets/index-CK4SMZuu.js +41 -0
  37. package/dist/apps/chat-vscode-web/index.html +13 -13
  38. package/dist/apps/cli-ui/cliSessionsCommand.js +23 -23
  39. package/dist/apps/context-files-ui/index.html +11 -11
  40. package/dist/cli-session/localSessionSource.js +34 -12
  41. package/dist/cli.js +61 -44
  42. package/dist/compute/cli.js +54 -54
  43. package/dist/compute/resource-health.js +35 -2
  44. package/dist/core/events.js +6 -1
  45. package/dist/core/routed-session.js +97 -5
  46. package/dist/core/runtime.js +6 -1
  47. package/dist/core/session-router.js +27 -8
  48. package/dist/cron/cli.js +15 -15
  49. package/dist/cron/store.js +49 -49
  50. package/dist/data/cli.js +23 -23
  51. package/dist/data/event-log.js +23 -23
  52. package/dist/data/ingest-service.js +3 -1
  53. package/dist/data/message-store.js +27 -27
  54. package/dist/data/navigation-store.js +9 -9
  55. package/dist/data/observation-store.js +4 -4
  56. package/dist/data/payload-store.js +17 -17
  57. package/dist/data/schema.js +433 -433
  58. package/dist/data/session-store.js +4 -4
  59. package/dist/data/telemetry-queries.js +54 -54
  60. package/dist/data/telemetry.js +197 -197
  61. package/dist/debug/events.js +12 -12
  62. package/dist/debug/failures.js +6 -6
  63. package/dist/debug/index.js +231 -227
  64. package/dist/debug/messages.js +6 -6
  65. package/dist/debug/pty.js +124 -124
  66. package/dist/debug/session.js +29 -29
  67. package/dist/debug/tools.js +5 -5
  68. package/dist/debug/trace.js +42 -7
  69. package/dist/debug/web-snapshot-browser-scripts.js +294 -294
  70. package/dist/debug/web-streaming-browser-library.js +925 -925
  71. package/dist/debug/web-streaming-browser-scripts.js +232 -232
  72. package/dist/debug/web-streaming-provider-telemetry.js +4 -4
  73. package/dist/debug/web.js +93 -93
  74. package/dist/gateway/cli.js +19 -19
  75. package/dist/gateway/server.js +4 -2
  76. package/dist/gateway/web.js +2 -2
  77. package/dist/index.js +1 -0
  78. package/dist/loops/accounting.js +19 -0
  79. package/dist/loops/channel.js +8 -0
  80. package/dist/loops/cli.js +224 -0
  81. package/dist/loops/plugin.js +16 -0
  82. package/dist/loops/prompts.js +86 -0
  83. package/dist/loops/service.js +446 -0
  84. package/dist/loops/stopping.js +170 -0
  85. package/dist/loops/store.js +642 -0
  86. package/dist/loops/templates.js +232 -0
  87. package/dist/loops/tools.js +184 -0
  88. package/dist/loops/types.js +1 -0
  89. package/dist/mcp/config-command.js +53 -53
  90. package/dist/mcp/index.js +21 -21
  91. package/dist/mcp/registry.js +11 -11
  92. package/dist/pi-packages/cli.js +11 -11
  93. package/dist/plugins/builtin.js +8 -0
  94. package/dist/plugins/context-files-store.js +110 -110
  95. package/dist/plugins/context-files.js +4 -4
  96. package/dist/plugins/registry.js +23 -12
  97. package/dist/ralph/cli.js +18 -18
  98. package/dist/ralph/templates.js +140 -140
  99. package/dist/reliability/store.js +256 -229
  100. package/dist/runs/lifecycle.js +59 -0
  101. package/dist/runs/registry.js +47 -1
  102. package/dist/runs/tools.js +31 -13
  103. package/dist/session-ui/terminalRows.js +66 -2
  104. package/dist/sessions/pibo-data-store.js +16 -16
  105. package/dist/sessions/sqlite-store.js +53 -53
  106. package/dist/setup/cli.js +58 -58
  107. package/dist/shared/trace-async-agent-runs.js +4 -4
  108. package/dist/shared/trace-event-projection.js +59 -19
  109. package/dist/shared/trace-nodes.js +5 -0
  110. package/dist/shared/trace-page-merge.js +15 -0
  111. package/dist/shared/trace-run-notifications.js +3 -1
  112. package/dist/signals/projector.js +6 -2
  113. package/dist/tools/agent-browser-wrapper.js +80 -80
  114. package/dist/tools/browser-pool.js +50 -0
  115. package/dist/tools/browser-use-cdp.js +12 -12
  116. package/dist/tools/browser-use-leases.js +12 -8
  117. package/dist/tools/browser-use-wrapper.js +762 -762
  118. package/dist/tools/guides.js +596 -538
  119. package/dist/tools/index.js +123 -99
  120. package/dist/tools/registry.js +21 -3
  121. package/dist/tools/runtime/node-worker-source.js +205 -205
  122. package/dist/tools/runtime/python-worker-source.js +177 -177
  123. package/dist/vscode/cli.js +9 -9
  124. package/dist/web-annotations/cdp.js +900 -900
  125. package/dist/web-annotations/store.js +96 -96
  126. package/docs/README.md +23 -23
  127. package/docs/ops/install-developer-host.md +112 -112
  128. package/docs/ops/install-user-host.md +96 -96
  129. package/docs/ops/upgrade-user-to-developer-host.md +69 -69
  130. package/docs/ops/vscode-extension-release.md +160 -160
  131. package/package.json +99 -95
  132. package/skills/builtin/graphify/SKILL.md +52 -52
  133. package/skills/builtin/loop/SKILL.md +78 -0
  134. package/skills/builtin/pi-agent-harness/SKILL.md +319 -319
  135. package/skills/builtin/pi-agent-harness/agents/openai.yaml +4 -4
  136. package/skills/builtin/pibo-docker-system/SKILL.md +170 -170
  137. package/skills/builtin/pibo-spec-writing/SKILL.md +330 -330
  138. package/skills/builtin/prd/SKILL.md +143 -143
  139. package/skills/builtin/ralph-loop/SKILL.md +361 -359
  140. package/skills/builtin/ralph-prd-json/SKILL.md +123 -123
  141. package/skills/builtin/skill-creator/LICENSE.txt +201 -201
  142. package/skills/builtin/skill-creator/SKILL.md +513 -513
  143. package/skills/builtin/skill-creator/agents/analyzer.md +274 -274
  144. package/skills/builtin/skill-creator/agents/comparator.md +202 -202
  145. package/skills/builtin/skill-creator/agents/grader.md +223 -223
  146. package/skills/builtin/skill-creator/assets/eval_review.html +146 -146
  147. package/skills/builtin/skill-creator/eval-viewer/generate_review.py +471 -471
  148. package/skills/builtin/skill-creator/eval-viewer/viewer.html +1325 -1325
  149. package/skills/builtin/skill-creator/references/schemas.md +430 -430
  150. package/skills/builtin/skill-creator/scripts/aggregate_benchmark.py +401 -401
  151. package/skills/builtin/skill-creator/scripts/generate_report.py +326 -326
  152. package/skills/builtin/skill-creator/scripts/improve_description.py +247 -247
  153. package/skills/builtin/skill-creator/scripts/package_skill.py +136 -136
  154. package/skills/builtin/skill-creator/scripts/quick_validate.py +102 -102
  155. package/skills/builtin/skill-creator/scripts/run_eval.py +310 -310
  156. package/skills/builtin/skill-creator/scripts/run_loop.py +328 -328
  157. package/skills/builtin/skill-creator/scripts/utils.py +47 -47
  158. package/skills/builtin/web-annotations/SKILL.md +93 -93
  159. package/src/mcp/LICENSE.mcp-cli +21 -21
  160. package/dist/apps/chat-ui/assets/index-DwHJfmiF.js +0 -173
  161. package/dist/apps/chat-vscode-web/assets/index-BAMxIaI_.js +0 -41
  162. package/dist/apps/vscode-artifacts/latest.vsix +0 -0
  163. package/dist/apps/vscode-artifacts/pibo-vscode-ext-1.9.13.vsix +0 -0
@@ -1,4 +1,5 @@
1
1
  import { SessionManager, shouldCompact } from "@earendil-works/pi-coding-agent";
2
+ import { PiboSteeringUnavailableError } from "./events.js";
2
3
  import { getOpenAiCodexProviderUsageForActiveModel } from "../auth/openai-codex-usage.js";
3
4
  import { normalizeSessionErrorDetails, runtimeSessionErrorDetails } from "./session-errors.js";
4
5
  import { expandInlineSkills } from "./skill-expansion.js";
@@ -29,6 +30,31 @@ function isAssistantMessage(message) {
29
30
  function numberValue(value) {
30
31
  return typeof value === "number" && Number.isFinite(value) ? value : undefined;
31
32
  }
33
+ export function normalizeAssistantUsageEvent(piboSessionId, message) {
34
+ const assistant = message;
35
+ if (!assistant?.usage || typeof assistant.usage !== "object")
36
+ return undefined;
37
+ const usage = assistant.usage;
38
+ const inputTokens = numberValue(usage.inputTokens) ?? numberValue(usage.input);
39
+ const outputTokens = numberValue(usage.outputTokens) ?? numberValue(usage.output);
40
+ const cacheReadTokens = numberValue(usage.cacheRead);
41
+ const cacheWriteTokens = numberValue(usage.cacheWrite);
42
+ const reportedTotal = numberValue(usage.totalTokens);
43
+ const normalizedTotal = reportedTotal ?? [inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens]
44
+ .filter((value) => value !== undefined)
45
+ .reduce((sum, value) => sum + value, 0);
46
+ if (normalizedTotal <= 0 && inputTokens === undefined && outputTokens === undefined && cacheReadTokens === undefined && cacheWriteTokens === undefined)
47
+ return undefined;
48
+ return {
49
+ type: "assistant_usage",
50
+ piboSessionId,
51
+ ...(inputTokens !== undefined ? { inputTokens } : {}),
52
+ ...(outputTokens !== undefined ? { outputTokens } : {}),
53
+ ...(cacheReadTokens !== undefined ? { cacheReadTokens } : {}),
54
+ ...(cacheWriteTokens !== undefined ? { cacheWriteTokens } : {}),
55
+ totalTokens: Math.max(0, normalizedTotal),
56
+ };
57
+ }
32
58
  function stringValue(value) {
33
59
  return typeof value === "string" && value.length > 0 ? value : undefined;
34
60
  }
@@ -397,6 +423,8 @@ export class RoutedSession {
397
423
  queue = [];
398
424
  processing = false;
399
425
  disposed = false;
426
+ disposePromise;
427
+ drainPromise;
400
428
  fastMode = false;
401
429
  fastModePatchedAgents = new WeakSet();
402
430
  activeMessage;
@@ -511,6 +539,9 @@ export class RoutedSession {
511
539
  const normalized = normalizePiEvent(this.piboSessionId, event, { contextWindow: numberValue(model?.contextWindow) });
512
540
  const candidate = event && typeof event === "object" ? event : undefined;
513
541
  const assistantMessageEnded = candidate?.type === "message_end" && isAssistantMessage(candidate.message);
542
+ const usageEvent = assistantMessageEnded ? normalizeAssistantUsageEvent(this.piboSessionId, candidate?.message) : undefined;
543
+ if (usageEvent)
544
+ this.emit(this.withActiveMessage(usageEvent));
514
545
  // Pi gets the first chance to recover through its short retry/compaction loop.
515
546
  // Keep the final error pending so the routed turn can continue durable recovery.
516
547
  if (assistantMessageEnded && normalized?.type === "session_error") {
@@ -655,7 +686,32 @@ export class RoutedSession {
655
686
  };
656
687
  this.emit(output);
657
688
  this.onStateChange?.({ processing: this.processing, queuedMessages: this.queue.length, disposed: this.disposed });
658
- void this.drain();
689
+ this.startDrain();
690
+ return output;
691
+ }
692
+ async steerMessage(event) {
693
+ this.assertActive();
694
+ const activeMessage = this.activeMessage;
695
+ if (!activeMessage || !this.processing || !this.runtime.session.isStreaming) {
696
+ throw new PiboSteeringUnavailableError();
697
+ }
698
+ const session = this.runtime.session;
699
+ const expandedText = expandInlineSkills(event.text, session.resourceLoader.getSkills().skills);
700
+ try {
701
+ await session.steer(expandedText);
702
+ }
703
+ catch (error) {
704
+ throw new PiboSteeringUnavailableError(`The active session could not accept steering: ${errorMessage(error)}`, { cause: error });
705
+ }
706
+ const output = {
707
+ type: "message_steered",
708
+ piboSessionId: this.piboSessionId,
709
+ eventId: event.id,
710
+ activeEventId: activeMessage.id,
711
+ text: event.text,
712
+ source: event.source,
713
+ };
714
+ this.emit(output);
659
715
  return output;
660
716
  }
661
717
  async executeAction(event) {
@@ -847,9 +903,26 @@ export class RoutedSession {
847
903
  return await this.runtime.session.compact(customInstructions);
848
904
  }
849
905
  async dispose() {
906
+ if (this.disposePromise)
907
+ return this.disposePromise;
908
+ this.disposePromise = this.disposeUnsafe();
909
+ return this.disposePromise;
910
+ }
911
+ async disposeUnsafe() {
850
912
  if (this.disposed)
851
913
  return;
914
+ const activeMessage = this.activeMessage;
852
915
  this.notifyMessagesInterrupted(this.activeAndQueuedMessages(), "session disposed");
916
+ if (activeMessage) {
917
+ const error = "Session disposed while a message was active.";
918
+ this.emit({
919
+ type: "session_error",
920
+ piboSessionId: this.piboSessionId,
921
+ eventId: activeMessage.id,
922
+ error,
923
+ errorDetails: runtimeSessionErrorDetails(error),
924
+ });
925
+ }
853
926
  this.cancelProviderRecovery();
854
927
  this.queue.length = 0;
855
928
  this.onStateChange?.({ processing: this.processing, queuedMessages: this.queue.length, disposed: true });
@@ -860,7 +933,15 @@ export class RoutedSession {
860
933
  this.recoverySession = undefined;
861
934
  }
862
935
  this.disposed = true;
863
- await this.runtime.dispose();
936
+ const abort = this.runtime.session.abort;
937
+ if (abort)
938
+ await Promise.allSettled([abort.call(this.runtime.session)]);
939
+ try {
940
+ await this.drainPromise;
941
+ }
942
+ finally {
943
+ await this.runtime.dispose();
944
+ }
864
945
  }
865
946
  async kill() {
866
947
  this.notifyMessagesInterrupted(this.activeAndQueuedMessages(), "session killed");
@@ -890,6 +971,16 @@ export class RoutedSession {
890
971
  }
891
972
  return false;
892
973
  }
974
+ startDrain() {
975
+ if (this.drainPromise)
976
+ return;
977
+ const drain = this.drain();
978
+ this.drainPromise = drain;
979
+ void drain.finally(() => {
980
+ if (this.drainPromise === drain)
981
+ this.drainPromise = undefined;
982
+ });
983
+ }
893
984
  async drain() {
894
985
  if (this.processing || this.disposed)
895
986
  return;
@@ -946,7 +1037,7 @@ export class RoutedSession {
946
1037
  }
947
1038
  }
948
1039
  catch (error) {
949
- if (error instanceof PiboProviderRecoveryCancelledError)
1040
+ if (error instanceof PiboProviderRecoveryCancelledError || this.disposed)
950
1041
  return;
951
1042
  const message = errorMessage(error);
952
1043
  this.emit({
@@ -1002,7 +1093,7 @@ export class RoutedSession {
1002
1093
  };
1003
1094
  this.emit(output);
1004
1095
  this.onStateChange?.({ processing: this.processing, queuedMessages: this.queue.length, disposed: this.disposed });
1005
- void this.drain();
1096
+ this.startDrain();
1006
1097
  return output;
1007
1098
  }
1008
1099
  async runAction(event) {
@@ -1150,7 +1241,8 @@ export class RoutedSession {
1150
1241
  return output;
1151
1242
  }
1152
1243
  if (this.activeMessage?.id &&
1153
- (event.type === "tool_call" ||
1244
+ (event.type === "assistant_usage" ||
1245
+ event.type === "tool_call" ||
1154
1246
  event.type === "tool_execution_started" ||
1155
1247
  event.type === "tool_execution_updated" ||
1156
1248
  event.type === "tool_execution_finished" ||
@@ -17,6 +17,7 @@ import { createPiboCompactionPromptExtension } from "./compaction-prompt.js";
17
17
  import { cancelPiboAssistantContextGuardRecovery, createPiboAssistantContextGuardExtension, createPiboAssistantContextGuardRecovery, isPiboAssistantContextGuardRecoveryPending, registerPiboAssistantContextGuardRecovery, } from "./context-guard.js";
18
18
  import { getPiPackageRuntimeOptions } from "../pi-packages/runtime.js";
19
19
  import { getDefaultPiboWorkspace } from "./workspace.js";
20
+ import { createPiboGoalToolDefinitions, PIBO_GOAL_TOOL_NAMES } from "../loops/tools.js";
20
21
  import { DEFAULT_USER_TIMEZONE } from "./user-settings.js";
21
22
  import { registerMiniMaxProvider } from "../providers/minimax.js";
22
23
  import { registerGlmProvider } from "../providers/glm.js";
@@ -109,6 +110,8 @@ function getEnabledToolDefinitions(profile, options, subagentRunner, runToolCont
109
110
  const profileToolDefinitions = profileTools.map((tool) => getToolDefinition(tool, options.toolContext));
110
111
  const codexCompatEnabled = profile.toolPackages.codexCompat === true;
111
112
  const runControlEnabled = profile.toolPackages.runControl === true;
113
+ const goalControlEnabled = profile.toolPackages.goalControl !== false;
114
+ const goalTools = goalControlEnabled ? createPiboGoalToolDefinitions(options.toolContext ?? {}) : [];
112
115
  const runControlBashTool = runControlEnabled && runToolController
113
116
  ? createBashToolDefinition(options.runtimeCwd, {
114
117
  commandPrefix: options.shellCommandPrefix,
@@ -137,6 +140,7 @@ function getEnabledToolDefinitions(profile, options, subagentRunner, runToolCont
137
140
  ...(runtimeTool ? [runtimeTool] : []),
138
141
  ...subagentTools,
139
142
  ...codexCompatTools,
143
+ ...goalTools,
140
144
  ...runTools,
141
145
  ];
142
146
  }
@@ -155,7 +159,7 @@ function isEnabledRuntimeTool(tool) {
155
159
  return tool.enabled !== false && isRuntimeTool(tool);
156
160
  }
157
161
  function isGeneratedPiboTool(name) {
158
- return name === "runtime" || name.startsWith("pibo_subagent_") || name.startsWith("pibo_run_");
162
+ return name === "runtime" || name.startsWith("pibo_subagent_") || name.startsWith("pibo_run_") || PIBO_GOAL_TOOL_NAMES.includes(name);
159
163
  }
160
164
  function getBuiltinToolAllowlist(profile, customTools) {
161
165
  if (profile.builtinTools === "disabled")
@@ -282,6 +286,7 @@ export async function createPiboRuntime(options = {}) {
282
286
  toolContext: {
283
287
  piboSessionId: options.sessionContext?.piboSessionId ?? profile.sessionId,
284
288
  piboRoomId: options.sessionContext?.piboRoomId,
289
+ profileName: profile.profileName,
285
290
  },
286
291
  }, options.subagentRunner, options.runToolController, runtimeToolController);
287
292
  const modelDefaults = options.modelDefaults ?? loadPiboModelDefaults(runtimeCwd);
@@ -6,6 +6,7 @@ import { RoutedSession } from "./routed-session.js";
6
6
  import { runtimeSessionErrorDetails } from "./session-errors.js";
7
7
  import { createSubagentToolName } from "../subagents/tool.js";
8
8
  import { PiboRunRegistry } from "../runs/registry.js";
9
+ import { PiboRunExecutionTimeoutError } from "../runs/lifecycle.js";
9
10
  import { createPiboSignalRegistry } from "../signals/registry.js";
10
11
  import { createDefaultPiboReliabilityStore } from "../reliability/store.js";
11
12
  import { InMemoryPiboSessionStore, } from "../sessions/store.js";
@@ -22,13 +23,15 @@ import { createPiboProviderTelemetryExtension } from "./provider-telemetry.js";
22
23
  import { AsyncTelemetryWriter } from "../data/telemetry-writer.js";
23
24
  const DEFAULT_SUBAGENT_REPLY_TIMEOUT_MS = 10 * 60 * 1000;
24
25
  const DEFAULT_ROUTED_SESSION_IDLE_TIMEOUT_MS = 30 * 60 * 1000;
25
- export const RALPH_RUNTIME_RETRY_DEFAULTS = {
26
+ export const LOOP_RUNTIME_RETRY_DEFAULTS = {
26
27
  enabled: true,
27
28
  maxRetries: 7,
28
29
  baseDelayMs: 2_000,
29
30
  };
31
+ /** @deprecated Use LOOP_RUNTIME_RETRY_DEFAULTS. */
32
+ export const RALPH_RUNTIME_RETRY_DEFAULTS = LOOP_RUNTIME_RETRY_DEFAULTS;
30
33
  export function resolvePiboSessionRetryDefaults(kind, configured) {
31
- return configured ?? (kind === "ralph" ? RALPH_RUNTIME_RETRY_DEFAULTS : undefined);
34
+ return configured ?? (kind === "loop" || kind === "ralph" ? LOOP_RUNTIME_RETRY_DEFAULTS : undefined);
32
35
  }
33
36
  export function resolvePiboSessionInitialThinkingLevel(session) {
34
37
  const value = session.metadata?.initialThinkingLevel;
@@ -83,6 +86,15 @@ function formatRunReminderMessage(notification) {
83
86
  toolName: run.toolName,
84
87
  summary: run.summary,
85
88
  })),
89
+ timedOut: notification.timedOut.map((run) => ({
90
+ runId: run.runId,
91
+ kind: run.kind,
92
+ status: run.status,
93
+ toolName: run.toolName,
94
+ summary: run.summary,
95
+ timeoutMs: run.timeoutMs,
96
+ timeoutPhase: run.timeoutPhase,
97
+ })),
86
98
  cancelled: notification.cancelled.map((run) => ({
87
99
  runId: run.runId,
88
100
  kind: run.kind,
@@ -97,7 +109,7 @@ function formatRunReminderMessage(notification) {
97
109
  toolName: run.toolName,
98
110
  summary: run.summary,
99
111
  })),
100
- instruction: "Use pibo_run_read for completed or failed runs. Use pibo_run_wait, pibo_run_status, pibo_run_cancel, or pibo_run_ack for runs you still need to manage.",
112
+ instruction: "Use pibo_run_read for completed, failed, or timed_out runs. Use pibo_run_wait, pibo_run_status, pibo_run_cancel, or pibo_run_ack for runs you still need to manage.",
101
113
  }),
102
114
  "</pibo_run_notification>",
103
115
  ].join("\n");
@@ -106,7 +118,7 @@ function isRunReminderServiceMessage(event) {
106
118
  return event.source === "service" && event.text.startsWith("<pibo_run_notification>");
107
119
  }
108
120
  function isTerminalRunStatus(status) {
109
- return status === "completed" || status === "failed" || status === "cancelled";
121
+ return status === "completed" || status === "failed" || status === "timed_out" || status === "cancelled";
110
122
  }
111
123
  function asJsonObject(value) {
112
124
  return value ?? {};
@@ -210,7 +222,9 @@ export class PiboSessionRouter {
210
222
  this.clearIdleSessionTimer(event.piboSessionId);
211
223
  try {
212
224
  if (event.type === "message") {
213
- return session.enqueueMessage(event);
225
+ return event.delivery === "steer"
226
+ ? await session.steerMessage(event)
227
+ : session.enqueueMessage(event);
214
228
  }
215
229
  if (event.action === "abort") {
216
230
  this.signalRegistry.project({ type: "session_interrupted", piboSessionId: event.piboSessionId, reason: "abort action" });
@@ -665,7 +679,7 @@ export class PiboSessionRouter {
665
679
  }
666
680
  createRunToolController(parentPiboSessionId) {
667
681
  return {
668
- startToolRun: ({ toolName, params, completionPolicy, retryable, maxAttempts, execute }) => {
682
+ startToolRun: ({ toolName, params, completionPolicy, retryable, maxAttempts, timeoutMs, serviceWarning, execute }) => {
669
683
  assertGatewayResourceAvailableForWork(`yielded run ${toolName}`);
670
684
  const run = this.runRegistry.startToolRun({
671
685
  controllerPiboSessionId: parentPiboSessionId,
@@ -674,6 +688,8 @@ export class PiboSessionRouter {
674
688
  completionPolicy,
675
689
  retryable,
676
690
  maxAttempts,
691
+ timeoutMs,
692
+ serviceWarning,
677
693
  });
678
694
  void (async () => {
679
695
  try {
@@ -683,8 +699,11 @@ export class PiboSessionRouter {
683
699
  this.scheduleRunReminder(parentPiboSessionId, false);
684
700
  }
685
701
  catch (error) {
686
- const failed = this.runRegistry.fail(run.runId, error instanceof Error ? error.message : String(error));
687
- if (failed)
702
+ const message = error instanceof Error ? error.message : String(error);
703
+ const terminalRun = error instanceof PiboRunExecutionTimeoutError
704
+ ? this.runRegistry.timeOut(run.runId, message, error.timeoutPhase)
705
+ : this.runRegistry.fail(run.runId, message);
706
+ if (terminalRun)
688
707
  this.scheduleRunReminder(parentPiboSessionId, false);
689
708
  }
690
709
  })();
package/dist/cron/cli.js CHANGED
@@ -2,21 +2,21 @@ import { Command } from "commander";
2
2
  import { parseFriendlySchedule } from "./schedule.js";
3
3
  import { createDefaultPiboCronStore } from "./store.js";
4
4
  function printDiscovery() {
5
- console.log(`pibo cron
6
-
7
- Manage scheduled Pibo agent jobs.
8
-
9
- Commands:
10
- status Show scheduler store status
11
- list List cron jobs
12
- add Create a cron job
13
- edit Update a cron job
14
- pause Disable a cron job
15
- resume Enable a cron job and recompute next run
16
- remove Delete a cron job
17
- runs List cron runs
18
-
19
- Next: pibo cron add --help
5
+ console.log(`pibo cron
6
+
7
+ Manage scheduled Pibo agent jobs.
8
+
9
+ Commands:
10
+ status Show scheduler store status
11
+ list List cron jobs
12
+ add Create a cron job
13
+ edit Update a cron job
14
+ pause Disable a cron job
15
+ resume Enable a cron job and recompute next run
16
+ remove Delete a cron job
17
+ runs List cron runs
18
+
19
+ Next: pibo cron add --help
20
20
  pibo cron edit --help`);
21
21
  }
22
22
  function printJson(value) {
@@ -172,10 +172,10 @@ export class PiboCronStore {
172
172
  const result = [];
173
173
  this.db.exec("BEGIN IMMEDIATE");
174
174
  try {
175
- const rows = this.db.prepare(`
176
- SELECT * FROM pibo_cron_jobs
177
- WHERE enabled = 1
178
- ORDER BY updated_at ASC
175
+ const rows = this.db.prepare(`
176
+ SELECT * FROM pibo_cron_jobs
177
+ WHERE enabled = 1
178
+ ORDER BY updated_at ASC
179
179
  `).all();
180
180
  for (const row of rows) {
181
181
  if (result.length >= limit)
@@ -242,10 +242,10 @@ export class PiboCronStore {
242
242
  lastPiboSessionId: input.piboSessionId ?? job.state.lastPiboSessionId,
243
243
  consecutiveErrors: input.status === "error" ? (job.state.consecutiveErrors ?? 0) + 1 : 0,
244
244
  };
245
- this.db.prepare(`
246
- UPDATE pibo_cron_runs
247
- SET status = ?, pibo_session_id = ?, reason = ?, error = ?, completed_at = ?, updated_at = ?
248
- WHERE id = ?
245
+ this.db.prepare(`
246
+ UPDATE pibo_cron_runs
247
+ SET status = ?, pibo_session_id = ?, reason = ?, error = ?, completed_at = ?, updated_at = ?
248
+ WHERE id = ?
249
249
  `).run(input.status, input.piboSessionId ?? null, input.reason ?? null, input.error ?? null, timestamp, timestamp, input.runId);
250
250
  this.db.prepare(`UPDATE pibo_cron_jobs SET enabled = ?, state_json = ?, updated_at = ? WHERE id = ?`).run(enabled ? 1 : 0, JSON.stringify(state), timestamp, job.id);
251
251
  if (job.deleteAfterRun && job.schedule.kind === "at" && input.status === "ok") {
@@ -286,50 +286,50 @@ export class PiboCronStore {
286
286
  this.createFreshSchema();
287
287
  }
288
288
  createFreshSchema() {
289
- this.db.exec(`
290
- CREATE TABLE IF NOT EXISTS pibo_cron_jobs (
291
- id TEXT PRIMARY KEY,
292
- name TEXT NOT NULL,
293
- description TEXT,
294
- enabled INTEGER NOT NULL,
295
- target_json TEXT NOT NULL,
296
- profile TEXT NOT NULL,
297
- prompt TEXT NOT NULL,
298
- schedule_json TEXT NOT NULL,
299
- schedule_ui_json TEXT,
300
- delete_after_run INTEGER NOT NULL DEFAULT 0,
301
- state_json TEXT NOT NULL,
302
- created_at TEXT NOT NULL,
303
- updated_at TEXT NOT NULL
304
- );
305
- CREATE INDEX IF NOT EXISTS idx_pibo_cron_jobs_enabled ON pibo_cron_jobs(enabled, updated_at DESC);
306
-
307
- CREATE TABLE IF NOT EXISTS pibo_cron_runs (
308
- id TEXT PRIMARY KEY,
309
- job_id TEXT NOT NULL,
310
- pibo_session_id TEXT,
311
- status TEXT NOT NULL,
312
- reason TEXT,
313
- error TEXT,
314
- started_at TEXT,
315
- completed_at TEXT,
316
- created_at TEXT NOT NULL,
317
- updated_at TEXT NOT NULL
318
- );
319
- CREATE INDEX IF NOT EXISTS idx_pibo_cron_runs_job_created ON pibo_cron_runs(job_id, created_at DESC);
289
+ this.db.exec(`
290
+ CREATE TABLE IF NOT EXISTS pibo_cron_jobs (
291
+ id TEXT PRIMARY KEY,
292
+ name TEXT NOT NULL,
293
+ description TEXT,
294
+ enabled INTEGER NOT NULL,
295
+ target_json TEXT NOT NULL,
296
+ profile TEXT NOT NULL,
297
+ prompt TEXT NOT NULL,
298
+ schedule_json TEXT NOT NULL,
299
+ schedule_ui_json TEXT,
300
+ delete_after_run INTEGER NOT NULL DEFAULT 0,
301
+ state_json TEXT NOT NULL,
302
+ created_at TEXT NOT NULL,
303
+ updated_at TEXT NOT NULL
304
+ );
305
+ CREATE INDEX IF NOT EXISTS idx_pibo_cron_jobs_enabled ON pibo_cron_jobs(enabled, updated_at DESC);
306
+
307
+ CREATE TABLE IF NOT EXISTS pibo_cron_runs (
308
+ id TEXT PRIMARY KEY,
309
+ job_id TEXT NOT NULL,
310
+ pibo_session_id TEXT,
311
+ status TEXT NOT NULL,
312
+ reason TEXT,
313
+ error TEXT,
314
+ started_at TEXT,
315
+ completed_at TEXT,
316
+ created_at TEXT NOT NULL,
317
+ updated_at TEXT NOT NULL
318
+ );
319
+ CREATE INDEX IF NOT EXISTS idx_pibo_cron_runs_job_created ON pibo_cron_runs(job_id, created_at DESC);
320
320
  `);
321
321
  }
322
322
  insertJob(job) {
323
- this.db.prepare(`
324
- INSERT INTO pibo_cron_jobs (id, name, description, enabled, target_json, profile, prompt, schedule_json, schedule_ui_json, delete_after_run, state_json, created_at, updated_at)
325
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
323
+ this.db.prepare(`
324
+ INSERT INTO pibo_cron_jobs (id, name, description, enabled, target_json, profile, prompt, schedule_json, schedule_ui_json, delete_after_run, state_json, created_at, updated_at)
325
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
326
326
  `).run(job.id, job.name, job.description ?? null, job.enabled ? 1 : 0, targetJson(job.target), job.profile, job.prompt, JSON.stringify(job.schedule), job.scheduleUi ? JSON.stringify(job.scheduleUi) : null, job.deleteAfterRun ? 1 : 0, JSON.stringify(job.state), job.createdAt, job.updatedAt);
327
327
  }
328
328
  writeJob(job) {
329
- this.db.prepare(`
330
- UPDATE pibo_cron_jobs
331
- SET name = ?, description = ?, enabled = ?, target_json = ?, profile = ?, prompt = ?, schedule_json = ?, schedule_ui_json = ?, delete_after_run = ?, state_json = ?, updated_at = ?
332
- WHERE id = ?
329
+ this.db.prepare(`
330
+ UPDATE pibo_cron_jobs
331
+ SET name = ?, description = ?, enabled = ?, target_json = ?, profile = ?, prompt = ?, schedule_json = ?, schedule_ui_json = ?, delete_after_run = ?, state_json = ?, updated_at = ?
332
+ WHERE id = ?
333
333
  `).run(job.name, job.description ?? null, job.enabled ? 1 : 0, targetJson(job.target), job.profile, job.prompt, JSON.stringify(job.schedule), job.scheduleUi ? JSON.stringify(job.scheduleUi) : null, job.deleteAfterRun ? 1 : 0, JSON.stringify(job.state), job.updatedAt, job.id);
334
334
  }
335
335
  updateJobStateLocked(id, state, updatedAt) {
@@ -337,9 +337,9 @@ export class PiboCronStore {
337
337
  }
338
338
  createRunLocked(job, timestamp, status, reason) {
339
339
  const run = { id: `crun_${randomUUID()}`, jobId: job.id, status, reason, startedAt: timestamp, createdAt: timestamp, updatedAt: timestamp };
340
- this.db.prepare(`
341
- INSERT INTO pibo_cron_runs (id, job_id, pibo_session_id, status, reason, error, started_at, completed_at, created_at, updated_at)
342
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
340
+ this.db.prepare(`
341
+ INSERT INTO pibo_cron_runs (id, job_id, pibo_session_id, status, reason, error, started_at, completed_at, created_at, updated_at)
342
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
343
343
  `).run(run.id, run.jobId, null, run.status, run.reason ?? null, null, run.startedAt ?? null, null, run.createdAt, run.updatedAt);
344
344
  return run;
345
345
  }
package/dist/data/cli.js CHANGED
@@ -102,19 +102,19 @@ function migrateSessionsToV2(input) {
102
102
  "channel", "kind", "profile", "active_model_json", "workspace", "title", "status",
103
103
  "metadata_json", "created_at", "updated_at", "last_activity_at",
104
104
  ];
105
- target.db.prepare(`
106
- INSERT INTO sessions (${columns.join(", ")})
107
- VALUES (${columns.map(() => "?").join(", ")})
105
+ target.db.prepare(`
106
+ INSERT INTO sessions (${columns.join(", ")})
107
+ VALUES (${columns.map(() => "?").join(", ")})
108
108
  `).run(row.id, row.pi_session_id, typeof metadata.chatRoomId === "string" ? metadata.chatRoomId : null, rootSessionId, row.parent_id, row.origin_id, row.channel, row.kind, row.profile, row.active_model_json, row.workspace, row.title ?? "Untitled Session", "idle", JSON.stringify(metadata), row.created_at, row.updated_at, row.updated_at);
109
109
  report.inserted++;
110
110
  }
111
111
  else if (row.updated_at > existing.updated_at) {
112
- target.db.prepare(`
113
- UPDATE sessions SET
114
- pi_session_id = ?, root_session_id = ?, parent_id = ?, origin_id = ?,
115
- channel = ?, kind = ?, profile = ?, active_model_json = ?, workspace = ?, title = ?,
116
- metadata_json = ?, updated_at = ?, last_activity_at = MAX(last_activity_at, ?)
117
- WHERE id = ?
112
+ target.db.prepare(`
113
+ UPDATE sessions SET
114
+ pi_session_id = ?, root_session_id = ?, parent_id = ?, origin_id = ?,
115
+ channel = ?, kind = ?, profile = ?, active_model_json = ?, workspace = ?, title = ?,
116
+ metadata_json = ?, updated_at = ?, last_activity_at = MAX(last_activity_at, ?)
117
+ WHERE id = ?
118
118
  `).run(row.pi_session_id, rootSessionId, row.parent_id, row.origin_id, row.channel, row.kind, row.profile, row.active_model_json, row.workspace, row.title ?? "Untitled Session", JSON.stringify(metadata), row.updated_at, row.updated_at, row.id);
119
119
  report.updated++;
120
120
  }
@@ -166,19 +166,19 @@ function printInventory(stores) {
166
166
  }
167
167
  }
168
168
  function printDataHelp() {
169
- console.log(`pibo data - inspect and maintain Pibo data stores
170
-
171
- Commands:
172
- inventory Read-only row counts, sizes, WAL sizes, and integrity checks; legacy-* rows are archived stores
173
- migrate sessions-to-v2 Import an explicit legacy pibo-sessions.sqlite into pibo.sqlite idempotently
174
-
175
- Options:
176
- --json Print machine-readable JSON
177
- --root DIR Inspect a specific Pibo home directory instead of ~/.pibo
178
- --to FILE Target pibo.sqlite path for migration or repair
179
-
180
- Next:
181
- pibo data inventory --json
182
- pibo data migrate sessions-to-v2 --from /path/to/pibo-sessions.sqlite --json
169
+ console.log(`pibo data - inspect and maintain Pibo data stores
170
+
171
+ Commands:
172
+ inventory Read-only row counts, sizes, WAL sizes, and integrity checks; legacy-* rows are archived stores
173
+ migrate sessions-to-v2 Import an explicit legacy pibo-sessions.sqlite into pibo.sqlite idempotently
174
+
175
+ Options:
176
+ --json Print machine-readable JSON
177
+ --root DIR Inspect a specific Pibo home directory instead of ~/.pibo
178
+ --to FILE Target pibo.sqlite path for migration or repair
179
+
180
+ Next:
181
+ pibo data inventory --json
182
+ pibo data migrate sessions-to-v2 --from /path/to/pibo-sessions.sqlite --json
183
183
  `);
184
184
  }
@@ -12,29 +12,29 @@ export class PiboEventLogStore {
12
12
  }
13
13
  const createdAt = input.createdAt ?? new Date().toISOString();
14
14
  const eventId = input.eventId ?? `evt_${randomUUID()}`;
15
- const result = this.db.prepare(`
16
- INSERT OR IGNORE INTO event_log (
17
- session_id,
18
- session_sequence,
19
- room_id,
20
- topic,
21
- type,
22
- source,
23
- actor_type,
24
- actor_id,
25
- turn_id,
26
- event_id,
27
- tool_call_id,
28
- run_id,
29
- workflow_run_id,
30
- idempotency_key,
31
- retention_class,
32
- payload_ref,
33
- preview_text,
34
- attributes_json,
35
- created_at,
36
- indexed_at
37
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
15
+ const result = this.db.prepare(`
16
+ INSERT OR IGNORE INTO event_log (
17
+ session_id,
18
+ session_sequence,
19
+ room_id,
20
+ topic,
21
+ type,
22
+ source,
23
+ actor_type,
24
+ actor_id,
25
+ turn_id,
26
+ event_id,
27
+ tool_call_id,
28
+ run_id,
29
+ workflow_run_id,
30
+ idempotency_key,
31
+ retention_class,
32
+ payload_ref,
33
+ preview_text,
34
+ attributes_json,
35
+ created_at,
36
+ indexed_at
37
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
38
38
  `).run(input.sessionId ?? null, input.sessionSequence ?? null, input.roomId ?? null, input.topic, input.type, input.source, input.actorType ?? null, input.actorId ?? null, input.turnId ?? null, eventId, input.toolCallId ?? null, input.runId ?? null, input.workflowRunId ?? null, input.idempotencyKey ?? null, input.retentionClass, input.payloadRef ?? null, input.previewText ?? null, JSON.stringify(input.attributes ?? {}), createdAt, input.indexedAt ?? null);
39
39
  if (input.idempotencyKey) {
40
40
  const existing = this.findByIdempotencyKey(input.idempotencyKey);
@@ -303,7 +303,7 @@ function payloadForOutputEvent(event) {
303
303
  function previewTextForOutputEvent(event) {
304
304
  if (event.type === "assistant_message" || event.type === "assistant_delta" || event.type === "thinking_delta" || event.type === "thinking_finished")
305
305
  return previewText(event.text ?? "");
306
- if (event.type === "message_queued" || event.type === "message_started")
306
+ if (event.type === "message_queued" || event.type === "message_steered" || event.type === "message_started")
307
307
  return previewText(event.text);
308
308
  if (event.type === "tool_call" || event.type === "tool_execution_started" || event.type === "tool_execution_updated" || event.type === "tool_execution_finished")
309
309
  return event.toolName;
@@ -320,6 +320,8 @@ function previewTextForOutputEvent(event) {
320
320
  function attributesForOutputEvent(event) {
321
321
  if (event.type === "message_queued")
322
322
  return { inlineText: event.text, source: event.source, queuedMessages: event.queuedMessages };
323
+ if (event.type === "message_steered")
324
+ return { inlineText: event.text, source: event.source, activeEventId: event.activeEventId };
323
325
  if (event.type === "assistant_message" || event.type === "assistant_delta")
324
326
  return { assistantIndex: event.assistantIndex, contentIndex: event.contentIndex };
325
327
  if (event.type === "thinking_started" || event.type === "thinking_delta" || event.type === "thinking_finished")