@jait/gateway 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (474) hide show
  1. package/bin/jait.mjs +144 -0
  2. package/dist/config.d.ts +24 -0
  3. package/dist/config.d.ts.map +1 -0
  4. package/dist/config.js +73 -0
  5. package/dist/config.js.map +1 -0
  6. package/dist/db/connection.d.ts +37 -0
  7. package/dist/db/connection.d.ts.map +1 -0
  8. package/dist/db/connection.js +85 -0
  9. package/dist/db/connection.js.map +1 -0
  10. package/dist/db/index.d.ts +4 -0
  11. package/dist/db/index.d.ts.map +1 -0
  12. package/dist/db/index.js +4 -0
  13. package/dist/db/index.js.map +1 -0
  14. package/dist/db/migrations.d.ts +24 -0
  15. package/dist/db/migrations.d.ts.map +1 -0
  16. package/dist/db/migrations.js +312 -0
  17. package/dist/db/migrations.js.map +1 -0
  18. package/dist/db/schema.d.ts +2253 -0
  19. package/dist/db/schema.d.ts.map +1 -0
  20. package/dist/db/schema.js +195 -0
  21. package/dist/db/schema.js.map +1 -0
  22. package/dist/foundation.d.ts +26 -0
  23. package/dist/foundation.d.ts.map +1 -0
  24. package/dist/foundation.js +15 -0
  25. package/dist/foundation.js.map +1 -0
  26. package/dist/index.d.ts +3 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +413 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/lib/uuidv7.d.ts +10 -0
  31. package/dist/lib/uuidv7.d.ts.map +1 -0
  32. package/dist/lib/uuidv7.js +33 -0
  33. package/dist/lib/uuidv7.js.map +1 -0
  34. package/dist/memory/contracts.d.ts +42 -0
  35. package/dist/memory/contracts.d.ts.map +1 -0
  36. package/dist/memory/contracts.js +2 -0
  37. package/dist/memory/contracts.js.map +1 -0
  38. package/dist/memory/embeddings.d.ts +4 -0
  39. package/dist/memory/embeddings.d.ts.map +1 -0
  40. package/dist/memory/embeddings.js +26 -0
  41. package/dist/memory/embeddings.js.map +1 -0
  42. package/dist/memory/service.d.ts +17 -0
  43. package/dist/memory/service.d.ts.map +1 -0
  44. package/dist/memory/service.js +82 -0
  45. package/dist/memory/service.js.map +1 -0
  46. package/dist/memory/sqlite-backend.d.ts +11 -0
  47. package/dist/memory/sqlite-backend.d.ts.map +1 -0
  48. package/dist/memory/sqlite-backend.js +68 -0
  49. package/dist/memory/sqlite-backend.js.map +1 -0
  50. package/dist/plugins/contracts.d.ts +11 -0
  51. package/dist/plugins/contracts.d.ts.map +1 -0
  52. package/dist/plugins/contracts.js +2 -0
  53. package/dist/plugins/contracts.js.map +1 -0
  54. package/dist/providers/claude-code-provider.d.ts +39 -0
  55. package/dist/providers/claude-code-provider.d.ts.map +1 -0
  56. package/dist/providers/claude-code-provider.js +322 -0
  57. package/dist/providers/claude-code-provider.js.map +1 -0
  58. package/dist/providers/codex-provider.d.ts +51 -0
  59. package/dist/providers/codex-provider.d.ts.map +1 -0
  60. package/dist/providers/codex-provider.js +826 -0
  61. package/dist/providers/codex-provider.js.map +1 -0
  62. package/dist/providers/contracts.d.ts +167 -0
  63. package/dist/providers/contracts.d.ts.map +1 -0
  64. package/dist/providers/contracts.js +13 -0
  65. package/dist/providers/contracts.js.map +1 -0
  66. package/dist/providers/index.d.ts +6 -0
  67. package/dist/providers/index.d.ts.map +1 -0
  68. package/dist/providers/index.js +5 -0
  69. package/dist/providers/index.js.map +1 -0
  70. package/dist/providers/jait-provider.d.ts +23 -0
  71. package/dist/providers/jait-provider.d.ts.map +1 -0
  72. package/dist/providers/jait-provider.js +67 -0
  73. package/dist/providers/jait-provider.js.map +1 -0
  74. package/dist/providers/registry.d.ts +39 -0
  75. package/dist/providers/registry.d.ts.map +1 -0
  76. package/dist/providers/registry.js +64 -0
  77. package/dist/providers/registry.js.map +1 -0
  78. package/dist/pty-broker-client.d.ts +46 -0
  79. package/dist/pty-broker-client.d.ts.map +1 -0
  80. package/dist/pty-broker-client.js +142 -0
  81. package/dist/pty-broker-client.js.map +1 -0
  82. package/dist/routes/auth.d.ts +6 -0
  83. package/dist/routes/auth.d.ts.map +1 -0
  84. package/dist/routes/auth.js +236 -0
  85. package/dist/routes/auth.js.map +1 -0
  86. package/dist/routes/chat.d.ts +32 -0
  87. package/dist/routes/chat.d.ts.map +1 -0
  88. package/dist/routes/chat.js +1503 -0
  89. package/dist/routes/chat.js.map +1 -0
  90. package/dist/routes/consent.d.ts +10 -0
  91. package/dist/routes/consent.d.ts.map +1 -0
  92. package/dist/routes/consent.js +127 -0
  93. package/dist/routes/consent.js.map +1 -0
  94. package/dist/routes/filesystem.d.ts +14 -0
  95. package/dist/routes/filesystem.d.ts.map +1 -0
  96. package/dist/routes/filesystem.js +152 -0
  97. package/dist/routes/filesystem.js.map +1 -0
  98. package/dist/routes/git.d.ts +17 -0
  99. package/dist/routes/git.d.ts.map +1 -0
  100. package/dist/routes/git.js +213 -0
  101. package/dist/routes/git.js.map +1 -0
  102. package/dist/routes/health.d.ts +7 -0
  103. package/dist/routes/health.d.ts.map +1 -0
  104. package/dist/routes/health.js +21 -0
  105. package/dist/routes/health.js.map +1 -0
  106. package/dist/routes/hooks.d.ts +9 -0
  107. package/dist/routes/hooks.d.ts.map +1 -0
  108. package/dist/routes/hooks.js +22 -0
  109. package/dist/routes/hooks.js.map +1 -0
  110. package/dist/routes/jobs.d.ts +5 -0
  111. package/dist/routes/jobs.d.ts.map +1 -0
  112. package/dist/routes/jobs.js +333 -0
  113. package/dist/routes/jobs.js.map +1 -0
  114. package/dist/routes/mcp-server.d.ts +23 -0
  115. package/dist/routes/mcp-server.d.ts.map +1 -0
  116. package/dist/routes/mcp-server.js +177 -0
  117. package/dist/routes/mcp-server.js.map +1 -0
  118. package/dist/routes/mobile.d.ts +12 -0
  119. package/dist/routes/mobile.d.ts.map +1 -0
  120. package/dist/routes/mobile.js +64 -0
  121. package/dist/routes/mobile.js.map +1 -0
  122. package/dist/routes/network.d.ts +3 -0
  123. package/dist/routes/network.d.ts.map +1 -0
  124. package/dist/routes/network.js +367 -0
  125. package/dist/routes/network.js.map +1 -0
  126. package/dist/routes/repositories.d.ts +18 -0
  127. package/dist/routes/repositories.d.ts.map +1 -0
  128. package/dist/routes/repositories.js +90 -0
  129. package/dist/routes/repositories.js.map +1 -0
  130. package/dist/routes/screen-share.d.ts +17 -0
  131. package/dist/routes/screen-share.d.ts.map +1 -0
  132. package/dist/routes/screen-share.js +92 -0
  133. package/dist/routes/screen-share.js.map +1 -0
  134. package/dist/routes/sessions.d.ts +18 -0
  135. package/dist/routes/sessions.d.ts.map +1 -0
  136. package/dist/routes/sessions.js +169 -0
  137. package/dist/routes/sessions.js.map +1 -0
  138. package/dist/routes/terminals.d.ts +15 -0
  139. package/dist/routes/terminals.d.ts.map +1 -0
  140. package/dist/routes/terminals.js +326 -0
  141. package/dist/routes/terminals.js.map +1 -0
  142. package/dist/routes/threads.d.ts +38 -0
  143. package/dist/routes/threads.d.ts.map +1 -0
  144. package/dist/routes/threads.js +488 -0
  145. package/dist/routes/threads.js.map +1 -0
  146. package/dist/routes/trust.d.ts +9 -0
  147. package/dist/routes/trust.d.ts.map +1 -0
  148. package/dist/routes/trust.js +25 -0
  149. package/dist/routes/trust.js.map +1 -0
  150. package/dist/routes/voice.d.ts +5 -0
  151. package/dist/routes/voice.d.ts.map +1 -0
  152. package/dist/routes/voice.js +37 -0
  153. package/dist/routes/voice.js.map +1 -0
  154. package/dist/routes/workspace.d.ts +13 -0
  155. package/dist/routes/workspace.d.ts.map +1 -0
  156. package/dist/routes/workspace.js +275 -0
  157. package/dist/routes/workspace.js.map +1 -0
  158. package/dist/scheduler/contracts.d.ts +15 -0
  159. package/dist/scheduler/contracts.d.ts.map +1 -0
  160. package/dist/scheduler/contracts.js +2 -0
  161. package/dist/scheduler/contracts.js.map +1 -0
  162. package/dist/scheduler/hooks.d.ts +20 -0
  163. package/dist/scheduler/hooks.d.ts.map +1 -0
  164. package/dist/scheduler/hooks.js +78 -0
  165. package/dist/scheduler/hooks.js.map +1 -0
  166. package/dist/scheduler/service.d.ts +65 -0
  167. package/dist/scheduler/service.d.ts.map +1 -0
  168. package/dist/scheduler/service.js +188 -0
  169. package/dist/scheduler/service.js.map +1 -0
  170. package/dist/security/consent-executor.d.ts +48 -0
  171. package/dist/security/consent-executor.d.ts.map +1 -0
  172. package/dist/security/consent-executor.js +158 -0
  173. package/dist/security/consent-executor.js.map +1 -0
  174. package/dist/security/consent-manager.d.ts +105 -0
  175. package/dist/security/consent-manager.d.ts.map +1 -0
  176. package/dist/security/consent-manager.js +227 -0
  177. package/dist/security/consent-manager.js.map +1 -0
  178. package/dist/security/contracts.d.ts +31 -0
  179. package/dist/security/contracts.d.ts.map +1 -0
  180. package/dist/security/contracts.js +2 -0
  181. package/dist/security/contracts.js.map +1 -0
  182. package/dist/security/http-auth.d.ts +10 -0
  183. package/dist/security/http-auth.d.ts.map +1 -0
  184. package/dist/security/http-auth.js +48 -0
  185. package/dist/security/http-auth.js.map +1 -0
  186. package/dist/security/index.d.ts +10 -0
  187. package/dist/security/index.d.ts.map +1 -0
  188. package/dist/security/index.js +9 -0
  189. package/dist/security/index.js.map +1 -0
  190. package/dist/security/path-guard.d.ts +40 -0
  191. package/dist/security/path-guard.d.ts.map +1 -0
  192. package/dist/security/path-guard.js +125 -0
  193. package/dist/security/path-guard.js.map +1 -0
  194. package/dist/security/sandbox-manager.d.ts +43 -0
  195. package/dist/security/sandbox-manager.d.ts.map +1 -0
  196. package/dist/security/sandbox-manager.js +110 -0
  197. package/dist/security/sandbox-manager.js.map +1 -0
  198. package/dist/security/ssrf-guard.d.ts +11 -0
  199. package/dist/security/ssrf-guard.d.ts.map +1 -0
  200. package/dist/security/ssrf-guard.js +59 -0
  201. package/dist/security/ssrf-guard.js.map +1 -0
  202. package/dist/security/tool-permissions.d.ts +61 -0
  203. package/dist/security/tool-permissions.d.ts.map +1 -0
  204. package/dist/security/tool-permissions.js +105 -0
  205. package/dist/security/tool-permissions.js.map +1 -0
  206. package/dist/security/tool-profiles.d.ts +23 -0
  207. package/dist/security/tool-profiles.d.ts.map +1 -0
  208. package/dist/security/tool-profiles.js +106 -0
  209. package/dist/security/tool-profiles.js.map +1 -0
  210. package/dist/security/trust-engine.d.ts +61 -0
  211. package/dist/security/trust-engine.d.ts.map +1 -0
  212. package/dist/security/trust-engine.js +192 -0
  213. package/dist/security/trust-engine.js.map +1 -0
  214. package/dist/server.d.ts +54 -0
  215. package/dist/server.d.ts.map +1 -0
  216. package/dist/server.js +188 -0
  217. package/dist/server.js.map +1 -0
  218. package/dist/services/audit.d.ts +60 -0
  219. package/dist/services/audit.d.ts.map +1 -0
  220. package/dist/services/audit.js +58 -0
  221. package/dist/services/audit.js.map +1 -0
  222. package/dist/services/device-registry.d.ts +15 -0
  223. package/dist/services/device-registry.d.ts.map +1 -0
  224. package/dist/services/device-registry.js +32 -0
  225. package/dist/services/device-registry.js.map +1 -0
  226. package/dist/services/git.d.ts +168 -0
  227. package/dist/services/git.d.ts.map +1 -0
  228. package/dist/services/git.js +957 -0
  229. package/dist/services/git.js.map +1 -0
  230. package/dist/services/repositories.d.ts +32 -0
  231. package/dist/services/repositories.d.ts.map +1 -0
  232. package/dist/services/repositories.js +70 -0
  233. package/dist/services/repositories.js.map +1 -0
  234. package/dist/services/session-state.d.ts +20 -0
  235. package/dist/services/session-state.d.ts.map +1 -0
  236. package/dist/services/session-state.js +89 -0
  237. package/dist/services/session-state.js.map +1 -0
  238. package/dist/services/sessions.d.ts +68 -0
  239. package/dist/services/sessions.d.ts.map +1 -0
  240. package/dist/services/sessions.js +136 -0
  241. package/dist/services/sessions.js.map +1 -0
  242. package/dist/services/thread-title.d.ts +23 -0
  243. package/dist/services/thread-title.d.ts.map +1 -0
  244. package/dist/services/thread-title.js +141 -0
  245. package/dist/services/thread-title.js.map +1 -0
  246. package/dist/services/threads.d.ts +64 -0
  247. package/dist/services/threads.d.ts.map +1 -0
  248. package/dist/services/threads.js +202 -0
  249. package/dist/services/threads.js.map +1 -0
  250. package/dist/services/users.d.ts +39 -0
  251. package/dist/services/users.d.ts.map +1 -0
  252. package/dist/services/users.js +203 -0
  253. package/dist/services/users.js.map +1 -0
  254. package/dist/sessions/contracts.d.ts +14 -0
  255. package/dist/sessions/contracts.d.ts.map +1 -0
  256. package/dist/sessions/contracts.js +2 -0
  257. package/dist/sessions/contracts.js.map +1 -0
  258. package/dist/surfaces/browser.d.ts +65 -0
  259. package/dist/surfaces/browser.d.ts.map +1 -0
  260. package/dist/surfaces/browser.js +615 -0
  261. package/dist/surfaces/browser.js.map +1 -0
  262. package/dist/surfaces/contracts.d.ts +34 -0
  263. package/dist/surfaces/contracts.d.ts.map +1 -0
  264. package/dist/surfaces/contracts.js +2 -0
  265. package/dist/surfaces/contracts.js.map +1 -0
  266. package/dist/surfaces/filesystem.d.ts +76 -0
  267. package/dist/surfaces/filesystem.d.ts.map +1 -0
  268. package/dist/surfaces/filesystem.js +245 -0
  269. package/dist/surfaces/filesystem.js.map +1 -0
  270. package/dist/surfaces/index.d.ts +6 -0
  271. package/dist/surfaces/index.d.ts.map +1 -0
  272. package/dist/surfaces/index.js +5 -0
  273. package/dist/surfaces/index.js.map +1 -0
  274. package/dist/surfaces/registry.d.ts +24 -0
  275. package/dist/surfaces/registry.d.ts.map +1 -0
  276. package/dist/surfaces/registry.js +59 -0
  277. package/dist/surfaces/registry.js.map +1 -0
  278. package/dist/surfaces/terminal.d.ts +76 -0
  279. package/dist/surfaces/terminal.d.ts.map +1 -0
  280. package/dist/surfaces/terminal.js +271 -0
  281. package/dist/surfaces/terminal.js.map +1 -0
  282. package/dist/tools/agent-loop.d.ts +302 -0
  283. package/dist/tools/agent-loop.d.ts.map +1 -0
  284. package/dist/tools/agent-loop.js +918 -0
  285. package/dist/tools/agent-loop.js.map +1 -0
  286. package/dist/tools/agent-tools.d.ts +39 -0
  287. package/dist/tools/agent-tools.d.ts.map +1 -0
  288. package/dist/tools/agent-tools.js +263 -0
  289. package/dist/tools/agent-tools.js.map +1 -0
  290. package/dist/tools/browser-tools.d.ts +38 -0
  291. package/dist/tools/browser-tools.d.ts.map +1 -0
  292. package/dist/tools/browser-tools.js +725 -0
  293. package/dist/tools/browser-tools.js.map +1 -0
  294. package/dist/tools/chat-modes.d.ts +75 -0
  295. package/dist/tools/chat-modes.d.ts.map +1 -0
  296. package/dist/tools/chat-modes.js +228 -0
  297. package/dist/tools/chat-modes.js.map +1 -0
  298. package/dist/tools/contracts.d.ts +69 -0
  299. package/dist/tools/contracts.d.ts.map +1 -0
  300. package/dist/tools/contracts.js +2 -0
  301. package/dist/tools/contracts.js.map +1 -0
  302. package/dist/tools/core/agent.d.ts +31 -0
  303. package/dist/tools/core/agent.d.ts.map +1 -0
  304. package/dist/tools/core/agent.js +65 -0
  305. package/dist/tools/core/agent.js.map +1 -0
  306. package/dist/tools/core/edit.d.ts +30 -0
  307. package/dist/tools/core/edit.d.ts.map +1 -0
  308. package/dist/tools/core/edit.js +109 -0
  309. package/dist/tools/core/edit.js.map +1 -0
  310. package/dist/tools/core/execute.d.ts +36 -0
  311. package/dist/tools/core/execute.d.ts.map +1 -0
  312. package/dist/tools/core/execute.js +81 -0
  313. package/dist/tools/core/execute.js.map +1 -0
  314. package/dist/tools/core/get-fs.d.ts +32 -0
  315. package/dist/tools/core/get-fs.d.ts.map +1 -0
  316. package/dist/tools/core/get-fs.js +143 -0
  317. package/dist/tools/core/get-fs.js.map +1 -0
  318. package/dist/tools/core/index.d.ts +26 -0
  319. package/dist/tools/core/index.d.ts.map +1 -0
  320. package/dist/tools/core/index.js +26 -0
  321. package/dist/tools/core/index.js.map +1 -0
  322. package/dist/tools/core/jait.d.ts +60 -0
  323. package/dist/tools/core/jait.d.ts.map +1 -0
  324. package/dist/tools/core/jait.js +256 -0
  325. package/dist/tools/core/jait.js.map +1 -0
  326. package/dist/tools/core/read.d.ts +26 -0
  327. package/dist/tools/core/read.d.ts.map +1 -0
  328. package/dist/tools/core/read.js +118 -0
  329. package/dist/tools/core/read.js.map +1 -0
  330. package/dist/tools/core/search.d.ts +34 -0
  331. package/dist/tools/core/search.d.ts.map +1 -0
  332. package/dist/tools/core/search.js +187 -0
  333. package/dist/tools/core/search.js.map +1 -0
  334. package/dist/tools/core/todo.d.ts +38 -0
  335. package/dist/tools/core/todo.d.ts.map +1 -0
  336. package/dist/tools/core/todo.js +116 -0
  337. package/dist/tools/core/todo.js.map +1 -0
  338. package/dist/tools/core/web.d.ts +34 -0
  339. package/dist/tools/core/web.d.ts.map +1 -0
  340. package/dist/tools/core/web.js +120 -0
  341. package/dist/tools/core/web.js.map +1 -0
  342. package/dist/tools/cron-tools.d.ts +7 -0
  343. package/dist/tools/cron-tools.d.ts.map +1 -0
  344. package/dist/tools/cron-tools.js +116 -0
  345. package/dist/tools/cron-tools.js.map +1 -0
  346. package/dist/tools/file-tools.d.ts +32 -0
  347. package/dist/tools/file-tools.d.ts.map +1 -0
  348. package/dist/tools/file-tools.js +178 -0
  349. package/dist/tools/file-tools.js.map +1 -0
  350. package/dist/tools/gateway-tools.d.ts +15 -0
  351. package/dist/tools/gateway-tools.d.ts.map +1 -0
  352. package/dist/tools/gateway-tools.js +39 -0
  353. package/dist/tools/gateway-tools.js.map +1 -0
  354. package/dist/tools/index.d.ts +57 -0
  355. package/dist/tools/index.d.ts.map +1 -0
  356. package/dist/tools/index.js +170 -0
  357. package/dist/tools/index.js.map +1 -0
  358. package/dist/tools/mcp-bridge.d.ts +111 -0
  359. package/dist/tools/mcp-bridge.d.ts.map +1 -0
  360. package/dist/tools/mcp-bridge.js +166 -0
  361. package/dist/tools/mcp-bridge.js.map +1 -0
  362. package/dist/tools/memory-tools.d.ts +19 -0
  363. package/dist/tools/memory-tools.d.ts.map +1 -0
  364. package/dist/tools/memory-tools.js +78 -0
  365. package/dist/tools/memory-tools.js.map +1 -0
  366. package/dist/tools/meta-tools.d.ts +25 -0
  367. package/dist/tools/meta-tools.d.ts.map +1 -0
  368. package/dist/tools/meta-tools.js +125 -0
  369. package/dist/tools/meta-tools.js.map +1 -0
  370. package/dist/tools/network-tools.d.ts +21 -0
  371. package/dist/tools/network-tools.d.ts.map +1 -0
  372. package/dist/tools/network-tools.js +189 -0
  373. package/dist/tools/network-tools.js.map +1 -0
  374. package/dist/tools/os-tools.d.ts +18 -0
  375. package/dist/tools/os-tools.d.ts.map +1 -0
  376. package/dist/tools/os-tools.js +210 -0
  377. package/dist/tools/os-tools.js.map +1 -0
  378. package/dist/tools/prompts/claude-prompt.d.ts +8 -0
  379. package/dist/tools/prompts/claude-prompt.d.ts.map +1 -0
  380. package/dist/tools/prompts/claude-prompt.js +228 -0
  381. package/dist/tools/prompts/claude-prompt.js.map +1 -0
  382. package/dist/tools/prompts/default-openai-prompt.d.ts +8 -0
  383. package/dist/tools/prompts/default-openai-prompt.d.ts.map +1 -0
  384. package/dist/tools/prompts/default-openai-prompt.js +67 -0
  385. package/dist/tools/prompts/default-openai-prompt.js.map +1 -0
  386. package/dist/tools/prompts/default-prompt.d.ts +7 -0
  387. package/dist/tools/prompts/default-prompt.d.ts.map +1 -0
  388. package/dist/tools/prompts/default-prompt.js +50 -0
  389. package/dist/tools/prompts/default-prompt.js.map +1 -0
  390. package/dist/tools/prompts/gemini-prompt.d.ts +8 -0
  391. package/dist/tools/prompts/gemini-prompt.d.ts.map +1 -0
  392. package/dist/tools/prompts/gemini-prompt.js +118 -0
  393. package/dist/tools/prompts/gemini-prompt.js.map +1 -0
  394. package/dist/tools/prompts/gpt5-codex-prompt.d.ts +8 -0
  395. package/dist/tools/prompts/gpt5-codex-prompt.d.ts.map +1 -0
  396. package/dist/tools/prompts/gpt5-codex-prompt.js +72 -0
  397. package/dist/tools/prompts/gpt5-codex-prompt.js.map +1 -0
  398. package/dist/tools/prompts/gpt5-prompt.d.ts +8 -0
  399. package/dist/tools/prompts/gpt5-prompt.d.ts.map +1 -0
  400. package/dist/tools/prompts/gpt5-prompt.js +177 -0
  401. package/dist/tools/prompts/gpt5-prompt.js.map +1 -0
  402. package/dist/tools/prompts/gpt51-prompt.d.ts +8 -0
  403. package/dist/tools/prompts/gpt51-prompt.d.ts.map +1 -0
  404. package/dist/tools/prompts/gpt51-prompt.js +178 -0
  405. package/dist/tools/prompts/gpt51-prompt.js.map +1 -0
  406. package/dist/tools/prompts/gpt52-prompt.d.ts +8 -0
  407. package/dist/tools/prompts/gpt52-prompt.d.ts.map +1 -0
  408. package/dist/tools/prompts/gpt52-prompt.js +198 -0
  409. package/dist/tools/prompts/gpt52-prompt.js.map +1 -0
  410. package/dist/tools/prompts/index.d.ts +22 -0
  411. package/dist/tools/prompts/index.d.ts.map +1 -0
  412. package/dist/tools/prompts/index.js +23 -0
  413. package/dist/tools/prompts/index.js.map +1 -0
  414. package/dist/tools/prompts/prompt-registry.d.ts +44 -0
  415. package/dist/tools/prompts/prompt-registry.d.ts.map +1 -0
  416. package/dist/tools/prompts/prompt-registry.js +60 -0
  417. package/dist/tools/prompts/prompt-registry.js.map +1 -0
  418. package/dist/tools/prompts/shared-sections.d.ts +28 -0
  419. package/dist/tools/prompts/shared-sections.d.ts.map +1 -0
  420. package/dist/tools/prompts/shared-sections.js +111 -0
  421. package/dist/tools/prompts/shared-sections.js.map +1 -0
  422. package/dist/tools/prompts/xai-prompt.d.ts +8 -0
  423. package/dist/tools/prompts/xai-prompt.d.ts.map +1 -0
  424. package/dist/tools/prompts/xai-prompt.js +68 -0
  425. package/dist/tools/prompts/xai-prompt.js.map +1 -0
  426. package/dist/tools/redeploy-tools.d.ts +30 -0
  427. package/dist/tools/redeploy-tools.d.ts.map +1 -0
  428. package/dist/tools/redeploy-tools.js +191 -0
  429. package/dist/tools/redeploy-tools.js.map +1 -0
  430. package/dist/tools/registry.d.ts +51 -0
  431. package/dist/tools/registry.d.ts.map +1 -0
  432. package/dist/tools/registry.js +148 -0
  433. package/dist/tools/registry.js.map +1 -0
  434. package/dist/tools/screen-share-tools.d.ts +31 -0
  435. package/dist/tools/screen-share-tools.d.ts.map +1 -0
  436. package/dist/tools/screen-share-tools.js +183 -0
  437. package/dist/tools/screen-share-tools.js.map +1 -0
  438. package/dist/tools/surface-tools.d.ts +23 -0
  439. package/dist/tools/surface-tools.d.ts.map +1 -0
  440. package/dist/tools/surface-tools.js +99 -0
  441. package/dist/tools/surface-tools.js.map +1 -0
  442. package/dist/tools/terminal-tools.d.ts +37 -0
  443. package/dist/tools/terminal-tools.d.ts.map +1 -0
  444. package/dist/tools/terminal-tools.js +448 -0
  445. package/dist/tools/terminal-tools.js.map +1 -0
  446. package/dist/tools/thread-tools.d.ts +61 -0
  447. package/dist/tools/thread-tools.d.ts.map +1 -0
  448. package/dist/tools/thread-tools.js +484 -0
  449. package/dist/tools/thread-tools.js.map +1 -0
  450. package/dist/tools/token-estimator.d.ts +55 -0
  451. package/dist/tools/token-estimator.d.ts.map +1 -0
  452. package/dist/tools/token-estimator.js +82 -0
  453. package/dist/tools/token-estimator.js.map +1 -0
  454. package/dist/tools/tool-names.d.ts +64 -0
  455. package/dist/tools/tool-names.d.ts.map +1 -0
  456. package/dist/tools/tool-names.js +76 -0
  457. package/dist/tools/tool-names.js.map +1 -0
  458. package/dist/tools/validate.d.ts +27 -0
  459. package/dist/tools/validate.d.ts.map +1 -0
  460. package/dist/tools/validate.js +99 -0
  461. package/dist/tools/validate.js.map +1 -0
  462. package/dist/tools/voice-tools.d.ts +8 -0
  463. package/dist/tools/voice-tools.d.ts.map +1 -0
  464. package/dist/tools/voice-tools.js +32 -0
  465. package/dist/tools/voice-tools.js.map +1 -0
  466. package/dist/voice/service.d.ts +42 -0
  467. package/dist/voice/service.d.ts.map +1 -0
  468. package/dist/voice/service.js +75 -0
  469. package/dist/voice/service.js.map +1 -0
  470. package/dist/ws.d.ts +90 -0
  471. package/dist/ws.d.ts.map +1 -0
  472. package/dist/ws.js +562 -0
  473. package/dist/ws.js.map +1 -0
  474. package/package.json +61 -0
@@ -0,0 +1,918 @@
1
+ /**
2
+ * Agent Loop — reusable, streamable tool-calling loop.
3
+ *
4
+ * Extracted from chat.ts and enhanced with:
5
+ * - Input validation (catches bad LLM args immediately)
6
+ * - Parallel tool execution (independent calls run concurrently)
7
+ * - Retry for individual failed tool calls
8
+ * - Steering (inject guidance mid-loop)
9
+ * - Tool call queueing with priority
10
+ *
11
+ * Both the main chat route and the agent.spawn sub-agent tool use this.
12
+ */
13
+ import { validateToolInput } from "./validate.js";
14
+ import { ASK_MODE_TOOLS, MUTATING_TOOLS } from "./chat-modes.js";
15
+ import { getReminderInstructions } from "./prompts/index.js";
16
+ import { computeContextUsage, estimateTokens } from "./token-estimator.js";
17
+ /** Format an LLM HTTP error into a user-friendly message, similar to VS Code Copilot. */
18
+ function formatLLMError(status, responseText) {
19
+ let parsed;
20
+ try {
21
+ parsed = JSON.parse(responseText);
22
+ }
23
+ catch { /* not JSON */ }
24
+ const serverMsg = parsed?.error?.message;
25
+ const code = parsed?.error?.code;
26
+ switch (status) {
27
+ case 401:
28
+ return "Your API key is invalid or expired. Please check your settings.";
29
+ case 403:
30
+ return "Access denied by the model provider. Please check your API key permissions.";
31
+ case 429:
32
+ if (code === "insufficient_quota" || serverMsg?.includes("quota"))
33
+ return "You've exceeded your API quota. Please check your plan and billing details.";
34
+ return `Rate limited by the model provider. Please wait a moment and try again.${serverMsg ? `\n${serverMsg}` : ""}`;
35
+ case 500:
36
+ case 502:
37
+ case 503:
38
+ return `The model provider is experiencing issues (${status}). Please try again later.`;
39
+ default:
40
+ return serverMsg
41
+ ? `Request failed (${status}): ${serverMsg}`
42
+ : `Request failed with status ${status}. Please try again.`;
43
+ }
44
+ }
45
+ /** Priority levels for queued tool calls */
46
+ export var ToolCallPriority;
47
+ (function (ToolCallPriority) {
48
+ /** Run before anything else (e.g. abort-checks, validation) */
49
+ ToolCallPriority[ToolCallPriority["Critical"] = 0] = "Critical";
50
+ /** Normal tool calls from the LLM */
51
+ ToolCallPriority[ToolCallPriority["Normal"] = 1] = "Normal";
52
+ /** Deferred / low-priority background work */
53
+ ToolCallPriority[ToolCallPriority["Low"] = 2] = "Low";
54
+ })(ToolCallPriority || (ToolCallPriority = {}));
55
+ // ── Steering controller ──────────────────────────────────────────────
56
+ /**
57
+ * Steering lets the user (or system) inject guidance into the agent
58
+ * loop while it's running. The steered message gets appended to the
59
+ * conversation as a system message before the next LLM call.
60
+ */
61
+ export class SteeringController {
62
+ queue = [];
63
+ /** Inject a steering message into the loop */
64
+ steer(message) {
65
+ this.queue.push(message);
66
+ }
67
+ /** Drain all pending steering messages (called by the loop) */
68
+ drain() {
69
+ const msgs = this.queue.splice(0);
70
+ return msgs;
71
+ }
72
+ get hasPending() {
73
+ return this.queue.length > 0;
74
+ }
75
+ }
76
+ // ── Tool call queue ──────────────────────────────────────────────────
77
+ /**
78
+ * Priority queue for tool calls. Sorts by priority (lower = first),
79
+ * then partitions into parallel-safe batches.
80
+ */
81
+ export class ToolCallQueue {
82
+ items = [];
83
+ /** Enqueue a tool call with optional priority and parallelism hint */
84
+ enqueue(toolCall, priority = ToolCallPriority.Normal, parallelSafe = false) {
85
+ this.items.push({ toolCall, priority, parallelSafe });
86
+ // Keep sorted by priority
87
+ this.items.sort((a, b) => a.priority - b.priority);
88
+ }
89
+ /** Enqueue multiple tool calls at the same priority */
90
+ enqueueAll(toolCalls, priority = ToolCallPriority.Normal, parallelSafe = false) {
91
+ for (const tc of toolCalls) {
92
+ this.enqueue(tc, priority, parallelSafe);
93
+ }
94
+ }
95
+ /**
96
+ * Dequeue the next batch. If parallel execution is enabled, returns
97
+ * all contiguous parallel-safe items at the same priority level.
98
+ * Otherwise returns one at a time.
99
+ */
100
+ dequeueBatch(allowParallel) {
101
+ if (this.items.length === 0)
102
+ return [];
103
+ if (!allowParallel) {
104
+ return [this.items.shift()];
105
+ }
106
+ const first = this.items[0];
107
+ if (!first.parallelSafe) {
108
+ return [this.items.shift()];
109
+ }
110
+ // Grab all contiguous items at the same priority that are parallel-safe
111
+ const batch = [];
112
+ while (this.items.length > 0 &&
113
+ this.items[0].priority === first.priority &&
114
+ this.items[0].parallelSafe) {
115
+ batch.push(this.items.shift());
116
+ }
117
+ return batch;
118
+ }
119
+ get length() {
120
+ return this.items.length;
121
+ }
122
+ get isEmpty() {
123
+ return this.items.length === 0;
124
+ }
125
+ }
126
+ // ── Tool name conversion ─────────────────────────────────────────────
127
+ /** OpenAI requires function names to match ^[a-zA-Z0-9_-]+$ — no dots */
128
+ export function toOpenAIName(name) {
129
+ return name.replace(/\./g, "_");
130
+ }
131
+ export function fromOpenAIName(name) {
132
+ const idx = name.indexOf("_");
133
+ if (idx === -1)
134
+ return name;
135
+ return name.slice(0, idx) + "." + name.slice(idx + 1);
136
+ }
137
+ // ── Tools that are safe to run in parallel ───────────────────────────
138
+ /**
139
+ * Read-only / side-effect-free tools that can safely execute concurrently.
140
+ * Tools NOT in this set run sequentially to preserve ordering guarantees.
141
+ */
142
+ const PARALLEL_SAFE_TOOLS = new Set([
143
+ "file.read",
144
+ "file.list",
145
+ "file.stat",
146
+ "os.query",
147
+ "memory.search",
148
+ "web.fetch",
149
+ "web.search",
150
+ "gateway.status",
151
+ "browser.snapshot",
152
+ ]);
153
+ function isParallelSafe(toolName) {
154
+ return PARALLEL_SAFE_TOOLS.has(toolName);
155
+ }
156
+ // ── Serialize messages for OpenAI API ────────────────────────────────
157
+ export function serializeMessages(messages) {
158
+ return messages.map((m) => {
159
+ const msg = { role: m.role, content: m.content };
160
+ if (m.tool_calls)
161
+ msg.tool_calls = m.tool_calls;
162
+ if (m.tool_call_id)
163
+ msg.tool_call_id = m.tool_call_id;
164
+ if (m.name)
165
+ msg.name = m.name;
166
+ return msg;
167
+ });
168
+ }
169
+ // ── Build OpenAI tool schemas ────────────────────────────────────────
170
+ export function buildToolSchemas(registry, allowedTools) {
171
+ let tools = registry.list();
172
+ if (allowedTools) {
173
+ tools = tools.filter((t) => allowedTools.has(t.name));
174
+ }
175
+ return tools.map((t) => ({
176
+ type: "function",
177
+ function: {
178
+ name: toOpenAIName(t.name),
179
+ description: t.description,
180
+ parameters: t.parameters,
181
+ },
182
+ }));
183
+ }
184
+ /**
185
+ * Build schemas respecting tiers and user disabled tools.
186
+ *
187
+ * Only "core" and "standard" (non-disabled) tools are included in the
188
+ * initial payload. External / MCP tools must be discovered via tools.search.
189
+ */
190
+ export function buildTieredToolSchemas(registry, disabledTools) {
191
+ const tools = registry.listForLLM(disabledTools);
192
+ return tools.map((t) => ({
193
+ type: "function",
194
+ function: {
195
+ name: toOpenAIName(t.name),
196
+ description: t.description,
197
+ parameters: t.parameters,
198
+ },
199
+ }));
200
+ }
201
+ /**
202
+ * Convert individual tool definitions into OpenAI schemas.
203
+ * Used to dynamically inject schemas discovered via tools.search.
204
+ */
205
+ export function toolDefsToSchemas(defs) {
206
+ return defs.map((t) => ({
207
+ type: "function",
208
+ function: {
209
+ name: toOpenAIName(t.name),
210
+ description: t.description,
211
+ parameters: t.parameters,
212
+ },
213
+ }));
214
+ }
215
+ export async function parseOpenAIStream(reader, onEvent) {
216
+ const decoder = new TextDecoder();
217
+ let buffer = "";
218
+ let contentText = "";
219
+ let finishReason = null;
220
+ const toolCallMap = new Map();
221
+ while (true) {
222
+ const { done, value } = await reader.read();
223
+ if (done)
224
+ break;
225
+ buffer += decoder.decode(value, { stream: true });
226
+ const lines = buffer.split("\n");
227
+ buffer = lines.pop() || "";
228
+ for (const line of lines) {
229
+ const trimmed = line.trim();
230
+ if (!trimmed || !trimmed.startsWith("data: "))
231
+ continue;
232
+ const payload = trimmed.slice(6);
233
+ if (payload === "[DONE]")
234
+ continue;
235
+ try {
236
+ const chunk = JSON.parse(payload);
237
+ const choice = chunk.choices?.[0];
238
+ if (!choice)
239
+ continue;
240
+ const delta = choice.delta;
241
+ if (!delta)
242
+ continue;
243
+ // Text content
244
+ if (delta.content) {
245
+ contentText += delta.content;
246
+ onEvent?.({ type: "token", content: delta.content });
247
+ }
248
+ // Tool calls (streamed incrementally)
249
+ if (delta.tool_calls) {
250
+ for (const tc of delta.tool_calls) {
251
+ const idx = tc.index ?? 0;
252
+ const isNew = !toolCallMap.has(idx);
253
+ if (isNew) {
254
+ toolCallMap.set(idx, {
255
+ id: tc.id ?? "",
256
+ type: "function",
257
+ function: { name: tc.function?.name ?? "", arguments: "" },
258
+ });
259
+ }
260
+ const existing = toolCallMap.get(idx);
261
+ if (tc.id)
262
+ existing.id = tc.id;
263
+ if (!isNew && tc.function?.name)
264
+ existing.function.name += tc.function.name;
265
+ if (tc.function?.arguments)
266
+ existing.function.arguments += tc.function.arguments;
267
+ const callId = existing.id || `pending-${idx}`;
268
+ onEvent?.({
269
+ type: "tool_call_delta",
270
+ call_id: callId,
271
+ index: idx,
272
+ name_delta: tc.function?.name || undefined,
273
+ args_delta: tc.function?.arguments || undefined,
274
+ });
275
+ }
276
+ }
277
+ if (choice.finish_reason) {
278
+ finishReason = choice.finish_reason;
279
+ }
280
+ }
281
+ catch {
282
+ // partial JSON chunk — ignore
283
+ }
284
+ }
285
+ }
286
+ const toolCalls = [...toolCallMap.entries()]
287
+ .sort(([a], [b]) => a - b)
288
+ .map(([, tc]) => tc);
289
+ return { contentText, toolCalls, finishReason };
290
+ }
291
+ async function executeOneToolCall(opts) {
292
+ const { tc, sessionId, auth, signal, toolRegistry, maxRetries, onEvent, executeTool } = opts;
293
+ const startedAt = Date.now();
294
+ let args;
295
+ try {
296
+ args = JSON.parse(tc.function.arguments);
297
+ }
298
+ catch {
299
+ args = {};
300
+ }
301
+ const internalName = fromOpenAIName(tc.function.name);
302
+ // ── Input validation (fast reject bad LLM args) ──
303
+ if (toolRegistry) {
304
+ const toolDef = toolRegistry.get(internalName);
305
+ if (toolDef) {
306
+ const validation = validateToolInput(toolDef.parameters, args);
307
+ if (!validation.valid) {
308
+ onEvent?.({
309
+ type: "tool_validation_error",
310
+ call_id: tc.id,
311
+ tool: internalName,
312
+ errors: validation.errors,
313
+ });
314
+ // Return the validation error as a tool result so the LLM can self-correct
315
+ const errorMsg = `INPUT VALIDATION ERROR: ${validation.errors.join("; ")}`;
316
+ const result = { ok: false, message: errorMsg };
317
+ return {
318
+ result,
319
+ executed: {
320
+ callId: tc.id,
321
+ tool: internalName,
322
+ args,
323
+ ok: false,
324
+ message: errorMsg,
325
+ startedAt,
326
+ completedAt: Date.now(),
327
+ retryCount: 0,
328
+ },
329
+ historyEntry: {
330
+ role: "tool",
331
+ content: JSON.stringify({ ok: false, message: errorMsg }),
332
+ tool_call_id: tc.id,
333
+ name: tc.function.name,
334
+ },
335
+ };
336
+ }
337
+ }
338
+ }
339
+ // ── Execute with retries ──
340
+ onEvent?.({ type: "tool_start", tool: internalName, args, call_id: tc.id });
341
+ let result = { ok: false, message: "Not executed" };
342
+ let retryCount = 0;
343
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
344
+ if (signal?.aborted) {
345
+ result = { ok: false, message: "Cancelled" };
346
+ break;
347
+ }
348
+ if (attempt > 0) {
349
+ onEvent?.({ type: "tool_retry", call_id: tc.id, attempt, maxAttempts: maxRetries });
350
+ // Exponential backoff: 500ms, 1s, 2s
351
+ await new Promise((r) => setTimeout(r, Math.min(500 * 2 ** (attempt - 1), 4000)));
352
+ }
353
+ result = await executeTool(internalName, args, sessionId, auth, (chunk) => {
354
+ onEvent?.({ type: "tool_output", call_id: tc.id, content: chunk });
355
+ }, signal);
356
+ if (result.ok)
357
+ break;
358
+ // Only retry transient failures, not logical errors
359
+ if (!isTransientFailure(result.message))
360
+ break;
361
+ retryCount = attempt + 1;
362
+ }
363
+ const completedAt = Date.now();
364
+ onEvent?.({
365
+ type: "tool_result",
366
+ call_id: tc.id,
367
+ tool: internalName,
368
+ ok: result.ok,
369
+ message: result.message,
370
+ data: result.data,
371
+ });
372
+ // If this was a todo tool call, emit todo_list event for the UI
373
+ if (internalName === "todo" && result.ok && result.data) {
374
+ const items = result.data.items;
375
+ if (Array.isArray(items)) {
376
+ onEvent?.({ type: "todo_list", items });
377
+ }
378
+ }
379
+ // If this was a file-modifying tool, emit file_changed event for cross-client sync
380
+ if (result.ok && (internalName === "file.write" || internalName === "file.patch" || internalName === "edit")) {
381
+ const filePath = String(args?.path ?? "");
382
+ if (filePath) {
383
+ onEvent?.({
384
+ type: "file_changed",
385
+ path: filePath,
386
+ name: filePath.split("/").pop() ?? filePath,
387
+ });
388
+ }
389
+ }
390
+ return {
391
+ result,
392
+ executed: {
393
+ callId: tc.id,
394
+ tool: internalName,
395
+ args,
396
+ ok: result.ok,
397
+ message: result.message,
398
+ data: result.data,
399
+ startedAt,
400
+ completedAt,
401
+ retryCount,
402
+ },
403
+ historyEntry: {
404
+ role: "tool",
405
+ content: JSON.stringify({ ok: result.ok, message: result.message, data: result.data }),
406
+ tool_call_id: tc.id,
407
+ name: tc.function.name,
408
+ },
409
+ };
410
+ }
411
+ /** Heuristic: is this error transient and worth retrying? */
412
+ function isTransientFailure(message) {
413
+ const lower = message.toLowerCase();
414
+ return (lower.includes("timeout") ||
415
+ lower.includes("econnrefused") ||
416
+ lower.includes("econnreset") ||
417
+ lower.includes("socket hang up") ||
418
+ lower.includes("rate limit") ||
419
+ lower.includes("429") ||
420
+ lower.includes("503") ||
421
+ lower.includes("502") ||
422
+ lower.includes("network") ||
423
+ lower.includes("unavailable"));
424
+ }
425
+ // ── Main agent loop ──────────────────────────────────────────────────
426
+ const DEFAULT_MAX_ROUNDS = 15;
427
+ const DEFAULT_MAX_RETRIES = 2;
428
+ /**
429
+ * Run the agentic tool-calling loop.
430
+ *
431
+ * This is the core reusable loop used by both the main chat route and
432
+ * the agent.spawn sub-agent tool. It streams LLM responses, executes
433
+ * tool calls (with validation, retry, parallel batching, and steering),
434
+ * and returns the accumulated result.
435
+ */
436
+ // ── Context pruning ──────────────────────────────────────────────────
437
+ /** Target ratio after pruning — leave headroom for the next LLM response */
438
+ const PRUNE_TARGET_RATIO = 0.65;
439
+ /**
440
+ * Prune oldest conversation turns to bring context usage below the target.
441
+ *
442
+ * Strategy (similar to Copilot):
443
+ * 1. Never remove the system prompt (index 0) or the last user message.
444
+ * 2. Remove oldest user/assistant/tool turn groups first.
445
+ * 3. Insert a `[conversation-summary]` placeholder so the model knows
446
+ * context was trimmed.
447
+ *
448
+ * Mutates `history` in place. Returns true if anything was pruned.
449
+ */
450
+ function pruneHistory(history, contextWindow, toolSchemas) {
451
+ const usage = computeContextUsage(history, toolSchemas, contextWindow);
452
+ const targetTokens = Math.floor(contextWindow * PRUNE_TARGET_RATIO);
453
+ if (usage.total <= targetTokens)
454
+ return false;
455
+ let tokensToFree = usage.total - targetTokens;
456
+ let pruned = false;
457
+ // Find removable range: skip system messages at the start and keep
458
+ // the last user message + everything after it.
459
+ let firstRemovable = 0;
460
+ while (firstRemovable < history.length && history[firstRemovable].role === "system") {
461
+ firstRemovable++;
462
+ }
463
+ // Find last user message index
464
+ let lastUserIdx = history.length - 1;
465
+ while (lastUserIdx >= 0 && history[lastUserIdx].role !== "user") {
466
+ lastUserIdx--;
467
+ }
468
+ // Keep the last user message and everything after it
469
+ const safeEnd = Math.max(lastUserIdx, firstRemovable);
470
+ // Remove messages from firstRemovable forward until we've freed enough
471
+ const removedIndices = [];
472
+ for (let i = firstRemovable; i < safeEnd && tokensToFree > 0; i++) {
473
+ const msg = history[i];
474
+ const cost = estimateTokens(msg.content) + 4; // rough per-message estimate
475
+ if (msg.role === "tool" && msg.tool_calls) {
476
+ // tool_calls are heavier
477
+ try {
478
+ tokensToFree -= estimateTokens(JSON.stringify(msg.tool_calls));
479
+ }
480
+ catch { /* */ }
481
+ }
482
+ tokensToFree -= cost;
483
+ removedIndices.push(i);
484
+ pruned = true;
485
+ }
486
+ if (removedIndices.length > 0) {
487
+ // Remove in reverse order to keep indices stable
488
+ for (let i = removedIndices.length - 1; i >= 0; i--) {
489
+ history.splice(removedIndices[i], 1);
490
+ }
491
+ // Insert a summary placeholder after the system messages
492
+ const insertAt = firstRemovable;
493
+ history.splice(insertAt, 0, {
494
+ role: "system",
495
+ content: `[conversation-summary] ${removedIndices.length} earlier messages were removed to fit the context window. The conversation continues from the remaining messages below.`,
496
+ });
497
+ }
498
+ return pruned;
499
+ }
500
+ export async function runAgentLoop(options, executeTool, steering) {
501
+ const { llm, history, toolSchemas: initialToolSchemas, hasTools, sessionId, auth, abort, maxRounds = DEFAULT_MAX_ROUNDS, maxRetries = DEFAULT_MAX_RETRIES, parallel = true, toolRegistry, disabledTools, mode = "agent", onEvent, onPersist, log = console, } = options;
502
+ let fullContent = "";
503
+ const executedToolCalls = [];
504
+ const segments = [];
505
+ const queue = new ToolCallQueue();
506
+ // ── Plan mode state ──
507
+ const plannedActions = [];
508
+ const planId = mode === "plan" ? `plan-${Date.now()}-${Math.random().toString(36).slice(2, 8)}` : "";
509
+ // ── Mode-aware schema filtering ──
510
+ // Ask mode: only read-only tools. Plan/Agent mode: full set.
511
+ let modeFilteredSchemas = initialToolSchemas;
512
+ if (mode === "ask") {
513
+ modeFilteredSchemas = initialToolSchemas.filter((s) => ASK_MODE_TOOLS.has(fromOpenAIName(s.function.name)));
514
+ onEvent?.({ type: "mode_notice", mode: "ask", message: "Running in Ask mode — read-only tools only." });
515
+ }
516
+ else if (mode === "plan") {
517
+ onEvent?.({ type: "mode_notice", mode: "plan", message: "Running in Plan mode — mutating actions will be proposed, not executed." });
518
+ }
519
+ // Dynamic schema set — starts with filtered schemas, grows when tools.search
520
+ // discovers additional tools (e.g. external/MCP tools).
521
+ const activeSchemas = [...modeFilteredSchemas];
522
+ const activeSchemaNames = new Set(activeSchemas.map((s) => s.function.name));
523
+ for (let round = 0; round < maxRounds; round++) {
524
+ // ── Check abort ──
525
+ if (abort.signal.aborted) {
526
+ log.info(`Agent loop cancelled for session ${sessionId} — stopping before round ${round}`);
527
+ return { content: fullContent, executedToolCalls, segments, rounds: round, aborted: true, hitMaxRounds: false };
528
+ }
529
+ // ── Apply steering messages ──
530
+ if (steering) {
531
+ const steered = steering.drain();
532
+ for (const msg of steered) {
533
+ history.push({ role: "system", content: `[STEERING] ${msg}` });
534
+ onEvent?.({ type: "steering", message: msg });
535
+ log.info(`Steering injected for session ${sessionId}: ${msg.slice(0, 100)}`);
536
+ }
537
+ }
538
+ // ── Periodic reminder (every 4 rounds) to reinforce good agent behaviour ──
539
+ if (round > 0 && round % 4 === 0 && mode !== "ask") {
540
+ const modelEndpoint = { model: llm.openaiModel, baseUrl: "" };
541
+ const reminder = getReminderInstructions(mode, modelEndpoint);
542
+ if (reminder) {
543
+ history.push({ role: "system", content: reminder });
544
+ }
545
+ }
546
+ // ── Context budget tracking & pruning ──────────────────────────────
547
+ const contextWindow = llm.contextWindow;
548
+ if (contextWindow > 0) {
549
+ let usage = computeContextUsage(history, activeSchemas, contextWindow);
550
+ onEvent?.({ type: "context_usage", ...usage });
551
+ // If context usage ≥ 85%, prune oldest conversation turns
552
+ if (usage.ratio >= 0.85) {
553
+ const pruned = pruneHistory(history, contextWindow, activeSchemas);
554
+ if (pruned) {
555
+ usage = computeContextUsage(history, activeSchemas, contextWindow);
556
+ onEvent?.({ type: "context_usage", ...usage, pruned: true });
557
+ log.info(`Context pruned: ${usage.total}/${contextWindow} tokens (${(usage.ratio * 100).toFixed(0)}%)`);
558
+ }
559
+ }
560
+ }
561
+ // ── LLM request ──
562
+ const reqBody = {
563
+ model: llm.openaiModel,
564
+ messages: serializeMessages(history),
565
+ stream: true,
566
+ };
567
+ if (hasTools) {
568
+ reqBody.tools = activeSchemas;
569
+ reqBody.tool_choice = "auto";
570
+ }
571
+ let contentText = "";
572
+ let toolCalls = [];
573
+ let finishReason = null;
574
+ try {
575
+ const response = await fetch(`${llm.openaiBaseUrl}/chat/completions`, {
576
+ method: "POST",
577
+ headers: {
578
+ "Content-Type": "application/json",
579
+ Authorization: `Bearer ${llm.openaiApiKey}`,
580
+ },
581
+ body: JSON.stringify(reqBody),
582
+ signal: abort.signal,
583
+ });
584
+ if (!response.ok) {
585
+ const errText = await response.text();
586
+ log.error(`LLM error ${response.status}: ${errText}`);
587
+ const friendlyMessage = formatLLMError(response.status, errText);
588
+ onEvent?.({ type: "error", message: friendlyMessage });
589
+ return { content: fullContent, executedToolCalls, segments, rounds: round + 1, aborted: false, hitMaxRounds: false };
590
+ }
591
+ const reader = response.body?.getReader();
592
+ if (!reader) {
593
+ onEvent?.({ type: "error", message: "No response body from LLM" });
594
+ return { content: fullContent, executedToolCalls, segments, rounds: round + 1, aborted: false, hitMaxRounds: false };
595
+ }
596
+ const parsed = await parseOpenAIStream(reader, onEvent);
597
+ contentText = parsed.contentText;
598
+ toolCalls = parsed.toolCalls;
599
+ finishReason = parsed.finishReason;
600
+ }
601
+ catch (fetchErr) {
602
+ if (abort.signal.aborted) {
603
+ log.info(`Agent loop cancelled during LLM streaming (round ${round})`);
604
+ return { content: fullContent, executedToolCalls, segments, rounds: round + 1, aborted: true, hitMaxRounds: false };
605
+ }
606
+ throw fetchErr;
607
+ }
608
+ fullContent += contentText;
609
+ // ── Track segments for interleaved rendering ──
610
+ if (contentText) {
611
+ const last = segments[segments.length - 1];
612
+ if (last?.type === "text") {
613
+ segments[segments.length - 1] = { type: "text", content: last.content + contentText };
614
+ }
615
+ else {
616
+ segments.push({ type: "text", content: contentText });
617
+ }
618
+ }
619
+ // ── Model returned tool calls → queue & execute ──
620
+ if (toolCalls.length > 0) {
621
+ if (finishReason && finishReason !== "tool_calls") {
622
+ log.warn(`LLM returned ${toolCalls.length} tool call(s) with finish_reason="${finishReason}" — executing anyway`);
623
+ }
624
+ // Push assistant message with tool_calls to history
625
+ history.push({
626
+ role: "assistant",
627
+ content: contentText || "",
628
+ tool_calls: toolCalls,
629
+ });
630
+ // Enqueue all tool calls with appropriate parallelism hints
631
+ for (const tc of toolCalls) {
632
+ const internalName = fromOpenAIName(tc.function.name);
633
+ queue.enqueue(tc, ToolCallPriority.Normal, isParallelSafe(internalName));
634
+ }
635
+ // Track tool calls as a segment group for interleaved rendering
636
+ const callIds = toolCalls.map(tc => tc.id);
637
+ const lastSeg = segments[segments.length - 1];
638
+ if (lastSeg?.type === "toolGroup") {
639
+ // Extend existing group (shouldn't normally happen, but defensive)
640
+ const merged = new Set([...lastSeg.callIds, ...callIds]);
641
+ segments[segments.length - 1] = { type: "toolGroup", callIds: [...merged] };
642
+ }
643
+ else {
644
+ segments.push({ type: "toolGroup", callIds });
645
+ }
646
+ // ── Plan-mode & Ask-mode interception ──
647
+ // In plan mode, mutating tools are captured as plan actions.
648
+ // In ask mode, any tool that slipped through is blocked.
649
+ if (mode === "plan" || mode === "ask") {
650
+ const intercepted = [];
651
+ const passthrough = [];
652
+ while (!queue.isEmpty) {
653
+ const batch = queue.dequeueBatch(false);
654
+ for (const item of batch) {
655
+ const name = fromOpenAIName(item.toolCall.function.name);
656
+ const isMutating = MUTATING_TOOLS.has(name);
657
+ if (mode === "ask" && !ASK_MODE_TOOLS.has(name)) {
658
+ // Ask mode: block non-read tools, return error to LLM
659
+ intercepted.push(item);
660
+ }
661
+ else if (mode === "plan" && isMutating) {
662
+ // Plan mode: capture mutating tools as planned actions
663
+ intercepted.push(item);
664
+ }
665
+ else {
666
+ passthrough.push(item);
667
+ }
668
+ }
669
+ }
670
+ // Handle intercepted tool calls
671
+ for (const item of intercepted) {
672
+ const tc = item.toolCall;
673
+ const name = fromOpenAIName(tc.function.name);
674
+ let args;
675
+ try {
676
+ args = JSON.parse(tc.function.arguments);
677
+ }
678
+ catch {
679
+ args = {};
680
+ }
681
+ if (mode === "ask") {
682
+ // Return an error to the LLM
683
+ const msg = `Tool "${name}" is not available in Ask mode. Only read-only tools can be used. Suggest the user switch to Agent or Plan mode for this action.`;
684
+ history.push({
685
+ role: "tool",
686
+ content: JSON.stringify({ ok: false, message: msg }),
687
+ tool_call_id: tc.id,
688
+ name: tc.function.name,
689
+ });
690
+ executedToolCalls.push({
691
+ callId: tc.id,
692
+ tool: name,
693
+ args,
694
+ ok: false,
695
+ message: msg,
696
+ startedAt: Date.now(),
697
+ completedAt: Date.now(),
698
+ });
699
+ }
700
+ else {
701
+ // Plan mode: capture as planned action
702
+ const action = {
703
+ id: tc.id,
704
+ tool: name,
705
+ args,
706
+ description: `${name}(${JSON.stringify(args).slice(0, 200)})`,
707
+ order: plannedActions.length,
708
+ status: "pending",
709
+ };
710
+ plannedActions.push(action);
711
+ onEvent?.({ type: "plan_action", action });
712
+ // Tell the LLM the action was captured
713
+ const msg = `[PLANNED] Action "${name}" has been added to the plan (step ${action.order + 1}). It will execute after user approval. Continue analyzing and propose more actions if needed.`;
714
+ history.push({
715
+ role: "tool",
716
+ content: JSON.stringify({ ok: true, message: msg }),
717
+ tool_call_id: tc.id,
718
+ name: tc.function.name,
719
+ });
720
+ executedToolCalls.push({
721
+ callId: tc.id,
722
+ tool: name,
723
+ args,
724
+ ok: true,
725
+ message: msg,
726
+ startedAt: Date.now(),
727
+ completedAt: Date.now(),
728
+ });
729
+ }
730
+ }
731
+ // Re-enqueue passthrough items
732
+ for (const item of passthrough) {
733
+ queue.enqueue(item.toolCall, item.priority, item.parallelSafe);
734
+ }
735
+ }
736
+ // ── Process the queue ──
737
+ while (!queue.isEmpty) {
738
+ if (abort.signal.aborted) {
739
+ // Mark remaining queued calls as cancelled
740
+ while (!queue.isEmpty) {
741
+ const batch = queue.dequeueBatch(false);
742
+ for (const item of batch) {
743
+ let rArgs;
744
+ try {
745
+ rArgs = JSON.parse(item.toolCall.function.arguments);
746
+ }
747
+ catch {
748
+ rArgs = {};
749
+ }
750
+ executedToolCalls.push({
751
+ callId: item.toolCall.id,
752
+ tool: fromOpenAIName(item.toolCall.function.name),
753
+ args: rArgs,
754
+ ok: false,
755
+ message: "Cancelled",
756
+ startedAt: Date.now(),
757
+ completedAt: Date.now(),
758
+ });
759
+ }
760
+ }
761
+ return { content: fullContent, executedToolCalls, segments, rounds: round + 1, aborted: true, hitMaxRounds: false };
762
+ }
763
+ const batch = queue.dequeueBatch(parallel);
764
+ if (batch.length === 1) {
765
+ // Sequential execution (single item or non-parallel-safe)
766
+ const item = batch[0];
767
+ const { executed, historyEntry } = await executeOneToolCall({
768
+ tc: item.toolCall,
769
+ sessionId,
770
+ auth,
771
+ signal: abort.signal,
772
+ toolRegistry,
773
+ maxRetries,
774
+ onEvent,
775
+ executeTool,
776
+ });
777
+ executedToolCalls.push(executed);
778
+ history.push(historyEntry);
779
+ }
780
+ else {
781
+ // ── Parallel execution ──
782
+ log.info(`Executing ${batch.length} tool calls in parallel`);
783
+ const results = await Promise.all(batch.map((item) => executeOneToolCall({
784
+ tc: item.toolCall,
785
+ sessionId,
786
+ auth,
787
+ signal: abort.signal,
788
+ toolRegistry,
789
+ maxRetries,
790
+ onEvent,
791
+ executeTool,
792
+ })));
793
+ for (const { executed, historyEntry } of results) {
794
+ executedToolCalls.push(executed);
795
+ history.push(historyEntry);
796
+ }
797
+ }
798
+ }
799
+ // ── Dynamic schema expansion ──
800
+ // If any tool call was tools.search/tools.list, check if the result
801
+ // contains new tool schemas that should be injected for subsequent rounds.
802
+ for (const exec of executedToolCalls) {
803
+ if (exec.tool === "tools.search" && exec.ok && exec.data) {
804
+ const data = exec.data;
805
+ if (Array.isArray(data.matches)) {
806
+ for (const match of data.matches) {
807
+ if (match.name && match.description && match.parameters) {
808
+ const oaiName = toOpenAIName(match.name);
809
+ // In ask mode, only add read-only tools
810
+ if (mode === "ask" && !ASK_MODE_TOOLS.has(match.name))
811
+ continue;
812
+ if (!activeSchemaNames.has(oaiName) && !disabledTools?.has(match.name)) {
813
+ activeSchemas.push({
814
+ type: "function",
815
+ function: {
816
+ name: oaiName,
817
+ description: match.description,
818
+ parameters: match.parameters,
819
+ },
820
+ });
821
+ activeSchemaNames.add(oaiName);
822
+ log.info(`Dynamic schema expansion: added ${match.name}`);
823
+ }
824
+ }
825
+ }
826
+ }
827
+ }
828
+ }
829
+ // Loop continues — LLM sees results and decides next
830
+ continue;
831
+ }
832
+ // ── Normal text response — done ──
833
+ if (contentText) {
834
+ history.push({ role: "assistant", content: contentText });
835
+ const tcJson = executedToolCalls.length > 0 ? JSON.stringify(executedToolCalls) : undefined;
836
+ const segJson = segments.length > 0 ? JSON.stringify(segments) : undefined;
837
+ onPersist?.(sessionId, "assistant", contentText, tcJson, segJson);
838
+ }
839
+ // ── Emit plan completion in plan mode ──
840
+ if (mode === "plan" && plannedActions.length > 0) {
841
+ onEvent?.({
842
+ type: "plan_complete",
843
+ planId,
844
+ summary: contentText || "Plan ready for review.",
845
+ actions: plannedActions,
846
+ });
847
+ }
848
+ const planResult = mode === "plan" && plannedActions.length > 0
849
+ ? { id: planId, summary: contentText || "Plan ready for review.", actions: plannedActions }
850
+ : undefined;
851
+ return { content: fullContent, executedToolCalls, segments, rounds: round + 1, aborted: false, hitMaxRounds: false, plan: planResult };
852
+ }
853
+ // Hit max rounds
854
+ log.warn(`Agent loop hit max rounds (${maxRounds}) for session ${sessionId}`);
855
+ const msg = "\n\n[Reached maximum tool execution rounds. Stopping.]";
856
+ onEvent?.({ type: "token", content: msg });
857
+ fullContent += msg;
858
+ const planResultMaxRounds = mode === "plan" && plannedActions.length > 0
859
+ ? { id: planId, summary: fullContent, actions: plannedActions }
860
+ : undefined;
861
+ return { content: fullContent, executedToolCalls, segments, rounds: maxRounds, aborted: false, hitMaxRounds: true, plan: planResultMaxRounds };
862
+ }
863
+ // ── Retry API ────────────────────────────────────────────────────────
864
+ /**
865
+ * Retry a specific failed tool call by its callId.
866
+ *
867
+ * This re-executes the tool with its original arguments, updates the
868
+ * conversation history in-place (replaces the old tool result message),
869
+ * and returns the new result.
870
+ *
871
+ * Designed to be called from a REST endpoint like:
872
+ * POST /api/sessions/:sessionId/retry-tool
873
+ * { callId: "call_abc123" }
874
+ */
875
+ export async function retryToolCall(callId, history, executedToolCalls, executeTool, sessionId, auth, onEvent, signal) {
876
+ // Find the original call
877
+ const original = executedToolCalls.find((tc) => tc.callId === callId);
878
+ if (!original) {
879
+ return { ok: false, message: `Tool call ${callId} not found` };
880
+ }
881
+ // Find and update history entry
882
+ const histIdx = history.findIndex((m) => m.role === "tool" && m.tool_call_id === callId);
883
+ const startedAt = Date.now();
884
+ onEvent?.({
885
+ type: "tool_start",
886
+ tool: original.tool,
887
+ args: original.args,
888
+ call_id: callId,
889
+ });
890
+ const result = await executeTool(original.tool, original.args, sessionId, auth, (chunk) => onEvent?.({ type: "tool_output", call_id: callId, content: chunk }), signal);
891
+ const completedAt = Date.now();
892
+ onEvent?.({
893
+ type: "tool_result",
894
+ call_id: callId,
895
+ tool: original.tool,
896
+ ok: result.ok,
897
+ message: result.message,
898
+ data: result.data,
899
+ });
900
+ // Update the executed tool call record
901
+ original.ok = result.ok;
902
+ original.message = result.message;
903
+ original.data = result.data;
904
+ original.startedAt = startedAt;
905
+ original.completedAt = completedAt;
906
+ original.retryCount = (original.retryCount ?? 0) + 1;
907
+ // Update conversation history so the LLM sees the new result
908
+ if (histIdx !== -1) {
909
+ history[histIdx] = {
910
+ role: "tool",
911
+ content: JSON.stringify({ ok: result.ok, message: result.message, data: result.data }),
912
+ tool_call_id: callId,
913
+ name: toOpenAIName(original.tool),
914
+ };
915
+ }
916
+ return result;
917
+ }
918
+ //# sourceMappingURL=agent-loop.js.map