@jait/gateway 0.1.562 → 0.1.563

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 (60) hide show
  1. package/dist/routes/chat.d.ts.map +1 -1
  2. package/dist/routes/chat.js +43 -10
  3. package/dist/routes/chat.js.map +1 -1
  4. package/package.json +1 -1
  5. package/web-dist/assets/{_basePickBy-DdrYZfaI.js → _basePickBy-BLPTTE12.js} +1 -1
  6. package/web-dist/assets/{_baseUniq-DtMqiRTR.js → _baseUniq-B-zWGRFc.js} +1 -1
  7. package/web-dist/assets/{arc-DPogbokA.js → arc-c7KoiUb0.js} +1 -1
  8. package/web-dist/assets/{architectureDiagram-2XIMDMQ5-DfgMoNuL.js → architectureDiagram-2XIMDMQ5-CTS9i3n0.js} +1 -1
  9. package/web-dist/assets/{blockDiagram-WCTKOSBZ-DDqk9Jy8.js → blockDiagram-WCTKOSBZ-5342Wdp1.js} +1 -1
  10. package/web-dist/assets/{c4Diagram-IC4MRINW-DzGpZBPK.js → c4Diagram-IC4MRINW-rIlEHjVS.js} +1 -1
  11. package/web-dist/assets/channel-Cq6b858S.js +1 -0
  12. package/web-dist/assets/{chunk-4BX2VUAB-D4Ps-h8T.js → chunk-4BX2VUAB-DVwbe9Y3.js} +1 -1
  13. package/web-dist/assets/{chunk-55IACEB6-G7hBRWq5.js → chunk-55IACEB6-D4NlHMGD.js} +1 -1
  14. package/web-dist/assets/{chunk-FMBD7UC4-CkHurVvQ.js → chunk-FMBD7UC4-OzGVGn6v.js} +1 -1
  15. package/web-dist/assets/{chunk-JSJVCQXG-DV8amfHR.js → chunk-JSJVCQXG-CJtuJK8m.js} +1 -1
  16. package/web-dist/assets/{chunk-KX2RTZJC-69DOW3Ue.js → chunk-KX2RTZJC-C-tKDpOw.js} +1 -1
  17. package/web-dist/assets/{chunk-NQ4KR5QH-DyQtg2WK.js → chunk-NQ4KR5QH-Dgh0SyHf.js} +1 -1
  18. package/web-dist/assets/{chunk-QZHKN3VN-BudZmvXI.js → chunk-QZHKN3VN-CFu972H6.js} +1 -1
  19. package/web-dist/assets/{chunk-WL4C6EOR-DDC-nJ_R.js → chunk-WL4C6EOR-C20z7J-u.js} +1 -1
  20. package/web-dist/assets/classDiagram-VBA2DB6C-o-1bc6HA.js +1 -0
  21. package/web-dist/assets/classDiagram-v2-RAHNMMFH-o-1bc6HA.js +1 -0
  22. package/web-dist/assets/clone-DrUp6gCK.js +1 -0
  23. package/web-dist/assets/{cose-bilkent-S5V4N54A-o6CERVjo.js → cose-bilkent-S5V4N54A-UqMqNApA.js} +1 -1
  24. package/web-dist/assets/{dagre-KLK3FWXG-D4C131qF.js → dagre-KLK3FWXG-DLwd_vTc.js} +1 -1
  25. package/web-dist/assets/{diagram-E7M64L7V-CIJwHXJn.js → diagram-E7M64L7V-CSdJH_3Y.js} +1 -1
  26. package/web-dist/assets/{diagram-IFDJBPK2-CanWXGSn.js → diagram-IFDJBPK2-B19jIMaK.js} +1 -1
  27. package/web-dist/assets/{diagram-P4PSJMXO-iuxqiQ-H.js → diagram-P4PSJMXO-Bco25wYY.js} +1 -1
  28. package/web-dist/assets/{erDiagram-INFDFZHY-EAkbUiau.js → erDiagram-INFDFZHY-CtNMhg4I.js} +1 -1
  29. package/web-dist/assets/{flowDiagram-PKNHOUZH-DDT5vFCI.js → flowDiagram-PKNHOUZH-CopSqBb8.js} +1 -1
  30. package/web-dist/assets/{ganttDiagram-A5KZAMGK-DQew1yq7.js → ganttDiagram-A5KZAMGK-BF2YHIC6.js} +1 -1
  31. package/web-dist/assets/{gitGraphDiagram-K3NZZRJ6-CTibtMAF.js → gitGraphDiagram-K3NZZRJ6-BNUoWVBT.js} +1 -1
  32. package/web-dist/assets/{graph-Bhy-ORc3.js → graph-ChkhkAte.js} +1 -1
  33. package/web-dist/assets/{index-Dwa2JHdR.js → index-CKatg4Cd.js} +38 -38
  34. package/web-dist/assets/{index-d9pVTxbs.js → index-CfExpmNa.js} +1 -1
  35. package/web-dist/assets/{index-Bji_CrGX.js → index-DANla4EU.js} +1 -1
  36. package/web-dist/assets/{index-DwcL2RTj.css → index-DnYkDO9H.css} +1 -1
  37. package/web-dist/assets/{infoDiagram-LFFYTUFH-jHwBFNRe.js → infoDiagram-LFFYTUFH-bCWdgFzd.js} +1 -1
  38. package/web-dist/assets/{ishikawaDiagram-PHBUUO56-yfzRKbME.js → ishikawaDiagram-PHBUUO56-rH-MGgWS.js} +1 -1
  39. package/web-dist/assets/{journeyDiagram-4ABVD52K-DAfMdAoJ.js → journeyDiagram-4ABVD52K-DewOB_2b.js} +1 -1
  40. package/web-dist/assets/{kanban-definition-K7BYSVSG-BqeHacw9.js → kanban-definition-K7BYSVSG-Bh-HbTjN.js} +1 -1
  41. package/web-dist/assets/{layout-D2Htaq1s.js → layout-CbhacZBJ.js} +1 -1
  42. package/web-dist/assets/{linear-DqZUIgTy.js → linear-DD_ODiYc.js} +1 -1
  43. package/web-dist/assets/{mindmap-definition-YRQLILUH-BcwrZEls.js → mindmap-definition-YRQLILUH-SKN0J_Wl.js} +1 -1
  44. package/web-dist/assets/{pieDiagram-SKSYHLDU-CcEY7LJn.js → pieDiagram-SKSYHLDU-ByrJbGfX.js} +1 -1
  45. package/web-dist/assets/{quadrantDiagram-337W2JSQ-DPafORvP.js → quadrantDiagram-337W2JSQ-zTzXcfHU.js} +1 -1
  46. package/web-dist/assets/{requirementDiagram-Z7DCOOCP-CKauR7Fa.js → requirementDiagram-Z7DCOOCP-BcmD_9aw.js} +1 -1
  47. package/web-dist/assets/{sankeyDiagram-WA2Y5GQK-B6c6bkar.js → sankeyDiagram-WA2Y5GQK-CNdRF6F9.js} +1 -1
  48. package/web-dist/assets/{sequenceDiagram-2WXFIKYE-DfwR0ief.js → sequenceDiagram-2WXFIKYE-CDkMorAJ.js} +1 -1
  49. package/web-dist/assets/{stateDiagram-RAJIS63D-L5jcmT-2.js → stateDiagram-RAJIS63D-CjVhLnLM.js} +1 -1
  50. package/web-dist/assets/stateDiagram-v2-FVOUBMTO-D3G3hOZ3.js +1 -0
  51. package/web-dist/assets/{timeline-definition-YZTLITO2-DwYKCKU2.js → timeline-definition-YZTLITO2-D4XWKQLS.js} +1 -1
  52. package/web-dist/assets/{treemap-KZPCXAKY-BTHOQHX6.js → treemap-KZPCXAKY-CmuaMYWg.js} +1 -1
  53. package/web-dist/assets/{vennDiagram-LZ73GAT5-kqHECFxm.js → vennDiagram-LZ73GAT5-CpTbfjvn.js} +1 -1
  54. package/web-dist/assets/{xychartDiagram-JWTSCODW-DIjyczsb.js → xychartDiagram-JWTSCODW-B-6wJCxq.js} +1 -1
  55. package/web-dist/index.html +2 -2
  56. package/web-dist/assets/channel-DSTwNl0W.js +0 -1
  57. package/web-dist/assets/classDiagram-VBA2DB6C-DiHGytB6.js +0 -1
  58. package/web-dist/assets/classDiagram-v2-RAHNMMFH-DiHGytB6.js +0 -1
  59. package/web-dist/assets/clone-CdjsjpLr.js +0 -1
  60. package/web-dist/assets/stateDiagram-v2-FVOUBMTO-oazjKK8g.js +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/routes/chat.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAA4B,MAAM,uBAAuB,CAAC;AACnF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAe,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACtF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAgCjE,OAAO,KAAK,EAAS,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AAqHvF,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAmBrE;AA8FD,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAE3D;AAydD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAyCtF;AAmiBD,MAAM,WAAW,aAAa;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,EAAE,CAAC,EAAE,cAAc,CAAC;IACpB,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,oBAAoB,CAAC,EAAE,0BAA0B,CAAC;IAClD,YAAY,CAAC,EAAE,CACb,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,KACtD,OAAO,CAAC,UAAU,CAAC,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,eAAe,EACpB,MAAM,EAAE,SAAS,EACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,aAAa,EACjC,iBAAiB,CAAC,EAAE,cAAc,QA2mEnC"}
1
+ {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/routes/chat.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAA4B,MAAM,uBAAuB,CAAC;AACnF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAe,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACtF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAgCjE,OAAO,KAAK,EAAS,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AAqHvF,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAmBrE;AA8FD,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAE3D;AAydD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAyCtF;AAmiBD,MAAM,WAAW,aAAa;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,EAAE,CAAC,EAAE,cAAc,CAAC;IACpB,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,oBAAoB,CAAC,EAAE,0BAA0B,CAAC;IAClD,YAAY,CAAC,EAAE,CACb,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,KACtD,OAAO,CAAC,UAAU,CAAC,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,eAAe,EACpB,MAAM,EAAE,SAAS,EACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,aAAa,EACjC,iBAAiB,CAAC,EAAE,cAAc,QA2oEnC"}
@@ -1578,11 +1578,21 @@ export function registerChatRoutes(app, config, depsOrDb, sessionServiceArg) {
1578
1578
  let resultSegmentsJson;
1579
1579
  let contextFlowJson;
1580
1580
  let hitMaxRounds = false;
1581
+ // Whether the turn ran through an external CLI provider (codex / claude-code)
1582
+ // instead of the Jait-managed agentic loop. Those providers keep their own
1583
+ // tool-call metadata opaque, so we cannot reliably detect Jait-managed tool
1584
+ // timeouts from their persisted `message` text — and grepping it for
1585
+ // "timed out" false-positives on any command that logs a timeout (curl, git,
1586
+ // network calls, agent prose, …). The has_timed_out_tools heuristic is only
1587
+ // meaningful for the Jait loop, where timed tools always emit a failed
1588
+ // result whose message starts with "timed out after …".
1589
+ let ranCliProvider = false;
1581
1590
  // Whether the agentic loop already persisted the assistant message via its
1582
1591
  // onPersist callback. The post-loop fallback persists must be skipped when
1583
1592
  // this is true to avoid writing a duplicate DB row (which scrambled message
1584
1593
  // order on reload because the rows share createdAt down to the millisecond).
1585
1594
  let loopPersisted = false;
1595
+ let assistantTurnPersisted = false;
1586
1596
  activeStreams.add(sessionId);
1587
1597
  // Reset streaming accumulator for this turn so reload snapshots start fresh.
1588
1598
  // Eagerly (re)create it so the invariant "activeStreams.has => accumulator
@@ -2139,6 +2149,7 @@ export function registerChatRoutes(app, config, depsOrDb, sessionServiceArg) {
2139
2149
  contextFlow: contextFlowJson ? JSON.parse(contextFlowJson) : undefined,
2140
2150
  });
2141
2151
  persistMessage(sessionId, "assistant", sessionError, undefined, errSegJson, contextFlowJson);
2152
+ assistantTurnPersisted = true;
2142
2153
  }
2143
2154
  else {
2144
2155
  history.push({
@@ -2149,10 +2160,12 @@ export function registerChatRoutes(app, config, depsOrDb, sessionServiceArg) {
2149
2160
  contextFlow: contextFlowJson ? JSON.parse(contextFlowJson) : undefined,
2150
2161
  });
2151
2162
  persistMessage(sessionId, "assistant", fullContent, cliTcJson, cliSegJson, contextFlowJson);
2163
+ assistantTurnPersisted = true;
2152
2164
  }
2153
2165
  // Session stays alive for the next turn — do NOT stop it.
2154
2166
  // It will be cleaned up on session error, provider switch, or server shutdown.
2155
2167
  usedCliProvider = true;
2168
+ ranCliProvider = true;
2156
2169
  } // end availability else
2157
2170
  }
2158
2171
  if (!usedCliProvider) {
@@ -2272,7 +2285,11 @@ export function registerChatRoutes(app, config, depsOrDb, sessionServiceArg) {
2272
2285
  ...(memoryFlow ? { memory: memoryFlow } : {}),
2273
2286
  });
2274
2287
  },
2275
- onPersist: (sid, role, content, tc, seg, thinking) => persistMessage(sid, role, content, tc, seg, contextFlowJson, thinking),
2288
+ onPersist: (sid, role, content, tc, seg, thinking) => {
2289
+ persistMessage(sid, role, content, tc, seg, contextFlowJson, thinking);
2290
+ if (sid === sessionId && role === "assistant")
2291
+ assistantTurnPersisted = true;
2292
+ },
2276
2293
  priorFingerprints: sessionFingerprints.get(sessionId),
2277
2294
  log: app.log,
2278
2295
  }, executeTool, steering);
@@ -2334,11 +2351,13 @@ export function registerChatRoutes(app, config, depsOrDb, sessionServiceArg) {
2334
2351
  if (!wasCancelled && !loopPersisted && (fullContent || partialToolCalls.length > 0)) {
2335
2352
  const tcJson = partialToolCalls.length > 0 ? JSON.stringify(partialToolCalls) : undefined;
2336
2353
  persistMessage(sessionId, "assistant", fullContent || "", tcJson, resultSegmentsJson, contextFlowJson);
2354
+ assistantTurnPersisted = true;
2337
2355
  }
2338
2356
  else if (!wasCancelled && !loopPersisted) {
2339
2357
  // No partial content — persist the error message itself so it's visible on reload.
2340
2358
  const errMsg2 = err instanceof Error ? err.message : `Failed to reach ${providerLabel}`;
2341
2359
  persistMessage(sessionId, "assistant", errMsg2, undefined, JSON.stringify([{ type: "error", content: errMsg2 }]), contextFlowJson);
2360
+ assistantTurnPersisted = true;
2342
2361
  }
2343
2362
  const errMsg = wasCancelled
2344
2363
  ? "cancelled"
@@ -2351,13 +2370,20 @@ export function registerChatRoutes(app, config, depsOrDb, sessionServiceArg) {
2351
2370
  }
2352
2371
  catch { /* client gone */ }
2353
2372
  }
2354
- // Persist partial results BEFORE clearing stream state so that a reload
2355
- // between these two steps loads the cancelled tool calls from the DB.
2356
- // Skip when the agentic loop already persisted via onPersist (avoids a
2357
- // duplicate row that scrambled message order on reload).
2358
- if (streamAbort.signal.aborted && !loopPersisted && (fullContent || partialToolCalls.length > 0)) {
2359
- const tcJson = partialToolCalls.length > 0 ? JSON.stringify(partialToolCalls) : undefined;
2360
- persistMessage(sessionId, "assistant", fullContent || "", tcJson, resultSegmentsJson, contextFlowJson);
2373
+ // Persist partial results BEFORE clearing stream state so a reload after
2374
+ // cancel can still render whatever had streamed, including thinking-only
2375
+ // output that may not have reached the provider loop finalization path.
2376
+ if (streamAbort.signal.aborted && !assistantTurnPersisted) {
2377
+ const acc = sessionStreamingState.get(sessionId);
2378
+ const fallbackContent = fullContent || acc?.content || "";
2379
+ const fallbackToolCalls = partialToolCalls.length > 0 ? partialToolCalls : (acc?.toolCalls ?? []);
2380
+ const fallbackSegmentsJson = resultSegmentsJson ?? (acc?.segments.length ? JSON.stringify(acc.segments) : undefined);
2381
+ const fallbackThinking = acc?.thinking || undefined;
2382
+ if (fallbackContent || fallbackThinking || fallbackToolCalls.length > 0 || fallbackSegmentsJson) {
2383
+ const tcJson = fallbackToolCalls.length > 0 ? JSON.stringify(fallbackToolCalls) : undefined;
2384
+ persistMessage(sessionId, "assistant", fallbackContent, tcJson, fallbackSegmentsJson, contextFlowJson, fallbackThinking);
2385
+ assistantTurnPersisted = true;
2386
+ }
2361
2387
  }
2362
2388
  // Stop the SSE keepalive heartbeat now that the turn is finishing.
2363
2389
  clearInterval(keepalive);
@@ -2390,8 +2416,15 @@ export function registerChatRoutes(app, config, depsOrDb, sessionServiceArg) {
2390
2416
  break;
2391
2417
  }
2392
2418
  }
2393
- // Detect whether any tool timed out during this turn
2394
- const hasTimedOutTools = (partialToolCalls ?? []).some((tc) => typeof tc.message === "string" && tc.message.includes("timed out"));
2419
+ // Detect whether any Jait-managed tool timed out during this turn. Only
2420
+ // meaningful for the Jait agentic loop: external CLI providers (codex /
2421
+ // claude-code) keep their tool-call output opaque, and grepping it for
2422
+ // "timed out" matched any command that logged a timeout (curl, git, network
2423
+ // calls, agent prose) — which made "Agent stopped — continue to resume"
2424
+ // show on nearly every Codex turn. Jait's timed tools (terminal / ssh /
2425
+ // elevated) always emit a *failed* result whose message starts with
2426
+ // "timed out after …", so gate on `ok === false` to avoid false positives.
2427
+ const hasTimedOutTools = !ranCliProvider && (partialToolCalls ?? []).some((tc) => tc.ok === false && typeof tc.message === "string" && tc.message.includes("timed out"));
2395
2428
  // Final done event
2396
2429
  const doneEvent = {
2397
2430
  type: "done",