@miller-tech/uap 1.0.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 (660) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +888 -0
  3. package/dist/analyzers/index.d.ts +3 -0
  4. package/dist/analyzers/index.d.ts.map +1 -0
  5. package/dist/analyzers/index.js +684 -0
  6. package/dist/analyzers/index.js.map +1 -0
  7. package/dist/benchmarks/agents/naive-agent.d.ts +60 -0
  8. package/dist/benchmarks/agents/naive-agent.d.ts.map +1 -0
  9. package/dist/benchmarks/agents/naive-agent.js +144 -0
  10. package/dist/benchmarks/agents/naive-agent.js.map +1 -0
  11. package/dist/benchmarks/agents/uap-agent.d.ts +167 -0
  12. package/dist/benchmarks/agents/uap-agent.d.ts.map +1 -0
  13. package/dist/benchmarks/agents/uap-agent.js +437 -0
  14. package/dist/benchmarks/agents/uap-agent.js.map +1 -0
  15. package/dist/benchmarks/benchmark.d.ts +328 -0
  16. package/dist/benchmarks/benchmark.d.ts.map +1 -0
  17. package/dist/benchmarks/benchmark.js +112 -0
  18. package/dist/benchmarks/benchmark.js.map +1 -0
  19. package/dist/benchmarks/execution-verifier.d.ts +41 -0
  20. package/dist/benchmarks/execution-verifier.d.ts.map +1 -0
  21. package/dist/benchmarks/execution-verifier.js +340 -0
  22. package/dist/benchmarks/execution-verifier.js.map +1 -0
  23. package/dist/benchmarks/hierarchical-prompting.d.ts +37 -0
  24. package/dist/benchmarks/hierarchical-prompting.d.ts.map +1 -0
  25. package/dist/benchmarks/hierarchical-prompting.js +246 -0
  26. package/dist/benchmarks/hierarchical-prompting.js.map +1 -0
  27. package/dist/benchmarks/improved-benchmark.d.ts +89 -0
  28. package/dist/benchmarks/improved-benchmark.d.ts.map +1 -0
  29. package/dist/benchmarks/improved-benchmark.js +585 -0
  30. package/dist/benchmarks/improved-benchmark.js.map +1 -0
  31. package/dist/benchmarks/index.d.ts +11 -0
  32. package/dist/benchmarks/index.d.ts.map +1 -0
  33. package/dist/benchmarks/index.js +11 -0
  34. package/dist/benchmarks/index.js.map +1 -0
  35. package/dist/benchmarks/model-integration.d.ts +111 -0
  36. package/dist/benchmarks/model-integration.d.ts.map +1 -0
  37. package/dist/benchmarks/model-integration.js +904 -0
  38. package/dist/benchmarks/model-integration.js.map +1 -0
  39. package/dist/benchmarks/multi-turn-agent.d.ts +44 -0
  40. package/dist/benchmarks/multi-turn-agent.d.ts.map +1 -0
  41. package/dist/benchmarks/multi-turn-agent.js +254 -0
  42. package/dist/benchmarks/multi-turn-agent.js.map +1 -0
  43. package/dist/benchmarks/multi-turn-loop.d.ts +57 -0
  44. package/dist/benchmarks/multi-turn-loop.d.ts.map +1 -0
  45. package/dist/benchmarks/multi-turn-loop.js +167 -0
  46. package/dist/benchmarks/multi-turn-loop.js.map +1 -0
  47. package/dist/benchmarks/tasks.d.ts +19 -0
  48. package/dist/benchmarks/tasks.d.ts.map +1 -0
  49. package/dist/benchmarks/tasks.js +435 -0
  50. package/dist/benchmarks/tasks.js.map +1 -0
  51. package/dist/bin/cli.d.ts +3 -0
  52. package/dist/bin/cli.d.ts.map +1 -0
  53. package/dist/bin/cli.js +546 -0
  54. package/dist/bin/cli.js.map +1 -0
  55. package/dist/bin/llama-server-optimize.d.ts +18 -0
  56. package/dist/bin/llama-server-optimize.d.ts.map +1 -0
  57. package/dist/bin/llama-server-optimize.js +708 -0
  58. package/dist/bin/llama-server-optimize.js.map +1 -0
  59. package/dist/bin/policy.d.ts +3 -0
  60. package/dist/bin/policy.d.ts.map +1 -0
  61. package/dist/bin/policy.js +143 -0
  62. package/dist/bin/policy.js.map +1 -0
  63. package/dist/bin/tool-calls.d.ts +3 -0
  64. package/dist/bin/tool-calls.d.ts.map +1 -0
  65. package/dist/bin/tool-calls.js +4 -0
  66. package/dist/bin/tool-calls.js.map +1 -0
  67. package/dist/browser/index.d.ts +2 -0
  68. package/dist/browser/index.d.ts.map +1 -0
  69. package/dist/browser/index.js +2 -0
  70. package/dist/browser/index.js.map +1 -0
  71. package/dist/browser/web-browser.d.ts +30 -0
  72. package/dist/browser/web-browser.d.ts.map +1 -0
  73. package/dist/browser/web-browser.js +93 -0
  74. package/dist/browser/web-browser.js.map +1 -0
  75. package/dist/cli/agent.d.ts +20 -0
  76. package/dist/cli/agent.d.ts.map +1 -0
  77. package/dist/cli/agent.js +474 -0
  78. package/dist/cli/agent.js.map +1 -0
  79. package/dist/cli/analyze.d.ts +7 -0
  80. package/dist/cli/analyze.d.ts.map +1 -0
  81. package/dist/cli/analyze.js +103 -0
  82. package/dist/cli/analyze.js.map +1 -0
  83. package/dist/cli/completion-gates.d.ts +51 -0
  84. package/dist/cli/completion-gates.d.ts.map +1 -0
  85. package/dist/cli/completion-gates.js +201 -0
  86. package/dist/cli/completion-gates.js.map +1 -0
  87. package/dist/cli/compliance.d.ts +8 -0
  88. package/dist/cli/compliance.d.ts.map +1 -0
  89. package/dist/cli/compliance.js +509 -0
  90. package/dist/cli/compliance.js.map +1 -0
  91. package/dist/cli/coord.d.ts +7 -0
  92. package/dist/cli/coord.d.ts.map +1 -0
  93. package/dist/cli/coord.js +138 -0
  94. package/dist/cli/coord.js.map +1 -0
  95. package/dist/cli/dashboard.d.ts +21 -0
  96. package/dist/cli/dashboard.d.ts.map +1 -0
  97. package/dist/cli/dashboard.js +1508 -0
  98. package/dist/cli/dashboard.js.map +1 -0
  99. package/dist/cli/deploy.d.ts +19 -0
  100. package/dist/cli/deploy.d.ts.map +1 -0
  101. package/dist/cli/deploy.js +387 -0
  102. package/dist/cli/deploy.js.map +1 -0
  103. package/dist/cli/droids.d.ts +9 -0
  104. package/dist/cli/droids.d.ts.map +1 -0
  105. package/dist/cli/droids.js +227 -0
  106. package/dist/cli/droids.js.map +1 -0
  107. package/dist/cli/generate.d.ts +17 -0
  108. package/dist/cli/generate.d.ts.map +1 -0
  109. package/dist/cli/generate.js +432 -0
  110. package/dist/cli/generate.js.map +1 -0
  111. package/dist/cli/hooks.d.ts +9 -0
  112. package/dist/cli/hooks.d.ts.map +1 -0
  113. package/dist/cli/hooks.js +464 -0
  114. package/dist/cli/hooks.js.map +1 -0
  115. package/dist/cli/init.d.ts +12 -0
  116. package/dist/cli/init.d.ts.map +1 -0
  117. package/dist/cli/init.js +364 -0
  118. package/dist/cli/init.js.map +1 -0
  119. package/dist/cli/mcp-router.d.ts +16 -0
  120. package/dist/cli/mcp-router.d.ts.map +1 -0
  121. package/dist/cli/mcp-router.js +143 -0
  122. package/dist/cli/mcp-router.js.map +1 -0
  123. package/dist/cli/memory.d.ts +24 -0
  124. package/dist/cli/memory.d.ts.map +1 -0
  125. package/dist/cli/memory.js +885 -0
  126. package/dist/cli/memory.js.map +1 -0
  127. package/dist/cli/model.d.ts +15 -0
  128. package/dist/cli/model.d.ts.map +1 -0
  129. package/dist/cli/model.js +290 -0
  130. package/dist/cli/model.js.map +1 -0
  131. package/dist/cli/patterns.d.ts +26 -0
  132. package/dist/cli/patterns.d.ts.map +1 -0
  133. package/dist/cli/patterns.js +862 -0
  134. package/dist/cli/patterns.js.map +1 -0
  135. package/dist/cli/rtk-validation.d.ts +9 -0
  136. package/dist/cli/rtk-validation.d.ts.map +1 -0
  137. package/dist/cli/rtk-validation.js +9 -0
  138. package/dist/cli/rtk-validation.js.map +1 -0
  139. package/dist/cli/rtk.d.ts +34 -0
  140. package/dist/cli/rtk.d.ts.map +1 -0
  141. package/dist/cli/rtk.js +401 -0
  142. package/dist/cli/rtk.js.map +1 -0
  143. package/dist/cli/schema-diff.d.ts +7 -0
  144. package/dist/cli/schema-diff.d.ts.map +1 -0
  145. package/dist/cli/schema-diff.js +11 -0
  146. package/dist/cli/schema-diff.js.map +1 -0
  147. package/dist/cli/setup-mcp-router.d.ts +8 -0
  148. package/dist/cli/setup-mcp-router.d.ts.map +1 -0
  149. package/dist/cli/setup-mcp-router.js +163 -0
  150. package/dist/cli/setup-mcp-router.js.map +1 -0
  151. package/dist/cli/setup-wizard.d.ts +2 -0
  152. package/dist/cli/setup-wizard.d.ts.map +1 -0
  153. package/dist/cli/setup-wizard.js +806 -0
  154. package/dist/cli/setup-wizard.js.map +1 -0
  155. package/dist/cli/setup.d.ts +15 -0
  156. package/dist/cli/setup.d.ts.map +1 -0
  157. package/dist/cli/setup.js +154 -0
  158. package/dist/cli/setup.js.map +1 -0
  159. package/dist/cli/sync.d.ts +8 -0
  160. package/dist/cli/sync.d.ts.map +1 -0
  161. package/dist/cli/sync.js +395 -0
  162. package/dist/cli/sync.js.map +1 -0
  163. package/dist/cli/task.d.ts +33 -0
  164. package/dist/cli/task.d.ts.map +1 -0
  165. package/dist/cli/task.js +672 -0
  166. package/dist/cli/task.js.map +1 -0
  167. package/dist/cli/tool-calls.d.ts +20 -0
  168. package/dist/cli/tool-calls.d.ts.map +1 -0
  169. package/dist/cli/tool-calls.js +605 -0
  170. package/dist/cli/tool-calls.js.map +1 -0
  171. package/dist/cli/uap.d.ts +10 -0
  172. package/dist/cli/uap.d.ts.map +1 -0
  173. package/dist/cli/uap.js +398 -0
  174. package/dist/cli/uap.js.map +1 -0
  175. package/dist/cli/update.d.ts +10 -0
  176. package/dist/cli/update.d.ts.map +1 -0
  177. package/dist/cli/update.js +300 -0
  178. package/dist/cli/update.js.map +1 -0
  179. package/dist/cli/visualize.d.ts +77 -0
  180. package/dist/cli/visualize.d.ts.map +1 -0
  181. package/dist/cli/visualize.js +287 -0
  182. package/dist/cli/visualize.js.map +1 -0
  183. package/dist/cli/worktree.d.ts +9 -0
  184. package/dist/cli/worktree.d.ts.map +1 -0
  185. package/dist/cli/worktree.js +213 -0
  186. package/dist/cli/worktree.js.map +1 -0
  187. package/dist/coordination/adaptive-patterns.d.ts +65 -0
  188. package/dist/coordination/adaptive-patterns.d.ts.map +1 -0
  189. package/dist/coordination/adaptive-patterns.js +108 -0
  190. package/dist/coordination/adaptive-patterns.js.map +1 -0
  191. package/dist/coordination/auto-agent.d.ts +82 -0
  192. package/dist/coordination/auto-agent.d.ts.map +1 -0
  193. package/dist/coordination/auto-agent.js +145 -0
  194. package/dist/coordination/auto-agent.js.map +1 -0
  195. package/dist/coordination/capability-router.d.ts +79 -0
  196. package/dist/coordination/capability-router.d.ts.map +1 -0
  197. package/dist/coordination/capability-router.js +334 -0
  198. package/dist/coordination/capability-router.js.map +1 -0
  199. package/dist/coordination/database.d.ts +13 -0
  200. package/dist/coordination/database.d.ts.map +1 -0
  201. package/dist/coordination/database.js +136 -0
  202. package/dist/coordination/database.js.map +1 -0
  203. package/dist/coordination/deploy-batcher.d.ts +122 -0
  204. package/dist/coordination/deploy-batcher.d.ts.map +1 -0
  205. package/dist/coordination/deploy-batcher.js +718 -0
  206. package/dist/coordination/deploy-batcher.js.map +1 -0
  207. package/dist/coordination/droid-validator.d.ts +59 -0
  208. package/dist/coordination/droid-validator.d.ts.map +1 -0
  209. package/dist/coordination/droid-validator.js +142 -0
  210. package/dist/coordination/droid-validator.js.map +1 -0
  211. package/dist/coordination/index.d.ts +10 -0
  212. package/dist/coordination/index.d.ts.map +1 -0
  213. package/dist/coordination/index.js +10 -0
  214. package/dist/coordination/index.js.map +1 -0
  215. package/dist/coordination/pattern-router.d.ts +50 -0
  216. package/dist/coordination/pattern-router.d.ts.map +1 -0
  217. package/dist/coordination/pattern-router.js +118 -0
  218. package/dist/coordination/pattern-router.js.map +1 -0
  219. package/dist/coordination/service.d.ts +81 -0
  220. package/dist/coordination/service.d.ts.map +1 -0
  221. package/dist/coordination/service.js +619 -0
  222. package/dist/coordination/service.js.map +1 -0
  223. package/dist/coordination/worktree-enforcer.d.ts +22 -0
  224. package/dist/coordination/worktree-enforcer.d.ts.map +1 -0
  225. package/dist/coordination/worktree-enforcer.js +71 -0
  226. package/dist/coordination/worktree-enforcer.js.map +1 -0
  227. package/dist/generators/claude-md.d.ts +3 -0
  228. package/dist/generators/claude-md.d.ts.map +1 -0
  229. package/dist/generators/claude-md.js +1020 -0
  230. package/dist/generators/claude-md.js.map +1 -0
  231. package/dist/generators/template-loader.d.ts +105 -0
  232. package/dist/generators/template-loader.d.ts.map +1 -0
  233. package/dist/generators/template-loader.js +291 -0
  234. package/dist/generators/template-loader.js.map +1 -0
  235. package/dist/index.d.ts +49 -0
  236. package/dist/index.d.ts.map +1 -0
  237. package/dist/index.js +63 -0
  238. package/dist/index.js.map +1 -0
  239. package/dist/mcp-router/config/parser.d.ts +9 -0
  240. package/dist/mcp-router/config/parser.d.ts.map +1 -0
  241. package/dist/mcp-router/config/parser.js +174 -0
  242. package/dist/mcp-router/config/parser.js.map +1 -0
  243. package/dist/mcp-router/executor/client.d.ts +31 -0
  244. package/dist/mcp-router/executor/client.d.ts.map +1 -0
  245. package/dist/mcp-router/executor/client.js +189 -0
  246. package/dist/mcp-router/executor/client.js.map +1 -0
  247. package/dist/mcp-router/index.d.ts +22 -0
  248. package/dist/mcp-router/index.d.ts.map +1 -0
  249. package/dist/mcp-router/index.js +18 -0
  250. package/dist/mcp-router/index.js.map +1 -0
  251. package/dist/mcp-router/output-compressor.d.ts +26 -0
  252. package/dist/mcp-router/output-compressor.d.ts.map +1 -0
  253. package/dist/mcp-router/output-compressor.js +236 -0
  254. package/dist/mcp-router/output-compressor.js.map +1 -0
  255. package/dist/mcp-router/search/fuzzy.d.ts +26 -0
  256. package/dist/mcp-router/search/fuzzy.d.ts.map +1 -0
  257. package/dist/mcp-router/search/fuzzy.js +94 -0
  258. package/dist/mcp-router/search/fuzzy.js.map +1 -0
  259. package/dist/mcp-router/server.d.ts +50 -0
  260. package/dist/mcp-router/server.d.ts.map +1 -0
  261. package/dist/mcp-router/server.js +229 -0
  262. package/dist/mcp-router/server.js.map +1 -0
  263. package/dist/mcp-router/session-stats.d.ts +37 -0
  264. package/dist/mcp-router/session-stats.d.ts.map +1 -0
  265. package/dist/mcp-router/session-stats.js +56 -0
  266. package/dist/mcp-router/session-stats.js.map +1 -0
  267. package/dist/mcp-router/tools/discover.d.ts +37 -0
  268. package/dist/mcp-router/tools/discover.d.ts.map +1 -0
  269. package/dist/mcp-router/tools/discover.js +65 -0
  270. package/dist/mcp-router/tools/discover.js.map +1 -0
  271. package/dist/mcp-router/tools/execute.d.ts +43 -0
  272. package/dist/mcp-router/tools/execute.d.ts.map +1 -0
  273. package/dist/mcp-router/tools/execute.js +144 -0
  274. package/dist/mcp-router/tools/execute.js.map +1 -0
  275. package/dist/mcp-router/types.d.ts +62 -0
  276. package/dist/mcp-router/types.d.ts.map +1 -0
  277. package/dist/mcp-router/types.js +6 -0
  278. package/dist/mcp-router/types.js.map +1 -0
  279. package/dist/memory/adaptive-context.d.ts +149 -0
  280. package/dist/memory/adaptive-context.d.ts.map +1 -0
  281. package/dist/memory/adaptive-context.js +1095 -0
  282. package/dist/memory/adaptive-context.js.map +1 -0
  283. package/dist/memory/agent-scoped-memory.d.ts +67 -0
  284. package/dist/memory/agent-scoped-memory.d.ts.map +1 -0
  285. package/dist/memory/agent-scoped-memory.js +126 -0
  286. package/dist/memory/agent-scoped-memory.js.map +1 -0
  287. package/dist/memory/ambiguity-detector.d.ts +54 -0
  288. package/dist/memory/ambiguity-detector.d.ts.map +1 -0
  289. package/dist/memory/ambiguity-detector.js +401 -0
  290. package/dist/memory/ambiguity-detector.js.map +1 -0
  291. package/dist/memory/backends/base.d.ts +18 -0
  292. package/dist/memory/backends/base.d.ts.map +1 -0
  293. package/dist/memory/backends/base.js +2 -0
  294. package/dist/memory/backends/base.js.map +1 -0
  295. package/dist/memory/backends/factory.d.ts +4 -0
  296. package/dist/memory/backends/factory.d.ts.map +1 -0
  297. package/dist/memory/backends/factory.js +53 -0
  298. package/dist/memory/backends/factory.js.map +1 -0
  299. package/dist/memory/backends/github.d.ts +27 -0
  300. package/dist/memory/backends/github.d.ts.map +1 -0
  301. package/dist/memory/backends/github.js +134 -0
  302. package/dist/memory/backends/github.js.map +1 -0
  303. package/dist/memory/backends/qdrant-cloud.d.ts +32 -0
  304. package/dist/memory/backends/qdrant-cloud.d.ts.map +1 -0
  305. package/dist/memory/backends/qdrant-cloud.js +167 -0
  306. package/dist/memory/backends/qdrant-cloud.js.map +1 -0
  307. package/dist/memory/context-compressor.d.ts +116 -0
  308. package/dist/memory/context-compressor.d.ts.map +1 -0
  309. package/dist/memory/context-compressor.js +430 -0
  310. package/dist/memory/context-compressor.js.map +1 -0
  311. package/dist/memory/context-pruner.d.ts +55 -0
  312. package/dist/memory/context-pruner.d.ts.map +1 -0
  313. package/dist/memory/context-pruner.js +85 -0
  314. package/dist/memory/context-pruner.js.map +1 -0
  315. package/dist/memory/correction-propagator.d.ts +44 -0
  316. package/dist/memory/correction-propagator.d.ts.map +1 -0
  317. package/dist/memory/correction-propagator.js +156 -0
  318. package/dist/memory/correction-propagator.js.map +1 -0
  319. package/dist/memory/daily-log.d.ts +67 -0
  320. package/dist/memory/daily-log.d.ts.map +1 -0
  321. package/dist/memory/daily-log.js +143 -0
  322. package/dist/memory/daily-log.js.map +1 -0
  323. package/dist/memory/dynamic-retrieval.d.ts +112 -0
  324. package/dist/memory/dynamic-retrieval.d.ts.map +1 -0
  325. package/dist/memory/dynamic-retrieval.js +908 -0
  326. package/dist/memory/dynamic-retrieval.js.map +1 -0
  327. package/dist/memory/embeddings.d.ts +172 -0
  328. package/dist/memory/embeddings.d.ts.map +1 -0
  329. package/dist/memory/embeddings.js +780 -0
  330. package/dist/memory/embeddings.js.map +1 -0
  331. package/dist/memory/generic-uap-patterns.d.ts +7 -0
  332. package/dist/memory/generic-uap-patterns.d.ts.map +1 -0
  333. package/dist/memory/generic-uap-patterns.js +43 -0
  334. package/dist/memory/generic-uap-patterns.js.map +1 -0
  335. package/dist/memory/hierarchical-memory.d.ts +141 -0
  336. package/dist/memory/hierarchical-memory.d.ts.map +1 -0
  337. package/dist/memory/hierarchical-memory.js +485 -0
  338. package/dist/memory/hierarchical-memory.js.map +1 -0
  339. package/dist/memory/knowledge-graph.d.ts +98 -0
  340. package/dist/memory/knowledge-graph.d.ts.map +1 -0
  341. package/dist/memory/knowledge-graph.js +275 -0
  342. package/dist/memory/knowledge-graph.js.map +1 -0
  343. package/dist/memory/memory-consolidator.d.ts +124 -0
  344. package/dist/memory/memory-consolidator.d.ts.map +1 -0
  345. package/dist/memory/memory-consolidator.js +514 -0
  346. package/dist/memory/memory-consolidator.js.map +1 -0
  347. package/dist/memory/memory-maintenance.d.ts +39 -0
  348. package/dist/memory/memory-maintenance.d.ts.map +1 -0
  349. package/dist/memory/memory-maintenance.js +336 -0
  350. package/dist/memory/memory-maintenance.js.map +1 -0
  351. package/dist/memory/model-router.d.ts +105 -0
  352. package/dist/memory/model-router.d.ts.map +1 -0
  353. package/dist/memory/model-router.js +474 -0
  354. package/dist/memory/model-router.js.map +1 -0
  355. package/dist/memory/multi-view-memory.d.ts +134 -0
  356. package/dist/memory/multi-view-memory.d.ts.map +1 -0
  357. package/dist/memory/multi-view-memory.js +430 -0
  358. package/dist/memory/multi-view-memory.js.map +1 -0
  359. package/dist/memory/predictive-memory.d.ts +79 -0
  360. package/dist/memory/predictive-memory.d.ts.map +1 -0
  361. package/dist/memory/predictive-memory.js +294 -0
  362. package/dist/memory/predictive-memory.js.map +1 -0
  363. package/dist/memory/prepopulate.d.ts +76 -0
  364. package/dist/memory/prepopulate.d.ts.map +1 -0
  365. package/dist/memory/prepopulate.js +832 -0
  366. package/dist/memory/prepopulate.js.map +1 -0
  367. package/dist/memory/semantic-compression.d.ts +77 -0
  368. package/dist/memory/semantic-compression.d.ts.map +1 -0
  369. package/dist/memory/semantic-compression.js +359 -0
  370. package/dist/memory/semantic-compression.js.map +1 -0
  371. package/dist/memory/serverless-qdrant.d.ts +102 -0
  372. package/dist/memory/serverless-qdrant.d.ts.map +1 -0
  373. package/dist/memory/serverless-qdrant.js +369 -0
  374. package/dist/memory/serverless-qdrant.js.map +1 -0
  375. package/dist/memory/short-term/factory.d.ts +26 -0
  376. package/dist/memory/short-term/factory.d.ts.map +1 -0
  377. package/dist/memory/short-term/factory.js +28 -0
  378. package/dist/memory/short-term/factory.js.map +1 -0
  379. package/dist/memory/short-term/indexeddb.d.ts +25 -0
  380. package/dist/memory/short-term/indexeddb.d.ts.map +1 -0
  381. package/dist/memory/short-term/indexeddb.js +64 -0
  382. package/dist/memory/short-term/indexeddb.js.map +1 -0
  383. package/dist/memory/short-term/schema.d.ts +6 -0
  384. package/dist/memory/short-term/schema.d.ts.map +1 -0
  385. package/dist/memory/short-term/schema.js +141 -0
  386. package/dist/memory/short-term/schema.js.map +1 -0
  387. package/dist/memory/short-term/sqlite.d.ts +64 -0
  388. package/dist/memory/short-term/sqlite.d.ts.map +1 -0
  389. package/dist/memory/short-term/sqlite.js +274 -0
  390. package/dist/memory/short-term/sqlite.js.map +1 -0
  391. package/dist/memory/speculative-cache.d.ts +111 -0
  392. package/dist/memory/speculative-cache.d.ts.map +1 -0
  393. package/dist/memory/speculative-cache.js +457 -0
  394. package/dist/memory/speculative-cache.js.map +1 -0
  395. package/dist/memory/task-classifier.d.ts +40 -0
  396. package/dist/memory/task-classifier.d.ts.map +1 -0
  397. package/dist/memory/task-classifier.js +342 -0
  398. package/dist/memory/task-classifier.js.map +1 -0
  399. package/dist/memory/terminal-bench-knowledge.d.ts +48 -0
  400. package/dist/memory/terminal-bench-knowledge.d.ts.map +1 -0
  401. package/dist/memory/terminal-bench-knowledge.js +622 -0
  402. package/dist/memory/terminal-bench-knowledge.js.map +1 -0
  403. package/dist/memory/write-gate.d.ts +39 -0
  404. package/dist/memory/write-gate.d.ts.map +1 -0
  405. package/dist/memory/write-gate.js +190 -0
  406. package/dist/memory/write-gate.js.map +1 -0
  407. package/dist/models/api-client.d.ts +46 -0
  408. package/dist/models/api-client.d.ts.map +1 -0
  409. package/dist/models/api-client.js +182 -0
  410. package/dist/models/api-client.js.map +1 -0
  411. package/dist/models/execution-profiles.d.ts +64 -0
  412. package/dist/models/execution-profiles.d.ts.map +1 -0
  413. package/dist/models/execution-profiles.js +403 -0
  414. package/dist/models/execution-profiles.js.map +1 -0
  415. package/dist/models/executor.d.ts +130 -0
  416. package/dist/models/executor.d.ts.map +1 -0
  417. package/dist/models/executor.js +382 -0
  418. package/dist/models/executor.js.map +1 -0
  419. package/dist/models/index.d.ts +19 -0
  420. package/dist/models/index.d.ts.map +1 -0
  421. package/dist/models/index.js +23 -0
  422. package/dist/models/index.js.map +1 -0
  423. package/dist/models/plan-validator.d.ts +37 -0
  424. package/dist/models/plan-validator.d.ts.map +1 -0
  425. package/dist/models/plan-validator.js +179 -0
  426. package/dist/models/plan-validator.js.map +1 -0
  427. package/dist/models/planner.d.ts +73 -0
  428. package/dist/models/planner.d.ts.map +1 -0
  429. package/dist/models/planner.js +375 -0
  430. package/dist/models/planner.js.map +1 -0
  431. package/dist/models/router.d.ts +96 -0
  432. package/dist/models/router.d.ts.map +1 -0
  433. package/dist/models/router.js +523 -0
  434. package/dist/models/router.js.map +1 -0
  435. package/dist/models/types.d.ts +370 -0
  436. package/dist/models/types.d.ts.map +1 -0
  437. package/dist/models/types.js +232 -0
  438. package/dist/models/types.js.map +1 -0
  439. package/dist/models/unified-router.d.ts +152 -0
  440. package/dist/models/unified-router.d.ts.map +1 -0
  441. package/dist/models/unified-router.js +313 -0
  442. package/dist/models/unified-router.js.map +1 -0
  443. package/dist/policies/convert-policy-to-claude.d.ts +3 -0
  444. package/dist/policies/convert-policy-to-claude.d.ts.map +1 -0
  445. package/dist/policies/convert-policy-to-claude.js +87 -0
  446. package/dist/policies/convert-policy-to-claude.js.map +1 -0
  447. package/dist/policies/database-manager.d.ts +27 -0
  448. package/dist/policies/database-manager.d.ts.map +1 -0
  449. package/dist/policies/database-manager.js +198 -0
  450. package/dist/policies/database-manager.js.map +1 -0
  451. package/dist/policies/enforced-tool-router.d.ts +53 -0
  452. package/dist/policies/enforced-tool-router.d.ts.map +1 -0
  453. package/dist/policies/enforced-tool-router.js +80 -0
  454. package/dist/policies/enforced-tool-router.js.map +1 -0
  455. package/dist/policies/index.d.ts +10 -0
  456. package/dist/policies/index.d.ts.map +1 -0
  457. package/dist/policies/index.js +8 -0
  458. package/dist/policies/index.js.map +1 -0
  459. package/dist/policies/policy-gate.d.ts +59 -0
  460. package/dist/policies/policy-gate.d.ts.map +1 -0
  461. package/dist/policies/policy-gate.js +171 -0
  462. package/dist/policies/policy-gate.js.map +1 -0
  463. package/dist/policies/policy-memory.d.ts +18 -0
  464. package/dist/policies/policy-memory.d.ts.map +1 -0
  465. package/dist/policies/policy-memory.js +126 -0
  466. package/dist/policies/policy-memory.js.map +1 -0
  467. package/dist/policies/policy-tools.d.ts +11 -0
  468. package/dist/policies/policy-tools.d.ts.map +1 -0
  469. package/dist/policies/policy-tools.js +66 -0
  470. package/dist/policies/policy-tools.js.map +1 -0
  471. package/dist/policies/schemas/policy.d.ts +69 -0
  472. package/dist/policies/schemas/policy.d.ts.map +1 -0
  473. package/dist/policies/schemas/policy.js +31 -0
  474. package/dist/policies/schemas/policy.js.map +1 -0
  475. package/dist/tasks/coordination.d.ts +83 -0
  476. package/dist/tasks/coordination.d.ts.map +1 -0
  477. package/dist/tasks/coordination.js +291 -0
  478. package/dist/tasks/coordination.js.map +1 -0
  479. package/dist/tasks/database.d.ts +19 -0
  480. package/dist/tasks/database.d.ts.map +1 -0
  481. package/dist/tasks/database.js +149 -0
  482. package/dist/tasks/database.js.map +1 -0
  483. package/dist/tasks/decoder-gate.d.ts +64 -0
  484. package/dist/tasks/decoder-gate.d.ts.map +1 -0
  485. package/dist/tasks/decoder-gate.js +268 -0
  486. package/dist/tasks/decoder-gate.js.map +1 -0
  487. package/dist/tasks/index.d.ts +6 -0
  488. package/dist/tasks/index.d.ts.map +1 -0
  489. package/dist/tasks/index.js +6 -0
  490. package/dist/tasks/index.js.map +1 -0
  491. package/dist/tasks/service.d.ts +40 -0
  492. package/dist/tasks/service.d.ts.map +1 -0
  493. package/dist/tasks/service.js +671 -0
  494. package/dist/tasks/service.js.map +1 -0
  495. package/dist/tasks/types.d.ts +238 -0
  496. package/dist/tasks/types.d.ts.map +1 -0
  497. package/dist/tasks/types.js +74 -0
  498. package/dist/tasks/types.js.map +1 -0
  499. package/dist/telemetry/index.d.ts +2 -0
  500. package/dist/telemetry/index.d.ts.map +1 -0
  501. package/dist/telemetry/index.js +2 -0
  502. package/dist/telemetry/index.js.map +1 -0
  503. package/dist/telemetry/session-telemetry.d.ts +56 -0
  504. package/dist/telemetry/session-telemetry.d.ts.map +1 -0
  505. package/dist/telemetry/session-telemetry.js +807 -0
  506. package/dist/telemetry/session-telemetry.js.map +1 -0
  507. package/dist/types/analysis.d.ts +82 -0
  508. package/dist/types/analysis.d.ts.map +1 -0
  509. package/dist/types/analysis.js +2 -0
  510. package/dist/types/analysis.js.map +1 -0
  511. package/dist/types/config.d.ts +3324 -0
  512. package/dist/types/config.d.ts.map +1 -0
  513. package/dist/types/config.js +418 -0
  514. package/dist/types/config.js.map +1 -0
  515. package/dist/types/coordination.d.ts +240 -0
  516. package/dist/types/coordination.d.ts.map +1 -0
  517. package/dist/types/coordination.js +43 -0
  518. package/dist/types/coordination.js.map +1 -0
  519. package/dist/types/index.d.ts +4 -0
  520. package/dist/types/index.d.ts.map +1 -0
  521. package/dist/types/index.js +4 -0
  522. package/dist/types/index.js.map +1 -0
  523. package/dist/uap-droids-strict.d.ts +59 -0
  524. package/dist/uap-droids-strict.d.ts.map +1 -0
  525. package/dist/uap-droids-strict.js +200 -0
  526. package/dist/uap-droids-strict.js.map +1 -0
  527. package/dist/utils/config-manager.d.ts +30 -0
  528. package/dist/utils/config-manager.d.ts.map +1 -0
  529. package/dist/utils/config-manager.js +41 -0
  530. package/dist/utils/config-manager.js.map +1 -0
  531. package/dist/utils/fetch-with-retry.d.ts +5 -0
  532. package/dist/utils/fetch-with-retry.d.ts.map +1 -0
  533. package/dist/utils/fetch-with-retry.js +61 -0
  534. package/dist/utils/fetch-with-retry.js.map +1 -0
  535. package/dist/utils/merge-claude-md.d.ts +28 -0
  536. package/dist/utils/merge-claude-md.d.ts.map +1 -0
  537. package/dist/utils/merge-claude-md.js +342 -0
  538. package/dist/utils/merge-claude-md.js.map +1 -0
  539. package/dist/utils/rate-limiter.d.ts +58 -0
  540. package/dist/utils/rate-limiter.d.ts.map +1 -0
  541. package/dist/utils/rate-limiter.js +100 -0
  542. package/dist/utils/rate-limiter.js.map +1 -0
  543. package/dist/utils/string-similarity.d.ts +37 -0
  544. package/dist/utils/string-similarity.d.ts.map +1 -0
  545. package/dist/utils/string-similarity.js +114 -0
  546. package/dist/utils/string-similarity.js.map +1 -0
  547. package/dist/utils/validate-json.d.ts +51 -0
  548. package/dist/utils/validate-json.d.ts.map +1 -0
  549. package/dist/utils/validate-json.js +94 -0
  550. package/dist/utils/validate-json.js.map +1 -0
  551. package/docs/INDEX.md +66 -0
  552. package/docs/architecture/MULTI_MODEL.md +224 -0
  553. package/docs/architecture/SYSTEM_ANALYSIS.md +1117 -0
  554. package/docs/architecture/UAP_COMPLIANCE.md +217 -0
  555. package/docs/architecture/UAP_PROTOCOL.md +339 -0
  556. package/docs/architecture/UAP_STRICT_DROIDS.md +172 -0
  557. package/docs/archive/BALLS_MODE_SELF_ANALYSIS.md +260 -0
  558. package/docs/archive/FAILING_TASKS_SOLUTION_PLAN.md +668 -0
  559. package/docs/archive/JINJA2-SYSTEM-MESSAGE-FIX.md +209 -0
  560. package/docs/archive/NPM-PUBLISH-V0.9.1.md +240 -0
  561. package/docs/archive/OPTIMIZATION_OPTIONS.md +334 -0
  562. package/docs/archive/SETUP_IMPROVEMENTS.md +213 -0
  563. package/docs/archive/UAP_GENERIC_OPTIMIZATION_PLAN.md +270 -0
  564. package/docs/archive/UAP_V103_PATTERN_DESIGN.md +315 -0
  565. package/docs/archive/UAP_V104_COMPLIANCE_DESIGN.md +223 -0
  566. package/docs/archive/changelog/2026-03-10_uap-100-compliance.md +77 -0
  567. package/docs/archive/changelog/2026-03-10_uap-full-system-verification.md +109 -0
  568. package/docs/benchmarks/ACCURACY_ANALYSIS.md +471 -0
  569. package/docs/benchmarks/TOKEN_OPTIMIZATION.md +572 -0
  570. package/docs/benchmarks/VALIDATION_PLAN.md +568 -0
  571. package/docs/benchmarks/VALIDATION_RESULTS.md +161 -0
  572. package/docs/deployment/DEPLOYMENT.md +895 -0
  573. package/docs/deployment/DEPLOYMENT_STRATEGIES.md +518 -0
  574. package/docs/deployment/DEPLOY_BATCHER_ANALYSIS.md +856 -0
  575. package/docs/deployment/DEPLOY_BATCHING.md +273 -0
  576. package/docs/deployment/DEPLOY_BUCKETING_ANALYSIS.md +420 -0
  577. package/docs/deployment/QWEN35_LLAMA_CPP.md +265 -0
  578. package/docs/getting-started/INTEGRATION.md +449 -0
  579. package/docs/getting-started/OVERVIEW.md +344 -0
  580. package/docs/getting-started/SETUP.md +203 -0
  581. package/docs/integrations/MCP_ROUTER_SETUP.md +445 -0
  582. package/docs/integrations/RTK_INTEGRATION.md +468 -0
  583. package/docs/operations/TROUBLESHOOTING.md +660 -0
  584. package/docs/reference/API_REFERENCE.md +903 -0
  585. package/docs/reference/FEATURES.md +472 -0
  586. package/docs/reference/HARNESS-MATRIX.md +318 -0
  587. package/docs/reference/UAP_CLI_REFERENCE.md +600 -0
  588. package/docs/research/BEHAVIORAL_PATTERNS.md +228 -0
  589. package/docs/research/DOMAIN_STRATEGIES.md +316 -0
  590. package/docs/research/MEMORY_SYSTEMS_COMPARISON.md +812 -0
  591. package/docs/research/PATTERN_ANALYSIS_2026-01-18.md +436 -0
  592. package/docs/research/PERFORMANCE_ANALYSIS_2026-01-18.md +209 -0
  593. package/docs/research/PERFORMANCE_TEST_PLAN.md +383 -0
  594. package/docs/research/TERMINAL_BENCH_LEARNINGS.md +217 -0
  595. package/package.json +113 -0
  596. package/scripts/README.md +161 -0
  597. package/templates/CLAUDE.template.md +10 -0
  598. package/templates/CLAUDE_ARCHITECTURE.template.md +103 -0
  599. package/templates/CLAUDE_CODING.template.md +127 -0
  600. package/templates/CLAUDE_DROIDS.template.md +109 -0
  601. package/templates/CLAUDE_MEMORY.template.md +131 -0
  602. package/templates/CLAUDE_WORKFLOWS.template.md +139 -0
  603. package/templates/PROJECT.template.md +209 -0
  604. package/templates/SCHEMA.md +57 -0
  605. package/templates/archive/CLAUDE.template.root-v6.md +534 -0
  606. package/templates/archive/CLAUDE.template.v6.md +534 -0
  607. package/templates/hooks/forgecode/pre-compact.sh +68 -0
  608. package/templates/hooks/forgecode/session-start.sh +169 -0
  609. package/templates/hooks/forgecode.plugin.sh +128 -0
  610. package/templates/hooks/pre-compact.sh +74 -0
  611. package/templates/hooks/session-start.sh +366 -0
  612. package/tools/agents/README.md +224 -0
  613. package/tools/agents/UAP/README.md +386 -0
  614. package/tools/agents/UAP/__init__.py +9 -0
  615. package/tools/agents/UAP/cli.py +901 -0
  616. package/tools/agents/UAP/compliance_verify.sh +108 -0
  617. package/tools/agents/UAP/full_verification.sh +126 -0
  618. package/tools/agents/UAP/version.py +32 -0
  619. package/tools/agents/benchmarks/benchmark_memory_systems.py +730 -0
  620. package/tools/agents/benchmarks/results/benchmark_20260106_064817.json +170 -0
  621. package/tools/agents/benchmarks/results/benchmark_20260106_064817.md +51 -0
  622. package/tools/agents/config/chat_template.jinja +77 -0
  623. package/tools/agents/config/tool-call-schema.json +19 -0
  624. package/tools/agents/config/tool-call.gbnf +58 -0
  625. package/tools/agents/docker/Dockerfile.python +52 -0
  626. package/tools/agents/docker/Dockerfile.ubuntu +55 -0
  627. package/tools/agents/docker-compose.qdrant.yml +24 -0
  628. package/tools/agents/install-opencode-local.sh.j2 +135 -0
  629. package/tools/agents/migrations/apply.py +256 -0
  630. package/tools/agents/opencode_uap_agent.py +1505 -0
  631. package/tools/agents/plugin/README.md +91 -0
  632. package/tools/agents/plugin/index.ts +46 -0
  633. package/tools/agents/plugin/pre-compact.sh +68 -0
  634. package/tools/agents/plugin/session-start.sh +175 -0
  635. package/tools/agents/plugin/uap-commands.ts +45 -0
  636. package/tools/agents/plugin/uap-droids.ts +54 -0
  637. package/tools/agents/plugin/uap-patterns.ts +54 -0
  638. package/tools/agents/plugin/uap-skills.ts +52 -0
  639. package/tools/agents/plugins/uap-enforce.ts +314 -0
  640. package/tools/agents/scripts/__pycache__/tool_call_wrapper.cpython-313.pyc +0 -0
  641. package/tools/agents/scripts/chat_template_verifier.py +343 -0
  642. package/tools/agents/scripts/fix-qwen-template.js +38 -0
  643. package/tools/agents/scripts/fix_qwen_chat_template.py +316 -0
  644. package/tools/agents/scripts/generate_lora_training_data.py +412 -0
  645. package/tools/agents/scripts/init_qdrant.py +151 -0
  646. package/tools/agents/scripts/memory_migration.py +560 -0
  647. package/tools/agents/scripts/migrate_memory_to_qdrant.py +110 -0
  648. package/tools/agents/scripts/prepare_lora.sh +512 -0
  649. package/tools/agents/scripts/query_memory.py +200 -0
  650. package/tools/agents/scripts/qwen-tool-call-test.js +38 -0
  651. package/tools/agents/scripts/qwen-tool-call-wrapper.js +38 -0
  652. package/tools/agents/scripts/qwen_tool_call_test.py +464 -0
  653. package/tools/agents/scripts/qwen_tool_call_wrapper.py +686 -0
  654. package/tools/agents/scripts/start-services.sh +96 -0
  655. package/tools/agents/scripts/tool-choice-proxy.cjs +296 -0
  656. package/tools/agents/scripts/tool_call_test.py +656 -0
  657. package/tools/agents/scripts/tool_call_wrapper.py +799 -0
  658. package/tools/agents/tests/test_uap_compliance.py +257 -0
  659. package/tools/agents/uap_agent.py +122 -0
  660. package/tools/agents/uap_agent_install.sh +12 -0
@@ -0,0 +1,686 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Qwen3.5 Tool Call Wrapper with Retry Logic
4
+
5
+ Provides robust tool calling for Qwen3.5 35B A3B with automatic retry
6
+ on failures, addressing known issues with early termination.
7
+
8
+ Strategies implemented:
9
+ 1. tool_choice="required" + parallel_tool_calls=true in API requests
10
+ 2. Improved multi-tool system prompt with explicit format guidance
11
+ 3. Retry escalation: auto -> required -> required+lower temp
12
+ 4. Per-tool tool_choice for single-tool scenarios
13
+ 5. Thinking mode suppression via chat_template_kwargs
14
+ 6. Dynamic temperature decay on retries
15
+
16
+ Known Issues Fixed:
17
+ 1. Template parsing failures after 1-2 tool calls
18
+ 2. Reasoning mode interference with structured output
19
+ 3. JSON parsing errors from leaked reasoning content
20
+ 4. Context window reprocessing issues
21
+ 5. Multi-tool calls truncated to single call
22
+
23
+ Usage:
24
+ from qwen_tool_call_wrapper import Qwen35ToolCallClient
25
+
26
+ client = Qwen35ToolCallClient()
27
+ response = client.chat_with_tools(
28
+ messages=[{"role": "user", "content": "Call read_file with path='/etc/hosts'"}],
29
+ tools=[...]
30
+ )
31
+ """
32
+
33
+ import openai
34
+ import time
35
+ import json
36
+ import logging
37
+ from typing import List, Dict, Any, Optional, Tuple
38
+ from dataclasses import dataclass, asdict
39
+ from datetime import datetime
40
+ from enum import Enum
41
+
42
+ # Configure logging
43
+ logging.basicConfig(
44
+ level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
45
+ )
46
+ logger = logging.getLogger("qwen35_tool_call")
47
+
48
+
49
+ class ToolCallStatus(Enum):
50
+ """Status of tool call attempts"""
51
+
52
+ SUCCESS = "success"
53
+ FAILURE = "failure"
54
+ RETRY = "retry"
55
+ MAX_RETRIES = "max_retries"
56
+
57
+
58
+ @dataclass
59
+ class ToolCallMetrics:
60
+ """Metrics for tool call performance"""
61
+
62
+ total_attempts: int = 0
63
+ successful_calls: int = 0
64
+ failed_calls: int = 0
65
+ retries: int = 0
66
+ avg_latency_ms: float = 0.0
67
+ last_error: Optional[str] = None
68
+ tool_choice_escalations: int = 0
69
+ parallel_calls_requested: int = 0
70
+ parallel_calls_received: int = 0
71
+
72
+ def to_dict(self) -> Dict:
73
+ return asdict(self)
74
+
75
+
76
+ class Qwen35ToolCallError(Exception):
77
+ """Custom exception for Qwen3.5 tool call failures"""
78
+
79
+ pass
80
+
81
+
82
+ class Qwen35ToolCallClient:
83
+ """
84
+ OpenAI-compatible client optimized for Qwen3.5 35B A3B tool calling.
85
+
86
+ Implements 6 strategies for maximum tool call reliability:
87
+ 1. tool_choice + parallel_tool_calls in every request
88
+ 2. Explicit multi-tool system prompt with format guidance
89
+ 3. Retry escalation: auto -> required -> required+lower temp
90
+ 4. Per-tool tool_choice for single-tool scenarios
91
+ 5. Thinking mode suppression
92
+ 6. Dynamic temperature decay on retries
93
+ """
94
+
95
+ # Default configuration for Qwen3.5 35B A3B (IQ4_XS quant)
96
+ # Tuned for reliable tool calling with MoE architecture
97
+ DEFAULT_CONFIG = {
98
+ "temperature": 0.6,
99
+ "top_p": 0.9,
100
+ "presence_penalty": 0.0,
101
+ "max_tokens": 4096,
102
+ "enable_thinking": False,
103
+ "max_retries": 3,
104
+ "backoff_factor": 2.0,
105
+ "base_url": "http://127.0.0.1:8080/v1",
106
+ "api_key": "not-needed",
107
+ "model": "qwen35-a3b-iq4xs",
108
+ # Strategy 1: Always pass tool_choice and parallel_tool_calls
109
+ "default_tool_choice": "auto",
110
+ "parallel_tool_calls": True,
111
+ # Strategy 2: Improved multi-tool system prompt
112
+ "batch_tool_calls": True,
113
+ "batch_system_prompt": (
114
+ "When multiple tools are needed, emit ALL tool calls in a single response. "
115
+ "Each tool call must be a separate <tool_call>...</tool_call> block. "
116
+ "Do not call one tool and wait for a response before calling the next. "
117
+ "Emit all <tool_call> blocks together in sequence."
118
+ ),
119
+ # Strategy 3: Retry escalation
120
+ "escalate_tool_choice": True,
121
+ # Strategy 5: Per-tool tool_choice for single expected tool
122
+ "use_per_tool_choice": True,
123
+ # Dynamic temperature: lower temp for subsequent tool calls
124
+ # in the same conversation to improve format adherence
125
+ "dynamic_temperature": True,
126
+ "dynamic_temp_decay": 0.5, # multiply temp by this for each retry
127
+ "dynamic_temp_floor": 0.2, # minimum temperature
128
+ }
129
+
130
+ def __init__(
131
+ self, config: Optional[Dict[str, Any]] = None, enable_metrics: bool = True
132
+ ):
133
+ """
134
+ Initialize Qwen3.5 tool call client.
135
+
136
+ Args:
137
+ config: Override default configuration
138
+ enable_metrics: Enable performance metrics tracking
139
+ """
140
+ self.config = {**self.DEFAULT_CONFIG, **(config or {})}
141
+ self.enable_metrics = enable_metrics
142
+ self.metrics = ToolCallMetrics()
143
+ self._client = None
144
+
145
+ # Initialize OpenAI client
146
+ self._init_client()
147
+
148
+ logger.info(f"Qwen35ToolCallClient initialized with config: {self.config}")
149
+
150
+ def _init_client(self):
151
+ """Initialize OpenAI-compatible client"""
152
+ try:
153
+ self._client = openai.Client(
154
+ base_url=self.config["base_url"], api_key=self.config["api_key"]
155
+ )
156
+ logger.info(f"Connected to {self.config['base_url']}")
157
+ except Exception as e:
158
+ logger.error(f"Failed to initialize OpenAI client: {e}")
159
+ raise Qwen35ToolCallError(f"Client initialization failed: {e}")
160
+
161
+ def _get_tool_choice(
162
+ self,
163
+ tools: List[Dict[str, Any]],
164
+ attempt: int,
165
+ expected_tool: Optional[str] = None,
166
+ ) -> Any:
167
+ """
168
+ Determine tool_choice based on strategy and attempt number.
169
+
170
+ Strategy 3 (escalation):
171
+ - Attempt 0: use default_tool_choice (usually "auto")
172
+ - Attempt 1+: escalate to "required"
173
+
174
+ Strategy 5 (per-tool):
175
+ - If expected_tool is set and only one tool matches, use per-tool choice
176
+ """
177
+ # Strategy 5: Per-tool choice for single expected tool
178
+ if expected_tool and self.config.get("use_per_tool_choice") and attempt == 0:
179
+ # Find the tool in the definitions
180
+ for tool in tools:
181
+ func = tool.get("function", {})
182
+ if func.get("name") == expected_tool:
183
+ logger.debug(f"Using per-tool choice: {expected_tool}")
184
+ return {
185
+ "type": "function",
186
+ "function": {"name": expected_tool},
187
+ }
188
+
189
+ # Strategy 3: Escalation on retries
190
+ if attempt > 0 and self.config.get("escalate_tool_choice"):
191
+ self.metrics.tool_choice_escalations += 1
192
+ logger.info(f"Escalating tool_choice to 'required' (attempt {attempt + 1})")
193
+ return "required"
194
+
195
+ return self.config.get("default_tool_choice", "auto")
196
+
197
+ def chat_with_tools(
198
+ self,
199
+ messages: List[Dict[str, str]],
200
+ tools: List[Dict[str, Any]],
201
+ max_retries: Optional[int] = None,
202
+ timeout: int = 120,
203
+ expected_tool: Optional[str] = None,
204
+ expected_tool_calls: Optional[int] = None,
205
+ **kwargs,
206
+ ) -> openai.types.chat.ChatCompletion:
207
+ """
208
+ Chat completion with automatic retry on tool call failures.
209
+
210
+ Implements all 6 strategies:
211
+ 1. tool_choice + parallel_tool_calls in every request
212
+ 2. Multi-tool system prompt injection
213
+ 3. Retry escalation (auto -> required -> required+lower temp)
214
+ 4. Per-tool tool_choice for single-tool scenarios
215
+ 5. Thinking mode suppression
216
+ 6. Dynamic temperature decay
217
+
218
+ Args:
219
+ messages: List of chat messages
220
+ tools: List of tool definitions
221
+ max_retries: Override default max retries
222
+ timeout: Request timeout in seconds
223
+ expected_tool: If set, use per-tool tool_choice (Strategy 5)
224
+ expected_tool_calls: Expected number of tool calls (for validation)
225
+ **kwargs: Additional parameters passed to OpenAI API
226
+
227
+ Returns:
228
+ ChatCompletion response with tool calls
229
+
230
+ Raises:
231
+ Qwen35ToolCallError: After max retries exhausted
232
+ """
233
+ max_retries = max_retries or self.config["max_retries"]
234
+
235
+ # Track timing
236
+ start_time = time.time()
237
+
238
+ # Make a copy of messages to avoid modifying original
239
+ current_messages = [msg.copy() for msg in messages]
240
+
241
+ # Strategy 2: Inject multi-tool system prompt
242
+ if self.config.get("batch_tool_calls") and len(tools) > 1:
243
+ batch_prompt = self.config.get("batch_system_prompt", "")
244
+ if batch_prompt:
245
+ has_system = any(m.get("role") == "system" for m in current_messages)
246
+ if has_system:
247
+ for m in current_messages:
248
+ if m.get("role") == "system":
249
+ m["content"] = m["content"] + "\n\n" + batch_prompt
250
+ break
251
+ else:
252
+ current_messages.insert(
253
+ 0,
254
+ {"role": "system", "content": batch_prompt},
255
+ )
256
+
257
+ # Track parallel call expectations
258
+ if expected_tool_calls and expected_tool_calls > 1:
259
+ self.metrics.parallel_calls_requested += 1
260
+
261
+ # Base temperature for dynamic adjustment
262
+ base_temperature = self.config["temperature"]
263
+
264
+ for attempt in range(max_retries):
265
+ self.metrics.total_attempts += 1
266
+
267
+ # Strategy 6: Dynamic temperature - reduce on retries
268
+ if self.config.get("dynamic_temperature") and attempt > 0:
269
+ decay = self.config.get("dynamic_temp_decay", 0.5)
270
+ floor = self.config.get("dynamic_temp_floor", 0.2)
271
+ current_temp = max(floor, base_temperature * (decay**attempt))
272
+ logger.info(
273
+ f"Dynamic temperature: {current_temp:.2f} (attempt {attempt + 1})"
274
+ )
275
+ else:
276
+ current_temp = base_temperature
277
+
278
+ # Strategy 1 + 3 + 5: Determine tool_choice
279
+ tool_choice = self._get_tool_choice(tools, attempt, expected_tool)
280
+
281
+ try:
282
+ # Build request with all strategies applied
283
+ request_params = {
284
+ "model": self.config["model"],
285
+ "messages": current_messages,
286
+ "tools": tools,
287
+ "tool_choice": tool_choice, # Strategy 1
288
+ "parallel_tool_calls": self.config.get(
289
+ "parallel_tool_calls", True
290
+ ), # Strategy 1
291
+ "temperature": current_temp,
292
+ "top_p": self.config["top_p"],
293
+ "presence_penalty": self.config["presence_penalty"],
294
+ "max_tokens": self.config["max_tokens"],
295
+ "timeout": timeout,
296
+ "extra_body": {
297
+ "chat_template_kwargs": {
298
+ "enable_thinking": self.config[
299
+ "enable_thinking"
300
+ ] # Strategy 5 (thinking suppression)
301
+ }
302
+ },
303
+ **kwargs,
304
+ }
305
+
306
+ logger.debug(
307
+ f"Attempt {attempt + 1}/{max_retries}: "
308
+ f"tool_choice={tool_choice}, temp={current_temp:.2f}, "
309
+ f"parallel={self.config.get('parallel_tool_calls', True)}"
310
+ )
311
+
312
+ # Make API call
313
+ response = self._client.chat.completions.create(**request_params)
314
+
315
+ # Validate response
316
+ tool_calls = response.choices[0].message.tool_calls
317
+
318
+ if self._validate_tool_call(tool_calls):
319
+ # Success!
320
+ self.metrics.successful_calls += 1
321
+
322
+ # Track parallel call success
323
+ if tool_calls and len(tool_calls) > 1:
324
+ self.metrics.parallel_calls_received += 1
325
+
326
+ # Calculate latency
327
+ latency_ms = (time.time() - start_time) * 1000
328
+ self.metrics.avg_latency_ms = latency_ms
329
+
330
+ logger.info(
331
+ f"Tool call successful after {attempt + 1} attempt(s): "
332
+ f"{len(tool_calls)} call(s)"
333
+ )
334
+ return response
335
+ else:
336
+ # Invalid format, retry with correction
337
+ logger.warning(f"Invalid tool call format on attempt {attempt + 1}")
338
+ current_messages = self._correct_prompt(current_messages, response)
339
+ self.metrics.retries += 1
340
+
341
+ if attempt < max_retries - 1:
342
+ # Exponential backoff
343
+ backoff = self.config["backoff_factor"] ** attempt
344
+ time.sleep(backoff)
345
+ logger.info(f"Retrying in {backoff:.1f}s...")
346
+
347
+ except Exception as e:
348
+ self.metrics.last_error = str(e)
349
+ logger.error(f"Error on attempt {attempt + 1}: {e}")
350
+
351
+ if attempt == max_retries - 1:
352
+ # Last attempt failed
353
+ self.metrics.failed_calls += 1
354
+ raise Qwen35ToolCallError(
355
+ f"Failed after {max_retries} attempts: {str(e)}"
356
+ )
357
+
358
+ # Retry with backoff
359
+ backoff = self.config["backoff_factor"] ** attempt
360
+ time.sleep(backoff)
361
+
362
+ # Should not reach here, but just in case
363
+ self.metrics.failed_calls += 1
364
+ raise Qwen35ToolCallError("Max retries exceeded")
365
+
366
+ def _validate_tool_call(self, tool_calls) -> bool:
367
+ """
368
+ Validate that tool call has correct format.
369
+
370
+ Checks for:
371
+ - Non-empty tool calls list
372
+ - Valid function name
373
+ - Parseable JSON arguments (OpenAI-compatible API returns JSON)
374
+ - No reasoning content leakage (<thinking>/<think> tags in arguments)
375
+ """
376
+ if not tool_calls:
377
+ logger.debug("No tool calls returned")
378
+ return False
379
+
380
+ for tool_call in tool_calls:
381
+ # Check function name exists
382
+ if not tool_call.function or not tool_call.function.name:
383
+ logger.debug("Tool call missing function name")
384
+ return False
385
+
386
+ # Check arguments are present
387
+ arguments = tool_call.function.arguments
388
+ if not arguments:
389
+ logger.debug("Tool call missing arguments")
390
+ return False
391
+
392
+ # Check for thinking/reasoning tag leakage in arguments
393
+ if "<thinking>" in arguments or "</thinking>" in arguments:
394
+ logger.debug("Thinking tag leakage detected in arguments")
395
+ return False
396
+
397
+ if "<think>" in arguments or "</think>" in arguments:
398
+ logger.debug("Think tag leakage detected in arguments")
399
+ return False
400
+
401
+ # Validate arguments are parseable JSON
402
+ try:
403
+ parsed = json.loads(arguments)
404
+ if not isinstance(parsed, dict):
405
+ logger.debug(f"Arguments not a JSON object: {type(parsed)}")
406
+ return False
407
+ except (json.JSONDecodeError, TypeError) as e:
408
+ logger.debug(f"Arguments not valid JSON: {e}")
409
+ return False
410
+
411
+ return True
412
+
413
+ def _correct_prompt(
414
+ self, messages: List[Dict], response: openai.types.chat.ChatCompletion
415
+ ) -> List[Dict]:
416
+ """
417
+ Correct prompt after invalid tool call.
418
+
419
+ Appends correction message to guide model toward proper format.
420
+ Uses the official Qwen3 <tool_call> format.
421
+ """
422
+ invalid_content = response.choices[0].message.content or ""
423
+
424
+ # Add assistant's failed attempt
425
+ messages.append(
426
+ {
427
+ "role": "assistant",
428
+ "content": f"I attempted a tool call but the format was invalid: "
429
+ f"{invalid_content[:200]}",
430
+ }
431
+ )
432
+
433
+ # Add user correction matching the chat template format
434
+ messages.append(
435
+ {
436
+ "role": "user",
437
+ "content": "Please call the tool using the correct format. "
438
+ "You must use the tool calling interface - respond with a tool call, "
439
+ "not with text describing the call. "
440
+ "Use <tool_call> tags with a JSON object containing 'name' and 'arguments' keys.",
441
+ }
442
+ )
443
+
444
+ return messages
445
+
446
+ def execute_tool_call(
447
+ self, tool_calls: List, tool_functions: Dict[str, callable]
448
+ ) -> List[Any]:
449
+ """
450
+ Execute tool calls and collect results.
451
+
452
+ Args:
453
+ tool_calls: List of tool call objects from response
454
+ tool_functions: Dict mapping tool names to functions
455
+
456
+ Returns:
457
+ List of tool results
458
+ """
459
+ results = []
460
+
461
+ for tool_call in tool_calls:
462
+ tool_name = tool_call.function.name
463
+ tool_args = json.loads(tool_call.function.arguments)
464
+
465
+ logger.info(f"Executing tool: {tool_name} with args: {tool_args}")
466
+
467
+ if tool_name not in tool_functions:
468
+ results.append(
469
+ {
470
+ "tool_name": tool_name,
471
+ "status": "error",
472
+ "error": f"Tool '{tool_name}' not found",
473
+ }
474
+ )
475
+ continue
476
+
477
+ try:
478
+ result = tool_functions[tool_name](**tool_args)
479
+ results.append(
480
+ {"tool_name": tool_name, "status": "success", "result": result}
481
+ )
482
+ except Exception as e:
483
+ results.append(
484
+ {"tool_name": tool_name, "status": "error", "error": str(e)}
485
+ )
486
+
487
+ return results
488
+
489
+ def get_metrics(self) -> ToolCallMetrics:
490
+ """Get current metrics"""
491
+ return self.metrics
492
+
493
+ def reset_metrics(self):
494
+ """Reset metrics counters"""
495
+ self.metrics = ToolCallMetrics()
496
+ logger.info("Metrics reset")
497
+
498
+ def get_status(self) -> Dict:
499
+ """Get client status"""
500
+ return {
501
+ "model": self.config["model"],
502
+ "base_url": self.config["base_url"],
503
+ "metrics": self.metrics.to_dict(),
504
+ "config": {
505
+ k: v for k, v in self.config.items() if k not in ["base_url", "api_key"]
506
+ },
507
+ }
508
+
509
+
510
+ class Qwen35ToolCallAgent:
511
+ """
512
+ Higher-level agent for Qwen3.5 tool calling workflows.
513
+
514
+ Combines tool calling with execution and result handling.
515
+
516
+ Args:
517
+ tool_definitions: List of OpenAI-format tool definitions (for the API)
518
+ tool_implementations: Dict mapping tool names to callable functions (for execution)
519
+ client_config: Configuration for tool call client
520
+ """
521
+
522
+ def __init__(
523
+ self,
524
+ tool_definitions: List[Dict[str, Any]],
525
+ tool_implementations: Dict[str, callable],
526
+ client_config: Optional[Dict] = None,
527
+ ):
528
+ self.tool_definitions = tool_definitions
529
+ self.tool_implementations = tool_implementations
530
+ self.client = Qwen35ToolCallClient(client_config)
531
+
532
+ logger.info(
533
+ f"Qwen35ToolCallAgent initialized with {len(tool_definitions)} tools: "
534
+ f"{list(tool_implementations.keys())}"
535
+ )
536
+
537
+ def run(
538
+ self,
539
+ user_query: str,
540
+ additional_messages: Optional[List[Dict]] = None,
541
+ expected_tool: Optional[str] = None,
542
+ ) -> Tuple[openai.types.chat.ChatCompletion, List[Any]]:
543
+ """
544
+ Run a complete tool calling workflow.
545
+
546
+ Args:
547
+ user_query: User's input query
548
+ additional_messages: Optional additional conversation history
549
+ expected_tool: If set, use per-tool tool_choice
550
+
551
+ Returns:
552
+ Tuple of (ChatCompletion response, List of tool results)
553
+ """
554
+ # Build messages
555
+ messages = []
556
+
557
+ if additional_messages:
558
+ messages.extend(additional_messages)
559
+
560
+ messages.append({"role": "user", "content": user_query})
561
+
562
+ # Make tool call request (pass definitions to API)
563
+ response = self.client.chat_with_tools(
564
+ messages=messages,
565
+ tools=self.tool_definitions,
566
+ expected_tool=expected_tool,
567
+ )
568
+
569
+ # Execute tool calls (pass implementations for execution)
570
+ tool_calls = response.choices[0].message.tool_calls
571
+
572
+ if tool_calls:
573
+ results = self.client.execute_tool_call(
574
+ tool_calls, self.tool_implementations
575
+ )
576
+ else:
577
+ results = []
578
+
579
+ return response, results
580
+
581
+ def get_status(self) -> Dict:
582
+ """Get agent status"""
583
+ return {
584
+ "tools": list(self.tool_implementations.keys()),
585
+ "client_status": self.client.get_status(),
586
+ }
587
+
588
+
589
+ # Convenience function for simple use cases
590
+ def qwen35_chat_with_tools(
591
+ user_query: str,
592
+ tool_definitions: List[Dict],
593
+ tool_implementations: Dict[str, callable],
594
+ config: Optional[Dict] = None,
595
+ ) -> Tuple[openai.types.chat.ChatCompletion, List[Any]]:
596
+ """
597
+ Simple function for quick tool calling with Qwen3.5.
598
+
599
+ Args:
600
+ user_query: User's input
601
+ tool_definitions: OpenAI-format tool definitions
602
+ tool_implementations: Dict mapping tool names to callables
603
+ config: Optional configuration
604
+
605
+ Returns:
606
+ Tuple of (response, results)
607
+ """
608
+ agent = Qwen35ToolCallAgent(tool_definitions, tool_implementations, config)
609
+ return agent.run(user_query)
610
+
611
+
612
+ # Example usage
613
+ if __name__ == "__main__":
614
+ # Example tool implementations (actual callables)
615
+ def read_file(path: str) -> str:
616
+ """Read file contents"""
617
+ with open(path, "r") as f:
618
+ return f.read()
619
+
620
+ def get_weather(city: str) -> str:
621
+ """Get weather for city"""
622
+ return f"Weather in {city}: Sunny, 25C"
623
+
624
+ # Tool implementations: name -> callable
625
+ implementations = {
626
+ "read_file": read_file,
627
+ "get_weather": get_weather,
628
+ }
629
+
630
+ # Tool definitions: OpenAI-format schemas (sent to the API)
631
+ definitions = [
632
+ {
633
+ "type": "function",
634
+ "function": {
635
+ "name": "read_file",
636
+ "description": "Read file contents",
637
+ "parameters": {
638
+ "type": "object",
639
+ "properties": {"path": {"type": "string"}},
640
+ "required": ["path"],
641
+ },
642
+ },
643
+ },
644
+ {
645
+ "type": "function",
646
+ "function": {
647
+ "name": "get_weather",
648
+ "description": "Get weather information",
649
+ "parameters": {
650
+ "type": "object",
651
+ "properties": {"city": {"type": "string"}},
652
+ "required": ["city"],
653
+ },
654
+ },
655
+ },
656
+ ]
657
+
658
+ # Initialize agent with both definitions and implementations
659
+ agent = Qwen35ToolCallAgent(definitions, implementations)
660
+
661
+ # Run example
662
+ try:
663
+ response, results = agent.run("Read /etc/hosts and get weather in Sydney")
664
+
665
+ print("\n=== Tool Call Results ===")
666
+ for result in results:
667
+ print(f"Tool: {result['tool_name']}")
668
+ print(f"Status: {result['status']}")
669
+ if result["status"] == "success":
670
+ print(f"Result: {str(result['result'])[:200]}...")
671
+ else:
672
+ print(f"Error: {result['error']}")
673
+
674
+ print("\n=== Metrics ===")
675
+ metrics = agent.client.get_metrics()
676
+ print(f"Total attempts: {metrics.total_attempts}")
677
+ print(f"Successful calls: {metrics.successful_calls}")
678
+ print(f"Escalations: {metrics.tool_choice_escalations}")
679
+ print(f"Parallel requested: {metrics.parallel_calls_requested}")
680
+ print(f"Parallel received: {metrics.parallel_calls_received}")
681
+ print(
682
+ f"Success rate: {metrics.successful_calls / metrics.total_attempts * 100:.1f}%"
683
+ )
684
+
685
+ except Qwen35ToolCallError as e:
686
+ print(f"Tool call failed: {e}")