@itphx/synth-core 0.2.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 (814) hide show
  1. package/LICENSE +18 -0
  2. package/dictionaries/coding.en.yaml +20 -0
  3. package/dictionaries/coding.ru.yaml +22 -0
  4. package/dictionaries/coding.tools.yaml +12 -0
  5. package/dictionaries/enum.en.yaml +54 -0
  6. package/dictionaries/enum.ru.yaml +67 -0
  7. package/dictionaries/injection.en.yaml +51 -0
  8. package/dictionaries/injection.ru.yaml +51 -0
  9. package/dictionaries/intents.en.yaml +68 -0
  10. package/dictionaries/intents.ru.yaml +78 -0
  11. package/dictionaries/research.en.yaml +17 -0
  12. package/dictionaries/research.ru.yaml +17 -0
  13. package/dictionaries/small-talk.en.yaml +67 -0
  14. package/dictionaries/small-talk.ru.yaml +81 -0
  15. package/dist/auth/local.d.ts +29 -0
  16. package/dist/auth/local.d.ts.map +1 -0
  17. package/dist/auth/local.js +107 -0
  18. package/dist/auth/local.js.map +1 -0
  19. package/dist/auth/local.test.d.ts +2 -0
  20. package/dist/auth/local.test.d.ts.map +1 -0
  21. package/dist/auth/local.test.js +131 -0
  22. package/dist/auth/local.test.js.map +1 -0
  23. package/dist/debug.d.ts +36 -0
  24. package/dist/debug.d.ts.map +1 -0
  25. package/dist/debug.js +171 -0
  26. package/dist/debug.js.map +1 -0
  27. package/dist/dictionaries/coding.en.yaml +20 -0
  28. package/dist/dictionaries/coding.ru.yaml +22 -0
  29. package/dist/dictionaries/coding.tools.yaml +12 -0
  30. package/dist/dictionaries/dictionaries/coding.en.yaml +20 -0
  31. package/dist/dictionaries/dictionaries/coding.ru.yaml +22 -0
  32. package/dist/dictionaries/dictionaries/coding.tools.yaml +12 -0
  33. package/dist/dictionaries/dictionaries/enum.en.yaml +54 -0
  34. package/dist/dictionaries/dictionaries/enum.ru.yaml +67 -0
  35. package/dist/dictionaries/dictionaries/injection.en.yaml +51 -0
  36. package/dist/dictionaries/dictionaries/injection.ru.yaml +51 -0
  37. package/dist/dictionaries/dictionaries/intents.en.yaml +68 -0
  38. package/dist/dictionaries/dictionaries/intents.ru.yaml +78 -0
  39. package/dist/dictionaries/dictionaries/research.en.yaml +17 -0
  40. package/dist/dictionaries/dictionaries/research.ru.yaml +17 -0
  41. package/dist/dictionaries/dictionaries/small-talk.en.yaml +67 -0
  42. package/dist/dictionaries/dictionaries/small-talk.ru.yaml +81 -0
  43. package/dist/dictionaries/enum.en.yaml +54 -0
  44. package/dist/dictionaries/enum.ru.yaml +67 -0
  45. package/dist/dictionaries/injection.en.yaml +51 -0
  46. package/dist/dictionaries/injection.ru.yaml +51 -0
  47. package/dist/dictionaries/intents.en.yaml +68 -0
  48. package/dist/dictionaries/intents.ru.yaml +78 -0
  49. package/dist/dictionaries/research.en.yaml +17 -0
  50. package/dist/dictionaries/research.ru.yaml +17 -0
  51. package/dist/dictionaries/small-talk.en.yaml +67 -0
  52. package/dist/dictionaries/small-talk.ru.yaml +81 -0
  53. package/dist/engine/agents/definitions/admin.json +24 -0
  54. package/dist/engine/agents/definitions/analyst.json +20 -0
  55. package/dist/engine/agents/definitions/assistant.json +25 -0
  56. package/dist/engine/agents/definitions/auditor.json +19 -0
  57. package/dist/engine/agents/definitions/developer.json +23 -0
  58. package/dist/engine/agents/definitions/devops.json +23 -0
  59. package/dist/engine/agents/definitions/explore.json +15 -0
  60. package/dist/engine/agents/definitions/general.json +15 -0
  61. package/dist/engine/agents/definitions/pm.json +20 -0
  62. package/dist/engine/agents/definitions/qa.json +22 -0
  63. package/dist/engine/agents/definitions/title.json +19 -0
  64. package/dist/engine/agents/index.d.ts +8 -0
  65. package/dist/engine/agents/index.d.ts.map +1 -0
  66. package/dist/engine/agents/index.js +71 -0
  67. package/dist/engine/agents/index.js.map +1 -0
  68. package/dist/engine/agents/mode.d.ts +14 -0
  69. package/dist/engine/agents/mode.d.ts.map +1 -0
  70. package/dist/engine/agents/mode.js +21 -0
  71. package/dist/engine/agents/mode.js.map +1 -0
  72. package/dist/engine/agents/mode.test.d.ts +2 -0
  73. package/dist/engine/agents/mode.test.d.ts.map +1 -0
  74. package/dist/engine/agents/mode.test.js +27 -0
  75. package/dist/engine/agents/mode.test.js.map +1 -0
  76. package/dist/engine/agents/registry.d.ts +17 -0
  77. package/dist/engine/agents/registry.d.ts.map +1 -0
  78. package/dist/engine/agents/registry.js +48 -0
  79. package/dist/engine/agents/registry.js.map +1 -0
  80. package/dist/engine/agents/registry.test.d.ts +2 -0
  81. package/dist/engine/agents/registry.test.d.ts.map +1 -0
  82. package/dist/engine/agents/registry.test.js +76 -0
  83. package/dist/engine/agents/registry.test.js.map +1 -0
  84. package/dist/engine/context/builder.d.ts +44 -0
  85. package/dist/engine/context/builder.d.ts.map +1 -0
  86. package/dist/engine/context/builder.js +225 -0
  87. package/dist/engine/context/builder.js.map +1 -0
  88. package/dist/engine/context/builder.test.d.ts +2 -0
  89. package/dist/engine/context/builder.test.d.ts.map +1 -0
  90. package/dist/engine/context/builder.test.js +69 -0
  91. package/dist/engine/context/builder.test.js.map +1 -0
  92. package/dist/engine/context/config.d.ts +56 -0
  93. package/dist/engine/context/config.d.ts.map +1 -0
  94. package/dist/engine/context/config.js +391 -0
  95. package/dist/engine/context/config.js.map +1 -0
  96. package/dist/engine/context/config.test.d.ts +2 -0
  97. package/dist/engine/context/config.test.d.ts.map +1 -0
  98. package/dist/engine/context/config.test.js +54 -0
  99. package/dist/engine/context/config.test.js.map +1 -0
  100. package/dist/engine/context/index.d.ts +5 -0
  101. package/dist/engine/context/index.d.ts.map +1 -0
  102. package/dist/engine/context/index.js +5 -0
  103. package/dist/engine/context/index.js.map +1 -0
  104. package/dist/engine/context/interview.d.ts +17 -0
  105. package/dist/engine/context/interview.d.ts.map +1 -0
  106. package/dist/engine/context/interview.js +84 -0
  107. package/dist/engine/context/interview.js.map +1 -0
  108. package/dist/engine/context/optimizer.d.ts +112 -0
  109. package/dist/engine/context/optimizer.d.ts.map +1 -0
  110. package/dist/engine/context/optimizer.js +517 -0
  111. package/dist/engine/context/optimizer.js.map +1 -0
  112. package/dist/engine/context/optimizer.test.d.ts +2 -0
  113. package/dist/engine/context/optimizer.test.d.ts.map +1 -0
  114. package/dist/engine/context/optimizer.test.js +101 -0
  115. package/dist/engine/context/optimizer.test.js.map +1 -0
  116. package/dist/engine/gateway/audit-logger.d.ts +52 -0
  117. package/dist/engine/gateway/audit-logger.d.ts.map +1 -0
  118. package/dist/engine/gateway/audit-logger.js +86 -0
  119. package/dist/engine/gateway/audit-logger.js.map +1 -0
  120. package/dist/engine/gateway/audit-logger.test.d.ts +6 -0
  121. package/dist/engine/gateway/audit-logger.test.d.ts.map +1 -0
  122. package/dist/engine/gateway/audit-logger.test.js +86 -0
  123. package/dist/engine/gateway/audit-logger.test.js.map +1 -0
  124. package/dist/engine/gateway/gateway-provider.d.ts +46 -0
  125. package/dist/engine/gateway/gateway-provider.d.ts.map +1 -0
  126. package/dist/engine/gateway/gateway-provider.js +223 -0
  127. package/dist/engine/gateway/gateway-provider.js.map +1 -0
  128. package/dist/engine/gateway/gateway-provider.test.d.ts +7 -0
  129. package/dist/engine/gateway/gateway-provider.test.d.ts.map +1 -0
  130. package/dist/engine/gateway/gateway-provider.test.js +251 -0
  131. package/dist/engine/gateway/gateway-provider.test.js.map +1 -0
  132. package/dist/engine/gateway/index.d.ts +23 -0
  133. package/dist/engine/gateway/index.d.ts.map +1 -0
  134. package/dist/engine/gateway/index.js +15 -0
  135. package/dist/engine/gateway/index.js.map +1 -0
  136. package/dist/engine/gateway/input-guard.d.ts +38 -0
  137. package/dist/engine/gateway/input-guard.d.ts.map +1 -0
  138. package/dist/engine/gateway/input-guard.js +109 -0
  139. package/dist/engine/gateway/input-guard.js.map +1 -0
  140. package/dist/engine/gateway/input-guard.test.d.ts +6 -0
  141. package/dist/engine/gateway/input-guard.test.d.ts.map +1 -0
  142. package/dist/engine/gateway/input-guard.test.js +109 -0
  143. package/dist/engine/gateway/input-guard.test.js.map +1 -0
  144. package/dist/engine/gateway/integration.test.d.ts +8 -0
  145. package/dist/engine/gateway/integration.test.d.ts.map +1 -0
  146. package/dist/engine/gateway/integration.test.js +341 -0
  147. package/dist/engine/gateway/integration.test.js.map +1 -0
  148. package/dist/engine/gateway/obfuscation-map-store.d.ts +14 -0
  149. package/dist/engine/gateway/obfuscation-map-store.d.ts.map +1 -0
  150. package/dist/engine/gateway/obfuscation-map-store.js +30 -0
  151. package/dist/engine/gateway/obfuscation-map-store.js.map +1 -0
  152. package/dist/engine/gateway/obfuscator.d.ts +32 -0
  153. package/dist/engine/gateway/obfuscator.d.ts.map +1 -0
  154. package/dist/engine/gateway/obfuscator.js +83 -0
  155. package/dist/engine/gateway/obfuscator.js.map +1 -0
  156. package/dist/engine/gateway/obfuscator.test.d.ts +6 -0
  157. package/dist/engine/gateway/obfuscator.test.d.ts.map +1 -0
  158. package/dist/engine/gateway/obfuscator.test.js +104 -0
  159. package/dist/engine/gateway/obfuscator.test.js.map +1 -0
  160. package/dist/engine/gateway/output-guard.d.ts +12 -0
  161. package/dist/engine/gateway/output-guard.d.ts.map +1 -0
  162. package/dist/engine/gateway/output-guard.js +12 -0
  163. package/dist/engine/gateway/output-guard.js.map +1 -0
  164. package/dist/engine/gateway/output-guard.test.d.ts +5 -0
  165. package/dist/engine/gateway/output-guard.test.d.ts.map +1 -0
  166. package/dist/engine/gateway/output-guard.test.js +31 -0
  167. package/dist/engine/gateway/output-guard.test.js.map +1 -0
  168. package/dist/engine/gateway/payload-logger.d.ts +52 -0
  169. package/dist/engine/gateway/payload-logger.d.ts.map +1 -0
  170. package/dist/engine/gateway/payload-logger.js +82 -0
  171. package/dist/engine/gateway/payload-logger.js.map +1 -0
  172. package/dist/engine/gateway/payload-logger.test.d.ts +6 -0
  173. package/dist/engine/gateway/payload-logger.test.d.ts.map +1 -0
  174. package/dist/engine/gateway/payload-logger.test.js +106 -0
  175. package/dist/engine/gateway/payload-logger.test.js.map +1 -0
  176. package/dist/engine/gateway/rate-limiter.d.ts +18 -0
  177. package/dist/engine/gateway/rate-limiter.d.ts.map +1 -0
  178. package/dist/engine/gateway/rate-limiter.js +44 -0
  179. package/dist/engine/gateway/rate-limiter.js.map +1 -0
  180. package/dist/engine/gateway/rate-limiter.test.d.ts +5 -0
  181. package/dist/engine/gateway/rate-limiter.test.d.ts.map +1 -0
  182. package/dist/engine/gateway/rate-limiter.test.js +61 -0
  183. package/dist/engine/gateway/rate-limiter.test.js.map +1 -0
  184. package/dist/engine/gateway/secret-detector.d.ts +25 -0
  185. package/dist/engine/gateway/secret-detector.d.ts.map +1 -0
  186. package/dist/engine/gateway/secret-detector.js +109 -0
  187. package/dist/engine/gateway/secret-detector.js.map +1 -0
  188. package/dist/engine/gateway/secret-detector.test.d.ts +6 -0
  189. package/dist/engine/gateway/secret-detector.test.d.ts.map +1 -0
  190. package/dist/engine/gateway/secret-detector.test.js +107 -0
  191. package/dist/engine/gateway/secret-detector.test.js.map +1 -0
  192. package/dist/engine/gateway/secret-pattern-store.d.ts +54 -0
  193. package/dist/engine/gateway/secret-pattern-store.d.ts.map +1 -0
  194. package/dist/engine/gateway/secret-pattern-store.js +133 -0
  195. package/dist/engine/gateway/secret-pattern-store.js.map +1 -0
  196. package/dist/engine/gateway/secret-pattern-store.test.d.ts +7 -0
  197. package/dist/engine/gateway/secret-pattern-store.test.d.ts.map +1 -0
  198. package/dist/engine/gateway/secret-pattern-store.test.js +102 -0
  199. package/dist/engine/gateway/secret-pattern-store.test.js.map +1 -0
  200. package/dist/engine/mcp/client.d.ts +31 -0
  201. package/dist/engine/mcp/client.d.ts.map +1 -0
  202. package/dist/engine/mcp/client.js +150 -0
  203. package/dist/engine/mcp/client.js.map +1 -0
  204. package/dist/engine/mcp/client.test.d.ts +2 -0
  205. package/dist/engine/mcp/client.test.d.ts.map +1 -0
  206. package/dist/engine/mcp/client.test.js +204 -0
  207. package/dist/engine/mcp/client.test.js.map +1 -0
  208. package/dist/engine/mcp/index.d.ts +5 -0
  209. package/dist/engine/mcp/index.d.ts.map +1 -0
  210. package/dist/engine/mcp/index.js +4 -0
  211. package/dist/engine/mcp/index.js.map +1 -0
  212. package/dist/engine/mcp/manager.d.ts +46 -0
  213. package/dist/engine/mcp/manager.d.ts.map +1 -0
  214. package/dist/engine/mcp/manager.js +227 -0
  215. package/dist/engine/mcp/manager.js.map +1 -0
  216. package/dist/engine/mcp/manager.test.d.ts +2 -0
  217. package/dist/engine/mcp/manager.test.d.ts.map +1 -0
  218. package/dist/engine/mcp/manager.test.js +269 -0
  219. package/dist/engine/mcp/manager.test.js.map +1 -0
  220. package/dist/engine/mcp/settings.d.ts +23 -0
  221. package/dist/engine/mcp/settings.d.ts.map +1 -0
  222. package/dist/engine/mcp/settings.js +56 -0
  223. package/dist/engine/mcp/settings.js.map +1 -0
  224. package/dist/engine/orchestrator.d.ts +171 -0
  225. package/dist/engine/orchestrator.d.ts.map +1 -0
  226. package/dist/engine/orchestrator.js +1651 -0
  227. package/dist/engine/orchestrator.js.map +1 -0
  228. package/dist/engine/orchestrator.test.d.ts +2 -0
  229. package/dist/engine/orchestrator.test.d.ts.map +1 -0
  230. package/dist/engine/orchestrator.test.js +83 -0
  231. package/dist/engine/orchestrator.test.js.map +1 -0
  232. package/dist/engine/permission/approval.d.ts +32 -0
  233. package/dist/engine/permission/approval.d.ts.map +1 -0
  234. package/dist/engine/permission/approval.js +66 -0
  235. package/dist/engine/permission/approval.js.map +1 -0
  236. package/dist/engine/permission/approval.test.d.ts +2 -0
  237. package/dist/engine/permission/approval.test.d.ts.map +1 -0
  238. package/dist/engine/permission/approval.test.js +139 -0
  239. package/dist/engine/permission/approval.test.js.map +1 -0
  240. package/dist/engine/permission/derive.d.ts +12 -0
  241. package/dist/engine/permission/derive.d.ts.map +1 -0
  242. package/dist/engine/permission/derive.js +25 -0
  243. package/dist/engine/permission/derive.js.map +1 -0
  244. package/dist/engine/permission/evaluator.d.ts +64 -0
  245. package/dist/engine/permission/evaluator.d.ts.map +1 -0
  246. package/dist/engine/permission/evaluator.js +236 -0
  247. package/dist/engine/permission/evaluator.js.map +1 -0
  248. package/dist/engine/permission/evaluator.test.d.ts +2 -0
  249. package/dist/engine/permission/evaluator.test.d.ts.map +1 -0
  250. package/dist/engine/permission/evaluator.test.js +367 -0
  251. package/dist/engine/permission/evaluator.test.js.map +1 -0
  252. package/dist/engine/permission/groups.d.ts +10 -0
  253. package/dist/engine/permission/groups.d.ts.map +1 -0
  254. package/dist/engine/permission/groups.js +96 -0
  255. package/dist/engine/permission/groups.js.map +1 -0
  256. package/dist/engine/permission/index.d.ts +8 -0
  257. package/dist/engine/permission/index.d.ts.map +1 -0
  258. package/dist/engine/permission/index.js +6 -0
  259. package/dist/engine/permission/index.js.map +1 -0
  260. package/dist/engine/permission/integration.test.d.ts +2 -0
  261. package/dist/engine/permission/integration.test.d.ts.map +1 -0
  262. package/dist/engine/permission/integration.test.js +433 -0
  263. package/dist/engine/permission/integration.test.js.map +1 -0
  264. package/dist/engine/plan.integration.test.d.ts +2 -0
  265. package/dist/engine/plan.integration.test.d.ts.map +1 -0
  266. package/dist/engine/plan.integration.test.js +363 -0
  267. package/dist/engine/plan.integration.test.js.map +1 -0
  268. package/dist/engine/router/content-classifier.d.ts +27 -0
  269. package/dist/engine/router/content-classifier.d.ts.map +1 -0
  270. package/dist/engine/router/content-classifier.js +72 -0
  271. package/dist/engine/router/content-classifier.js.map +1 -0
  272. package/dist/engine/router/dictionary-store.d.ts +41 -0
  273. package/dist/engine/router/dictionary-store.d.ts.map +1 -0
  274. package/dist/engine/router/dictionary-store.js +239 -0
  275. package/dist/engine/router/dictionary-store.js.map +1 -0
  276. package/dist/engine/router/index.d.ts +21 -0
  277. package/dist/engine/router/index.d.ts.map +1 -0
  278. package/dist/engine/router/index.js +15 -0
  279. package/dist/engine/router/index.js.map +1 -0
  280. package/dist/engine/router/micro/index.d.ts +22 -0
  281. package/dist/engine/router/micro/index.d.ts.map +1 -0
  282. package/dist/engine/router/micro/index.js +72 -0
  283. package/dist/engine/router/micro/index.js.map +1 -0
  284. package/dist/engine/router/micro/index.test.d.ts +2 -0
  285. package/dist/engine/router/micro/index.test.d.ts.map +1 -0
  286. package/dist/engine/router/micro/index.test.js +81 -0
  287. package/dist/engine/router/micro/index.test.js.map +1 -0
  288. package/dist/engine/router/micro/models/base.d.ts +18 -0
  289. package/dist/engine/router/micro/models/base.d.ts.map +1 -0
  290. package/dist/engine/router/micro/models/base.js +2 -0
  291. package/dist/engine/router/micro/models/base.js.map +1 -0
  292. package/dist/engine/router/micro/models/embedding-model.d.ts +38 -0
  293. package/dist/engine/router/micro/models/embedding-model.d.ts.map +1 -0
  294. package/dist/engine/router/micro/models/embedding-model.js +248 -0
  295. package/dist/engine/router/micro/models/embedding-model.js.map +1 -0
  296. package/dist/engine/router/micro/models/index.d.ts +9 -0
  297. package/dist/engine/router/micro/models/index.d.ts.map +1 -0
  298. package/dist/engine/router/micro/models/index.js +4 -0
  299. package/dist/engine/router/micro/models/index.js.map +1 -0
  300. package/dist/engine/router/micro/models/micro-llm-model.d.ts +28 -0
  301. package/dist/engine/router/micro/models/micro-llm-model.d.ts.map +1 -0
  302. package/dist/engine/router/micro/models/micro-llm-model.js +115 -0
  303. package/dist/engine/router/micro/models/micro-llm-model.js.map +1 -0
  304. package/dist/engine/router/micro/models/rules-model.d.ts +23 -0
  305. package/dist/engine/router/micro/models/rules-model.d.ts.map +1 -0
  306. package/dist/engine/router/micro/models/rules-model.js +186 -0
  307. package/dist/engine/router/micro/models/rules-model.js.map +1 -0
  308. package/dist/engine/router/micro/models/rules-model.test.d.ts +2 -0
  309. package/dist/engine/router/micro/models/rules-model.test.d.ts.map +1 -0
  310. package/dist/engine/router/micro/models/rules-model.test.js +77 -0
  311. package/dist/engine/router/micro/models/rules-model.test.js.map +1 -0
  312. package/dist/engine/router/micro/task-classifier.d.ts +29 -0
  313. package/dist/engine/router/micro/task-classifier.d.ts.map +1 -0
  314. package/dist/engine/router/micro/task-classifier.js +106 -0
  315. package/dist/engine/router/micro/task-classifier.js.map +1 -0
  316. package/dist/engine/router/micro/task-classifier.test.d.ts +2 -0
  317. package/dist/engine/router/micro/task-classifier.test.d.ts.map +1 -0
  318. package/dist/engine/router/micro/task-classifier.test.js +134 -0
  319. package/dist/engine/router/micro/task-classifier.test.js.map +1 -0
  320. package/dist/engine/router/micro/tasks/classify-intent.d.ts +8 -0
  321. package/dist/engine/router/micro/tasks/classify-intent.d.ts.map +1 -0
  322. package/dist/engine/router/micro/tasks/classify-intent.js +36 -0
  323. package/dist/engine/router/micro/tasks/classify-intent.js.map +1 -0
  324. package/dist/engine/router/micro/tasks/classify-intent.test.d.ts +2 -0
  325. package/dist/engine/router/micro/tasks/classify-intent.test.d.ts.map +1 -0
  326. package/dist/engine/router/micro/tasks/classify-intent.test.js +107 -0
  327. package/dist/engine/router/micro/tasks/classify-intent.test.js.map +1 -0
  328. package/dist/engine/router/micro/tasks/enum-decision.d.ts +7 -0
  329. package/dist/engine/router/micro/tasks/enum-decision.d.ts.map +1 -0
  330. package/dist/engine/router/micro/tasks/enum-decision.js +36 -0
  331. package/dist/engine/router/micro/tasks/enum-decision.js.map +1 -0
  332. package/dist/engine/router/micro/tasks/enum-decision.test.d.ts +2 -0
  333. package/dist/engine/router/micro/tasks/enum-decision.test.d.ts.map +1 -0
  334. package/dist/engine/router/micro/tasks/enum-decision.test.js +96 -0
  335. package/dist/engine/router/micro/tasks/enum-decision.test.js.map +1 -0
  336. package/dist/engine/router/micro/tasks/index.d.ts +7 -0
  337. package/dist/engine/router/micro/tasks/index.d.ts.map +1 -0
  338. package/dist/engine/router/micro/tasks/index.js +7 -0
  339. package/dist/engine/router/micro/tasks/index.js.map +1 -0
  340. package/dist/engine/router/micro/tasks/small-talk.d.ts +7 -0
  341. package/dist/engine/router/micro/tasks/small-talk.d.ts.map +1 -0
  342. package/dist/engine/router/micro/tasks/small-talk.js +29 -0
  343. package/dist/engine/router/micro/tasks/small-talk.js.map +1 -0
  344. package/dist/engine/router/micro/tasks/small-talk.test.d.ts +2 -0
  345. package/dist/engine/router/micro/tasks/small-talk.test.d.ts.map +1 -0
  346. package/dist/engine/router/micro/tasks/small-talk.test.js +71 -0
  347. package/dist/engine/router/micro/tasks/small-talk.test.js.map +1 -0
  348. package/dist/engine/router/micro/types.d.ts +42 -0
  349. package/dist/engine/router/micro/types.d.ts.map +1 -0
  350. package/dist/engine/router/micro/types.js +2 -0
  351. package/dist/engine/router/micro/types.js.map +1 -0
  352. package/dist/engine/router/provider-pool.d.ts +24 -0
  353. package/dist/engine/router/provider-pool.d.ts.map +1 -0
  354. package/dist/engine/router/provider-pool.js +57 -0
  355. package/dist/engine/router/provider-pool.js.map +1 -0
  356. package/dist/engine/router/provider-pool.test.d.ts +7 -0
  357. package/dist/engine/router/provider-pool.test.d.ts.map +1 -0
  358. package/dist/engine/router/provider-pool.test.js +138 -0
  359. package/dist/engine/router/provider-pool.test.js.map +1 -0
  360. package/dist/engine/router/quality-checker.d.ts +25 -0
  361. package/dist/engine/router/quality-checker.d.ts.map +1 -0
  362. package/dist/engine/router/quality-checker.js +121 -0
  363. package/dist/engine/router/quality-checker.js.map +1 -0
  364. package/dist/engine/router/router.d.ts +48 -0
  365. package/dist/engine/router/router.d.ts.map +1 -0
  366. package/dist/engine/router/router.js +195 -0
  367. package/dist/engine/router/router.js.map +1 -0
  368. package/dist/engine/router/utils.d.ts +7 -0
  369. package/dist/engine/router/utils.d.ts.map +1 -0
  370. package/dist/engine/router/utils.js +14 -0
  371. package/dist/engine/router/utils.js.map +1 -0
  372. package/dist/engine/security/index.d.ts +5 -0
  373. package/dist/engine/security/index.d.ts.map +1 -0
  374. package/dist/engine/security/index.js +3 -0
  375. package/dist/engine/security/index.js.map +1 -0
  376. package/dist/engine/security/integration.test.d.ts +2 -0
  377. package/dist/engine/security/integration.test.d.ts.map +1 -0
  378. package/dist/engine/security/integration.test.js +246 -0
  379. package/dist/engine/security/integration.test.js.map +1 -0
  380. package/dist/engine/security/prompt-injection.d.ts +52 -0
  381. package/dist/engine/security/prompt-injection.d.ts.map +1 -0
  382. package/dist/engine/security/prompt-injection.js +78 -0
  383. package/dist/engine/security/prompt-injection.js.map +1 -0
  384. package/dist/engine/security/prompt-injection.test.d.ts +2 -0
  385. package/dist/engine/security/prompt-injection.test.d.ts.map +1 -0
  386. package/dist/engine/security/prompt-injection.test.js +110 -0
  387. package/dist/engine/security/prompt-injection.test.js.map +1 -0
  388. package/dist/engine/security/trust.d.ts +22 -0
  389. package/dist/engine/security/trust.d.ts.map +1 -0
  390. package/dist/engine/security/trust.js +107 -0
  391. package/dist/engine/security/trust.js.map +1 -0
  392. package/dist/engine/security/trust.test.d.ts +2 -0
  393. package/dist/engine/security/trust.test.d.ts.map +1 -0
  394. package/dist/engine/security/trust.test.js +92 -0
  395. package/dist/engine/security/trust.test.js.map +1 -0
  396. package/dist/engine/tools/classify-conversation.d.ts +3 -0
  397. package/dist/engine/tools/classify-conversation.d.ts.map +1 -0
  398. package/dist/engine/tools/classify-conversation.js +28 -0
  399. package/dist/engine/tools/classify-conversation.js.map +1 -0
  400. package/dist/engine/tools/fs-read.d.ts +5 -0
  401. package/dist/engine/tools/fs-read.d.ts.map +1 -0
  402. package/dist/engine/tools/fs-read.js +123 -0
  403. package/dist/engine/tools/fs-read.js.map +1 -0
  404. package/dist/engine/tools/fs-read.test.d.ts +2 -0
  405. package/dist/engine/tools/fs-read.test.d.ts.map +1 -0
  406. package/dist/engine/tools/fs-read.test.js +69 -0
  407. package/dist/engine/tools/fs-read.test.js.map +1 -0
  408. package/dist/engine/tools/fs-write.d.ts +6 -0
  409. package/dist/engine/tools/fs-write.d.ts.map +1 -0
  410. package/dist/engine/tools/fs-write.js +196 -0
  411. package/dist/engine/tools/fs-write.js.map +1 -0
  412. package/dist/engine/tools/fs-write.test.d.ts +2 -0
  413. package/dist/engine/tools/fs-write.test.d.ts.map +1 -0
  414. package/dist/engine/tools/fs-write.test.js +58 -0
  415. package/dist/engine/tools/fs-write.test.js.map +1 -0
  416. package/dist/engine/tools/git.d.ts +17 -0
  417. package/dist/engine/tools/git.d.ts.map +1 -0
  418. package/dist/engine/tools/git.js +501 -0
  419. package/dist/engine/tools/git.js.map +1 -0
  420. package/dist/engine/tools/git.test.d.ts +2 -0
  421. package/dist/engine/tools/git.test.d.ts.map +1 -0
  422. package/dist/engine/tools/git.test.js +47 -0
  423. package/dist/engine/tools/git.test.js.map +1 -0
  424. package/dist/engine/tools/index.d.ts +7 -0
  425. package/dist/engine/tools/index.d.ts.map +1 -0
  426. package/dist/engine/tools/index.js +53 -0
  427. package/dist/engine/tools/index.js.map +1 -0
  428. package/dist/engine/tools/json-schema.d.ts +3 -0
  429. package/dist/engine/tools/json-schema.d.ts.map +1 -0
  430. package/dist/engine/tools/json-schema.js +131 -0
  431. package/dist/engine/tools/json-schema.js.map +1 -0
  432. package/dist/engine/tools/obfuscation.d.ts +12 -0
  433. package/dist/engine/tools/obfuscation.d.ts.map +1 -0
  434. package/dist/engine/tools/obfuscation.js +24 -0
  435. package/dist/engine/tools/obfuscation.js.map +1 -0
  436. package/dist/engine/tools/path-utils.d.ts +3 -0
  437. package/dist/engine/tools/path-utils.d.ts.map +1 -0
  438. package/dist/engine/tools/path-utils.js +20 -0
  439. package/dist/engine/tools/path-utils.js.map +1 -0
  440. package/dist/engine/tools/path-utils.test.d.ts +2 -0
  441. package/dist/engine/tools/path-utils.test.d.ts.map +1 -0
  442. package/dist/engine/tools/path-utils.test.js +38 -0
  443. package/dist/engine/tools/path-utils.test.js.map +1 -0
  444. package/dist/engine/tools/plan.d.ts +13 -0
  445. package/dist/engine/tools/plan.d.ts.map +1 -0
  446. package/dist/engine/tools/plan.js +153 -0
  447. package/dist/engine/tools/plan.js.map +1 -0
  448. package/dist/engine/tools/plan.test.d.ts +2 -0
  449. package/dist/engine/tools/plan.test.d.ts.map +1 -0
  450. package/dist/engine/tools/plan.test.js +106 -0
  451. package/dist/engine/tools/plan.test.js.map +1 -0
  452. package/dist/engine/tools/project-context.d.ts +4 -0
  453. package/dist/engine/tools/project-context.d.ts.map +1 -0
  454. package/dist/engine/tools/project-context.js +232 -0
  455. package/dist/engine/tools/project-context.js.map +1 -0
  456. package/dist/engine/tools/project-context.test.d.ts +2 -0
  457. package/dist/engine/tools/project-context.test.d.ts.map +1 -0
  458. package/dist/engine/tools/project-context.test.js +175 -0
  459. package/dist/engine/tools/project-context.test.js.map +1 -0
  460. package/dist/engine/tools/read-reference.d.ts +3 -0
  461. package/dist/engine/tools/read-reference.d.ts.map +1 -0
  462. package/dist/engine/tools/read-reference.js +41 -0
  463. package/dist/engine/tools/read-reference.js.map +1 -0
  464. package/dist/engine/tools/read-reference.test.d.ts +2 -0
  465. package/dist/engine/tools/read-reference.test.d.ts.map +1 -0
  466. package/dist/engine/tools/read-reference.test.js +57 -0
  467. package/dist/engine/tools/read-reference.test.js.map +1 -0
  468. package/dist/engine/tools/registry.d.ts +15 -0
  469. package/dist/engine/tools/registry.d.ts.map +1 -0
  470. package/dist/engine/tools/registry.js +66 -0
  471. package/dist/engine/tools/registry.js.map +1 -0
  472. package/dist/engine/tools/search.d.ts +3 -0
  473. package/dist/engine/tools/search.d.ts.map +1 -0
  474. package/dist/engine/tools/search.js +70 -0
  475. package/dist/engine/tools/search.js.map +1 -0
  476. package/dist/engine/tools/shell.d.ts +3 -0
  477. package/dist/engine/tools/shell.d.ts.map +1 -0
  478. package/dist/engine/tools/shell.js +69 -0
  479. package/dist/engine/tools/shell.js.map +1 -0
  480. package/dist/engine/tools/shell.test.d.ts +2 -0
  481. package/dist/engine/tools/shell.test.d.ts.map +1 -0
  482. package/dist/engine/tools/shell.test.js +39 -0
  483. package/dist/engine/tools/shell.test.js.map +1 -0
  484. package/dist/engine/tools/task.d.ts +35 -0
  485. package/dist/engine/tools/task.d.ts.map +1 -0
  486. package/dist/engine/tools/task.js +944 -0
  487. package/dist/engine/tools/task.js.map +1 -0
  488. package/dist/engine/tools/task.test.d.ts +2 -0
  489. package/dist/engine/tools/task.test.d.ts.map +1 -0
  490. package/dist/engine/tools/task.test.js +707 -0
  491. package/dist/engine/tools/task.test.js.map +1 -0
  492. package/dist/engine/tools/todo.d.ts +10 -0
  493. package/dist/engine/tools/todo.d.ts.map +1 -0
  494. package/dist/engine/tools/todo.js +56 -0
  495. package/dist/engine/tools/todo.js.map +1 -0
  496. package/dist/engine/tools/todo.test.d.ts +2 -0
  497. package/dist/engine/tools/todo.test.d.ts.map +1 -0
  498. package/dist/engine/tools/todo.test.js +90 -0
  499. package/dist/engine/tools/todo.test.js.map +1 -0
  500. package/dist/engine/tools/web.d.ts +12 -0
  501. package/dist/engine/tools/web.d.ts.map +1 -0
  502. package/dist/engine/tools/web.js +355 -0
  503. package/dist/engine/tools/web.js.map +1 -0
  504. package/dist/engine/tools/web.test.d.ts +2 -0
  505. package/dist/engine/tools/web.test.d.ts.map +1 -0
  506. package/dist/engine/tools/web.test.js +223 -0
  507. package/dist/engine/tools/web.test.js.map +1 -0
  508. package/dist/events/bus.d.ts +20 -0
  509. package/dist/events/bus.d.ts.map +1 -0
  510. package/dist/events/bus.js +93 -0
  511. package/dist/events/bus.js.map +1 -0
  512. package/dist/events/bus.test.d.ts +2 -0
  513. package/dist/events/bus.test.d.ts.map +1 -0
  514. package/dist/events/bus.test.js +147 -0
  515. package/dist/events/bus.test.js.map +1 -0
  516. package/dist/index.d.ts +40 -0
  517. package/dist/index.d.ts.map +1 -0
  518. package/dist/index.js +27 -0
  519. package/dist/index.js.map +1 -0
  520. package/dist/logger.d.ts +11 -0
  521. package/dist/logger.d.ts.map +1 -0
  522. package/dist/logger.js +98 -0
  523. package/dist/logger.js.map +1 -0
  524. package/dist/main.d.ts +2 -0
  525. package/dist/main.d.ts.map +1 -0
  526. package/dist/main.js +520 -0
  527. package/dist/main.js.map +1 -0
  528. package/dist/prompts/modes/act.md +18 -0
  529. package/dist/prompts/modes/plan.md +20 -0
  530. package/dist/prompts/modes/yolo.md +20 -0
  531. package/dist/prompts/prompts/modes/act.md +18 -0
  532. package/dist/prompts/prompts/modes/plan.md +20 -0
  533. package/dist/prompts/prompts/modes/yolo.md +20 -0
  534. package/dist/prompts/prompts/roles/ADMIN.en.md +33 -0
  535. package/dist/prompts/prompts/roles/ADMIN.ru.md +33 -0
  536. package/dist/prompts/prompts/roles/ANALYST.en.md +33 -0
  537. package/dist/prompts/prompts/roles/ANALYST.ru.md +33 -0
  538. package/dist/prompts/prompts/roles/ASSISTANT.en.md +38 -0
  539. package/dist/prompts/prompts/roles/ASSISTANT.ru.md +38 -0
  540. package/dist/prompts/prompts/roles/AUDITOR.en.md +33 -0
  541. package/dist/prompts/prompts/roles/AUDITOR.ru.md +33 -0
  542. package/dist/prompts/prompts/roles/DEVELOPER.en.md +42 -0
  543. package/dist/prompts/prompts/roles/DEVELOPER.ru.md +42 -0
  544. package/dist/prompts/prompts/roles/DEVOPS.en.md +35 -0
  545. package/dist/prompts/prompts/roles/DEVOPS.ru.md +35 -0
  546. package/dist/prompts/prompts/roles/PM.en.md +33 -0
  547. package/dist/prompts/prompts/roles/PM.ru.md +33 -0
  548. package/dist/prompts/prompts/roles/QA.en.md +33 -0
  549. package/dist/prompts/prompts/roles/QA.ru.md +33 -0
  550. package/dist/prompts/prompts/roles/TITLE.ru.md +30 -0
  551. package/dist/prompts/prompts/subagents/explore.ru.md +23 -0
  552. package/dist/prompts/prompts/subagents/general.ru.md +19 -0
  553. package/dist/prompts/prompts/system/COMPRESSED_DIALOG.en.md +5 -0
  554. package/dist/prompts/prompts/system/COMPRESSED_DIALOG.ru.md +5 -0
  555. package/dist/prompts/prompts/system/GATEWAY.en.md +10 -0
  556. package/dist/prompts/prompts/system/GATEWAY.ru.md +10 -0
  557. package/dist/prompts/prompts/system/INTERVIEW.en.md +18 -0
  558. package/dist/prompts/prompts/system/INTERVIEW.ru.md +18 -0
  559. package/dist/prompts/prompts/system/PARTICIPANTS_NOTICE.en.md +7 -0
  560. package/dist/prompts/prompts/system/PARTICIPANTS_NOTICE.ru.md +7 -0
  561. package/dist/prompts/prompts/system/ROLES_DESCRIPTION.en.md +16 -0
  562. package/dist/prompts/prompts/system/ROLES_DESCRIPTION.ru.md +16 -0
  563. package/dist/prompts/prompts/system/ROUTING.en.md +13 -0
  564. package/dist/prompts/prompts/system/ROUTING.md +6 -0
  565. package/dist/prompts/prompts/system/ROUTING.ru.md +13 -0
  566. package/dist/prompts/prompts/system/RULES.en.md +10 -0
  567. package/dist/prompts/prompts/system/RULES.md +10 -0
  568. package/dist/prompts/prompts/system/RULES.ru.md +10 -0
  569. package/dist/prompts/prompts/system/STICKY_NOTES.en.md +6 -0
  570. package/dist/prompts/prompts/system/STICKY_NOTES.ru.md +6 -0
  571. package/dist/prompts/prompts/system/SUMMARIZER.en.md +54 -0
  572. package/dist/prompts/prompts/system/SUMMARIZER.ru.md +54 -0
  573. package/dist/prompts/prompts/system/USER_CONTEXT.en.md +5 -0
  574. package/dist/prompts/prompts/system/USER_CONTEXT.ru.md +5 -0
  575. package/dist/prompts/roles/ADMIN.en.md +32 -0
  576. package/dist/prompts/roles/ADMIN.ru.md +32 -0
  577. package/dist/prompts/roles/ANALYST.en.md +32 -0
  578. package/dist/prompts/roles/ANALYST.ru.md +32 -0
  579. package/dist/prompts/roles/ASSISTANT.en.md +37 -0
  580. package/dist/prompts/roles/ASSISTANT.ru.md +37 -0
  581. package/dist/prompts/roles/AUDITOR.en.md +32 -0
  582. package/dist/prompts/roles/AUDITOR.ru.md +32 -0
  583. package/dist/prompts/roles/DEVELOPER.en.md +41 -0
  584. package/dist/prompts/roles/DEVELOPER.ru.md +41 -0
  585. package/dist/prompts/roles/DEVOPS.en.md +34 -0
  586. package/dist/prompts/roles/DEVOPS.ru.md +34 -0
  587. package/dist/prompts/roles/PM.en.md +32 -0
  588. package/dist/prompts/roles/PM.ru.md +32 -0
  589. package/dist/prompts/roles/QA.en.md +32 -0
  590. package/dist/prompts/roles/QA.ru.md +32 -0
  591. package/dist/prompts/roles/TITLE.ru.md +38 -0
  592. package/dist/prompts/subagents/explore.ru.md +23 -0
  593. package/dist/prompts/subagents/general.ru.md +19 -0
  594. package/dist/prompts/system/COMPRESSED_DIALOG.en.md +5 -0
  595. package/dist/prompts/system/COMPRESSED_DIALOG.ru.md +5 -0
  596. package/dist/prompts/system/INTERVIEW.en.md +18 -0
  597. package/dist/prompts/system/INTERVIEW.ru.md +18 -0
  598. package/dist/prompts/system/PARTICIPANTS_NOTICE.en.md +7 -0
  599. package/dist/prompts/system/PARTICIPANTS_NOTICE.ru.md +7 -0
  600. package/dist/prompts/system/ROLES_DESCRIPTION.en.md +16 -0
  601. package/dist/prompts/system/ROLES_DESCRIPTION.ru.md +16 -0
  602. package/dist/prompts/system/ROUTING.en.md +13 -0
  603. package/dist/prompts/system/ROUTING.md +6 -0
  604. package/dist/prompts/system/ROUTING.ru.md +13 -0
  605. package/dist/prompts/system/RULES.en.md +10 -0
  606. package/dist/prompts/system/RULES.md +10 -0
  607. package/dist/prompts/system/RULES.ru.md +10 -0
  608. package/dist/prompts/system/STICKY_NOTES.en.md +6 -0
  609. package/dist/prompts/system/STICKY_NOTES.ru.md +6 -0
  610. package/dist/prompts/system/SUMMARIZER.en.md +54 -0
  611. package/dist/prompts/system/SUMMARIZER.ru.md +54 -0
  612. package/dist/prompts/system/USER_CONTEXT.en.md +5 -0
  613. package/dist/prompts/system/USER_CONTEXT.ru.md +5 -0
  614. package/dist/providers/anthropic.d.ts +15 -0
  615. package/dist/providers/anthropic.d.ts.map +1 -0
  616. package/dist/providers/anthropic.js +378 -0
  617. package/dist/providers/anthropic.js.map +1 -0
  618. package/dist/providers/base.d.ts +72 -0
  619. package/dist/providers/base.d.ts.map +1 -0
  620. package/dist/providers/base.js +94 -0
  621. package/dist/providers/base.js.map +1 -0
  622. package/dist/providers/exceptions.d.ts +13 -0
  623. package/dist/providers/exceptions.d.ts.map +1 -0
  624. package/dist/providers/exceptions.js +25 -0
  625. package/dist/providers/exceptions.js.map +1 -0
  626. package/dist/providers/index.d.ts +7 -0
  627. package/dist/providers/index.d.ts.map +1 -0
  628. package/dist/providers/index.js +14 -0
  629. package/dist/providers/index.js.map +1 -0
  630. package/dist/providers/ollama.d.ts +15 -0
  631. package/dist/providers/ollama.d.ts.map +1 -0
  632. package/dist/providers/ollama.js +301 -0
  633. package/dist/providers/ollama.js.map +1 -0
  634. package/dist/providers/openai.d.ts +14 -0
  635. package/dist/providers/openai.d.ts.map +1 -0
  636. package/dist/providers/openai.js +292 -0
  637. package/dist/providers/openai.js.map +1 -0
  638. package/dist/queue/processor.d.ts +51 -0
  639. package/dist/queue/processor.d.ts.map +1 -0
  640. package/dist/queue/processor.js +363 -0
  641. package/dist/queue/processor.js.map +1 -0
  642. package/dist/server/app.d.ts +31 -0
  643. package/dist/server/app.d.ts.map +1 -0
  644. package/dist/server/app.js +573 -0
  645. package/dist/server/app.js.map +1 -0
  646. package/dist/server/chat.d.ts +11 -0
  647. package/dist/server/chat.d.ts.map +1 -0
  648. package/dist/server/chat.js +140 -0
  649. package/dist/server/chat.js.map +1 -0
  650. package/dist/server/routes/agents.d.ts +7 -0
  651. package/dist/server/routes/agents.d.ts.map +1 -0
  652. package/dist/server/routes/agents.js +91 -0
  653. package/dist/server/routes/agents.js.map +1 -0
  654. package/dist/server/routes/auth.d.ts +4 -0
  655. package/dist/server/routes/auth.d.ts.map +1 -0
  656. package/dist/server/routes/auth.js +82 -0
  657. package/dist/server/routes/auth.js.map +1 -0
  658. package/dist/server/routes/fs.d.ts +4 -0
  659. package/dist/server/routes/fs.d.ts.map +1 -0
  660. package/dist/server/routes/fs.js +67 -0
  661. package/dist/server/routes/fs.js.map +1 -0
  662. package/dist/server/routes/health.d.ts +3 -0
  663. package/dist/server/routes/health.d.ts.map +1 -0
  664. package/dist/server/routes/health.js +9 -0
  665. package/dist/server/routes/health.js.map +1 -0
  666. package/dist/server/routes/i18n.d.ts +3 -0
  667. package/dist/server/routes/i18n.d.ts.map +1 -0
  668. package/dist/server/routes/i18n.js +83 -0
  669. package/dist/server/routes/i18n.js.map +1 -0
  670. package/dist/server/routes/mcp.d.ts +15 -0
  671. package/dist/server/routes/mcp.d.ts.map +1 -0
  672. package/dist/server/routes/mcp.js +43 -0
  673. package/dist/server/routes/mcp.js.map +1 -0
  674. package/dist/server/routes/mcp.test.d.ts +2 -0
  675. package/dist/server/routes/mcp.test.d.ts.map +1 -0
  676. package/dist/server/routes/mcp.test.js +88 -0
  677. package/dist/server/routes/mcp.test.js.map +1 -0
  678. package/dist/server/routes/messages.d.ts +5 -0
  679. package/dist/server/routes/messages.d.ts.map +1 -0
  680. package/dist/server/routes/messages.js +122 -0
  681. package/dist/server/routes/messages.js.map +1 -0
  682. package/dist/server/routes/models.d.ts +6 -0
  683. package/dist/server/routes/models.d.ts.map +1 -0
  684. package/dist/server/routes/models.js +96 -0
  685. package/dist/server/routes/models.js.map +1 -0
  686. package/dist/server/routes/projects.d.ts +5 -0
  687. package/dist/server/routes/projects.d.ts.map +1 -0
  688. package/dist/server/routes/projects.js +92 -0
  689. package/dist/server/routes/projects.js.map +1 -0
  690. package/dist/server/routes/projects.test.d.ts +2 -0
  691. package/dist/server/routes/projects.test.d.ts.map +1 -0
  692. package/dist/server/routes/projects.test.js +65 -0
  693. package/dist/server/routes/projects.test.js.map +1 -0
  694. package/dist/server/routes/providers.d.ts +6 -0
  695. package/dist/server/routes/providers.d.ts.map +1 -0
  696. package/dist/server/routes/providers.js +118 -0
  697. package/dist/server/routes/providers.js.map +1 -0
  698. package/dist/server/routes/queue.d.ts +5 -0
  699. package/dist/server/routes/queue.d.ts.map +1 -0
  700. package/dist/server/routes/queue.js +64 -0
  701. package/dist/server/routes/queue.js.map +1 -0
  702. package/dist/server/routes/sessions.d.ts +5 -0
  703. package/dist/server/routes/sessions.d.ts.map +1 -0
  704. package/dist/server/routes/sessions.js +346 -0
  705. package/dist/server/routes/sessions.js.map +1 -0
  706. package/dist/server/routes/sessions.test.d.ts +2 -0
  707. package/dist/server/routes/sessions.test.d.ts.map +1 -0
  708. package/dist/server/routes/sessions.test.js +162 -0
  709. package/dist/server/routes/sessions.test.js.map +1 -0
  710. package/dist/server/routes/settings.d.ts +21 -0
  711. package/dist/server/routes/settings.d.ts.map +1 -0
  712. package/dist/server/routes/settings.js +125 -0
  713. package/dist/server/routes/settings.js.map +1 -0
  714. package/dist/server/routes/settings.test.d.ts +2 -0
  715. package/dist/server/routes/settings.test.d.ts.map +1 -0
  716. package/dist/server/routes/settings.test.js +358 -0
  717. package/dist/server/routes/settings.test.js.map +1 -0
  718. package/dist/server/routes/updates.d.ts +4 -0
  719. package/dist/server/routes/updates.d.ts.map +1 -0
  720. package/dist/server/routes/updates.js +82 -0
  721. package/dist/server/routes/updates.js.map +1 -0
  722. package/dist/server/serialize.d.ts +204 -0
  723. package/dist/server/serialize.d.ts.map +1 -0
  724. package/dist/server/serialize.js +133 -0
  725. package/dist/server/serialize.js.map +1 -0
  726. package/dist/sessions/auto-title.d.ts +5 -0
  727. package/dist/sessions/auto-title.d.ts.map +1 -0
  728. package/dist/sessions/auto-title.js +75 -0
  729. package/dist/sessions/auto-title.js.map +1 -0
  730. package/dist/sessions/manager.d.ts +81 -0
  731. package/dist/sessions/manager.d.ts.map +1 -0
  732. package/dist/sessions/manager.js +508 -0
  733. package/dist/sessions/manager.js.map +1 -0
  734. package/dist/sessions/manager.test.d.ts +2 -0
  735. package/dist/sessions/manager.test.d.ts.map +1 -0
  736. package/dist/sessions/manager.test.js +525 -0
  737. package/dist/sessions/manager.test.js.map +1 -0
  738. package/dist/storage/file-store.d.ts +27 -0
  739. package/dist/storage/file-store.d.ts.map +1 -0
  740. package/dist/storage/file-store.js +398 -0
  741. package/dist/storage/file-store.js.map +1 -0
  742. package/dist/storage/file-store.test.d.ts +2 -0
  743. package/dist/storage/file-store.test.d.ts.map +1 -0
  744. package/dist/storage/file-store.test.js +169 -0
  745. package/dist/storage/file-store.test.js.map +1 -0
  746. package/dist/storage/json-store.d.ts +19 -0
  747. package/dist/storage/json-store.d.ts.map +1 -0
  748. package/dist/storage/json-store.js +85 -0
  749. package/dist/storage/json-store.js.map +1 -0
  750. package/dist/storage/profile-store.d.ts +20 -0
  751. package/dist/storage/profile-store.d.ts.map +1 -0
  752. package/dist/storage/profile-store.js +147 -0
  753. package/dist/storage/profile-store.js.map +1 -0
  754. package/dist/storage/project-store.d.ts +23 -0
  755. package/dist/storage/project-store.d.ts.map +1 -0
  756. package/dist/storage/project-store.js +94 -0
  757. package/dist/storage/project-store.js.map +1 -0
  758. package/dist/storage/project-store.test.d.ts +2 -0
  759. package/dist/storage/project-store.test.d.ts.map +1 -0
  760. package/dist/storage/project-store.test.js +122 -0
  761. package/dist/storage/project-store.test.js.map +1 -0
  762. package/dist/storage/runtime-settings.d.ts +53 -0
  763. package/dist/storage/runtime-settings.d.ts.map +1 -0
  764. package/dist/storage/runtime-settings.js +95 -0
  765. package/dist/storage/runtime-settings.js.map +1 -0
  766. package/dist/update-checker.d.ts +9 -0
  767. package/dist/update-checker.d.ts.map +1 -0
  768. package/dist/update-checker.js +81 -0
  769. package/dist/update-checker.js.map +1 -0
  770. package/package.json +72 -0
  771. package/prompts/modes/act.md +18 -0
  772. package/prompts/modes/plan.md +20 -0
  773. package/prompts/modes/yolo.md +20 -0
  774. package/prompts/roles/ADMIN.en.md +33 -0
  775. package/prompts/roles/ADMIN.ru.md +33 -0
  776. package/prompts/roles/ANALYST.en.md +33 -0
  777. package/prompts/roles/ANALYST.ru.md +33 -0
  778. package/prompts/roles/ASSISTANT.en.md +38 -0
  779. package/prompts/roles/ASSISTANT.ru.md +38 -0
  780. package/prompts/roles/AUDITOR.en.md +33 -0
  781. package/prompts/roles/AUDITOR.ru.md +33 -0
  782. package/prompts/roles/DEVELOPER.en.md +42 -0
  783. package/prompts/roles/DEVELOPER.ru.md +42 -0
  784. package/prompts/roles/DEVOPS.en.md +35 -0
  785. package/prompts/roles/DEVOPS.ru.md +35 -0
  786. package/prompts/roles/PM.en.md +33 -0
  787. package/prompts/roles/PM.ru.md +33 -0
  788. package/prompts/roles/QA.en.md +33 -0
  789. package/prompts/roles/QA.ru.md +33 -0
  790. package/prompts/roles/TITLE.ru.md +30 -0
  791. package/prompts/subagents/explore.ru.md +23 -0
  792. package/prompts/subagents/general.ru.md +19 -0
  793. package/prompts/system/COMPRESSED_DIALOG.en.md +5 -0
  794. package/prompts/system/COMPRESSED_DIALOG.ru.md +5 -0
  795. package/prompts/system/GATEWAY.en.md +10 -0
  796. package/prompts/system/GATEWAY.ru.md +10 -0
  797. package/prompts/system/INTERVIEW.en.md +18 -0
  798. package/prompts/system/INTERVIEW.ru.md +18 -0
  799. package/prompts/system/PARTICIPANTS_NOTICE.en.md +7 -0
  800. package/prompts/system/PARTICIPANTS_NOTICE.ru.md +7 -0
  801. package/prompts/system/ROLES_DESCRIPTION.en.md +16 -0
  802. package/prompts/system/ROLES_DESCRIPTION.ru.md +16 -0
  803. package/prompts/system/ROUTING.en.md +13 -0
  804. package/prompts/system/ROUTING.md +6 -0
  805. package/prompts/system/ROUTING.ru.md +13 -0
  806. package/prompts/system/RULES.en.md +10 -0
  807. package/prompts/system/RULES.md +10 -0
  808. package/prompts/system/RULES.ru.md +10 -0
  809. package/prompts/system/STICKY_NOTES.en.md +6 -0
  810. package/prompts/system/STICKY_NOTES.ru.md +6 -0
  811. package/prompts/system/SUMMARIZER.en.md +54 -0
  812. package/prompts/system/SUMMARIZER.ru.md +54 -0
  813. package/prompts/system/USER_CONTEXT.en.md +5 -0
  814. package/prompts/system/USER_CONTEXT.ru.md +5 -0
@@ -0,0 +1,1651 @@
1
+ import { MessageRole, nowISO, ToolCapability, generateId, makeTextPart } from '@itphx/synth-shared';
2
+ import { join, isAbsolute, normalize, resolve } from 'node:path';
3
+ import { mkdir } from 'node:fs/promises';
4
+ import { DebugCollector } from '../debug.js';
5
+ import { ProviderFactory } from '../providers/base.js';
6
+ import { info, warning } from '../logger.js';
7
+ import { autoTitleSession } from '../sessions/auto-title.js';
8
+ import { ModelRouter } from './router/router.js';
9
+ import { ContentClassifier } from './router/content-classifier.js';
10
+ import { ProviderPool } from './router/provider-pool.js';
11
+ import { QualityChecker } from './router/quality-checker.js';
12
+ import { DictionaryStore } from './router/dictionary-store.js';
13
+ import { MicroPipeline } from './router/micro/index.js';
14
+ import { TaskClassifier } from './router/micro/task-classifier.js';
15
+ import { RulesModel, EmbeddingModel, MicroLlmModel } from './router/micro/models/index.js';
16
+ import { PermissionEvaluator } from './permission/evaluator.js';
17
+ import { PermissionApprovalManager } from './permission/approval.js';
18
+ import { emptyPermissionConfig } from './permission/derive.js';
19
+ import { getToolTrust } from './security/trust.js';
20
+ import { detectPromptInjection, applyPolicy, wrapContent, buildWarnLine } from './security/prompt-injection.js';
21
+ import { GatewayProvider, AuditLogger, RateLimiter, ObfuscationMapStore, obfuscateSecrets, maskSecret, PLACEHOLDER_PATTERN } from './gateway/index.js';
22
+ const MAX_DOOM_LOOP_COUNT = 3;
23
+ const DEFAULT_MAX_ITERATIONS = Number.POSITIVE_INFINITY;
24
+ function toCoreProviderConfig(shared, model) {
25
+ return {
26
+ name: shared.name,
27
+ type: shared.type,
28
+ url: shared.baseUrl || '',
29
+ apiKey: shared.apiKey || '',
30
+ model,
31
+ timeout: shared.timeout,
32
+ };
33
+ }
34
+ /**
35
+ * ChatOrchestrator — единый оркестратор обработки чат-сообщений.
36
+ * Предоставляет processMessage callback для QueueProcessor.
37
+ */
38
+ export class ChatOrchestrator {
39
+ _sessionManager;
40
+ _eventBus;
41
+ _contextBuilder;
42
+ _providerLoader;
43
+ _optimizer;
44
+ _modelPriceLoader;
45
+ _toolRegistry;
46
+ _agentRegistry;
47
+ _mcpManager;
48
+ _loadedMcpServers = new Set();
49
+ _cancellationTokens = new Map();
50
+ _router;
51
+ _routerConfig;
52
+ _microPipeline;
53
+ _contextConfig;
54
+ _projectStore;
55
+ _defaultWorkingDir;
56
+ _workspacesRoot;
57
+ _permissionConfig;
58
+ _approvalManager;
59
+ _defaultPlanMode;
60
+ _securityConfig;
61
+ _dictionaryStore;
62
+ _gatewayConfig;
63
+ _obfMapStore;
64
+ _gatewayAudit;
65
+ _gatewayRateLimiter;
66
+ _gatewayPatternStore;
67
+ _dataDir;
68
+ /** Путь к JSONL полного лога запросов/ответов LLM (передаётся в GatewayProvider). */
69
+ _gatewayPayloadLogPath;
70
+ /** Внешний audit-logger (backend/runner) — переиспользуется при live-включении gateway. */
71
+ _gatewayAuditExternal;
72
+ _providerPool;
73
+ /** Публичный доступ к реестру агентов (для сериализации modeApplicable). */
74
+ get agentRegistry() {
75
+ return this._agentRegistry;
76
+ }
77
+ constructor(options) {
78
+ this._sessionManager = options.sessionManager;
79
+ this._eventBus = options.eventBus;
80
+ this._contextBuilder = options.contextBuilder;
81
+ this._providerLoader = options.providerLoader;
82
+ this._optimizer = options.contextOptimizer ?? null;
83
+ this._modelPriceLoader = options.modelPriceLoader ?? null;
84
+ this._toolRegistry = options.toolRegistry ?? null;
85
+ this._agentRegistry = options.agentRegistry ?? null;
86
+ this._mcpManager = options.mcpManager ?? null;
87
+ this._routerConfig = options.routerConfig ?? null;
88
+ this._contextConfig = options.contextConfig ?? null;
89
+ this._projectStore = options.projectStore ?? null;
90
+ this._defaultWorkingDir = options.defaultWorkingDir ?? join(options.dataDir || '/var/synth/data', 'workspaces', 'default');
91
+ this._workspacesRoot = options.workspacesRoot ?? join(options.dataDir || '/var/synth/data', 'workspaces');
92
+ this._permissionConfig = options.permissionConfig ?? emptyPermissionConfig();
93
+ this._approvalManager = new PermissionApprovalManager(this._eventBus);
94
+ this._defaultPlanMode = options.defaultPlanMode ?? 'auto';
95
+ this._securityConfig = options.securityConfig
96
+ ?? { promptInjection: { enabled: true, wrapContent: true, mode: 'flag' } };
97
+ this._dataDir = options.dataDir || '/var/synth/data';
98
+ this._gatewayPayloadLogPath = options.gatewayPayloadLogPath
99
+ ?? join(options.dataDir || '/var/synth/data', 'audit', 'llm-payloads.jsonl');
100
+ // AD-036: LLM Gateway — включается только при gatewayConfig.enabled=true.
101
+ // ObfuscationMapStore живёт в сессии, RateLimiter и AuditLogger — общие.
102
+ this._gatewayAuditExternal = options.gatewayAuditLogger ?? null;
103
+ const gatewayConfig = options.gatewayConfig?.enabled ? options.gatewayConfig : null;
104
+ this._gatewayConfig = gatewayConfig;
105
+ if (gatewayConfig) {
106
+ this._obfMapStore = new ObfuscationMapStore(this._sessionManager);
107
+ this._gatewayAudit = options.gatewayAuditLogger ?? new AuditLogger(gatewayConfig.audit.logPath || join(options.dataDir || '/var/synth/data', 'audit', 'llm-gateway.jsonl'));
108
+ this._gatewayRateLimiter = new RateLimiter(gatewayConfig.rateLimit.userPerMinute, gatewayConfig.rateLimit.providerPerMinute);
109
+ }
110
+ else {
111
+ this._obfMapStore = null;
112
+ this._gatewayAudit = options.gatewayAuditLogger ?? null;
113
+ this._gatewayRateLimiter = null;
114
+ }
115
+ this._gatewayPatternStore = options.gatewayPatternStore ?? null;
116
+ // AD-036: суммаризация (ContextOptimizer) создаёт провайдера напрямую —
117
+ // передаём ему общую gateway-обвязку, чтобы эта точка тоже была защищена.
118
+ this._optimizer?.setGatewayHooks(gatewayConfig && this._obfMapStore && this._gatewayAudit && this._gatewayRateLimiter
119
+ ? {
120
+ config: gatewayConfig,
121
+ audit: this._gatewayAudit,
122
+ rateLimiter: this._gatewayRateLimiter,
123
+ obfMapStore: this._obfMapStore,
124
+ }
125
+ : null);
126
+ // DictionaryStore и ProviderPool создаём всегда (нужны микро-слою и роутеру)
127
+ const dictionaryStore = new DictionaryStore(options.dataDir || '/var/synth/data');
128
+ this._dictionaryStore = dictionaryStore;
129
+ // Фабрика обёртки для пула: у пула нет сессии, поэтому оборачиваем с пустой
130
+ // картой обфускации (защита от утечки секретов работает, карта не персистится).
131
+ // Для вызовов с сессией оркестратор дополнительно оборачивает через _wrapWithGateway.
132
+ const pool = new ProviderPool(options.providerLoader, gatewayConfig ?? undefined, gatewayConfig
133
+ ? (inner) => new GatewayProvider(inner, gatewayConfig, {
134
+ getMap: async () => ({}),
135
+ saveMap: async () => { },
136
+ getAudit: () => this._gatewayAudit,
137
+ getRateLimiter: () => this._gatewayRateLimiter,
138
+ payloadLogPath: this._gatewayPayloadLogPath,
139
+ sessionId: '',
140
+ userId: '',
141
+ })
142
+ : undefined);
143
+ this._providerPool = pool;
144
+ // AD-035: Micro-first pipeline — создаём всегда, не зависит от роутера
145
+ const microClassifier = new TaskClassifier(dictionaryStore);
146
+ const microModels = [
147
+ new RulesModel(microClassifier),
148
+ new EmbeddingModel(pool),
149
+ new MicroLlmModel(pool),
150
+ ];
151
+ this._microPipeline = new MicroPipeline(microClassifier, microModels);
152
+ // AD-034: Router — только если включён в конфиге
153
+ if (options.routerConfig && options.routerConfig.enabled) {
154
+ const classifier = new ContentClassifier(dictionaryStore);
155
+ const qualityChecker = new QualityChecker();
156
+ this._router = new ModelRouter(classifier, pool, qualityChecker, options.routerConfig);
157
+ }
158
+ else {
159
+ this._router = null;
160
+ }
161
+ }
162
+ /**
163
+ * AD-036: live-переключение LLM Gateway (runtime-настройка из UI).
164
+ * config === null/undefined или enabled:false → выключить (убрать обвязку).
165
+ * enabled:true → создать ObfuscationMapStore/AuditLogger/RateLimiter, обновить
166
+ * фабрику ProviderPool, обновить hooks суммаризации.
167
+ */
168
+ setGatewayConfig(config) {
169
+ const gatewayConfig = config?.enabled ? config : null;
170
+ this._gatewayConfig = gatewayConfig;
171
+ if (gatewayConfig) {
172
+ // Карта обфускации живёт в сессиях (Session.obfuscationMap) — не теряется,
173
+ // поэтому store не пересоздаём, если он уже есть.
174
+ this._obfMapStore = this._obfMapStore ?? new ObfuscationMapStore(this._sessionManager);
175
+ // Внешний audit-logger (backend/runner) переиспользуем; иначе создаём по пути runtime-конфига.
176
+ this._gatewayAudit = this._gatewayAuditExternal
177
+ ?? new AuditLogger(gatewayConfig.audit.logPath || join(this._dataDir, 'audit', 'llm-gateway.jsonl'));
178
+ // Лимиты могли поменяться — RateLimiter пересоздаём всегда.
179
+ this._gatewayRateLimiter = new RateLimiter(gatewayConfig.rateLimit.userPerMinute, gatewayConfig.rateLimit.providerPerMinute);
180
+ }
181
+ else {
182
+ this._obfMapStore = null;
183
+ this._gatewayAudit = null;
184
+ this._gatewayRateLimiter = null;
185
+ }
186
+ // AD-036: суммаризация (ContextOptimizer) — обновляем gateway-обвязку.
187
+ this._optimizer?.setGatewayHooks(gatewayConfig && this._obfMapStore && this._gatewayAudit && this._gatewayRateLimiter
188
+ ? {
189
+ config: gatewayConfig,
190
+ audit: this._gatewayAudit,
191
+ rateLimiter: this._gatewayRateLimiter,
192
+ obfMapStore: this._obfMapStore,
193
+ }
194
+ : null);
195
+ // AD-036: пул кешировал провайдеров без новой обёртки — сбрасываем кеш
196
+ // и обновляем фабрику (по образцу конструктора, с пустой картой обфускации).
197
+ this._providerPool?.setGateway(gatewayConfig, gatewayConfig
198
+ ? (inner) => new GatewayProvider(inner, gatewayConfig, {
199
+ getMap: async () => ({}),
200
+ saveMap: async () => { },
201
+ getAudit: () => this._gatewayAudit,
202
+ getRateLimiter: () => this._gatewayRateLimiter,
203
+ payloadLogPath: this._gatewayPayloadLogPath,
204
+ sessionId: '',
205
+ userId: '',
206
+ })
207
+ : null);
208
+ }
209
+ /** AD-036: включён ли LLM Gateway (runtime-тумблер / конфиг). */
210
+ isGatewayEnabled() {
211
+ return !!this._gatewayConfig;
212
+ }
213
+ /**
214
+ * AD-036: обфусцирует user-сообщение при сохранении в историю (до отправки в LLM).
215
+ * Карта обфускации сессии обновляется и сохраняется; в message.metadata.secrets
216
+ * встраиваются реальные значения для раскрытия в UI. Если gateway выключен или
217
+ * секретов не найдено — возвращает сообщение без изменений (обратная совместимость).
218
+ */
219
+ async obfuscateUserMessageForHistory(sessionId, message) {
220
+ if (!this._gatewayConfig || !this._obfMapStore)
221
+ return message;
222
+ try {
223
+ const map = await this._obfMapStore.get(sessionId);
224
+ const { text, map: newMap, found } = obfuscateSecrets(message.content, map);
225
+ if (found.length === 0)
226
+ return message;
227
+ await this._obfMapStore.set(sessionId, newMap);
228
+ // AD-036: аудит обфускации user-сообщения (секреты — только маской,
229
+ // плейсхолдеры — без значений). Не должен ронять обфускацию.
230
+ try {
231
+ await this._gatewayAudit?.append({
232
+ ts: nowISO(),
233
+ type: 'obfuscated',
234
+ sessionId,
235
+ userId: message.author || undefined,
236
+ provider: message.provider,
237
+ model: message.model,
238
+ secretsFound: found.map((s) => maskSecret(s)),
239
+ placeholders: Object.keys(newMap),
240
+ });
241
+ }
242
+ catch (e) {
243
+ warning('ORCHESTRATOR', `Ошибка аудита обфускации: ${e instanceof Error ? e.message : String(e)}`);
244
+ }
245
+ const metadata = { ...(message.metadata || {}) };
246
+ const secrets = { ...metadata.secrets };
247
+ for (const ph of Object.keys(newMap)) {
248
+ if (text.includes(ph))
249
+ secrets[ph] = newMap[ph];
250
+ }
251
+ if (Object.keys(secrets).length > 0)
252
+ metadata.secrets = secrets;
253
+ return { ...message, content: text, parts: [makeTextPart(text)], metadata };
254
+ }
255
+ catch (e) {
256
+ warning('ORCHESTRATOR', `Ошибка обфускации user-сообщения: ${e instanceof Error ? e.message : String(e)}`);
257
+ return message;
258
+ }
259
+ }
260
+ async _resolveWorkingDir(session) {
261
+ if (session.projectId && this._projectStore) {
262
+ try {
263
+ const project = await this._projectStore.load(session.projectId);
264
+ if (project?.workspace) {
265
+ // Абсолютный workspace — как есть (normalize); относительный —
266
+ // резолвим относительно workspacesRoot (AD-014).
267
+ return isAbsolute(project.workspace)
268
+ ? normalize(project.workspace)
269
+ : resolve(this._workspacesRoot, project.workspace);
270
+ }
271
+ }
272
+ catch {
273
+ // проект не загрузился — используем fallback
274
+ }
275
+ }
276
+ const dir = this._defaultWorkingDir;
277
+ await mkdir(dir, { recursive: true }).catch(() => { });
278
+ return dir;
279
+ }
280
+ /**
281
+ * AD-025/AD-027: добавляет в system prompt блоки режима Plan/Act и
282
+ * утверждённого плана. Вызывается при старте обработки и пересобирается
283
+ * после plan_enter/plan_exit в текущей итерации.
284
+ */
285
+ _buildPlanSystemPrompt(base, session, planMode, sessionMode, planApproved, planContent) {
286
+ const parts = [];
287
+ // AD-025: промпт текущего режима загружается из контекстных файлов
288
+ // (prompts/modes/{mode}.md, переопределяемые через dataDir/context/modes).
289
+ // Если файл не найден — fallback на встроенный текст ниже.
290
+ const language = session.settings.language || 'ru';
291
+ const modePrompt = this._contextConfig?.getModePrompt(sessionMode, language) ?? null;
292
+ if (modePrompt) {
293
+ parts.push(modePrompt);
294
+ }
295
+ else if (sessionMode === 'plan') {
296
+ parts.push('[MODE: PLAN]\n'
297
+ + 'Ты в режиме планирования: чтение и исследование разрешены, но запись/изменение файлов '
298
+ + 'заблокированы (единственное исключение — .synth/plans/*.md). Изучи задачу, составь план '
299
+ + 'и утверди его через plan_exit(plan="..."), чтобы перейти в режим act.');
300
+ }
301
+ if (planMode === 'auto') {
302
+ parts.push('[PLAN MODE: AUTO]\n'
303
+ + 'Если задача сложная, затрагивает несколько файлов или требует архитектурных решений — '
304
+ + 'вызови plan_enter перед изменениями. Для простых фиксов — делай сразу.');
305
+ }
306
+ else if (planMode === 'strict') {
307
+ if (planApproved) {
308
+ parts.push('[PLAN MODE: STRICT]\n'
309
+ + 'План утверждён — ты можешь вносить изменения в соответствии с ним.');
310
+ }
311
+ else {
312
+ parts.push('[PLAN MODE: STRICT]\n'
313
+ + 'Перед любым изменением файлов план обязателен: вызови plan_enter, составь план и утверди '
314
+ + 'его через plan_exit. До утверждения плана запись файлов заблокирована (чтение разрешено).');
315
+ }
316
+ }
317
+ const approvedPlan = planContent ?? session.planContent;
318
+ if (approvedPlan) {
319
+ parts.push(`[APPROVED PLAN]\n${approvedPlan}`);
320
+ }
321
+ if (parts.length === 0)
322
+ return base;
323
+ return `${base}\n\n${parts.join('\n\n')}`;
324
+ }
325
+ /**
326
+ * processMessage callback для QueueProcessor.
327
+ */
328
+ createProcessMessage() {
329
+ return async (session, message, signal, publishChunk) => {
330
+ return this._processMessage(session, message, signal, publishChunk);
331
+ };
332
+ }
333
+ async _processMessage(session, message, signal, publishChunk) {
334
+ const streamId = message.metadata?.stream_id || 'unknown';
335
+ const effectiveAgentRole = message.agentRole || session.settings.agentRole || 'assistant';
336
+ const author = message.author || 'unknown';
337
+ const workingDir = await this._resolveWorkingDir(session);
338
+ // AD-025: режим Plan/Act — runtime-состояние сессии + строгость из настроек
339
+ const planMode = session.settings.planMode ?? this._defaultPlanMode ?? 'auto';
340
+ let sessionMode = session.mode ?? 'act';
341
+ let planApproved = Boolean(session.planContent);
342
+ // AD-029: permissions — сессионный override приоритетнее глобального конфига.
343
+ // Конфиг может быть расширен «разрешить в сессии» (once:false) в процессе
344
+ // обработки, поэтому ссылка и эвалуатор пересоздаются.
345
+ let effectivePermissionConfig = session.settings.permission ?? this._permissionConfig;
346
+ let permissionEvaluator = new PermissionEvaluator(effectivePermissionConfig);
347
+ const agentDef = effectiveAgentRole ? this._agentRegistry?.get(effectiveAgentRole) : undefined;
348
+ const agentMaxSteps = agentDef?.maxSteps;
349
+ const maxIterations = (agentMaxSteps !== undefined && agentMaxSteps > 0)
350
+ ? agentMaxSteps
351
+ : DEFAULT_MAX_ITERATIONS;
352
+ const debugCollector = new DebugCollector(session.settings.debugEnabled);
353
+ // --- Обработка системных сообщений (суммаризация, шедулер, etc.) ---
354
+ if (message.role === MessageRole.SYSTEM && message.metadata?.type === 'summarization_request') {
355
+ return this._handleSummarization(session, message, signal, publishChunk, debugCollector, streamId);
356
+ }
357
+ if (message.role === MessageRole.SYSTEM && message.metadata?.type === 'debug_system_message') {
358
+ return this._handleDebugSystemMessage(session, message, signal, publishChunk, debugCollector, streamId);
359
+ }
360
+ // --- AD-035: Micro-first — пробуем ответить без LLM ---
361
+ if (this._microPipeline && session.settings.microFirst) {
362
+ const microResult = await this._microPipeline.handle({
363
+ userMessage: message.content,
364
+ language: session.settings.language,
365
+ sessionSettings: session.settings,
366
+ embedProvider: session.settings.embedProvider,
367
+ embedModel: session.settings.embedModel,
368
+ });
369
+ if (microResult.handled && microResult.microResult?.answer) {
370
+ // Микрослой уверен — возвращаем ответ без вызова LLM
371
+ const finalContent = microResult.microResult.answer;
372
+ const finalModel = `micro:${microResult.microResult.taskClass}`;
373
+ const finalUsage = {
374
+ inputTokens: microResult.microResult.usage?.inputTokens ?? 0,
375
+ outputTokens: microResult.microResult.usage?.outputTokens ?? 0,
376
+ totalTokens: (microResult.microResult.usage?.inputTokens ?? 0) + (microResult.microResult.usage?.outputTokens ?? 0),
377
+ };
378
+ publishChunk('text', { content: finalContent });
379
+ publishChunk('done', { stopped: true });
380
+ // Сохраняем сообщение ассистента
381
+ const microMetadata = {
382
+ stream_id: streamId,
383
+ micro_first: {
384
+ label: microResult.microResult.label,
385
+ confidence: microResult.microResult.confidence,
386
+ latencyMs: microResult.microResult.latencyMs,
387
+ signals: microResult.microResult.signals,
388
+ taskClass: microResult.microResult.taskClass,
389
+ },
390
+ };
391
+ const assistantMsg = {
392
+ id: generateId(),
393
+ role: MessageRole.ASSISTANT,
394
+ seq: 0,
395
+ origin: 'local',
396
+ parts: [makeTextPart(finalContent)],
397
+ content: finalContent,
398
+ createdAt: nowISO(),
399
+ disabled: false,
400
+ pinned: false,
401
+ hidden: false,
402
+ model: finalModel,
403
+ provider: 'micro',
404
+ usage: finalUsage,
405
+ agentRole: effectiveAgentRole,
406
+ metadata: microMetadata,
407
+ };
408
+ await this._sessionManager.addMessage(session.id, assistantMsg);
409
+ // Обновляем токены сессии
410
+ session.inputTokens += finalUsage.inputTokens;
411
+ session.outputTokens += finalUsage.outputTokens;
412
+ session.totalTokens += finalUsage.totalTokens;
413
+ // Авто-тайтл если это первое сообщение
414
+ if (session.messages.filter((m) => m.role === MessageRole.USER).length <= 1) {
415
+ try {
416
+ session.title = `Диалог — ${session.id.slice(0, 8)}`;
417
+ await this._sessionManager.saveSession(session);
418
+ }
419
+ catch {
420
+ // ok
421
+ }
422
+ }
423
+ info('MICRO', `Ответ через микро-слой: ${microResult.microResult.taskClass} (${microResult.microResult.latencyMs}ms, confidence=${microResult.microResult.confidence.toFixed(2)})`);
424
+ return {};
425
+ }
426
+ // Если handled=false — продолжаем обычный путь (router → LLM)
427
+ if (microResult.fallbackSignals?.length) {
428
+ debugCollector.addContext('micro_first', {
429
+ status: 'fallback',
430
+ signals: microResult.fallbackSignals,
431
+ taskClass: microResult.microResult?.taskClass ?? 'llm_task',
432
+ });
433
+ }
434
+ }
435
+ try {
436
+ // 1. Get provider (через роутер если доступен, иначе напрямую)
437
+ const routeResult = this._routeProvider(session, message);
438
+ if (!routeResult) {
439
+ const providerName = message.provider || session.settings.provider || '';
440
+ return {
441
+ error: `Провайдер ${providerName || 'не указан'} не найден или не настроен`,
442
+ errorType: 'provider_not_found',
443
+ canRetry: false,
444
+ };
445
+ }
446
+ const { provider, providerName, decision: routingDecision } = routeResult;
447
+ debugCollector.captureSessionInfo(session.id, provider.model, provider.name, {
448
+ provider_type: provider.type,
449
+ debug_enabled: session.settings.debugEnabled,
450
+ stream_enabled: session.settings.streamEnabled,
451
+ context_optimization: session.settings.contextOptimization,
452
+ });
453
+ // 2. Build context (сначала получить summary из сообщений)
454
+ const optimizedMessages = this._optimizer
455
+ ? this._optimizer.getMessagesForLlm(session)
456
+ : session.messages;
457
+ const summaryContent = optimizedMessages
458
+ .filter((m) => m.role === MessageRole.SUMMARY)
459
+ .map((m) => m.content)
460
+ .join('\n\n');
461
+ const systemPrompt = session.settings.systemPrompt
462
+ || await this._contextBuilder.buildSystemPrompt({
463
+ agentRole: effectiveAgentRole,
464
+ agentContextFile: agentDef?.contextFile,
465
+ historyMessages: session.messages,
466
+ userId: session.userId,
467
+ projectName: session.projectId,
468
+ language: session.settings.language,
469
+ showInterview: session.settings.showInterview,
470
+ stickyNotes: session.stickyNotes,
471
+ summaryContent: summaryContent || undefined,
472
+ });
473
+ // Добавляем инструкцию classify_conversation если routing включен (AD-034)
474
+ let finalSystemPrompt = systemPrompt;
475
+ if (this._router && session.settings.routingEnabled !== false) {
476
+ const lang = session.settings.language || 'ru';
477
+ const classifyInstruction = lang === 'ru'
478
+ ? '\n\n[CLASSIFICATION]\n\nКогда определишь характер задачи, вызови инструмент `classify_conversation` с категорией: coding (написание/изменение кода), research (анализ/исследование), или chat (общий разговор). Это поможет выбрать оптимальную модель для последующих запросов.'
479
+ : '\n\n[CLASSIFICATION]\n\nWhen you determine the nature of the task, call the `classify_conversation` tool with the category: coding (writing/modifying code), research (analysis/investigation), or chat (general conversation). This helps select the optimal model for subsequent requests.';
480
+ finalSystemPrompt = systemPrompt + classifyInstruction;
481
+ }
482
+ // AD-036: если включена обфускация — сообщаем модели о токенах ⟦SYNTH_SECRET_N⟧
483
+ if (this._gatewayConfig && this._contextBuilder) {
484
+ const lang = session.settings.language || 'ru';
485
+ const gatewayInstructions = this._contextBuilder.getGatewayInstructions(lang);
486
+ if (gatewayInstructions) {
487
+ finalSystemPrompt = `${finalSystemPrompt}\n\n${gatewayInstructions}`;
488
+ }
489
+ }
490
+ // AD-025/AD-027: блоки режима Plan/Act + утверждённый план
491
+ finalSystemPrompt = this._buildPlanSystemPrompt(finalSystemPrompt, session, planMode, sessionMode, planApproved);
492
+ // 3. Convert messages for LLM (без summary — они уже в system prompt)
493
+ const messagesForLlm = optimizedMessages.filter((m) => m.role !== MessageRole.SUMMARY);
494
+ const baseLlmMessages = ChatOrchestrator._sessionMessagesToLlm(messagesForLlm, effectiveAgentRole, author);
495
+ // 3.5. Load MCP tools for the session (дифференциально — только изменившиеся серверы)
496
+ const activeMcpServers = session.settings.mcpServers || [];
497
+ const active = new Set(activeMcpServers);
498
+ if (this._mcpManager && this._toolRegistry) {
499
+ const toRemove = [...this._loadedMcpServers].filter((s) => !active.has(s));
500
+ const toAdd = activeMcpServers.filter((s) => !this._loadedMcpServers.has(s));
501
+ for (const name of toRemove) {
502
+ try {
503
+ await this._mcpManager.deregisterTools(name, this._toolRegistry);
504
+ this._loadedMcpServers.delete(name);
505
+ }
506
+ catch (err) {
507
+ warning(`ORCHESTRATOR`, `Ошибка отключения MCP-сервера "${name}": ${err instanceof Error ? err.message : String(err)}`);
508
+ }
509
+ }
510
+ for (const name of toAdd) {
511
+ try {
512
+ await this._mcpManager.connectServer(name);
513
+ await this._mcpManager.registerTools(name, this._toolRegistry);
514
+ this._loadedMcpServers.add(name);
515
+ }
516
+ catch (err) {
517
+ warning(`ORCHESTRATOR`, `Ошибка загрузки MCP-сервера "${name}": ${err instanceof Error ? err.message : String(err)}`);
518
+ }
519
+ }
520
+ }
521
+ // 4. Get tools from registry, filtered by agent capabilities
522
+ let tools;
523
+ if (this._toolRegistry) {
524
+ if (this._agentRegistry && effectiveAgentRole) {
525
+ tools = this._agentRegistry.getToolsForAgent(effectiveAgentRole);
526
+ }
527
+ if (tools === undefined) {
528
+ // Агент не найден в реестре — отдаём только встроенные инструменты (без MCP)
529
+ const allNonMcp = Object.values(ToolCapability).filter((c) => c !== ToolCapability.MCP);
530
+ tools = this._toolRegistry.filterByCapabilities(allNonMcp);
531
+ }
532
+ else if (tools.length === 0) {
533
+ tools = [];
534
+ }
535
+ }
536
+ // 5. Create cancellation token
537
+ const cancelToken = {
538
+ cancelled: false,
539
+ cancel: () => {
540
+ cancelToken.cancelled = true;
541
+ },
542
+ };
543
+ this._cancellationTokens.set(streamId, cancelToken);
544
+ signal.addEventListener('abort', () => {
545
+ cancelToken.cancel();
546
+ }, { once: true });
547
+ // 6. Tool loop — stream LLM, execute tools, continue until no tool calls
548
+ let toolIteration = 0;
549
+ const currentMessages = [...baseLlmMessages];
550
+ const doomLoopTracker = new Map();
551
+ let finalContent = '';
552
+ const allReasoning = [];
553
+ const allIntermediateTexts = [];
554
+ let finalUsage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
555
+ let finalModel;
556
+ const allToolCalls = [];
557
+ let stopAfterDeny = false;
558
+ let denyStopReason;
559
+ while (toolIteration < maxIterations) {
560
+ if (cancelToken.cancelled)
561
+ break;
562
+ let accumulatedContent = '';
563
+ let accumulatedReasoning = '';
564
+ let toolCalls = [];
565
+ let chunkModel;
566
+ try {
567
+ for await (const chunk of provider.chatAsync(currentMessages, finalSystemPrompt, tools, debugCollector, cancelToken)) {
568
+ if (cancelToken.cancelled)
569
+ break;
570
+ if (chunk.isFinal) {
571
+ accumulatedContent = chunk.content || accumulatedContent;
572
+ }
573
+ else {
574
+ accumulatedContent += chunk.content;
575
+ }
576
+ if (chunk.reasoning)
577
+ accumulatedReasoning = chunk.reasoning;
578
+ if (chunk.usage)
579
+ finalUsage = chunk.usage;
580
+ if (chunk.model)
581
+ chunkModel = chunk.model;
582
+ if (chunk.toolCalls && chunk.toolCalls.length > 0) {
583
+ toolCalls = chunk.toolCalls;
584
+ }
585
+ // Stream UI chunks (content from all iterations; reasoning always)
586
+ if (toolIteration === 0) {
587
+ publishChunk('stream.chunk', {
588
+ stream_id: streamId,
589
+ content: chunk.isFinal ? '' : chunk.content,
590
+ reasoning: chunk.reasoning,
591
+ iteration: toolIteration,
592
+ is_final: chunk.isFinal,
593
+ agent_role: effectiveAgentRole,
594
+ model: chunkModel,
595
+ provider: providerName,
596
+ });
597
+ }
598
+ else {
599
+ publishChunk('stream.chunk', {
600
+ stream_id: streamId,
601
+ content: chunk.isFinal ? '' : chunk.content,
602
+ reasoning: chunk.reasoning,
603
+ iteration: toolIteration,
604
+ agent_role: effectiveAgentRole,
605
+ model: chunkModel,
606
+ provider: providerName,
607
+ });
608
+ }
609
+ }
610
+ }
611
+ catch (e) {
612
+ const errMsg = String(e);
613
+ warning('ORCHESTRATOR', `LLM stream error: ${errMsg}`);
614
+ if (accumulatedContent || accumulatedReasoning) {
615
+ await this._saveAssistantMessage(session.id, accumulatedContent, streamId, effectiveAgentRole, finalUsage, chunkModel, accumulatedReasoning, debugCollector, true, providerName);
616
+ }
617
+ this._cancellationTokens.delete(streamId);
618
+ return {
619
+ error: errMsg,
620
+ errorType: this._classifyError(errMsg),
621
+ canRetry: this._isRecoverable(errMsg),
622
+ };
623
+ }
624
+ if (cancelToken.cancelled) {
625
+ if (accumulatedContent || accumulatedReasoning) {
626
+ await this._saveAssistantMessage(session.id, accumulatedContent, streamId, effectiveAgentRole, finalUsage, chunkModel, accumulatedReasoning, debugCollector, true, providerName);
627
+ }
628
+ publishChunk('stream.cancelled', {
629
+ stream_id: streamId,
630
+ content: accumulatedContent,
631
+ });
632
+ this._cancellationTokens.delete(streamId);
633
+ return {};
634
+ }
635
+ finalModel = chunkModel ?? finalModel;
636
+ if (accumulatedReasoning) {
637
+ allReasoning.push({ text: accumulatedReasoning, iteration: toolIteration });
638
+ }
639
+ // No tool calls — final response
640
+ if (!toolCalls || toolCalls.length === 0) {
641
+ finalContent = accumulatedContent;
642
+ break;
643
+ }
644
+ if (accumulatedContent) {
645
+ allIntermediateTexts.push({ text: accumulatedContent, iteration: toolIteration });
646
+ }
647
+ // Tool calls detected — execute them
648
+ debugCollector.captureRawModelResponse(`[tool_calls iteration ${toolIteration}]: ${JSON.stringify(toolCalls)}`);
649
+ // Add assistant message with tool calls to currentMessages
650
+ currentMessages.push({
651
+ id: '',
652
+ role: 'assistant',
653
+ content: accumulatedContent || '',
654
+ usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 },
655
+ disabled: false,
656
+ pinned: false,
657
+ branchId: '',
658
+ toolUse: toolCalls,
659
+ agentRole: effectiveAgentRole,
660
+ });
661
+ // Execute each tool call
662
+ for (const tc of toolCalls) {
663
+ const tcId = tc.id || `call_${Date.now()}`;
664
+ const func = tc.function;
665
+ if (!func?.name)
666
+ continue;
667
+ const toolName = func.name;
668
+ let toolArgs;
669
+ if (typeof func.arguments === 'string') {
670
+ try {
671
+ toolArgs = JSON.parse(func.arguments);
672
+ }
673
+ catch {
674
+ toolArgs = {};
675
+ }
676
+ }
677
+ else {
678
+ toolArgs = func.arguments || {};
679
+ }
680
+ // Doom loop detection
681
+ const doomKey = `${toolName}:${JSON.stringify(toolArgs)}`;
682
+ const doomCount = (doomLoopTracker.get(doomKey) || 0) + 1;
683
+ doomLoopTracker.set(doomKey, doomCount);
684
+ if (doomCount >= MAX_DOOM_LOOP_COUNT) {
685
+ warning('ORCHESTRATOR', `Doom loop detected: ${toolName} called ${doomCount} times with same args`);
686
+ currentMessages.push({
687
+ id: '',
688
+ role: 'tool',
689
+ content: `Ошибка: инструмент "${toolName}" вызван ${doomCount} раз(а) с одинаковыми аргументами. Цикл прерван.`,
690
+ usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 },
691
+ disabled: false,
692
+ pinned: false,
693
+ branchId: '',
694
+ toolCallId: tcId,
695
+ });
696
+ continue;
697
+ }
698
+ const tcStartedAt = new Date().toISOString();
699
+ publishChunk('tool_call.started', {
700
+ stream_id: streamId,
701
+ session_id: session.id,
702
+ call_id: tcId,
703
+ name: toolName,
704
+ arguments: toolArgs,
705
+ iteration: toolIteration,
706
+ });
707
+ const toolDef = this._toolRegistry?.get(toolName);
708
+ let toolResult;
709
+ // AD-029: гранулярные permissions — проверяем перед выполнением тула.
710
+ // AD-025: учитываем текущий режим Plan/Act и строгость плана.
711
+ const permissionDecision = permissionEvaluator.check({
712
+ toolName,
713
+ params: toolArgs,
714
+ workingDir,
715
+ capabilities: toolDef?.capabilities,
716
+ sessionMode,
717
+ planMode,
718
+ planApproved,
719
+ mcpToolSettings: session.settings.mcpToolSettings,
720
+ });
721
+ let executeTool = permissionDecision.action === 'allow';
722
+ let deniedReason;
723
+ let userDenied = false;
724
+ if (permissionDecision.action === 'deny') {
725
+ deniedReason = permissionDecision.reason;
726
+ }
727
+ else if (permissionDecision.action === 'ask') {
728
+ const approval = await this._approvalManager.waitForDecision(session.id, {
729
+ approvalId: `approval_${tcId}`,
730
+ callId: tcId,
731
+ toolName,
732
+ arguments: toolArgs,
733
+ reason: permissionDecision.reason,
734
+ }, effectivePermissionConfig.askTimeoutMs);
735
+ if (approval.approved) {
736
+ executeTool = true;
737
+ // «Разрешить в сессии» (once:false) — добавляем allow-правило для
738
+ // тула в permission-конфиг сессии, чтобы не спрашивать повторно.
739
+ if (approval.once === false) {
740
+ effectivePermissionConfig = await this._grantSessionToolAllow(session, toolName);
741
+ permissionEvaluator = new PermissionEvaluator(effectivePermissionConfig);
742
+ }
743
+ }
744
+ else {
745
+ const why = approval.timeout
746
+ ? 'истекло время ожидания подтверждения'
747
+ : approval.noSubscribers
748
+ ? 'нет подключённого пользователя для подтверждения'
749
+ : 'отклонено пользователем';
750
+ deniedReason = `${permissionDecision.reason} (${why})`;
751
+ userDenied = !approval.timeout && !approval.noSubscribers;
752
+ }
753
+ }
754
+ if (!executeTool) {
755
+ this._eventBus.publish(session.id, 'permission.denied', {
756
+ session_id: session.id,
757
+ call_id: tcId,
758
+ tool: toolName,
759
+ arguments: toolArgs,
760
+ reason: deniedReason,
761
+ matched_rule: permissionDecision.matchedRule,
762
+ });
763
+ toolResult = {
764
+ content: `Permission denied: ${deniedReason}`,
765
+ isError: true,
766
+ metadata: {
767
+ permission: {
768
+ action: 'deny',
769
+ reason: deniedReason,
770
+ matched_rule: permissionDecision.matchedRule,
771
+ },
772
+ },
773
+ };
774
+ }
775
+ else {
776
+ if (toolDef) {
777
+ const parsed = toolDef.parameters.safeParse(toolArgs);
778
+ if (!parsed.success) {
779
+ toolResult = {
780
+ content: `Ошибка аргументов инструмента "${toolName}": ${parsed.error.issues.map(i => `${i.path.join('.') || 'root'}: ${i.message}`).join('; ')}`,
781
+ isError: true,
782
+ };
783
+ }
784
+ else {
785
+ try {
786
+ toolResult = await toolDef.execute(parsed.data, {
787
+ sessionId: session.id,
788
+ messageId: message.metadata?.stream_id || streamId,
789
+ abortSignal: signal,
790
+ agentRole: effectiveAgentRole,
791
+ workingDir,
792
+ dataDir: this._modelPriceLoader ? undefined : undefined,
793
+ extra: {
794
+ provider,
795
+ agentRegistry: this._agentRegistry,
796
+ sessionManager: this._sessionManager,
797
+ projectStore: this._projectStore ?? undefined,
798
+ workspacesRoot: this._workspacesRoot,
799
+ eventBus: this._eventBus,
800
+ contextOptimizer: this._optimizer ?? undefined,
801
+ callerAgentRole: effectiveAgentRole,
802
+ sessionSettings: {
803
+ temperature: session.settings.temperature,
804
+ maxTokens: session.settings.maxTokens,
805
+ },
806
+ parentSessionSettings: session.settings,
807
+ modelRouter: this._router ?? undefined,
808
+ routerConfig: this._routerConfig ?? undefined,
809
+ contextConfig: this._contextConfig ?? undefined,
810
+ securityConfig: this._securityConfig,
811
+ publish: (type, data) => publishChunk(type, data),
812
+ streamId,
813
+ sessionId: session.id,
814
+ toolRegistry: this._toolRegistry,
815
+ permissionConfig: effectivePermissionConfig,
816
+ },
817
+ });
818
+ }
819
+ catch (execError) {
820
+ toolResult = {
821
+ content: `Ошибка исполнения инструмента "${toolName}": ${String(execError)}`,
822
+ isError: true,
823
+ };
824
+ }
825
+ }
826
+ }
827
+ else {
828
+ toolResult = {
829
+ content: `Инструмент "${toolName}" не найден`,
830
+ isError: true,
831
+ };
832
+ }
833
+ }
834
+ publishChunk('tool_call.result', {
835
+ stream_id: streamId,
836
+ session_id: session.id,
837
+ call_id: tcId,
838
+ name: toolName,
839
+ result: toolResult,
840
+ iteration: toolIteration,
841
+ });
842
+ // IPI-защита: оборачиваем tool-контент по матрице доверия + детектируем
843
+ // подозрительные паттерны (флаг/sanitize/block по конфигу).
844
+ if (this._securityConfig.promptInjection.enabled && !toolResult.isError) {
845
+ const trustInfo = getToolTrust(toolName, toolArgs, workingDir, toolDef?.capabilities);
846
+ if (trustInfo) {
847
+ const piConfig = this._securityConfig.promptInjection;
848
+ const lang = session.settings.language || 'ru';
849
+ // Детекция по обоим словарям (ru+en) — веб-контент может быть на любом языке
850
+ const langs = lang === 'en' ? ['en', 'ru'] : ['ru', 'en'];
851
+ let detection = { suspicious: false, matches: [] };
852
+ for (const l of langs) {
853
+ const d = detectPromptInjection(toolResult.content, this._dictionaryStore, l);
854
+ if (d.suspicious) {
855
+ detection = { suspicious: true, matches: [...detection.matches, ...d.matches] };
856
+ }
857
+ }
858
+ const applied = applyPolicy(toolResult.content, piConfig.mode, detection);
859
+ if (applied.blocked) {
860
+ toolResult = {
861
+ content: `[BLOCKED] Результат инструмента "${toolName}" заблокирован: обнаружены признаки prompt injection (${detection.matches.slice(0, 5).join(', ')})`,
862
+ isError: true,
863
+ metadata: {
864
+ ...toolResult.metadata,
865
+ injection_suspicious: true,
866
+ injection_matches: detection.matches,
867
+ },
868
+ };
869
+ }
870
+ else {
871
+ const wrapped = piConfig.wrapContent
872
+ ? wrapContent(applied.content, trustInfo.source, trustInfo.attrs, trustInfo.trust)
873
+ : applied.content;
874
+ // IPI: предупреждение [WARN] ставится ПЕРЕД блоком [CONTENT | ...]
875
+ const content = detection.suspicious && piConfig.mode === 'flag'
876
+ ? `${buildWarnLine(detection.matches)}\n${wrapped}`
877
+ : wrapped;
878
+ toolResult = {
879
+ ...toolResult,
880
+ content,
881
+ metadata: {
882
+ ...toolResult.metadata,
883
+ ...(detection.suspicious
884
+ ? { injection_suspicious: true, injection_matches: detection.matches }
885
+ : {}),
886
+ },
887
+ };
888
+ }
889
+ }
890
+ }
891
+ // classify_conversation: сохраняем категорию в настройках сессии (AD-034)
892
+ if (toolName === 'classify_conversation' && !toolResult.isError) {
893
+ const cat = toolResult.metadata?.routingCategory || undefined;
894
+ if (cat && (cat === 'coding' || cat === 'chat' || cat === 'research')) {
895
+ await this._sessionManager.withLock(session.id, async (s) => {
896
+ s.settings.routingCategory = cat;
897
+ await this._sessionManager.saveSession(s);
898
+ });
899
+ this._eventBus.publish(session.id, 'session.routing_category', {
900
+ category: cat,
901
+ source: 'model',
902
+ });
903
+ }
904
+ }
905
+ // AD-025/AD-027: обновляем локальный режим после plan_enter/plan_exit,
906
+ // чтобы ограничения и system prompt применились к следующим тулам/итерациям.
907
+ if (!toolResult.isError && toolName === 'plan_enter') {
908
+ sessionMode = 'plan';
909
+ finalSystemPrompt = this._buildPlanSystemPrompt(finalSystemPrompt, session, planMode, sessionMode, planApproved);
910
+ }
911
+ else if (!toolResult.isError && toolName === 'plan_exit') {
912
+ const meta = (toolResult.metadata ?? {});
913
+ const planContent = typeof meta.plan_content === 'string' ? meta.plan_content : undefined;
914
+ if (planContent) {
915
+ planApproved = true;
916
+ sessionMode = 'act';
917
+ }
918
+ finalSystemPrompt = this._buildPlanSystemPrompt(finalSystemPrompt, session, planMode, sessionMode, planApproved, planContent);
919
+ }
920
+ allToolCalls.push({
921
+ name: toolName,
922
+ args: toolArgs,
923
+ id: tcId,
924
+ result: toolResult,
925
+ started_at: tcStartedAt,
926
+ completed_at: new Date().toISOString(),
927
+ iteration: toolIteration,
928
+ });
929
+ debugCollector.captureToolCall(toolName, toolArgs, toolResult);
930
+ currentMessages.push({
931
+ id: '',
932
+ role: 'tool',
933
+ content: toolResult.content,
934
+ usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 },
935
+ disabled: false,
936
+ pinned: false,
937
+ branchId: '',
938
+ toolCallId: tcId,
939
+ });
940
+ // AD-029: пользователь отклонил запрос (ask→deny) — прекращаем
941
+ // обработку: не продолжаем цикл LLM, но уже выполненные tool_result
942
+ // и промежуточные ответы остаются в истории (сохраняются ниже).
943
+ if (userDenied) {
944
+ stopAfterDeny = true;
945
+ denyStopReason = deniedReason;
946
+ break;
947
+ }
948
+ }
949
+ publishChunk('tool_call.loop', {
950
+ stream_id: streamId,
951
+ session_id: session.id,
952
+ iteration: toolIteration,
953
+ total_tool_calls: toolCalls.length,
954
+ });
955
+ toolIteration++;
956
+ if (stopAfterDeny)
957
+ break;
958
+ }
959
+ // 7. Handle max iterations exceeded
960
+ if (toolIteration >= maxIterations && !finalContent) {
961
+ finalContent = '(достигнут лимит итераций инструментов)';
962
+ }
963
+ // AD-029: пользователь отклонил ask — обработка завершена. Фиксируем
964
+ // причину в финальном сообщении (история tool_result уже собрана).
965
+ if (stopAfterDeny && !finalContent) {
966
+ finalContent = `Обработка остановлена: ${denyStopReason ?? 'пользователь отклонил запрос'}`;
967
+ }
968
+ // 7.5. Quality check + escalation (AD-034)
969
+ let qaPass;
970
+ let qaReason;
971
+ const escalation = this._router?.getEscalationConfig();
972
+ if (this._router && escalation?.enabled && routingDecision && finalContent) {
973
+ const qaResult = await this._router.checkQuality(finalContent, routingDecision, session.settings);
974
+ if (!qaResult.pass) {
975
+ qaPass = false;
976
+ qaReason = qaResult.reason;
977
+ // Эскалация на fallback-модель
978
+ const sessionEscalation = session.settings.routingEscalation;
979
+ const fallbackProvider = sessionEscalation?.fallbackProvider || escalation.fallbackProvider;
980
+ const fallbackModel = sessionEscalation?.fallbackModel || escalation.fallbackModel;
981
+ if (fallbackProvider && fallbackModel) {
982
+ const fbDecision = {
983
+ providerName: fallbackProvider,
984
+ modelName: fallbackModel,
985
+ reason: 'escalation_fallback',
986
+ strategy: 'default',
987
+ };
988
+ const fbProvider = this._router.getProvider(fbDecision);
989
+ if (fbProvider) {
990
+ // Перевызываем LLM с fallback-моделью (без стриминга в UI)
991
+ try {
992
+ const fbMessages = [
993
+ ...currentMessages.filter((m) => m.role !== 'assistant' || m.toolUse === undefined || m.toolUse.length === 0),
994
+ ];
995
+ const fbResponse = await fbProvider.chat(fbMessages, finalSystemPrompt, undefined, false);
996
+ if (fbResponse.content) {
997
+ finalContent = fbResponse.content;
998
+ qaPass = true;
999
+ qaReason = `Эскалация на ${fallbackProvider}/${fallbackModel}: ${qaResult.reason}`;
1000
+ if (fbResponse.usage)
1001
+ finalUsage = fbResponse.usage;
1002
+ if (fbResponse.model)
1003
+ finalModel = fbResponse.model;
1004
+ }
1005
+ }
1006
+ catch (fbErr) {
1007
+ warning('ORCHESTRATOR', `Fallback LLM call failed: ${fbErr}`);
1008
+ }
1009
+ }
1010
+ else {
1011
+ warning('ORCHESTRATOR', `Fallback provider/model not found: ${fallbackProvider}/${fallbackModel}`);
1012
+ }
1013
+ }
1014
+ }
1015
+ else {
1016
+ qaPass = true;
1017
+ qaReason = qaResult.reason;
1018
+ }
1019
+ // Публикуем событие quality check
1020
+ if (qaPass !== undefined) {
1021
+ const sessionAfterMsg = await this._sessionManager.getSession(session.id);
1022
+ const msgIndex = sessionAfterMsg
1023
+ ? sessionAfterMsg.messages.length
1024
+ : session.messages.length;
1025
+ this._eventBus.publish(session.id, 'message.quality_check', {
1026
+ qa_pass: qaPass,
1027
+ qa_reason: qaReason,
1028
+ message_index: msgIndex,
1029
+ });
1030
+ }
1031
+ }
1032
+ // 8. Save final assistant message
1033
+ const reasoningJoined = allReasoning.map((r) => r.text).join('\n\n---\n\n');
1034
+ const savedContent = await this._saveAssistantMessage(session.id, finalContent, streamId, effectiveAgentRole, finalUsage, finalModel, reasoningJoined, debugCollector, false, providerName, MessageRole.ASSISTANT, undefined, false, allToolCalls, allIntermediateTexts, qaPass, qaReason);
1035
+ // Получаем актуальную сессию после сохранения
1036
+ const updatedSession = await this._sessionManager.getSession(session.id);
1037
+ const doneData = {
1038
+ stream_id: streamId,
1039
+ content: savedContent,
1040
+ message_index: (updatedSession?.messages.length ?? session.messages.length + 1) - 1,
1041
+ pending_count: Math.max(0, (updatedSession?.pendingMessages.length ?? 1) - 1),
1042
+ model: finalModel,
1043
+ provider: providerName,
1044
+ usage: finalUsage,
1045
+ reasoning_blocks: allReasoning.length > 0 ? allReasoning : undefined,
1046
+ intermediate_text_blocks: allIntermediateTexts.length > 0 ? allIntermediateTexts : undefined,
1047
+ };
1048
+ // AD-036: проброс secrets в real-time событие — UI раскрывает плейсхолдеры
1049
+ // без перезагрузки списка сообщений (см. transportStore/chatStore).
1050
+ if (finalContent) {
1051
+ const secrets = await this._getAssistantSecrets(session.id, savedContent);
1052
+ if (Object.keys(secrets).length > 0) {
1053
+ doneData.metadata = { secrets };
1054
+ }
1055
+ }
1056
+ if (stopAfterDeny) {
1057
+ doneData.stopped_by_deny = true;
1058
+ doneData.deny_reason = denyStopReason;
1059
+ }
1060
+ const debugInfo = debugCollector.getDebugInfo();
1061
+ if (debugInfo) {
1062
+ doneData.debug_info = debugInfo;
1063
+ }
1064
+ publishChunk('stream.done', doneData);
1065
+ // 8.5. Auto-rename session on first exchange
1066
+ if (updatedSession) {
1067
+ const userMsgCount = updatedSession.messages.filter((m) => m.role === MessageRole.USER && !m.metadata?.synthetic).length;
1068
+ if (userMsgCount === 1) {
1069
+ autoTitleSession(updatedSession, this._sessionManager, provider).catch(() => { });
1070
+ }
1071
+ }
1072
+ // 9. Check context optimization triggers
1073
+ if (this._optimizer && updatedSession) {
1074
+ const optSession = updatedSession;
1075
+ // Проверить скользящее окно
1076
+ if (optSession.settings.contextOptimization === 'sliding_window') {
1077
+ const swResult = this._optimizer.shouldApplySlidingWindow(optSession);
1078
+ if (swResult.triggered) {
1079
+ let disabledIndices = [];
1080
+ await this._sessionManager.withLock(optSession.id, async (s) => {
1081
+ const applied = this._optimizer.applySlidingWindow(s);
1082
+ disabledIndices = applied.disabledIndices;
1083
+ await this._sessionManager.saveSession(s);
1084
+ });
1085
+ this._eventBus.publish(optSession.id, 'context.sliding_window_applied', {
1086
+ reason: swResult.reason,
1087
+ trigger_type: swResult.reason,
1088
+ disabled_indices: disabledIndices,
1089
+ });
1090
+ }
1091
+ }
1092
+ // Проверить суммаризацию
1093
+ if (optSession.settings.contextOptimization === 'summarization') {
1094
+ const sumResult = this._optimizer.shouldSummarize(optSession);
1095
+ if (sumResult.triggered) {
1096
+ await this._sessionManager.withLock(optSession.id, async (s) => {
1097
+ s.summarizationPending = true;
1098
+ await this._sessionManager.saveSession(s);
1099
+ });
1100
+ this._eventBus.publish(optSession.id, 'context.summarization_pending', {
1101
+ reason: sumResult.reason,
1102
+ current_tokens: sumResult.currentTokens,
1103
+ threshold: sumResult.threshold,
1104
+ user_count: sumResult.userCount,
1105
+ });
1106
+ }
1107
+ }
1108
+ // Обновить canSummarize после всех мутаций
1109
+ await this._sessionManager.withLock(optSession.id, async (s) => {
1110
+ s.canSummarize = this._optimizer.canSummarize(s);
1111
+ await this._sessionManager.saveSession(s);
1112
+ });
1113
+ // Уведомить UI об изменении сессии
1114
+ const updatedSession2 = await this._sessionManager.getSession(optSession.id);
1115
+ if (updatedSession2) {
1116
+ this._eventBus.publish(optSession.id, 'session.updated', {
1117
+ session_id: optSession.id,
1118
+ can_summarize: updatedSession2.canSummarize,
1119
+ input_tokens: updatedSession2.inputTokens,
1120
+ output_tokens: updatedSession2.outputTokens,
1121
+ total_tokens: updatedSession2.totalTokens,
1122
+ cache_read_tokens: updatedSession2.cacheReadTokens,
1123
+ cache_write_tokens: updatedSession2.cacheWriteTokens,
1124
+ reasoning_tokens: updatedSession2.reasoningTokens,
1125
+ input_cost: updatedSession2.inputCost,
1126
+ output_cost: updatedSession2.outputCost,
1127
+ cache_read_cost: updatedSession2.cacheReadCost,
1128
+ cache_write_cost: updatedSession2.cacheWriteCost,
1129
+ });
1130
+ }
1131
+ }
1132
+ this._cancellationTokens.delete(streamId);
1133
+ return {};
1134
+ }
1135
+ catch (e) {
1136
+ const errMsg = String(e);
1137
+ warning('ORCHESTRATOR', `Unexpected error: ${errMsg}`);
1138
+ return {
1139
+ error: errMsg,
1140
+ errorType: 'internal',
1141
+ canRetry: false,
1142
+ };
1143
+ }
1144
+ }
1145
+ cancel(streamId) {
1146
+ const token = this._cancellationTokens.get(streamId);
1147
+ if (token)
1148
+ token.cancel();
1149
+ }
1150
+ async _handleDebugSystemMessage(session, message, signal, publishChunk, debugCollector, streamId) {
1151
+ const providerName = message.provider || session.settings.provider || '';
1152
+ const provider = this._getProvider(providerName, session);
1153
+ if (!provider) {
1154
+ return {
1155
+ error: `Провайдер ${providerName || 'не указан'} не найден или не настроен`,
1156
+ errorType: 'provider_not_found',
1157
+ canRetry: false,
1158
+ };
1159
+ }
1160
+ debugCollector.captureSessionInfo(session.id, provider.model, providerName, {
1161
+ provider_type: provider.type,
1162
+ debug_enabled: session.settings.debugEnabled,
1163
+ context_optimization: 'debug_system_message',
1164
+ });
1165
+ const lang = session.settings.language || 'ru';
1166
+ const systemPrompt = lang === 'ru'
1167
+ ? 'Ты получил отладочное системное сообщение. Ответь коротко, подтвердив, что ты его получил и обработал. Опиши свою текущую роль и модель.'
1168
+ : 'You received a debug system message. Respond briefly, confirming you received and processed it. Describe your current role and model.';
1169
+ const llmMessages = [
1170
+ { id: '', role: 'system', content: systemPrompt, usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 }, disabled: false, pinned: false, branchId: '' },
1171
+ { id: '', role: 'user', content: lang === 'ru' ? 'Привет! Это отладочное системное сообщение. Как ты здесь оказался?' : 'Hi! This is a debug system message. How did you get here?', usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 }, disabled: false, pinned: false, branchId: '' },
1172
+ ];
1173
+ let accumulatedContent = '';
1174
+ let accumulatedReasoning = '';
1175
+ let finalUsage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
1176
+ let finalModel;
1177
+ const cancelToken = {
1178
+ cancelled: false,
1179
+ cancel: () => { cancelToken.cancelled = true; },
1180
+ };
1181
+ this._cancellationTokens.set(streamId, cancelToken);
1182
+ signal.addEventListener('abort', () => cancelToken.cancel(), { once: true });
1183
+ try {
1184
+ for await (const chunk of provider.chatAsync(llmMessages, systemPrompt, undefined, debugCollector, cancelToken)) {
1185
+ if (cancelToken.cancelled)
1186
+ break;
1187
+ if (chunk.isFinal)
1188
+ accumulatedContent = chunk.content;
1189
+ else
1190
+ accumulatedContent += chunk.content;
1191
+ if (chunk.usage)
1192
+ finalUsage = chunk.usage;
1193
+ if (chunk.model)
1194
+ finalModel = chunk.model;
1195
+ if (chunk.reasoning)
1196
+ accumulatedReasoning = chunk.reasoning;
1197
+ publishChunk('stream.chunk', {
1198
+ stream_id: streamId,
1199
+ content: chunk.isFinal ? '' : chunk.content,
1200
+ reasoning: chunk.reasoning,
1201
+ is_final: chunk.isFinal,
1202
+ agent_role: 'debug',
1203
+ model: finalModel,
1204
+ provider: providerName,
1205
+ });
1206
+ }
1207
+ }
1208
+ catch (e) {
1209
+ warning('ORCHESTRATOR', `Debug system message stream error: ${e}`);
1210
+ return { error: String(e), errorType: this._classifyError(String(e)), canRetry: this._isRecoverable(String(e)) };
1211
+ }
1212
+ if (cancelToken.cancelled) {
1213
+ publishChunk('stream.cancelled', { stream_id: streamId, content: accumulatedContent });
1214
+ this._cancellationTokens.delete(streamId);
1215
+ return {};
1216
+ }
1217
+ // Сохранить debug-сообщение (без message.added — UI получит его через stream.done)
1218
+ await this._saveAssistantMessage(session.id, accumulatedContent, streamId, 'debug', finalUsage, finalModel, accumulatedReasoning, debugCollector, false, providerName, MessageRole.DEBUG, undefined, true);
1219
+ const updatedSession = await this._sessionManager.getSession(session.id);
1220
+ publishChunk('stream.done', {
1221
+ stream_id: streamId,
1222
+ content: accumulatedContent,
1223
+ message_index: (updatedSession?.messages.length ?? session.messages.length + 1) - 1,
1224
+ pending_count: Math.max(0, (updatedSession?.pendingMessages.length ?? 1) - 1),
1225
+ model: finalModel,
1226
+ provider: providerName,
1227
+ usage: finalUsage,
1228
+ metadata: { type: 'debug_system_message' },
1229
+ });
1230
+ this._cancellationTokens.delete(streamId);
1231
+ return {};
1232
+ }
1233
+ async _handleSummarization(session, message, signal, publishChunk, debugCollector, streamId) {
1234
+ if (!this._optimizer) {
1235
+ return { error: 'ContextOptimizer not available', errorType: 'internal', canRetry: false };
1236
+ }
1237
+ const lang = session.settings.language || 'ru';
1238
+ let prep;
1239
+ try {
1240
+ prep = this._optimizer.prepareSummarizationForOrchestrator(session, lang);
1241
+ }
1242
+ catch (e) {
1243
+ return { error: String(e), errorType: 'summarization_prep_failed', canRetry: false };
1244
+ }
1245
+ const provider = prep.provider;
1246
+ const providerName = message.provider || session.settings.provider || '';
1247
+ debugCollector.captureSessionInfo(session.id, provider.model, providerName, {
1248
+ provider_type: provider.type,
1249
+ debug_enabled: session.settings.debugEnabled,
1250
+ context_optimization: 'summarization',
1251
+ });
1252
+ // Стрим от LLM суммаризатора
1253
+ let accumulatedContent = '';
1254
+ let accumulatedReasoning = '';
1255
+ let finalUsage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
1256
+ let finalModel;
1257
+ const cancelToken = {
1258
+ cancelled: false,
1259
+ cancel: () => { cancelToken.cancelled = true; },
1260
+ };
1261
+ this._cancellationTokens.set(streamId, cancelToken);
1262
+ signal.addEventListener('abort', () => cancelToken.cancel(), { once: true });
1263
+ try {
1264
+ for await (const chunk of provider.chatAsync(prep.llmMessages, prep.summarizerPrompt, undefined, debugCollector, cancelToken)) {
1265
+ if (cancelToken.cancelled)
1266
+ break;
1267
+ if (chunk.isFinal)
1268
+ accumulatedContent = chunk.content;
1269
+ else
1270
+ accumulatedContent += chunk.content;
1271
+ if (chunk.usage)
1272
+ finalUsage = chunk.usage;
1273
+ if (chunk.model)
1274
+ finalModel = chunk.model;
1275
+ if (chunk.reasoning)
1276
+ accumulatedReasoning = chunk.reasoning;
1277
+ publishChunk('stream.chunk', {
1278
+ stream_id: streamId,
1279
+ content: chunk.isFinal ? '' : chunk.content,
1280
+ reasoning: chunk.reasoning,
1281
+ is_final: chunk.isFinal,
1282
+ agent_role: 'summary',
1283
+ model: finalModel,
1284
+ provider: providerName,
1285
+ });
1286
+ }
1287
+ }
1288
+ catch (e) {
1289
+ warning('ORCHESTRATOR', `Summarization stream error: ${e}`);
1290
+ return { error: String(e), errorType: this._classifyError(String(e)), canRetry: this._isRecoverable(String(e)) };
1291
+ }
1292
+ if (cancelToken.cancelled) {
1293
+ publishChunk('stream.cancelled', { stream_id: streamId, content: accumulatedContent });
1294
+ this._cancellationTokens.delete(streamId);
1295
+ return {};
1296
+ }
1297
+ // Сохранить summary-сообщение (без message.added — UI получит его через stream.done)
1298
+ await this._saveAssistantMessage(session.id, accumulatedContent, streamId, 'summary', finalUsage, finalModel, accumulatedReasoning, debugCollector, false, providerName, MessageRole.SUMMARY, prep.indices, true);
1299
+ // Отключить засуммаризированные сообщения
1300
+ await this._sessionManager.withLock(session.id, async (s) => {
1301
+ for (const idx of prep.indices) {
1302
+ if (idx >= 0 && idx < s.messages.length && !s.messages[idx].pinned) {
1303
+ s.messages[idx].disabled = true;
1304
+ }
1305
+ }
1306
+ await this._sessionManager.saveSession(s);
1307
+ });
1308
+ const updatedSession = await this._sessionManager.getSession(session.id);
1309
+ const doneData = {
1310
+ stream_id: streamId,
1311
+ content: accumulatedContent,
1312
+ message_index: (updatedSession?.messages.length ?? session.messages.length + 1) - 1,
1313
+ pending_count: Math.max(0, (updatedSession?.pendingMessages.length ?? 1) - 1),
1314
+ model: finalModel,
1315
+ provider: providerName,
1316
+ usage: finalUsage,
1317
+ metadata: { type: 'summary', indices: prep.indices },
1318
+ };
1319
+ publishChunk('stream.done', doneData);
1320
+ // Обновить canSummarize
1321
+ if (updatedSession) {
1322
+ await this._sessionManager.withLock(session.id, async (s) => {
1323
+ s.canSummarize = this._optimizer.canSummarize(s);
1324
+ await this._sessionManager.saveSession(s);
1325
+ });
1326
+ const freshSession = await this._sessionManager.getSession(session.id);
1327
+ this._eventBus.publish(session.id, 'session.updated', {
1328
+ session_id: session.id,
1329
+ summarization_pending: false,
1330
+ can_summarize: freshSession?.canSummarize ?? false,
1331
+ input_tokens: freshSession?.inputTokens ?? 0,
1332
+ output_tokens: freshSession?.outputTokens ?? 0,
1333
+ total_tokens: freshSession?.totalTokens ?? 0,
1334
+ cache_read_tokens: freshSession?.cacheReadTokens ?? 0,
1335
+ cache_write_tokens: freshSession?.cacheWriteTokens ?? 0,
1336
+ reasoning_tokens: freshSession?.reasoningTokens ?? 0,
1337
+ input_cost: freshSession?.inputCost ?? 0,
1338
+ output_cost: freshSession?.outputCost ?? 0,
1339
+ cache_read_cost: freshSession?.cacheReadCost ?? 0,
1340
+ cache_write_cost: freshSession?.cacheWriteCost ?? 0,
1341
+ });
1342
+ }
1343
+ this._cancellationTokens.delete(streamId);
1344
+ return {};
1345
+ }
1346
+ _getProvider(providerName, session) {
1347
+ const modelName = session.settings.model || '';
1348
+ const sharedConfig = this._providerLoader(providerName);
1349
+ if (!sharedConfig)
1350
+ return null;
1351
+ try {
1352
+ const provider = ProviderFactory.create(providerName, toCoreProviderConfig(sharedConfig, modelName || sharedConfig.defaultModel || ''), session.settings.temperature);
1353
+ return this._wrapWithGateway(provider, session);
1354
+ }
1355
+ catch (e) {
1356
+ warning('ORCHESTRATOR', `Failed to create provider ${providerName}: ${e}`);
1357
+ return null;
1358
+ }
1359
+ }
1360
+ /**
1361
+ * AD-036: оборачивает провайдер в GatewayProvider с привязкой к сессии.
1362
+ * Если gateway выключен — возвращает провайдер как есть (обратная совместимость).
1363
+ */
1364
+ _wrapWithGateway(provider, session) {
1365
+ if (!this._gatewayConfig)
1366
+ return provider;
1367
+ const patternStore = this._gatewayPatternStore;
1368
+ return new GatewayProvider(provider, this._gatewayConfig, {
1369
+ getMap: () => this._obfMapStore.get(session.id),
1370
+ saveMap: (map) => this._obfMapStore.set(session.id, map),
1371
+ getAudit: () => this._gatewayAudit,
1372
+ getRateLimiter: () => this._gatewayRateLimiter,
1373
+ getPatterns: patternStore ? () => patternStore.getPatterns() : undefined,
1374
+ payloadLogPath: this._gatewayPayloadLogPath,
1375
+ sessionId: session.id,
1376
+ userId: session.userId ?? '',
1377
+ });
1378
+ }
1379
+ _getEffectiveModel(session, providerName) {
1380
+ return session.settings.model || this._providerLoader(providerName)?.defaultModel || '';
1381
+ }
1382
+ /**
1383
+ * Выбор провайдера и модели через роутер (AD-034).
1384
+ * Если роутер недоступен — fallback на _getProvider().
1385
+ */
1386
+ _routeProvider(session, message) {
1387
+ if (this._router && session.settings.routingEnabled !== false) {
1388
+ const toolCallNames = message.toolCalls?.map((tc) => {
1389
+ const func = tc.function;
1390
+ return func?.name || '';
1391
+ }).filter(Boolean);
1392
+ const decision = this._router.route({
1393
+ sessionSettings: session.settings,
1394
+ userMessage: message.content,
1395
+ toolCalls: toolCallNames,
1396
+ });
1397
+ let provider = this._router.getProvider(decision);
1398
+ if (provider) {
1399
+ provider = this._wrapWithGateway(provider, session);
1400
+ return {
1401
+ provider,
1402
+ providerName: decision.providerName,
1403
+ modelName: decision.modelName,
1404
+ decision,
1405
+ };
1406
+ }
1407
+ // Fallback: если decision не содержит валидного провайдера/модели
1408
+ // (например, категория не имеет маппинга в routingContent),
1409
+ // используем стандартный _getProvider() для провайдера сессии
1410
+ const fallbackName = session.settings.provider || '';
1411
+ provider = this._getProvider(fallbackName, session);
1412
+ if (provider) {
1413
+ return {
1414
+ provider,
1415
+ providerName: fallbackName,
1416
+ modelName: this._getEffectiveModel(session, fallbackName),
1417
+ decision,
1418
+ };
1419
+ }
1420
+ }
1421
+ // Fallback: старый метод (если роутер недоступен или все пути выше не сработали)
1422
+ const providerName = message.provider || session.settings.provider || '';
1423
+ const provider = this._getProvider(providerName, session);
1424
+ if (!provider)
1425
+ return null;
1426
+ return {
1427
+ provider,
1428
+ providerName,
1429
+ modelName: provider.model,
1430
+ };
1431
+ }
1432
+ static _sessionMessagesToLlm(messages, currentAgentRole, currentAuthor) {
1433
+ const result = [];
1434
+ for (const msg of messages) {
1435
+ if (msg.disabled || msg.hidden)
1436
+ continue;
1437
+ const role = msg.role;
1438
+ if (role === MessageRole.INFO)
1439
+ continue;
1440
+ const isOwnMessage = role === MessageRole.TOOL ||
1441
+ (role === MessageRole.ASSISTANT && msg.agentRole === currentAgentRole) ||
1442
+ (role === MessageRole.USER && msg.author === currentAuthor);
1443
+ let content;
1444
+ let llmRole;
1445
+ if (isOwnMessage) {
1446
+ content = msg.content;
1447
+ llmRole = role;
1448
+ }
1449
+ else {
1450
+ llmRole = 'user';
1451
+ if (msg.agentRole) {
1452
+ content = `[${msg.agentRole}]: ${msg.content}`;
1453
+ }
1454
+ else if (msg.author) {
1455
+ content = `{${msg.author}}: ${msg.content}`;
1456
+ }
1457
+ else {
1458
+ content = `[anonymous]: ${msg.content}`;
1459
+ }
1460
+ }
1461
+ result.push({
1462
+ id: '',
1463
+ role: llmRole,
1464
+ content,
1465
+ usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 },
1466
+ disabled: false,
1467
+ pinned: false,
1468
+ branchId: '',
1469
+ toolUse: isOwnMessage ? msg.toolCalls : undefined,
1470
+ toolCallId: isOwnMessage ? msg.toolCallId : undefined,
1471
+ agentRole: msg.agentRole,
1472
+ });
1473
+ }
1474
+ return result;
1475
+ }
1476
+ /**
1477
+ * AD-036: возвращает реальные значения секретов для плейсхолдеров
1478
+ * ⟦SYNTH_SECRET_N⟧ в тексте сообщения (из карты обфускации сессии).
1479
+ * Пустой объект если карты нет, плейсхолдеров нет или gateway выключен.
1480
+ */
1481
+ async _getAssistantSecrets(sessionId, content) {
1482
+ if (!content || !this._obfMapStore)
1483
+ return {};
1484
+ try {
1485
+ const obfMap = await this._obfMapStore.get(sessionId);
1486
+ if (Object.keys(obfMap).length === 0)
1487
+ return {};
1488
+ const found = new Set();
1489
+ let match;
1490
+ const placeholderRe = new RegExp(PLACEHOLDER_PATTERN.source, 'g');
1491
+ while ((match = placeholderRe.exec(content)) !== null) {
1492
+ found.add(match[0]);
1493
+ }
1494
+ const secrets = {};
1495
+ for (const ph of found) {
1496
+ if (ph in obfMap)
1497
+ secrets[ph] = obfMap[ph];
1498
+ }
1499
+ return secrets;
1500
+ }
1501
+ catch (e) {
1502
+ warning('ORCHESTRATOR', `Ошибка раскрытия секретов в metadata: ${e instanceof Error ? e.message : String(e)}`);
1503
+ return {};
1504
+ }
1505
+ }
1506
+ async _saveAssistantMessage(sessionId, content, streamId, agentRole, usage, model, reasoning, debugCollector, isCancelled, provider, role = MessageRole.ASSISTANT, summaryOf, skipEvent = false, toolResults, intermediateTextBlocks, qaPass, qaReason) {
1507
+ const finalContent = content;
1508
+ if (!isCancelled && content) {
1509
+ debugCollector.captureRawModelResponse(content);
1510
+ }
1511
+ if (debugCollector.enabled) {
1512
+ debugCollector.captureReasoning(reasoning);
1513
+ }
1514
+ const debugInfo = debugCollector.getDebugInfo();
1515
+ const metadata = { stream_id: streamId };
1516
+ if (toolResults && toolResults.length > 0) {
1517
+ metadata.tool_results = toolResults;
1518
+ }
1519
+ if (intermediateTextBlocks && intermediateTextBlocks.length > 0) {
1520
+ metadata.intermediate_text_blocks = intermediateTextBlocks;
1521
+ }
1522
+ // AD-036: раскрытие секретов в UI. Реальные значения плейсхолдеров из
1523
+ // карты обфускации сессии встраиваются в metadata.secrets (клик раскрывает
1524
+ // локально). Только существующие плейсхолдеры; карта — секрет, в логи не пишется.
1525
+ if (role === MessageRole.ASSISTANT && finalContent && this._obfMapStore) {
1526
+ const secrets = await this._getAssistantSecrets(sessionId, finalContent);
1527
+ if (Object.keys(secrets).length > 0) {
1528
+ metadata.secrets = { ...metadata.secrets, ...secrets };
1529
+ }
1530
+ }
1531
+ const msg = {
1532
+ id: generateId(),
1533
+ role,
1534
+ seq: 0, // filled by addMessage
1535
+ origin: 'local',
1536
+ parts: [makeTextPart(finalContent)],
1537
+ content: finalContent,
1538
+ createdAt: nowISO(),
1539
+ disabled: false,
1540
+ pinned: false,
1541
+ hidden: false,
1542
+ model,
1543
+ provider: provider || '',
1544
+ usage,
1545
+ reasoning,
1546
+ agentRole,
1547
+ debugData: debugInfo ?? undefined,
1548
+ metadata,
1549
+ ...(summaryOf ? { summaryOf } : {}),
1550
+ ...(qaPass !== undefined ? { qa_pass: qaPass } : {}),
1551
+ ...(qaReason !== undefined ? { qa_reason: qaReason } : {}),
1552
+ };
1553
+ await this._sessionManager.addMessage(sessionId, msg);
1554
+ // Accumulate session token counters and costs
1555
+ if (usage) {
1556
+ await this._sessionManager.withLock(sessionId, async (s) => {
1557
+ s.inputTokens += usage.inputTokens || 0;
1558
+ s.outputTokens += usage.outputTokens || 0;
1559
+ s.totalTokens += usage.totalTokens || 0;
1560
+ s.cacheReadTokens += usage.cacheReadTokens || 0;
1561
+ s.cacheWriteTokens += usage.cacheWriteTokens || 0;
1562
+ s.reasoningTokens += usage.reasoningTokens || 0;
1563
+ const effectiveModel = model || msg.model;
1564
+ if (effectiveModel && this._modelPriceLoader) {
1565
+ const pricing = this._modelPriceLoader(effectiveModel);
1566
+ if (pricing) {
1567
+ const div = 1_000_000;
1568
+ s.inputCost += ((usage.inputTokens || 0) * (pricing.inputPrice ?? 0)) / div;
1569
+ s.outputCost += ((usage.outputTokens || 0) * (pricing.outputPrice ?? 0)) / div;
1570
+ if (usage.cacheReadTokens && pricing.cacheReadPrice) {
1571
+ s.cacheReadCost += (usage.cacheReadTokens * pricing.cacheReadPrice) / div;
1572
+ }
1573
+ if (usage.cacheWriteTokens && pricing.cacheWritePrice) {
1574
+ s.cacheWriteCost += (usage.cacheWriteTokens * pricing.cacheWritePrice) / div;
1575
+ }
1576
+ }
1577
+ }
1578
+ s.updatedAt = nowISO();
1579
+ await this._sessionManager.saveSession(s);
1580
+ });
1581
+ }
1582
+ // Publish message.added for UI
1583
+ if (!skipEvent) {
1584
+ const session = await this._sessionManager.getSession(sessionId);
1585
+ if (session) {
1586
+ this._eventBus.publish(sessionId, 'message.added', {
1587
+ message_index: session.messages.length - 1,
1588
+ role: msg.role,
1589
+ content: finalContent.slice(0, 500),
1590
+ model,
1591
+ provider: provider || '',
1592
+ agent_role: agentRole,
1593
+ reasoning: reasoning || null,
1594
+ tool_calls: toolResults && toolResults.length > 0 ? toolResults : null,
1595
+ intermediate_text_blocks: intermediateTextBlocks && intermediateTextBlocks.length > 0 ? intermediateTextBlocks : null,
1596
+ metadata: Object.keys(metadata).length > 0 ? metadata : undefined,
1597
+ });
1598
+ }
1599
+ }
1600
+ return finalContent;
1601
+ }
1602
+ _classifyError(errMsg) {
1603
+ const lower = errMsg.toLowerCase();
1604
+ if (lower.includes('rate') || lower.includes('limit') || lower.includes('429'))
1605
+ return 'rate_limit';
1606
+ if (lower.includes('timeout') || lower.includes('timed out'))
1607
+ return 'timeout';
1608
+ if (lower.includes('502') || lower.includes('503') || lower.includes('bad gateway'))
1609
+ return 'server_error';
1610
+ if (lower.includes('context length') || lower.includes('too long'))
1611
+ return 'context_length';
1612
+ if (lower.includes('401') || lower.includes('403') || lower.includes('auth'))
1613
+ return 'auth_error';
1614
+ if (lower.includes('model') && (lower.includes('not found') || lower.includes('invalid')))
1615
+ return 'model_not_found';
1616
+ return 'unknown';
1617
+ }
1618
+ _isRecoverable(errMsg) {
1619
+ const lower = errMsg.toLowerCase();
1620
+ const unrecoverable = [
1621
+ 'model not found', 'model_not_found', 'does not exist',
1622
+ 'invalid model', 'unknown model', 'invalid api key',
1623
+ 'incorrect api key', '401', 'authentication', 'unauthorized',
1624
+ ];
1625
+ return !unrecoverable.some((p) => lower.includes(p));
1626
+ }
1627
+ /**
1628
+ * AD-029: «Разрешить в сессии» (once:false). Добавляет allow-правило для тула
1629
+ * в permission-конфиг сессии и сохраняет его. Если у сессии не было своего
1630
+ * конфига — наследует глобальные правила, чтобы не потерять их при оверрайде.
1631
+ */
1632
+ async _grantSessionToolAllow(session, toolName) {
1633
+ let cfg = session.settings.permission;
1634
+ if (!cfg) {
1635
+ cfg = {
1636
+ rules: { ...this._permissionConfig.rules },
1637
+ askTimeoutMs: this._permissionConfig.askTimeoutMs,
1638
+ };
1639
+ }
1640
+ const next = {
1641
+ ...cfg,
1642
+ rules: { ...cfg.rules, [toolName]: 'allow' },
1643
+ };
1644
+ await this._sessionManager.withLock(session.id, async (s) => {
1645
+ s.settings.permission = next;
1646
+ await this._sessionManager.saveSession(s);
1647
+ });
1648
+ return next;
1649
+ }
1650
+ }
1651
+ //# sourceMappingURL=orchestrator.js.map