dominds 1.16.2 → 1.16.4

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 (170) hide show
  1. package/dist/dialog-display-state.d.ts +3 -1
  2. package/dist/dialog-display-state.js +8 -1
  3. package/dist/dialog-fork.js +9 -0
  4. package/dist/dialog-global-registry.d.ts +5 -1
  5. package/dist/dialog-global-registry.js +45 -1
  6. package/dist/dialog.d.ts +3 -0
  7. package/dist/dialog.js +4 -0
  8. package/dist/llm/gen/anthropic.d.ts +3 -3
  9. package/dist/llm/gen/anthropic.js +115 -21
  10. package/dist/llm/gen/codex.js +78 -13
  11. package/dist/llm/gen/failure-classifier.js +10 -0
  12. package/dist/llm/gen/openai-compatible.d.ts +6 -3
  13. package/dist/llm/gen/openai-compatible.js +132 -16
  14. package/dist/llm/gen/openai.d.ts +2 -2
  15. package/dist/llm/gen/openai.js +95 -15
  16. package/dist/llm/gen/tool-result-image-ingest.d.ts +39 -0
  17. package/dist/llm/gen/tool-result-image-ingest.js +158 -0
  18. package/dist/llm/gen.d.ts +17 -1
  19. package/dist/llm/kernel-driver/drive.js +15 -0
  20. package/dist/llm/kernel-driver/flow.js +230 -177
  21. package/dist/llm/kernel-driver/loop.js +5 -0
  22. package/dist/persistence.d.ts +2 -0
  23. package/dist/persistence.js +107 -0
  24. package/dist/priming.js +76 -0
  25. package/package.json +3 -3
  26. package/webapp/dist/assets/{_basePickBy-BJWCmtUm.js → _basePickBy-BKLfvXfr.js} +3 -3
  27. package/webapp/dist/assets/_basePickBy-BKLfvXfr.js.map +1 -0
  28. package/webapp/dist/assets/{_baseUniq-D6k_lGfs.js → _baseUniq-DeO2MBcA.js} +2 -2
  29. package/webapp/dist/assets/_baseUniq-DeO2MBcA.js.map +1 -0
  30. package/webapp/dist/assets/{arc-DYDaESgj.js → arc-Bez5-ouI.js} +2 -2
  31. package/webapp/dist/assets/arc-Bez5-ouI.js.map +1 -0
  32. package/webapp/dist/assets/{architectureDiagram-VXUJARFQ-DZMT7dqc.js → architectureDiagram-2XIMDMQ5-BiDh8CGJ.js} +26 -8
  33. package/webapp/dist/assets/architectureDiagram-2XIMDMQ5-BiDh8CGJ.js.map +1 -0
  34. package/webapp/dist/assets/{blockDiagram-VD42YOAC-CABpgVAa.js → blockDiagram-WCTKOSBZ-fSZbZ3PY.js} +187 -170
  35. package/webapp/dist/assets/blockDiagram-WCTKOSBZ-fSZbZ3PY.js.map +1 -0
  36. package/webapp/dist/assets/{c4Diagram-YG6GDRKO-COLZS8Ul.js → c4Diagram-IC4MRINW-C-WxkPD_.js} +4 -4
  37. package/webapp/dist/assets/c4Diagram-IC4MRINW-C-WxkPD_.js.map +1 -0
  38. package/webapp/dist/assets/{channel-CYFm9Cri.js → channel-CbXK2-c_.js} +2 -2
  39. package/webapp/dist/assets/channel-CbXK2-c_.js.map +1 -0
  40. package/webapp/dist/assets/{chunk-4BX2VUAB-CX_-XbaN.js → chunk-4BX2VUAB-D6CgMaUm.js} +2 -2
  41. package/webapp/dist/assets/chunk-4BX2VUAB-D6CgMaUm.js.map +1 -0
  42. package/webapp/dist/assets/{chunk-55IACEB6-ByD-NdBC.js → chunk-55IACEB6-CafQjmEn.js} +2 -2
  43. package/webapp/dist/assets/chunk-55IACEB6-CafQjmEn.js.map +1 -0
  44. package/webapp/dist/assets/{chunk-FMBD7UC4-DYGviJnf.js → chunk-FMBD7UC4-CZRe1oW9.js} +2 -2
  45. package/webapp/dist/assets/chunk-FMBD7UC4-CZRe1oW9.js.map +1 -0
  46. package/webapp/dist/assets/{chunk-TZMSLE5B-_HISzxl3.js → chunk-JSJVCQXG-C3KJDde2.js} +14 -6
  47. package/webapp/dist/assets/chunk-JSJVCQXG-C3KJDde2.js.map +1 -0
  48. package/webapp/dist/assets/{chunk-QN33PNHL-B8DWRL9f.js → chunk-KX2RTZJC-1gHfMJyM.js} +2 -2
  49. package/webapp/dist/assets/chunk-KX2RTZJC-1gHfMJyM.js.map +1 -0
  50. package/webapp/dist/assets/{chunk-DI55MBZ5-DV7sdJmQ.js → chunk-NQ4KR5QH-CEZ0VIio.js} +9 -7
  51. package/webapp/dist/assets/chunk-NQ4KR5QH-CEZ0VIio.js.map +1 -0
  52. package/webapp/dist/assets/{chunk-QZHKN3VN-B1aYIzMR.js → chunk-QZHKN3VN-BE5nbumW.js} +2 -2
  53. package/webapp/dist/assets/chunk-QZHKN3VN-BE5nbumW.js.map +1 -0
  54. package/webapp/dist/assets/{chunk-B4BG7PRW-BANemsDD.js → chunk-WL4C6EOR-CY1FogYe.js} +171 -121
  55. package/webapp/dist/assets/chunk-WL4C6EOR-CY1FogYe.js.map +1 -0
  56. package/webapp/dist/assets/{classDiagram-2ON5EDUG-CpyYj1Rc.js → classDiagram-VBA2DB6C-DIAo1m4U.js} +7 -6
  57. package/webapp/dist/assets/classDiagram-VBA2DB6C-DIAo1m4U.js.map +1 -0
  58. package/webapp/dist/assets/{classDiagram-v2-WZHVMYZB-CpyYj1Rc.js → classDiagram-v2-RAHNMMFH-DIAo1m4U.js} +7 -6
  59. package/webapp/dist/assets/classDiagram-v2-RAHNMMFH-DIAo1m4U.js.map +1 -0
  60. package/webapp/dist/assets/{clone-B_9AxWIU.js → clone-BzZfwhKW.js} +2 -2
  61. package/webapp/dist/assets/clone-BzZfwhKW.js.map +1 -0
  62. package/webapp/dist/assets/{cose-bilkent-S5V4N54A-17ECLfPR.js → cose-bilkent-S5V4N54A-DIRdD9UY.js} +2 -2
  63. package/webapp/dist/assets/cose-bilkent-S5V4N54A-DIRdD9UY.js.map +1 -0
  64. package/webapp/dist/assets/cytoscape.esm-Bm8DJGmZ.js.map +1 -1
  65. package/webapp/dist/assets/{dagre-6UL2VRFP-DhRqcF1o.js → dagre-KLK3FWXG-BCEgv7zL.js} +7 -7
  66. package/webapp/dist/assets/dagre-KLK3FWXG-BCEgv7zL.js.map +1 -0
  67. package/webapp/dist/assets/defaultLocale-B2RvLBDe.js.map +1 -1
  68. package/webapp/dist/assets/{diagram-PSM6KHXK-lpDT6Wwb.js → diagram-E7M64L7V-CwNdHUlg.js} +10 -10
  69. package/webapp/dist/assets/diagram-E7M64L7V-CwNdHUlg.js.map +1 -0
  70. package/webapp/dist/assets/{diagram-QEK2KX5R-ohxbPpDH.js → diagram-IFDJBPK2-DBtRFFBv.js} +9 -8
  71. package/webapp/dist/assets/diagram-IFDJBPK2-DBtRFFBv.js.map +1 -0
  72. package/webapp/dist/assets/{diagram-S2PKOQOG-DAFFGfch.js → diagram-P4PSJMXO-BJRf8VnU.js} +8 -8
  73. package/webapp/dist/assets/diagram-P4PSJMXO-BJRf8VnU.js.map +1 -0
  74. package/webapp/dist/assets/{erDiagram-Q2GNP2WA-BH-7rI43.js → erDiagram-INFDFZHY-BoZdWdP2.js} +96 -75
  75. package/webapp/dist/assets/erDiagram-INFDFZHY-BoZdWdP2.js.map +1 -0
  76. package/webapp/dist/assets/{flowDiagram-NV44I4VS-CdEjFbz4.js → flowDiagram-PKNHOUZH-Dptcw76l.js} +98 -81
  77. package/webapp/dist/assets/flowDiagram-PKNHOUZH-Dptcw76l.js.map +1 -0
  78. package/webapp/dist/assets/{ganttDiagram-JELNMOA3-Cju2t-lK.js → ganttDiagram-A5KZAMGK-qM3zsgxI.js} +28 -3
  79. package/webapp/dist/assets/ganttDiagram-A5KZAMGK-qM3zsgxI.js.map +1 -0
  80. package/webapp/dist/assets/{gitGraphDiagram-V2S2FVAM-CUJ5oxCg.js → gitGraphDiagram-K3NZZRJ6-125S1YW0.js} +38 -46
  81. package/webapp/dist/assets/gitGraphDiagram-K3NZZRJ6-125S1YW0.js.map +1 -0
  82. package/webapp/dist/assets/graph-PACfG8qk.js +782 -0
  83. package/webapp/dist/assets/graph-PACfG8qk.js.map +1 -0
  84. package/webapp/dist/assets/{index-BLnM-uON.js → index-D8Klc1n-.js} +1114 -1048
  85. package/webapp/dist/assets/{index-BLnM-uON.js.map → index-D8Klc1n-.js.map} +1 -1
  86. package/webapp/dist/assets/{index-xvYYeHuy.css → index-YaxF76or.css} +1 -1
  87. package/webapp/dist/assets/{infoDiagram-HS3SLOUP-Df8p0okQ.js → infoDiagram-LFFYTUFH-B9vrFy_9.js} +7 -7
  88. package/webapp/dist/assets/infoDiagram-LFFYTUFH-B9vrFy_9.js.map +1 -0
  89. package/webapp/dist/assets/init-ZxktEp_H.js.map +1 -1
  90. package/webapp/dist/assets/ishikawaDiagram-PHBUUO56-CzcXR0Tc.js +966 -0
  91. package/webapp/dist/assets/ishikawaDiagram-PHBUUO56-CzcXR0Tc.js.map +1 -0
  92. package/webapp/dist/assets/{journeyDiagram-XKPGCS4Q-BXMl8H-d.js → journeyDiagram-4ABVD52K-BzoWs6ft.js} +5 -5
  93. package/webapp/dist/assets/journeyDiagram-4ABVD52K-BzoWs6ft.js.map +1 -0
  94. package/webapp/dist/assets/{kanban-definition-3W4ZIXB7-Cc5RwCEh.js → kanban-definition-K7BYSVSG-TJm1UiSH.js} +5 -3
  95. package/webapp/dist/assets/kanban-definition-K7BYSVSG-TJm1UiSH.js.map +1 -0
  96. package/webapp/dist/assets/{layout-BB2SvQcE.js → layout-D-kg27bk.js} +5 -5
  97. package/webapp/dist/assets/layout-D-kg27bk.js.map +1 -0
  98. package/webapp/dist/assets/{linear-Cj50lA0a.js → linear-l0qAHpRW.js} +2 -2
  99. package/webapp/dist/assets/linear-l0qAHpRW.js.map +1 -0
  100. package/webapp/dist/assets/{mindmap-definition-VGOIOE7T-BLBklJVX.js → mindmap-definition-YRQLILUH-D4282T7u.js} +7 -5
  101. package/webapp/dist/assets/mindmap-definition-YRQLILUH-D4282T7u.js.map +1 -0
  102. package/webapp/dist/assets/ordinal-CxptdPJm.js.map +1 -1
  103. package/webapp/dist/assets/{pieDiagram-ADFJNKIX-BQrOgSc-.js → pieDiagram-SKSYHLDU-BKJYIUkU.js} +8 -8
  104. package/webapp/dist/assets/pieDiagram-SKSYHLDU-BKJYIUkU.js.map +1 -0
  105. package/webapp/dist/assets/{quadrantDiagram-AYHSOK5B-C62TxtsO.js → quadrantDiagram-337W2JSQ-yjekONzR.js} +3 -3
  106. package/webapp/dist/assets/quadrantDiagram-337W2JSQ-yjekONzR.js.map +1 -0
  107. package/webapp/dist/assets/{requirementDiagram-UZGBJVZJ-Is6Q3osM.js → requirementDiagram-Z7DCOOCP-DMH1wutn.js} +16 -6
  108. package/webapp/dist/assets/requirementDiagram-Z7DCOOCP-DMH1wutn.js.map +1 -0
  109. package/webapp/dist/assets/{sankeyDiagram-TZEHDZUN-CCAW8Dr2.js → sankeyDiagram-WA2Y5GQK-Cs4ACtdq.js} +2 -2
  110. package/webapp/dist/assets/sankeyDiagram-WA2Y5GQK-Cs4ACtdq.js.map +1 -0
  111. package/webapp/dist/assets/{sequenceDiagram-WL72ISMW-DpODpbl6.js → sequenceDiagram-2WXFIKYE-4sriOpV9.js} +601 -201
  112. package/webapp/dist/assets/sequenceDiagram-2WXFIKYE-4sriOpV9.js.map +1 -0
  113. package/webapp/dist/assets/{stateDiagram-FKZM4ZOC-B8LHaf5T.js → stateDiagram-RAJIS63D-BUMObt6W.js} +9 -9
  114. package/webapp/dist/assets/stateDiagram-RAJIS63D-BUMObt6W.js.map +1 -0
  115. package/webapp/dist/assets/{stateDiagram-v2-4FDKWEC3-4FzTkpgz.js → stateDiagram-v2-FVOUBMTO-DazzpfnH.js} +5 -5
  116. package/webapp/dist/assets/stateDiagram-v2-FVOUBMTO-DazzpfnH.js.map +1 -0
  117. package/webapp/dist/assets/{timeline-definition-IT6M3QCI-Ckxc4qZe.js → timeline-definition-YZTLITO2-CdChFPnp.js} +3 -3
  118. package/webapp/dist/assets/timeline-definition-YZTLITO2-CdChFPnp.js.map +1 -0
  119. package/webapp/dist/assets/{treemap-GDKQZRPO-QQa4vKMv.js → treemap-KZPCXAKY-DW9mBchB.js} +37 -24
  120. package/webapp/dist/assets/treemap-KZPCXAKY-DW9mBchB.js.map +1 -0
  121. package/webapp/dist/assets/vennDiagram-LZ73GAT5-Bu9N_8Cu.js +2487 -0
  122. package/webapp/dist/assets/vennDiagram-LZ73GAT5-Bu9N_8Cu.js.map +1 -0
  123. package/webapp/dist/assets/{xychartDiagram-PRI3JC2R-Ba2uJcs6.js → xychartDiagram-JWTSCODW-BI_N4JiZ.js} +4 -4
  124. package/webapp/dist/assets/xychartDiagram-JWTSCODW-BI_N4JiZ.js.map +1 -0
  125. package/webapp/dist/index.html +2 -2
  126. package/webapp/dist/assets/_basePickBy-BJWCmtUm.js.map +0 -1
  127. package/webapp/dist/assets/_baseUniq-D6k_lGfs.js.map +0 -1
  128. package/webapp/dist/assets/arc-DYDaESgj.js.map +0 -1
  129. package/webapp/dist/assets/architectureDiagram-VXUJARFQ-DZMT7dqc.js.map +0 -1
  130. package/webapp/dist/assets/blockDiagram-VD42YOAC-CABpgVAa.js.map +0 -1
  131. package/webapp/dist/assets/c4Diagram-YG6GDRKO-COLZS8Ul.js.map +0 -1
  132. package/webapp/dist/assets/channel-CYFm9Cri.js.map +0 -1
  133. package/webapp/dist/assets/chunk-4BX2VUAB-CX_-XbaN.js.map +0 -1
  134. package/webapp/dist/assets/chunk-55IACEB6-ByD-NdBC.js.map +0 -1
  135. package/webapp/dist/assets/chunk-B4BG7PRW-BANemsDD.js.map +0 -1
  136. package/webapp/dist/assets/chunk-DI55MBZ5-DV7sdJmQ.js.map +0 -1
  137. package/webapp/dist/assets/chunk-FMBD7UC4-DYGviJnf.js.map +0 -1
  138. package/webapp/dist/assets/chunk-QN33PNHL-B8DWRL9f.js.map +0 -1
  139. package/webapp/dist/assets/chunk-QZHKN3VN-B1aYIzMR.js.map +0 -1
  140. package/webapp/dist/assets/chunk-TZMSLE5B-_HISzxl3.js.map +0 -1
  141. package/webapp/dist/assets/classDiagram-2ON5EDUG-CpyYj1Rc.js.map +0 -1
  142. package/webapp/dist/assets/classDiagram-v2-WZHVMYZB-CpyYj1Rc.js.map +0 -1
  143. package/webapp/dist/assets/clone-B_9AxWIU.js.map +0 -1
  144. package/webapp/dist/assets/cose-bilkent-S5V4N54A-17ECLfPR.js.map +0 -1
  145. package/webapp/dist/assets/dagre-6UL2VRFP-DhRqcF1o.js.map +0 -1
  146. package/webapp/dist/assets/diagram-PSM6KHXK-lpDT6Wwb.js.map +0 -1
  147. package/webapp/dist/assets/diagram-QEK2KX5R-ohxbPpDH.js.map +0 -1
  148. package/webapp/dist/assets/diagram-S2PKOQOG-DAFFGfch.js.map +0 -1
  149. package/webapp/dist/assets/erDiagram-Q2GNP2WA-BH-7rI43.js.map +0 -1
  150. package/webapp/dist/assets/flowDiagram-NV44I4VS-CdEjFbz4.js.map +0 -1
  151. package/webapp/dist/assets/ganttDiagram-JELNMOA3-Cju2t-lK.js.map +0 -1
  152. package/webapp/dist/assets/gitGraphDiagram-V2S2FVAM-CUJ5oxCg.js.map +0 -1
  153. package/webapp/dist/assets/graph-mhcc7ldf.js +0 -425
  154. package/webapp/dist/assets/graph-mhcc7ldf.js.map +0 -1
  155. package/webapp/dist/assets/infoDiagram-HS3SLOUP-Df8p0okQ.js.map +0 -1
  156. package/webapp/dist/assets/journeyDiagram-XKPGCS4Q-BXMl8H-d.js.map +0 -1
  157. package/webapp/dist/assets/kanban-definition-3W4ZIXB7-Cc5RwCEh.js.map +0 -1
  158. package/webapp/dist/assets/layout-BB2SvQcE.js.map +0 -1
  159. package/webapp/dist/assets/linear-Cj50lA0a.js.map +0 -1
  160. package/webapp/dist/assets/mindmap-definition-VGOIOE7T-BLBklJVX.js.map +0 -1
  161. package/webapp/dist/assets/pieDiagram-ADFJNKIX-BQrOgSc-.js.map +0 -1
  162. package/webapp/dist/assets/quadrantDiagram-AYHSOK5B-C62TxtsO.js.map +0 -1
  163. package/webapp/dist/assets/requirementDiagram-UZGBJVZJ-Is6Q3osM.js.map +0 -1
  164. package/webapp/dist/assets/sankeyDiagram-TZEHDZUN-CCAW8Dr2.js.map +0 -1
  165. package/webapp/dist/assets/sequenceDiagram-WL72ISMW-DpODpbl6.js.map +0 -1
  166. package/webapp/dist/assets/stateDiagram-FKZM4ZOC-B8LHaf5T.js.map +0 -1
  167. package/webapp/dist/assets/stateDiagram-v2-4FDKWEC3-4FzTkpgz.js.map +0 -1
  168. package/webapp/dist/assets/timeline-definition-IT6M3QCI-Ckxc4qZe.js.map +0 -1
  169. package/webapp/dist/assets/treemap-GDKQZRPO-QQa4vKMv.js.map +0 -1
  170. package/webapp/dist/assets/xychartDiagram-PRI3JC2R-Ba2uJcs6.js.map +0 -1
@@ -34,7 +34,9 @@ export declare function broadcastRunControlCountsSnapshot(): Promise<void>;
34
34
  export declare function hasActiveRun(dialogId: DialogID): boolean;
35
35
  export declare function getActiveRunSignal(dialogId: DialogID): AbortSignal | undefined;
36
36
  export declare function createActiveRun(dialogId: DialogID): AbortSignal;
37
- export declare function clearActiveRun(dialogId: DialogID): void;
37
+ export declare function clearActiveRun(dialogId: DialogID, options?: Readonly<{
38
+ notifyBackendLoop?: boolean;
39
+ }>): void;
38
40
  export declare function clearRootDialogQuarantiningIfIdle(rootDialogId: DialogID): void;
39
41
  export declare function markRootDialogQuarantining(rootDialogId: DialogID): void;
40
42
  export declare function clearRootDialogQuarantining(rootDialogId: DialogID): void;
@@ -44,6 +44,7 @@ exports.requestInterruptDialog = requestInterruptDialog;
44
44
  exports.requestEmergencyStopAll = requestEmergencyStopAll;
45
45
  const time_1 = require("@longrun-ai/kernel/utils/time");
46
46
  const dialog_1 = require("./dialog");
47
+ const dialog_global_registry_1 = require("./dialog-global-registry");
47
48
  const dialog_interruption_1 = require("./dialog-interruption");
48
49
  const evt_registry_1 = require("./evt-registry");
49
50
  const log_1 = require("./log");
@@ -178,13 +179,19 @@ function createActiveRun(dialogId) {
178
179
  syncRunControlCountsAfterActiveRunChange('create_active_run', dialogId);
179
180
  return run.abortController.signal;
180
181
  }
181
- function clearActiveRun(dialogId) {
182
+ function clearActiveRun(dialogId, options) {
182
183
  const deleted = activeRunsByDialogKey.delete(dialogId.key());
183
184
  if (!deleted) {
184
185
  clearQuarantiningRootDialogIfIdle(dialogId.rootId);
185
186
  return;
186
187
  }
187
188
  clearQuarantiningRootDialogIfIdle(dialogId.rootId);
189
+ if (dialogId.selfId === dialogId.rootId && options?.notifyBackendLoop !== false) {
190
+ dialog_global_registry_1.globalDialogRegistry.notifyActiveRunCleared(dialogId.rootId, {
191
+ source: 'dialog_display_state_active_run_clear',
192
+ reason: 'root_active_run_cleared',
193
+ });
194
+ }
188
195
  syncRunControlCountsAfterActiveRunChange('clear_active_run', dialogId);
189
196
  }
190
197
  function clearQuarantiningRootDialogIfIdle(rootId) {
@@ -113,6 +113,7 @@ function isPersistedMessageRecord(record) {
113
113
  // not contribute to message-count / context reconstruction semantics.
114
114
  case 'web_search_call_record':
115
115
  case 'native_tool_call_record':
116
+ case 'tool_result_image_ingest_record':
116
117
  case 'quest_for_sup_record':
117
118
  case 'tellask_reply_resolution_record':
118
119
  case 'tellask_call_anchor_record':
@@ -199,6 +200,14 @@ function rewriteRecordForFork(record, newRootId) {
199
200
  ...record,
200
201
  contentItems: rewriteFuncResultContentItems(record.contentItems, newRootId),
201
202
  };
203
+ case 'tool_result_image_ingest_record':
204
+ return {
205
+ ...record,
206
+ artifact: {
207
+ ...record.artifact,
208
+ rootId: newRootId,
209
+ },
210
+ };
202
211
  case 'subdialog_created_record':
203
212
  case 'reminders_reconciled_record':
204
213
  case 'questions4human_reconciled_record':
@@ -1,7 +1,7 @@
1
1
  import type { RootDialog } from './dialog';
2
2
  export type DriveTriggerEvent = Readonly<{
3
3
  type: 'drive_trigger_evt';
4
- action: 'mark_needs_drive' | 'mark_not_needing_drive';
4
+ action: 'mark_needs_drive' | 'mark_not_needing_drive' | 'active_run_cleared';
5
5
  rootId: string;
6
6
  entryFound: boolean;
7
7
  previousNeedsDrive: boolean | null;
@@ -28,6 +28,10 @@ declare class GlobalDialogRegistry {
28
28
  waitForDriveTrigger(): Promise<DriveTriggerEvent>;
29
29
  markNeedsDrive(rootId: string, meta?: DriveTriggerMeta): void;
30
30
  markNotNeedingDrive(rootId: string, meta?: DriveTriggerMeta): void;
31
+ notifyActiveRunCleared(rootId: string, meta?: DriveTriggerMeta): void;
32
+ noteActiveRunBlockedQueuedDrive(rootId: string): void;
33
+ hasPendingActiveRunClearedWake(rootId: string): boolean;
34
+ isMarkedNeedingDrive(rootId: string): boolean;
31
35
  getDialogsNeedingDrive(): RootDialog[];
32
36
  getLastDriveTrigger(rootId: string): DriveTriggerEvent | undefined;
33
37
  getAll(): RootDialog[];
@@ -29,7 +29,11 @@ class GlobalDialogRegistry {
29
29
  if (existing) {
30
30
  return;
31
31
  }
32
- this.entries.set(rootDialog.id.rootId, { rootDialog, needsDrive: false });
32
+ this.entries.set(rootDialog.id.rootId, {
33
+ rootDialog,
34
+ needsDrive: false,
35
+ activeRunClearedWakePending: false,
36
+ });
33
37
  void (async () => {
34
38
  try {
35
39
  const needsDrive = await persistence_1.DialogPersistence.getNeedsDrive(rootDialog.id);
@@ -82,6 +86,8 @@ class GlobalDialogRegistry {
82
86
  const previousNeedsDrive = entry ? entry.needsDrive : null;
83
87
  if (entry) {
84
88
  entry.needsDrive = true;
89
+ // A fresh queueing trigger supersedes any earlier "wake me once active run clears" debt.
90
+ entry.activeRunClearedWakePending = false;
85
91
  }
86
92
  this.publishDriveTrigger({
87
93
  action: 'mark_needs_drive',
@@ -101,6 +107,7 @@ class GlobalDialogRegistry {
101
107
  const previousNeedsDrive = entry ? entry.needsDrive : null;
102
108
  if (entry) {
103
109
  entry.needsDrive = false;
110
+ entry.activeRunClearedWakePending = false;
104
111
  }
105
112
  this.publishDriveTrigger({
106
113
  action: 'mark_not_needing_drive',
@@ -111,6 +118,43 @@ class GlobalDialogRegistry {
111
118
  meta: triggerMeta,
112
119
  });
113
120
  }
121
+ notifyActiveRunCleared(rootId, meta) {
122
+ const triggerMeta = meta ?? {
123
+ source: 'unknown',
124
+ reason: 'unspecified',
125
+ };
126
+ const entry = this.entries.get(rootId);
127
+ if (!entry) {
128
+ return;
129
+ }
130
+ if (!entry.activeRunClearedWakePending || !entry.needsDrive) {
131
+ entry.activeRunClearedWakePending = false;
132
+ return;
133
+ }
134
+ const currentNeedsDrive = entry ? entry.needsDrive : null;
135
+ entry.activeRunClearedWakePending = false;
136
+ this.publishDriveTrigger({
137
+ action: 'active_run_cleared',
138
+ rootId,
139
+ entryFound: true,
140
+ previousNeedsDrive: currentNeedsDrive,
141
+ nextNeedsDrive: entry.needsDrive,
142
+ meta: triggerMeta,
143
+ });
144
+ }
145
+ noteActiveRunBlockedQueuedDrive(rootId) {
146
+ const entry = this.entries.get(rootId);
147
+ if (!entry || !entry.needsDrive) {
148
+ return;
149
+ }
150
+ entry.activeRunClearedWakePending = true;
151
+ }
152
+ hasPendingActiveRunClearedWake(rootId) {
153
+ return this.entries.get(rootId)?.activeRunClearedWakePending === true;
154
+ }
155
+ isMarkedNeedingDrive(rootId) {
156
+ return this.entries.get(rootId)?.needsDrive === true;
157
+ }
114
158
  getDialogsNeedingDrive() {
115
159
  return Array.from(this.entries.values())
116
160
  .filter((entry) => entry.needsDrive)
package/dist/dialog.d.ts CHANGED
@@ -18,6 +18,7 @@ import type { DialogPrompt, DialogRunControlSpec, DialogSubdialogReplyTarget, Dr
18
18
  import type { LanguageCode } from '@longrun-ai/kernel/types/language';
19
19
  import type { CalleeCourseNumber, CalleeGenerationSeqNumber, CallingCourseNumber, DialogMetadataFile, HumanQuestion, ProviderData, ReasoningPayload, TellaskCallRecordName, TellaskReplyDirective } from '@longrun-ai/kernel/types/storage';
20
20
  import { ChatMessage, FuncResultMsg, TellaskCarryoverMsg, TellaskResultMsg } from './llm/client';
21
+ import type { ToolResultImageIngest } from './llm/gen';
21
22
  import type { JsonValue } from './tool';
22
23
  import { Reminder, ReminderOptions, ReminderOwner } from './tool';
23
24
  type NewCourseHookResult = {
@@ -406,6 +407,7 @@ export declare abstract class Dialog {
406
407
  action?: WebSearchCallAction;
407
408
  }): Promise<void>;
408
409
  nativeToolCall(payload: NativeToolCallPayload): Promise<void>;
410
+ toolResultImageIngest(payload: ToolResultImageIngest): Promise<void>;
409
411
  callingStart(payload: {
410
412
  callName: 'tellaskBack' | 'tellask' | 'tellaskSessionless' | 'askHuman' | 'freshBootsReasoning';
411
413
  callId: string;
@@ -624,6 +626,7 @@ export declare abstract class DialogStore {
624
626
  action?: WebSearchCallAction;
625
627
  }): Promise<void>;
626
628
  nativeToolCall(_dialog: Dialog, _payload: NativeToolCallPayload): Promise<void>;
629
+ toolResultImageIngest(_dialog: Dialog, _payload: ToolResultImageIngest): Promise<void>;
627
630
  /**
628
631
  * Load current course number from persisted metadata
629
632
  * This method should be implemented by subclasses to read from storage
package/dist/dialog.js CHANGED
@@ -1144,6 +1144,9 @@ class Dialog {
1144
1144
  async nativeToolCall(payload) {
1145
1145
  await this.dlgStore.nativeToolCall(this, payload);
1146
1146
  }
1147
+ async toolResultImageIngest(payload) {
1148
+ await this.dlgStore.toolResultImageIngest(this, payload);
1149
+ }
1147
1150
  // Tellask-special call lifecycle events
1148
1151
  async callingStart(payload) {
1149
1152
  // Store callId for inline call-result correlation
@@ -1578,6 +1581,7 @@ class DialogStore {
1578
1581
  async funcCallRequested(_dialog, _funcId, _funcName, _argumentsStr) { }
1579
1582
  async webSearchCall(_dialog, _payload) { }
1580
1583
  async nativeToolCall(_dialog, _payload) { }
1584
+ async toolResultImageIngest(_dialog, _payload) { }
1581
1585
  /**
1582
1586
  * Load current course number from persisted metadata
1583
1587
  * This method should be implemented by subclasses to read from storage
@@ -8,7 +8,7 @@ export type AnthropicStreamConsumeResult = {
8
8
  usage: LlmUsageStats;
9
9
  llmGenModel?: string;
10
10
  };
11
- export declare function buildAnthropicRequestMessagesWrapper(context: ChatMessage[], providerConfig?: ProviderConfig): Promise<MessageParam[]>;
11
+ export declare function buildAnthropicRequestMessagesWrapper(context: ChatMessage[], requestContextOrProviderConfig?: LlmRequestContext | ProviderConfig, providerConfigMaybe?: ProviderConfig): Promise<MessageParam[]>;
12
12
  export declare function consumeAnthropicStream(stream: AsyncIterable<MessageStreamEvent>, receiver: LlmStreamReceiver, abortSignal?: AbortSignal, forcedJsonToolName?: string): Promise<AnthropicStreamConsumeResult>;
13
13
  /**
14
14
  * Reconstruct Anthropic context from persisted messages with genseq tracking.
@@ -29,6 +29,6 @@ export declare function reconstructAnthropicContextWrapperAsync(persistedMessage
29
29
  export declare class AnthropicGen implements LlmGenerator {
30
30
  get apiType(): string;
31
31
  classifyFailure(error: unknown): LlmFailureDisposition | undefined;
32
- genToReceiver(providerConfig: ProviderConfig, agent: Team.Member, systemPrompt: string, funcTools: FuncTool[], _requestContext: LlmRequestContext, context: ChatMessage[], receiver: LlmStreamReceiver, _genseq: number, abortSignal?: AbortSignal): Promise<LlmStreamResult>;
33
- genMoreMessages(providerConfig: ProviderConfig, agent: Team.Member, systemPrompt: string, funcTools: FuncTool[], _requestContext: LlmRequestContext, context: ChatMessage[], genseq: number, abortSignal?: AbortSignal): Promise<LlmBatchResult>;
32
+ genToReceiver(providerConfig: ProviderConfig, agent: Team.Member, systemPrompt: string, funcTools: FuncTool[], requestContext: LlmRequestContext, context: ChatMessage[], receiver: LlmStreamReceiver, _genseq: number, abortSignal?: AbortSignal): Promise<LlmStreamResult>;
33
+ genMoreMessages(providerConfig: ProviderConfig, agent: Team.Member, systemPrompt: string, funcTools: FuncTool[], requestContext: LlmRequestContext, context: ChatMessage[], genseq: number, abortSignal?: AbortSignal): Promise<LlmBatchResult>;
34
34
  }
@@ -18,6 +18,7 @@ const artifacts_1 = require("./artifacts");
18
18
  const failure_classifier_1 = require("./failure-classifier");
19
19
  const tool_call_context_1 = require("./tool-call-context");
20
20
  const tool_output_limit_1 = require("./tool-output-limit");
21
+ const tool_result_image_ingest_1 = require("./tool-result-image-ingest");
21
22
  const log = (0, log_1.createLogger)('llm/anthropic');
22
23
  const ANTHROPIC_JSON_RESPONSE_TOOL_NAME = 'dominds_json_response';
23
24
  const ANTHROPIC_JSON_RESPONSE_TOOL_DESCRIPTION = 'Return the final answer as a JSON object. Do not include any non-JSON text.';
@@ -75,6 +76,13 @@ function isRecord(value) {
75
76
  function isNonArrayRecord(value) {
76
77
  return isRecord(value) && !Array.isArray(value);
77
78
  }
79
+ function isLlmRequestContext(value) {
80
+ return (isNonArrayRecord(value) &&
81
+ typeof value.dialogSelfId === 'string' &&
82
+ typeof value.dialogRootId === 'string' &&
83
+ typeof value.providerKey === 'string' &&
84
+ typeof value.modelKey === 'string');
85
+ }
78
86
  function tryExtractApiReturnedModel(value) {
79
87
  // NOTE: External API payload; a runtime check is unavoidable.
80
88
  if (!isRecord(value))
@@ -177,7 +185,7 @@ function parseForcedJsonToolInput(rawJson, fallbackInput, at) {
177
185
  }
178
186
  throw new Error(`Invalid ${at}: ${errorText}; raw=${JSON.stringify(preview)}`);
179
187
  }
180
- async function funcResultToAnthropicToolResultBlock(chatMsg, limitChars) {
188
+ async function funcResultToAnthropicToolResultBlock(chatMsg, limitChars, requestContext, allowedImageKeys, onToolResultImageIngest) {
181
189
  const items = chatMsg.contentItems;
182
190
  if (!Array.isArray(items) || items.length === 0) {
183
191
  return {
@@ -194,22 +202,85 @@ async function funcResultToAnthropicToolResultBlock(chatMsg, limitChars) {
194
202
  }
195
203
  if (item.type === 'input_image') {
196
204
  if (!(0, artifacts_1.isVisionImageMimeType)(item.mimeType)) {
205
+ if (onToolResultImageIngest) {
206
+ await onToolResultImageIngest((0, tool_result_image_ingest_1.buildToolResultImageIngest)({
207
+ requestContext,
208
+ toolCallId: chatMsg.id,
209
+ toolName: chatMsg.name,
210
+ artifact: item.artifact,
211
+ disposition: 'filtered_mime_unsupported',
212
+ mimeType: item.mimeType,
213
+ providerPathLabel: 'Anthropic Messages path',
214
+ }));
215
+ }
197
216
  content.push({
198
217
  type: 'text',
199
218
  text: `[image omitted: unsupported mimeType=${item.mimeType}]`,
200
219
  });
201
220
  continue;
202
221
  }
203
- const bytes = await (0, artifacts_1.readDialogArtifactBytes)({
204
- rootId: item.artifact.rootId,
205
- selfId: item.artifact.selfId,
206
- status: item.artifact.status,
207
- relPath: item.artifact.relPath,
208
- });
209
- if (!bytes) {
222
+ if (!allowedImageKeys.has((0, tool_result_image_ingest_1.buildToolResultImageBudgetKeyForMsg)(chatMsg, item.artifact))) {
223
+ if (onToolResultImageIngest) {
224
+ await onToolResultImageIngest((0, tool_result_image_ingest_1.buildToolResultImageIngest)({
225
+ requestContext,
226
+ toolCallId: chatMsg.id,
227
+ toolName: chatMsg.name,
228
+ artifact: item.artifact,
229
+ disposition: 'filtered_size_limit',
230
+ detail: (0, tool_result_image_ingest_1.buildToolResultImageBudgetLimitDetail)({
231
+ byteLength: item.byteLength,
232
+ budgetBytes: tool_result_image_ingest_1.ANTHROPIC_TOOL_RESULT_IMAGE_BUDGET_BYTES,
233
+ }),
234
+ providerPathLabel: 'Anthropic Messages path',
235
+ }));
236
+ }
237
+ content.push({
238
+ type: 'text',
239
+ text: `[image omitted: request image budget exceeded bytes=${String(item.byteLength)} budget=${String(tool_result_image_ingest_1.ANTHROPIC_TOOL_RESULT_IMAGE_BUDGET_BYTES)}]`,
240
+ });
241
+ continue;
242
+ }
243
+ const bytesResult = await (0, tool_result_image_ingest_1.readToolResultImageBytesSafe)(item.artifact);
244
+ if (bytesResult.kind === 'missing') {
245
+ if (onToolResultImageIngest) {
246
+ await onToolResultImageIngest((0, tool_result_image_ingest_1.buildToolResultImageIngest)({
247
+ requestContext,
248
+ toolCallId: chatMsg.id,
249
+ toolName: chatMsg.name,
250
+ artifact: item.artifact,
251
+ disposition: 'filtered_missing',
252
+ providerPathLabel: 'Anthropic Messages path',
253
+ }));
254
+ }
210
255
  content.push({ type: 'text', text: `[image missing: ${item.artifact.relPath}]` });
211
256
  continue;
212
257
  }
258
+ if (bytesResult.kind === 'read_failed') {
259
+ if (onToolResultImageIngest) {
260
+ await onToolResultImageIngest((0, tool_result_image_ingest_1.buildToolResultImageIngest)({
261
+ requestContext,
262
+ toolCallId: chatMsg.id,
263
+ toolName: chatMsg.name,
264
+ artifact: item.artifact,
265
+ disposition: 'filtered_read_failed',
266
+ detail: bytesResult.detail,
267
+ providerPathLabel: 'Anthropic Messages path',
268
+ }));
269
+ }
270
+ content.push({ type: 'text', text: `[image unreadable: ${item.artifact.relPath}]` });
271
+ continue;
272
+ }
273
+ if (onToolResultImageIngest) {
274
+ await onToolResultImageIngest((0, tool_result_image_ingest_1.buildToolResultImageIngest)({
275
+ requestContext,
276
+ toolCallId: chatMsg.id,
277
+ toolName: chatMsg.name,
278
+ artifact: item.artifact,
279
+ disposition: 'fed_native',
280
+ providerPathLabel: 'Anthropic Messages path',
281
+ }));
282
+ }
283
+ const bytes = bytesResult.bytes;
213
284
  const base64 = bytes.toString('base64');
214
285
  content.push({
215
286
  type: 'image',
@@ -237,14 +308,16 @@ async function funcResultToAnthropicToolResultBlock(chatMsg, limitChars) {
237
308
  content: limitAnthropicToolOutputBlocks(content, chatMsg, limitChars),
238
309
  };
239
310
  }
240
- async function chatMessageToContentBlocksAsync(chatMsg, limitChars) {
311
+ async function chatMessageToContentBlocksAsync(chatMsg, limitChars, requestContext, allowedImageKeys, onToolResultImageIngest) {
241
312
  if (chatMsg.type !== 'func_result_msg') {
242
313
  return chatMessageToContentBlocks(chatMsg);
243
314
  }
244
- return [await funcResultToAnthropicToolResultBlock(chatMsg, limitChars)];
315
+ return [
316
+ await funcResultToAnthropicToolResultBlock(chatMsg, limitChars, requestContext, allowedImageKeys, onToolResultImageIngest),
317
+ ];
245
318
  }
246
- async function chatMessageToAnthropicAsync(chatMsg, limitChars) {
247
- const contentBlocks = await chatMessageToContentBlocksAsync(chatMsg, limitChars);
319
+ async function chatMessageToAnthropicAsync(chatMsg, limitChars, requestContext, allowedImageKeys, onToolResultImageIngest) {
320
+ const contentBlocks = await chatMessageToContentBlocksAsync(chatMsg, limitChars, requestContext, allowedImageKeys, onToolResultImageIngest);
248
321
  if (contentBlocks.length === 0) {
249
322
  throw new Error(`No content blocks generated for message: ${JSON.stringify(chatMsg)}`);
250
323
  }
@@ -257,7 +330,7 @@ async function chatMessageToAnthropicAsync(chatMsg, limitChars) {
257
330
  content: contentBlocks.length === 1 ? contentBlocks : contentBlocks,
258
331
  };
259
332
  }
260
- async function buildAnthropicRequestMessages(context, providerConfig) {
333
+ async function buildAnthropicRequestMessages(context, requestContext, providerConfig, onToolResultImageIngest) {
261
334
  // We keep the async path for func_result_msg because it may contain image artifacts.
262
335
  const normalized = (0, tool_call_context_1.normalizeToolCallPairs)(context);
263
336
  const violation = (0, tool_call_context_1.findFirstToolCallAdjacencyViolation)(normalized);
@@ -273,13 +346,25 @@ async function buildAnthropicRequestMessages(context, providerConfig) {
273
346
  }
274
347
  const messages = [];
275
348
  const toolResultMaxChars = (0, tool_output_limit_1.resolveProviderToolResultMaxChars)(providerConfig);
349
+ const allowedImageKeys = (0, tool_result_image_ingest_1.selectLatestToolResultImagesWithinBudget)(normalized, tool_result_image_ingest_1.ANTHROPIC_TOOL_RESULT_IMAGE_BUDGET_BYTES);
276
350
  for (const msg of normalized) {
277
- messages.push(await chatMessageToAnthropicAsync(msg, toolResultMaxChars));
351
+ messages.push(await chatMessageToAnthropicAsync(msg, toolResultMaxChars, requestContext, allowedImageKeys, onToolResultImageIngest));
278
352
  }
279
353
  return assembleAnthropicTurns(messages);
280
354
  }
281
- async function buildAnthropicRequestMessagesWrapper(context, providerConfig) {
282
- return await buildAnthropicRequestMessages(context, providerConfig);
355
+ async function buildAnthropicRequestMessagesWrapper(context, requestContextOrProviderConfig, providerConfigMaybe) {
356
+ const requestContext = isLlmRequestContext(requestContextOrProviderConfig)
357
+ ? requestContextOrProviderConfig
358
+ : {
359
+ dialogSelfId: '',
360
+ dialogRootId: '',
361
+ providerKey: 'anthropic',
362
+ modelKey: 'unknown',
363
+ };
364
+ const providerConfig = isLlmRequestContext(requestContextOrProviderConfig)
365
+ ? providerConfigMaybe
366
+ : requestContextOrProviderConfig;
367
+ return await buildAnthropicRequestMessages(context, requestContext, providerConfig);
283
368
  }
284
369
  /**
285
370
  * Reconstruct Anthropic context from persisted messages.
@@ -800,7 +885,12 @@ function reconstructAnthropicContextWrapper(persistedMessages) {
800
885
  return reconstructed;
801
886
  }
802
887
  async function reconstructAnthropicContextWrapperAsync(persistedMessages) {
803
- const reconstructed = await buildAnthropicRequestMessages(persistedMessages);
888
+ const reconstructed = await buildAnthropicRequestMessages(persistedMessages, {
889
+ dialogSelfId: '',
890
+ dialogRootId: '',
891
+ providerKey: 'anthropic',
892
+ modelKey: 'unknown',
893
+ });
804
894
  // Validate the reconstructed context
805
895
  try {
806
896
  validateReconstructedContext(reconstructed);
@@ -824,12 +914,12 @@ class AnthropicGen {
824
914
  classifyFailure(error) {
825
915
  return (0, failure_classifier_1.classifyAnthropicFailure)(error);
826
916
  }
827
- async genToReceiver(providerConfig, agent, systemPrompt, funcTools, _requestContext, context, receiver, _genseq, abortSignal) {
917
+ async genToReceiver(providerConfig, agent, systemPrompt, funcTools, requestContext, context, receiver, _genseq, abortSignal) {
828
918
  const apiKey = process.env[providerConfig.apiKeyEnvVar];
829
919
  if (!apiKey)
830
920
  throw new Error(`Missing API key env var ${providerConfig.apiKeyEnvVar}`);
831
921
  const client = new sdk_1.Anthropic({ apiKey, baseURL: providerConfig.baseUrl });
832
- const requestMessages = await buildAnthropicRequestMessages(context, providerConfig);
922
+ const requestMessages = await buildAnthropicRequestMessages(context, requestContext, providerConfig, receiver.toolResultImageIngest);
833
923
  const anthropicParams = agent.model_params?.anthropic || {};
834
924
  const forceJsonResponse = resolveAnthropicJsonResponseEnabled(agent);
835
925
  const maxTokens = agent.model_params?.max_tokens;
@@ -874,12 +964,15 @@ class AnthropicGen {
874
964
  const stream = client.messages.stream(streamParams);
875
965
  return consumeAnthropicStream(stream, receiver, abortSignal, forceJsonResponse ? ANTHROPIC_JSON_RESPONSE_TOOL_NAME : undefined);
876
966
  }
877
- async genMoreMessages(providerConfig, agent, systemPrompt, funcTools, _requestContext, context, genseq, abortSignal) {
967
+ async genMoreMessages(providerConfig, agent, systemPrompt, funcTools, requestContext, context, genseq, abortSignal) {
878
968
  const apiKey = process.env[providerConfig.apiKeyEnvVar];
879
969
  if (!apiKey)
880
970
  throw new Error(`Missing API key env var ${providerConfig.apiKeyEnvVar}`);
881
971
  const client = new sdk_1.Anthropic({ apiKey, baseURL: providerConfig.baseUrl });
882
- const requestMessages = await buildAnthropicRequestMessages(context, providerConfig);
972
+ const outputs = [];
973
+ const requestMessages = await buildAnthropicRequestMessages(context, requestContext, providerConfig, async (ingest) => {
974
+ outputs.push({ kind: 'tool_result_image_ingest', ingest });
975
+ });
883
976
  const anthropicParams = agent.model_params?.anthropic || {};
884
977
  const forceJsonResponse = resolveAnthropicJsonResponseEnabled(agent);
885
978
  const maxTokens = agent.model_params?.max_tokens;
@@ -940,6 +1033,7 @@ class AnthropicGen {
940
1033
  };
941
1034
  return {
942
1035
  messages: anthropicToChatMessages(response, genseq, forceJsonResponse ? ANTHROPIC_JSON_RESPONSE_TOOL_NAME : undefined),
1036
+ ...(outputs.length > 0 ? { outputs } : {}),
943
1037
  usage,
944
1038
  llmGenModel: returnedModel,
945
1039
  };
@@ -44,6 +44,7 @@ const artifacts_1 = require("./artifacts");
44
44
  const failure_classifier_1 = require("./failure-classifier");
45
45
  const tool_call_context_1 = require("./tool-call-context");
46
46
  const tool_output_limit_1 = require("./tool-output-limit");
47
+ const tool_result_image_ingest_1 = require("./tool-result-image-ingest");
47
48
  const log = (0, log_1.createLogger)('llm/codex');
48
49
  const codexFallbackInstructions = 'You are Codex CLI.';
49
50
  const CODEX_SYSTEM_PROMPT_DIRECTIVE_PATTERN = /^([ \t]*)@codex-system-prompt(?::([A-Za-z0-9._-]+))?([ \t]*)$/gm;
@@ -331,7 +332,7 @@ function chatMessageToCodexItems(msg) {
331
332
  }
332
333
  }
333
334
  }
334
- async function buildCodexFunctionCallOutput(msg, limitChars) {
335
+ async function buildCodexFunctionCallOutput(msg, limitChars, requestContext, allowedImageKeys, onToolResultImageIngest) {
335
336
  const items = msg.contentItems;
336
337
  if (!Array.isArray(items) || items.length === 0) {
337
338
  return limitCodexToolOutputText(msg.content, msg, limitChars);
@@ -344,22 +345,85 @@ async function buildCodexFunctionCallOutput(msg, limitChars) {
344
345
  }
345
346
  if (item.type === 'input_image') {
346
347
  if (!(0, artifacts_1.isVisionImageMimeType)(item.mimeType)) {
348
+ if (onToolResultImageIngest) {
349
+ await onToolResultImageIngest((0, tool_result_image_ingest_1.buildToolResultImageIngest)({
350
+ requestContext,
351
+ toolCallId: msg.id,
352
+ toolName: msg.name,
353
+ artifact: item.artifact,
354
+ disposition: 'filtered_mime_unsupported',
355
+ mimeType: item.mimeType,
356
+ providerPathLabel: 'Codex path',
357
+ }));
358
+ }
347
359
  out.push({
348
360
  type: 'input_text',
349
361
  text: `[image omitted: unsupported mimeType=${item.mimeType}]`,
350
362
  });
351
363
  continue;
352
364
  }
353
- const bytes = await (0, artifacts_1.readDialogArtifactBytes)({
354
- rootId: item.artifact.rootId,
355
- selfId: item.artifact.selfId,
356
- status: item.artifact.status,
357
- relPath: item.artifact.relPath,
358
- });
359
- if (!bytes) {
365
+ if (!allowedImageKeys.has((0, tool_result_image_ingest_1.buildToolResultImageBudgetKeyForMsg)(msg, item.artifact))) {
366
+ if (onToolResultImageIngest) {
367
+ await onToolResultImageIngest((0, tool_result_image_ingest_1.buildToolResultImageIngest)({
368
+ requestContext,
369
+ toolCallId: msg.id,
370
+ toolName: msg.name,
371
+ artifact: item.artifact,
372
+ disposition: 'filtered_size_limit',
373
+ detail: (0, tool_result_image_ingest_1.buildToolResultImageBudgetLimitDetail)({
374
+ byteLength: item.byteLength,
375
+ budgetBytes: tool_result_image_ingest_1.CODEX_TOOL_RESULT_IMAGE_BUDGET_BYTES,
376
+ }),
377
+ providerPathLabel: 'Codex path',
378
+ }));
379
+ }
380
+ out.push({
381
+ type: 'input_text',
382
+ text: `[image omitted: request image budget exceeded bytes=${String(item.byteLength)} budget=${String(tool_result_image_ingest_1.CODEX_TOOL_RESULT_IMAGE_BUDGET_BYTES)}]`,
383
+ });
384
+ continue;
385
+ }
386
+ const bytesResult = await (0, tool_result_image_ingest_1.readToolResultImageBytesSafe)(item.artifact);
387
+ if (bytesResult.kind === 'missing') {
388
+ if (onToolResultImageIngest) {
389
+ await onToolResultImageIngest((0, tool_result_image_ingest_1.buildToolResultImageIngest)({
390
+ requestContext,
391
+ toolCallId: msg.id,
392
+ toolName: msg.name,
393
+ artifact: item.artifact,
394
+ disposition: 'filtered_missing',
395
+ providerPathLabel: 'Codex path',
396
+ }));
397
+ }
360
398
  out.push({ type: 'input_text', text: `[image missing: ${item.artifact.relPath}]` });
361
399
  continue;
362
400
  }
401
+ if (bytesResult.kind === 'read_failed') {
402
+ if (onToolResultImageIngest) {
403
+ await onToolResultImageIngest((0, tool_result_image_ingest_1.buildToolResultImageIngest)({
404
+ requestContext,
405
+ toolCallId: msg.id,
406
+ toolName: msg.name,
407
+ artifact: item.artifact,
408
+ disposition: 'filtered_read_failed',
409
+ detail: bytesResult.detail,
410
+ providerPathLabel: 'Codex path',
411
+ }));
412
+ }
413
+ out.push({ type: 'input_text', text: `[image unreadable: ${item.artifact.relPath}]` });
414
+ continue;
415
+ }
416
+ if (onToolResultImageIngest) {
417
+ await onToolResultImageIngest((0, tool_result_image_ingest_1.buildToolResultImageIngest)({
418
+ requestContext,
419
+ toolCallId: msg.id,
420
+ toolName: msg.name,
421
+ artifact: item.artifact,
422
+ disposition: 'fed_native',
423
+ providerPathLabel: 'Codex path',
424
+ }));
425
+ }
426
+ const bytes = bytesResult.bytes;
363
427
  out.push({
364
428
  type: 'input_image',
365
429
  image_url: (0, artifacts_1.bytesToDataUrl)({ mimeType: item.mimeType, bytes }),
@@ -373,7 +437,7 @@ async function buildCodexFunctionCallOutput(msg, limitChars) {
373
437
  ? limitCodexToolOutputItems(out, msg, limitChars)
374
438
  : limitCodexToolOutputText(msg.content, msg, limitChars);
375
439
  }
376
- async function buildCodexInput(context, providerConfig) {
440
+ async function buildCodexInput(context, requestContext, providerConfig, onToolResultImageIngest) {
377
441
  const normalized = (0, tool_call_context_1.normalizeToolCallPairs)(context);
378
442
  const violation = (0, tool_call_context_1.findFirstToolCallAdjacencyViolation)(normalized);
379
443
  if (violation) {
@@ -388,6 +452,7 @@ async function buildCodexInput(context, providerConfig) {
388
452
  }
389
453
  const input = [];
390
454
  const toolResultMaxChars = (0, tool_output_limit_1.resolveProviderToolResultMaxChars)(providerConfig);
455
+ const allowedImageKeys = (0, tool_result_image_ingest_1.selectLatestToolResultImagesWithinBudget)(normalized, tool_result_image_ingest_1.CODEX_TOOL_RESULT_IMAGE_BUDGET_BYTES);
391
456
  for (const msg of normalized) {
392
457
  if (msg.type === 'func_call_msg') {
393
458
  input.push({
@@ -402,7 +467,7 @@ async function buildCodexInput(context, providerConfig) {
402
467
  input.push({
403
468
  type: 'function_call_output',
404
469
  call_id: msg.id,
405
- output: await buildCodexFunctionCallOutput(msg, toolResultMaxChars),
470
+ output: await buildCodexFunctionCallOutput(msg, toolResultMaxChars, requestContext, allowedImageKeys, onToolResultImageIngest),
406
471
  });
407
472
  continue;
408
473
  }
@@ -413,11 +478,11 @@ async function buildCodexInput(context, providerConfig) {
413
478
  }
414
479
  return input;
415
480
  }
416
- async function buildCodexRequest(providerConfig, agent, instructions, funcTools, requestContext, context) {
481
+ async function buildCodexRequest(providerConfig, agent, instructions, funcTools, requestContext, context, onToolResultImageIngest) {
417
482
  if (!agent.model) {
418
483
  throw new Error(`Internal error: Model is undefined for agent '${agent.id}'`);
419
484
  }
420
- const input = await buildCodexInput(context, providerConfig);
485
+ const input = await buildCodexInput(context, requestContext, providerConfig, onToolResultImageIngest);
421
486
  // Provider isolation rule: request construction must only read Codex-native params here.
422
487
  const codexParams = agent.model_params?.codex;
423
488
  const parallelToolCalls = codexParams?.parallel_tool_calls ?? true;
@@ -473,7 +538,7 @@ class CodexGen {
473
538
  defaultModel: agent.model,
474
539
  loadPrompt: codexAuth.loadCodexPromptSync,
475
540
  });
476
- const payload = await buildCodexRequest(providerConfig, agent, instructions, funcTools, requestContext, context);
541
+ const payload = await buildCodexRequest(providerConfig, agent, instructions, funcTools, requestContext, context, receiver.toolResultImageIngest);
477
542
  let sayingStarted = false;
478
543
  let thinkingStarted = false;
479
544
  let sawOutputText = false;
@@ -231,6 +231,16 @@ function isOpenAiLikeRateLimitFailure(error) {
231
231
  if (lowerMessage.includes('rate limit')) {
232
232
  return true;
233
233
  }
234
+ if (lowerMessage.includes('concurrency limit exceeded')) {
235
+ return true;
236
+ }
237
+ if (lowerMessage.includes('concurrent request limit')) {
238
+ return true;
239
+ }
240
+ if (lowerMessage.includes('concurrency limit') &&
241
+ (lowerMessage.includes('retry later') || lowerMessage.includes('try again later'))) {
242
+ return true;
243
+ }
234
244
  if (lowerMessage.includes('requests per min')) {
235
245
  return true;
236
246
  }
@@ -15,13 +15,16 @@ import type { Team } from '../../team';
15
15
  import type { FuncTool } from '../../tool';
16
16
  import type { ChatMessage, ProviderConfig } from '../client';
17
17
  import { type LlmBatchResult, type LlmFailureDisposition, type LlmGenerator, type LlmRequestContext, type LlmStreamReceiver, type LlmStreamResult } from '../gen';
18
- export declare function buildOpenAiCompatibleRequestMessagesWrapper(systemPrompt: string, context: ChatMessage[], options?: {
18
+ export declare function buildOpenAiCompatibleRequestMessagesWrapper(systemPrompt: string, context: ChatMessage[], requestContextOrOptions?: LlmRequestContext | {
19
+ reasoningContentMode?: boolean;
20
+ providerConfig?: ProviderConfig;
21
+ }, optionsMaybe?: {
19
22
  reasoningContentMode?: boolean;
20
23
  providerConfig?: ProviderConfig;
21
24
  }): Promise<ChatCompletionMessageParam[]>;
22
25
  export declare class OpenAiCompatibleGen implements LlmGenerator {
23
26
  get apiType(): string;
24
27
  classifyFailure(error: unknown): LlmFailureDisposition | undefined;
25
- genToReceiver(providerConfig: ProviderConfig, agent: Team.Member, systemPrompt: string, funcTools: FuncTool[], _requestContext: LlmRequestContext, context: ChatMessage[], receiver: LlmStreamReceiver, genseq: number, abortSignal?: AbortSignal): Promise<LlmStreamResult>;
26
- genMoreMessages(providerConfig: ProviderConfig, agent: Team.Member, systemPrompt: string, funcTools: FuncTool[], _requestContext: LlmRequestContext, context: ChatMessage[], genseq: number, abortSignal?: AbortSignal): Promise<LlmBatchResult>;
28
+ genToReceiver(providerConfig: ProviderConfig, agent: Team.Member, systemPrompt: string, funcTools: FuncTool[], requestContext: LlmRequestContext, context: ChatMessage[], receiver: LlmStreamReceiver, genseq: number, abortSignal?: AbortSignal): Promise<LlmStreamResult>;
29
+ genMoreMessages(providerConfig: ProviderConfig, agent: Team.Member, systemPrompt: string, funcTools: FuncTool[], requestContext: LlmRequestContext, context: ChatMessage[], genseq: number, abortSignal?: AbortSignal): Promise<LlmBatchResult>;
27
30
  }