@soederpop/luca 0.1.2 → 0.2.1

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 (381) hide show
  1. package/.github/workflows/release.yaml +167 -0
  2. package/CLAUDE.md +2 -0
  3. package/README.md +3 -0
  4. package/assistants/codingAssistant/ABOUT.md +3 -0
  5. package/assistants/codingAssistant/CORE.md +22 -17
  6. package/assistants/codingAssistant/hooks.ts +17 -4
  7. package/assistants/codingAssistant/tools.ts +1 -106
  8. package/assistants/inkbot/ABOUT.md +5 -0
  9. package/assistants/inkbot/CORE.md +71 -0
  10. package/assistants/inkbot/hooks.ts +14 -0
  11. package/assistants/inkbot/tools.ts +47 -0
  12. package/bun.lock +20 -4
  13. package/commands/inkbot.ts +353 -0
  14. package/commands/release.ts +75 -181
  15. package/dist/agi/container.server.d.ts +63 -0
  16. package/dist/agi/container.server.d.ts.map +1 -0
  17. package/dist/agi/endpoints/ask.d.ts +20 -0
  18. package/dist/agi/endpoints/ask.d.ts.map +1 -0
  19. package/dist/agi/endpoints/conversations/[id].d.ts +27 -0
  20. package/dist/agi/endpoints/conversations/[id].d.ts.map +1 -0
  21. package/dist/agi/endpoints/conversations.d.ts +18 -0
  22. package/dist/agi/endpoints/conversations.d.ts.map +1 -0
  23. package/dist/agi/endpoints/experts.d.ts +8 -0
  24. package/dist/agi/endpoints/experts.d.ts.map +1 -0
  25. package/dist/agi/feature.d.ts +9 -0
  26. package/dist/agi/feature.d.ts.map +1 -0
  27. package/dist/agi/features/assistant.d.ts +509 -0
  28. package/dist/agi/features/assistant.d.ts.map +1 -0
  29. package/dist/agi/features/assistants-manager.d.ts +236 -0
  30. package/dist/agi/features/assistants-manager.d.ts.map +1 -0
  31. package/dist/agi/features/autonomous-assistant.d.ts +281 -0
  32. package/dist/agi/features/autonomous-assistant.d.ts.map +1 -0
  33. package/dist/agi/features/browser-use.d.ts +479 -0
  34. package/dist/agi/features/browser-use.d.ts.map +1 -0
  35. package/dist/agi/features/claude-code.d.ts +824 -0
  36. package/dist/agi/features/claude-code.d.ts.map +1 -0
  37. package/dist/agi/features/conversation-history.d.ts +245 -0
  38. package/dist/agi/features/conversation-history.d.ts.map +1 -0
  39. package/dist/agi/features/conversation.d.ts +464 -0
  40. package/dist/agi/features/conversation.d.ts.map +1 -0
  41. package/dist/agi/features/docs-reader.d.ts +72 -0
  42. package/dist/agi/features/docs-reader.d.ts.map +1 -0
  43. package/dist/agi/features/file-tools.d.ts +110 -0
  44. package/dist/agi/features/file-tools.d.ts.map +1 -0
  45. package/dist/agi/features/luca-coder.d.ts +323 -0
  46. package/dist/agi/features/luca-coder.d.ts.map +1 -0
  47. package/dist/agi/features/openai-codex.d.ts +381 -0
  48. package/dist/agi/features/openai-codex.d.ts.map +1 -0
  49. package/dist/agi/features/openapi.d.ts +200 -0
  50. package/dist/agi/features/openapi.d.ts.map +1 -0
  51. package/dist/agi/features/skills-library.d.ts +167 -0
  52. package/dist/agi/features/skills-library.d.ts.map +1 -0
  53. package/dist/agi/index.d.ts +5 -0
  54. package/dist/agi/index.d.ts.map +1 -0
  55. package/dist/agi/lib/interceptor-chain.d.ts +44 -0
  56. package/dist/agi/lib/interceptor-chain.d.ts.map +1 -0
  57. package/dist/agi/lib/token-counter.d.ts +13 -0
  58. package/dist/agi/lib/token-counter.d.ts.map +1 -0
  59. package/dist/bootstrap/generated.d.ts +5 -0
  60. package/dist/bootstrap/generated.d.ts.map +1 -0
  61. package/dist/browser.d.ts +12 -0
  62. package/dist/browser.d.ts.map +1 -0
  63. package/dist/bus.d.ts +29 -0
  64. package/dist/bus.d.ts.map +1 -0
  65. package/dist/cli/build-info.d.ts +4 -0
  66. package/dist/cli/build-info.d.ts.map +1 -0
  67. package/dist/cli/cli.d.ts +3 -0
  68. package/dist/cli/cli.d.ts.map +1 -0
  69. package/dist/client.d.ts +60 -0
  70. package/dist/client.d.ts.map +1 -0
  71. package/dist/clients/civitai/index.d.ts +472 -0
  72. package/dist/clients/civitai/index.d.ts.map +1 -0
  73. package/dist/clients/client-template.d.ts +30 -0
  74. package/dist/clients/client-template.d.ts.map +1 -0
  75. package/dist/clients/comfyui/index.d.ts +281 -0
  76. package/dist/clients/comfyui/index.d.ts.map +1 -0
  77. package/dist/clients/elevenlabs/index.d.ts +197 -0
  78. package/dist/clients/elevenlabs/index.d.ts.map +1 -0
  79. package/dist/clients/graph.d.ts +64 -0
  80. package/dist/clients/graph.d.ts.map +1 -0
  81. package/dist/clients/openai/index.d.ts +247 -0
  82. package/dist/clients/openai/index.d.ts.map +1 -0
  83. package/dist/clients/rest.d.ts +92 -0
  84. package/dist/clients/rest.d.ts.map +1 -0
  85. package/dist/clients/supabase/index.d.ts +176 -0
  86. package/dist/clients/supabase/index.d.ts.map +1 -0
  87. package/dist/clients/websocket.d.ts +127 -0
  88. package/dist/clients/websocket.d.ts.map +1 -0
  89. package/dist/command.d.ts +163 -0
  90. package/dist/command.d.ts.map +1 -0
  91. package/dist/commands/bootstrap.d.ts +20 -0
  92. package/dist/commands/bootstrap.d.ts.map +1 -0
  93. package/dist/commands/chat.d.ts +37 -0
  94. package/dist/commands/chat.d.ts.map +1 -0
  95. package/dist/commands/code.d.ts +28 -0
  96. package/dist/commands/code.d.ts.map +1 -0
  97. package/dist/commands/console.d.ts +22 -0
  98. package/dist/commands/console.d.ts.map +1 -0
  99. package/dist/commands/describe.d.ts +50 -0
  100. package/dist/commands/describe.d.ts.map +1 -0
  101. package/dist/commands/eval.d.ts +23 -0
  102. package/dist/commands/eval.d.ts.map +1 -0
  103. package/dist/commands/help.d.ts +25 -0
  104. package/dist/commands/help.d.ts.map +1 -0
  105. package/dist/commands/index.d.ts +18 -0
  106. package/dist/commands/index.d.ts.map +1 -0
  107. package/dist/commands/introspect.d.ts +24 -0
  108. package/dist/commands/introspect.d.ts.map +1 -0
  109. package/dist/commands/mcp.d.ts +35 -0
  110. package/dist/commands/mcp.d.ts.map +1 -0
  111. package/dist/commands/prompt.d.ts +38 -0
  112. package/dist/commands/prompt.d.ts.map +1 -0
  113. package/dist/commands/run.d.ts +24 -0
  114. package/dist/commands/run.d.ts.map +1 -0
  115. package/dist/commands/sandbox-mcp.d.ts +34 -0
  116. package/dist/commands/sandbox-mcp.d.ts.map +1 -0
  117. package/dist/commands/save-api-docs.d.ts +21 -0
  118. package/dist/commands/save-api-docs.d.ts.map +1 -0
  119. package/dist/commands/scaffold.d.ts +24 -0
  120. package/dist/commands/scaffold.d.ts.map +1 -0
  121. package/dist/commands/select.d.ts +22 -0
  122. package/dist/commands/select.d.ts.map +1 -0
  123. package/dist/commands/serve.d.ts +29 -0
  124. package/dist/commands/serve.d.ts.map +1 -0
  125. package/dist/container-describer.d.ts +144 -0
  126. package/dist/container-describer.d.ts.map +1 -0
  127. package/dist/container.d.ts +451 -0
  128. package/dist/container.d.ts.map +1 -0
  129. package/dist/endpoint.d.ts +113 -0
  130. package/dist/endpoint.d.ts.map +1 -0
  131. package/dist/feature.d.ts +47 -0
  132. package/dist/feature.d.ts.map +1 -0
  133. package/dist/graft.d.ts +29 -0
  134. package/dist/graft.d.ts.map +1 -0
  135. package/dist/hash-object.d.ts +8 -0
  136. package/dist/hash-object.d.ts.map +1 -0
  137. package/dist/helper.d.ts +209 -0
  138. package/dist/helper.d.ts.map +1 -0
  139. package/dist/introspection/generated.node.d.ts +44623 -0
  140. package/dist/introspection/generated.node.d.ts.map +1 -0
  141. package/dist/introspection/generated.web.d.ts +1412 -0
  142. package/dist/introspection/generated.web.d.ts.map +1 -0
  143. package/dist/introspection/index.d.ts +156 -0
  144. package/dist/introspection/index.d.ts.map +1 -0
  145. package/dist/introspection/scan.d.ts +147 -0
  146. package/dist/introspection/scan.d.ts.map +1 -0
  147. package/dist/node/container.d.ts +256 -0
  148. package/dist/node/container.d.ts.map +1 -0
  149. package/dist/node/feature.d.ts +9 -0
  150. package/dist/node/feature.d.ts.map +1 -0
  151. package/dist/node/features/container-link.d.ts +213 -0
  152. package/dist/node/features/container-link.d.ts.map +1 -0
  153. package/dist/node/features/content-db.d.ts +354 -0
  154. package/dist/node/features/content-db.d.ts.map +1 -0
  155. package/dist/node/features/disk-cache.d.ts +236 -0
  156. package/dist/node/features/disk-cache.d.ts.map +1 -0
  157. package/dist/node/features/dns.d.ts +511 -0
  158. package/dist/node/features/dns.d.ts.map +1 -0
  159. package/dist/node/features/docker.d.ts +485 -0
  160. package/dist/node/features/docker.d.ts.map +1 -0
  161. package/dist/node/features/downloader.d.ts +73 -0
  162. package/dist/node/features/downloader.d.ts.map +1 -0
  163. package/dist/node/features/figlet-fonts.d.ts +4 -0
  164. package/dist/node/features/figlet-fonts.d.ts.map +1 -0
  165. package/dist/node/features/file-manager.d.ts +177 -0
  166. package/dist/node/features/file-manager.d.ts.map +1 -0
  167. package/dist/node/features/fs.d.ts +635 -0
  168. package/dist/node/features/fs.d.ts.map +1 -0
  169. package/dist/node/features/git.d.ts +329 -0
  170. package/dist/node/features/git.d.ts.map +1 -0
  171. package/dist/node/features/google-auth.d.ts +200 -0
  172. package/dist/node/features/google-auth.d.ts.map +1 -0
  173. package/dist/node/features/google-calendar.d.ts +194 -0
  174. package/dist/node/features/google-calendar.d.ts.map +1 -0
  175. package/dist/node/features/google-docs.d.ts +138 -0
  176. package/dist/node/features/google-docs.d.ts.map +1 -0
  177. package/dist/node/features/google-drive.d.ts +202 -0
  178. package/dist/node/features/google-drive.d.ts.map +1 -0
  179. package/dist/node/features/google-mail.d.ts +221 -0
  180. package/dist/node/features/google-mail.d.ts.map +1 -0
  181. package/dist/node/features/google-sheets.d.ts +157 -0
  182. package/dist/node/features/google-sheets.d.ts.map +1 -0
  183. package/dist/node/features/grep.d.ts +207 -0
  184. package/dist/node/features/grep.d.ts.map +1 -0
  185. package/dist/node/features/helpers.d.ts +236 -0
  186. package/dist/node/features/helpers.d.ts.map +1 -0
  187. package/dist/node/features/ink.d.ts +332 -0
  188. package/dist/node/features/ink.d.ts.map +1 -0
  189. package/dist/node/features/ipc-socket.d.ts +298 -0
  190. package/dist/node/features/ipc-socket.d.ts.map +1 -0
  191. package/dist/node/features/json-tree.d.ts +140 -0
  192. package/dist/node/features/json-tree.d.ts.map +1 -0
  193. package/dist/node/features/networking.d.ts +373 -0
  194. package/dist/node/features/networking.d.ts.map +1 -0
  195. package/dist/node/features/nlp.d.ts +125 -0
  196. package/dist/node/features/nlp.d.ts.map +1 -0
  197. package/dist/node/features/opener.d.ts +93 -0
  198. package/dist/node/features/opener.d.ts.map +1 -0
  199. package/dist/node/features/os.d.ts +168 -0
  200. package/dist/node/features/os.d.ts.map +1 -0
  201. package/dist/node/features/package-finder.d.ts +419 -0
  202. package/dist/node/features/package-finder.d.ts.map +1 -0
  203. package/dist/node/features/postgres.d.ts +173 -0
  204. package/dist/node/features/postgres.d.ts.map +1 -0
  205. package/dist/node/features/proc.d.ts +285 -0
  206. package/dist/node/features/proc.d.ts.map +1 -0
  207. package/dist/node/features/process-manager.d.ts +427 -0
  208. package/dist/node/features/process-manager.d.ts.map +1 -0
  209. package/dist/node/features/python.d.ts +477 -0
  210. package/dist/node/features/python.d.ts.map +1 -0
  211. package/dist/node/features/redis.d.ts +247 -0
  212. package/dist/node/features/redis.d.ts.map +1 -0
  213. package/dist/node/features/repl.d.ts +84 -0
  214. package/dist/node/features/repl.d.ts.map +1 -0
  215. package/dist/node/features/runpod.d.ts +527 -0
  216. package/dist/node/features/runpod.d.ts.map +1 -0
  217. package/dist/node/features/secure-shell.d.ts +145 -0
  218. package/dist/node/features/secure-shell.d.ts.map +1 -0
  219. package/dist/node/features/semantic-search.d.ts +207 -0
  220. package/dist/node/features/semantic-search.d.ts.map +1 -0
  221. package/dist/node/features/sqlite.d.ts +180 -0
  222. package/dist/node/features/sqlite.d.ts.map +1 -0
  223. package/dist/node/features/telegram.d.ts +173 -0
  224. package/dist/node/features/telegram.d.ts.map +1 -0
  225. package/dist/node/features/transpiler.d.ts +51 -0
  226. package/dist/node/features/transpiler.d.ts.map +1 -0
  227. package/dist/node/features/tts.d.ts +108 -0
  228. package/dist/node/features/tts.d.ts.map +1 -0
  229. package/dist/node/features/ui.d.ts +562 -0
  230. package/dist/node/features/ui.d.ts.map +1 -0
  231. package/dist/node/features/vault.d.ts +90 -0
  232. package/dist/node/features/vault.d.ts.map +1 -0
  233. package/dist/node/features/vm.d.ts +285 -0
  234. package/dist/node/features/vm.d.ts.map +1 -0
  235. package/dist/node/features/yaml-tree.d.ts +118 -0
  236. package/dist/node/features/yaml-tree.d.ts.map +1 -0
  237. package/dist/node/features/yaml.d.ts +127 -0
  238. package/dist/node/features/yaml.d.ts.map +1 -0
  239. package/dist/node.d.ts +67 -0
  240. package/dist/node.d.ts.map +1 -0
  241. package/dist/python/generated.d.ts +2 -0
  242. package/dist/python/generated.d.ts.map +1 -0
  243. package/dist/react/index.d.ts +36 -0
  244. package/dist/react/index.d.ts.map +1 -0
  245. package/dist/registry.d.ts +97 -0
  246. package/dist/registry.d.ts.map +1 -0
  247. package/dist/scaffolds/generated.d.ts +13 -0
  248. package/dist/scaffolds/generated.d.ts.map +1 -0
  249. package/dist/scaffolds/template.d.ts +11 -0
  250. package/dist/scaffolds/template.d.ts.map +1 -0
  251. package/dist/schemas/base.d.ts +254 -0
  252. package/dist/schemas/base.d.ts.map +1 -0
  253. package/dist/selector.d.ts +130 -0
  254. package/dist/selector.d.ts.map +1 -0
  255. package/dist/server.d.ts +89 -0
  256. package/dist/server.d.ts.map +1 -0
  257. package/dist/servers/express.d.ts +104 -0
  258. package/dist/servers/express.d.ts.map +1 -0
  259. package/dist/servers/mcp.d.ts +201 -0
  260. package/dist/servers/mcp.d.ts.map +1 -0
  261. package/dist/servers/socket.d.ts +121 -0
  262. package/dist/servers/socket.d.ts.map +1 -0
  263. package/dist/state.d.ts +24 -0
  264. package/dist/state.d.ts.map +1 -0
  265. package/dist/web/clients/socket.d.ts +37 -0
  266. package/dist/web/clients/socket.d.ts.map +1 -0
  267. package/dist/web/container.d.ts +55 -0
  268. package/dist/web/container.d.ts.map +1 -0
  269. package/dist/web/extension.d.ts +4 -0
  270. package/dist/web/extension.d.ts.map +1 -0
  271. package/dist/web/feature.d.ts +8 -0
  272. package/dist/web/feature.d.ts.map +1 -0
  273. package/dist/web/features/asset-loader.d.ts +35 -0
  274. package/dist/web/features/asset-loader.d.ts.map +1 -0
  275. package/dist/web/features/container-link.d.ts +167 -0
  276. package/dist/web/features/container-link.d.ts.map +1 -0
  277. package/dist/web/features/esbuild.d.ts +51 -0
  278. package/dist/web/features/esbuild.d.ts.map +1 -0
  279. package/dist/web/features/helpers.d.ts +140 -0
  280. package/dist/web/features/helpers.d.ts.map +1 -0
  281. package/dist/web/features/network.d.ts +69 -0
  282. package/dist/web/features/network.d.ts.map +1 -0
  283. package/dist/web/features/speech.d.ts +71 -0
  284. package/dist/web/features/speech.d.ts.map +1 -0
  285. package/dist/web/features/vault.d.ts +62 -0
  286. package/dist/web/features/vault.d.ts.map +1 -0
  287. package/dist/web/features/vm.d.ts +48 -0
  288. package/dist/web/features/vm.d.ts.map +1 -0
  289. package/dist/web/features/voice-recognition.d.ts +96 -0
  290. package/dist/web/features/voice-recognition.d.ts.map +1 -0
  291. package/dist/web/shims/isomorphic-vm.d.ts +22 -0
  292. package/dist/web/shims/isomorphic-vm.d.ts.map +1 -0
  293. package/docs/apis/features/agi/assistant.md +1 -0
  294. package/docs/apis/features/agi/assistants-manager.md +62 -2
  295. package/docs/apis/features/agi/auto-assistant.md +11 -109
  296. package/docs/apis/features/agi/claude-code.md +138 -0
  297. package/docs/apis/features/agi/conversation.md +60 -31
  298. package/docs/apis/features/agi/luca-coder.md +407 -0
  299. package/docs/apis/features/agi/openapi.md +2 -2
  300. package/docs/apis/features/agi/skills-library.md +12 -0
  301. package/docs/apis/features/node/python.md +81 -11
  302. package/docs/apis/features/node/transpiler.md +74 -0
  303. package/docs/apis/features/web/esbuild.md +0 -6
  304. package/docs/apis/servers/mcp.md +2 -2
  305. package/docs/examples/entity.md +124 -0
  306. package/docs/ideas/assistant-factory-pattern.md +142 -0
  307. package/package.json +74 -21
  308. package/src/agi/container.server.ts +10 -0
  309. package/src/agi/feature.ts +13 -0
  310. package/src/agi/features/agent-memory.ts +694 -0
  311. package/src/agi/features/assistant.ts +37 -26
  312. package/src/agi/features/assistants-manager.ts +95 -5
  313. package/src/agi/features/autonomous-assistant.ts +1 -5
  314. package/src/agi/features/browser-use.ts +32 -2
  315. package/src/agi/features/claude-code.ts +165 -1
  316. package/src/agi/features/coding-tools.ts +175 -0
  317. package/src/agi/features/conversation-history.ts +2 -6
  318. package/src/agi/features/conversation.ts +95 -3
  319. package/src/agi/features/docs-reader.ts +2 -1
  320. package/src/agi/features/file-tools.ts +35 -28
  321. package/src/agi/features/luca-coder.ts +1 -5
  322. package/src/agi/features/openai-codex.ts +1 -1
  323. package/src/agi/features/openapi.ts +3 -3
  324. package/src/agi/features/skills-library.ts +111 -13
  325. package/src/agi/lib/interceptor-chain.ts +10 -0
  326. package/src/agi/lib/token-counter.ts +1 -1
  327. package/src/bootstrap/generated.ts +126 -1
  328. package/src/bus.ts +27 -5
  329. package/src/cli/build-info.ts +2 -2
  330. package/src/client.ts +2 -2
  331. package/src/clients/elevenlabs/index.ts +5 -0
  332. package/src/clients/voicebox/index.ts +300 -0
  333. package/src/commands/bootstrap.ts +2 -1
  334. package/src/commands/chat.ts +1 -0
  335. package/src/commands/code.ts +4 -2
  336. package/src/commands/prompt.ts +34 -34
  337. package/src/commands/sandbox-mcp.ts +69 -163
  338. package/src/commands/save-api-docs.ts +10 -8
  339. package/src/commands/select.ts +8 -3
  340. package/src/container-describer.ts +70 -84
  341. package/src/container.ts +93 -3
  342. package/src/endpoint.ts +1 -1
  343. package/src/entity.ts +173 -0
  344. package/src/feature.ts +3 -3
  345. package/src/helper.ts +8 -4
  346. package/src/introspection/generated.agi.ts +3012 -1356
  347. package/src/introspection/generated.node.ts +179 -33
  348. package/src/introspection/generated.web.ts +95 -3
  349. package/src/introspection/scan.ts +1 -1
  350. package/src/node/container.ts +1 -1
  351. package/src/node/features/content-db.ts +57 -30
  352. package/src/node/features/file-manager.ts +10 -9
  353. package/src/node/features/git.ts +5 -5
  354. package/src/node/features/helpers.ts +1 -1
  355. package/src/node/features/json-tree.ts +1 -1
  356. package/src/node/features/os.ts +3 -3
  357. package/src/node/features/package-finder.ts +1 -1
  358. package/src/node/features/process-manager.ts +51 -18
  359. package/src/node/features/python.ts +3 -3
  360. package/src/node/features/redis.ts +1 -1
  361. package/src/node/features/repl.ts +2 -2
  362. package/src/node/features/transpiler.ts +2 -2
  363. package/src/node/features/ui.ts +1 -1
  364. package/src/node/features/vm.ts +3 -3
  365. package/src/node/features/yaml-tree.ts +1 -1
  366. package/src/node.ts +1 -0
  367. package/src/python/generated.ts +1 -1
  368. package/src/scaffolds/generated.ts +1 -1
  369. package/src/selector.ts +74 -4
  370. package/src/server.ts +2 -2
  371. package/src/servers/mcp.ts +6 -6
  372. package/src/web/features/helpers.ts +1 -1
  373. package/src/web/features/network.ts +1 -0
  374. package/test/assistant.test.ts +14 -5
  375. package/test/conversation.test.ts +220 -0
  376. package/test-integration/memory.test.ts +204 -0
  377. package/tsconfig.build.json +12 -0
  378. package/tsconfig.json +1 -1
  379. package/scripts/examples/telegram-ink-ui.ts +0 -302
  380. package/scripts/examples/using-openai-codex.ts +0 -23
  381. package/scripts/examples/vm-loading-esm-modules.ts +0 -16
@@ -0,0 +1,175 @@
1
+ import { z } from 'zod'
2
+ import { FeatureStateSchema, FeatureOptionsSchema } from '../../schemas/base.js'
3
+ import { Feature } from '../feature.js'
4
+ import type { Helper } from '../../helper.js'
5
+ import type { ChildProcess } from '../../node/features/proc.js'
6
+
7
+ declare module '@soederpop/luca/feature' {
8
+ interface AvailableFeatures {
9
+ codingTools: typeof CodingTools
10
+ }
11
+ }
12
+
13
+ export const CodingToolsStateSchema = FeatureStateSchema.extend({})
14
+ export const CodingToolsOptionsSchema = FeatureOptionsSchema.extend({})
15
+
16
+ /**
17
+ * Shell primitives for AI coding assistants: rg, ls, cat, sed, awk.
18
+ *
19
+ * Wraps standard Unix tools into the assistant tool surface with
20
+ * LLM-optimized descriptions and system prompt guidance. These are
21
+ * the raw, flexible tools for reading, searching, and exploring code.
22
+ *
23
+ * Compose with other features (fileTools, processManager, skillsLibrary)
24
+ * in assistant hooks for a complete coding tool surface.
25
+ *
26
+ * Usage:
27
+ * ```typescript
28
+ * assistant.use(container.feature('codingTools'))
29
+ * ```
30
+ *
31
+ * @extends Feature
32
+ */
33
+ export class CodingTools extends Feature {
34
+ static override shortcut = 'features.codingTools' as const
35
+ static override stateSchema = CodingToolsStateSchema
36
+ static override optionsSchema = CodingToolsOptionsSchema
37
+
38
+ static { Feature.register(this, 'codingTools') }
39
+
40
+ static override tools: Record<string, { schema: z.ZodType; description?: string }> = {
41
+ rg: {
42
+ description: 'ripgrep — fast content search across files. The fastest way to find where something is defined, referenced, or used. Supports regex, file type filtering, context lines, and everything ripgrep supports.',
43
+ schema: z.object({
44
+ args: z.string().describe(
45
+ 'Arguments to pass to rg, exactly as you would on the command line. ' +
46
+ 'Examples: "TODO --type ts", "-n "function handleAuth" src/", ' +
47
+ '"import.*lodash -g "*.ts" --count", "-C 3 "class User" src/models/"'
48
+ ),
49
+ cwd: z.string().optional().describe('Working directory. Defaults to project root.'),
50
+ }).describe('ripgrep — fast content search across files. Supports regex, file type filtering, context lines. Use this as your primary search tool for finding code.'),
51
+ },
52
+ ls: {
53
+ description: 'List files and directories. Use to orient yourself in the project structure, check what exists in a directory, or verify paths before operating on them.',
54
+ schema: z.object({
55
+ args: z.string().optional().describe(
56
+ 'Arguments to pass to ls. Examples: "-la src/", "-R --color=never commands/", "-1 *.ts". ' +
57
+ 'Defaults to listing the project root.'
58
+ ),
59
+ cwd: z.string().optional().describe('Working directory. Defaults to project root.'),
60
+ }).describe('List files and directories. Use to orient yourself, check directory contents, or verify paths.'),
61
+ },
62
+ cat: {
63
+ description: 'Read file contents. Use for reading entire files or specific line ranges. For large files, prefer reading specific ranges with sed or use rg to find the relevant section first.',
64
+ schema: z.object({
65
+ args: z.string().describe(
66
+ 'Arguments to pass to cat. Typically just a file path. ' +
67
+ 'Examples: "src/index.ts", "-n src/index.ts" (with line numbers). ' +
68
+ 'For line ranges, use sed instead: sed -n "10,20p" file.ts'
69
+ ),
70
+ cwd: z.string().optional().describe('Working directory. Defaults to project root.'),
71
+ }).describe('Read file contents. Best for reading entire files or viewing file content with line numbers.'),
72
+ },
73
+ sed: {
74
+ description: 'Stream editor for extracting or transforming text. Use for reading specific line ranges from files, or performing find-and-replace operations.',
75
+ schema: z.object({
76
+ args: z.string().describe(
77
+ 'Arguments to pass to sed. Examples: ' +
78
+ '"-n \\"10,30p\\" src/index.ts" (print lines 10-30), ' +
79
+ '"-n \\"1,5p\\" package.json" (first 5 lines), ' +
80
+ '"s/oldName/newName/g src/config.ts" (find-and-replace)'
81
+ ),
82
+ cwd: z.string().optional().describe('Working directory. Defaults to project root.'),
83
+ }).describe('Stream editor for extracting line ranges or transforming text in files.'),
84
+ },
85
+ awk: {
86
+ description: 'Pattern scanning and text processing. Use for extracting specific fields from structured output, summarizing data, or complex text transformations.',
87
+ schema: z.object({
88
+ args: z.string().describe(
89
+ 'Arguments to pass to awk. Examples: ' +
90
+ '"\'{print $1}\' file.txt" (first column), ' +
91
+ '"-F: \'{print $1, $3}\' /etc/passwd" (colon-delimited fields), ' +
92
+ '"\'/pattern/ {print}\' file.txt" (lines matching pattern)'
93
+ ),
94
+ cwd: z.string().optional().describe('Working directory. Defaults to project root.'),
95
+ }).describe('Pattern scanning and text processing. Extract fields, summarize data, or perform complex text transformations.'),
96
+ },
97
+ }
98
+
99
+ private get proc(): ChildProcess {
100
+ return this.container.feature('proc') as unknown as ChildProcess
101
+ }
102
+
103
+ // -------------------------------------------------------------------------
104
+ // Shell tool implementations
105
+ // -------------------------------------------------------------------------
106
+
107
+ private async _exec(command: string, args: string, cwd?: string): Promise<string> {
108
+ const fullCommand = args ? `${command} ${args}` : command
109
+ const result = await this.proc.execAndCapture(fullCommand, {
110
+ cwd: cwd ?? this.container.cwd,
111
+ })
112
+
113
+ if (result.exitCode !== 0) {
114
+ const parts: string[] = []
115
+ if (result.stdout?.trim()) parts.push(result.stdout.trim())
116
+ if (result.stderr?.trim()) parts.push(`[stderr] ${result.stderr.trim()}`)
117
+ parts.push(`[exit code: ${result.exitCode}]`)
118
+ return parts.join('\n')
119
+ }
120
+
121
+ return result.stdout || '(no output)'
122
+ }
123
+
124
+ async rg(args: { args: string; cwd?: string }): Promise<string> {
125
+ return this._exec('rg', args.args, args.cwd)
126
+ }
127
+
128
+ async ls(args: { args?: string; cwd?: string }): Promise<string> {
129
+ return this._exec('ls', args.args || '', args.cwd)
130
+ }
131
+
132
+ async cat(args: { args: string; cwd?: string }): Promise<string> {
133
+ return this._exec('cat', args.args, args.cwd)
134
+ }
135
+
136
+ async sed(args: { args: string; cwd?: string }): Promise<string> {
137
+ return this._exec('sed', args.args, args.cwd)
138
+ }
139
+
140
+ async awk(args: { args: string; cwd?: string }): Promise<string> {
141
+ return this._exec('awk', args.args, args.cwd)
142
+ }
143
+
144
+ override setupToolsConsumer(consumer: Helper) {
145
+ if (typeof (consumer as any).addSystemPromptExtension === 'function') {
146
+ (consumer as any).addSystemPromptExtension('codingTools', SYSTEM_PROMPT_EXTENSION)
147
+ }
148
+ }
149
+ }
150
+
151
+ // ─── System Prompt Extension ──────────────────────────────────────────────────
152
+
153
+ const SYSTEM_PROMPT_EXTENSION = [
154
+ '## Shell Tools',
155
+ '',
156
+ 'You have direct access to standard Unix tools. These are your primary read/search/explore tools:',
157
+ '',
158
+ '**`rg` (ripgrep) — your most important tool.** Use it before guessing where anything is.',
159
+ '- `rg -n "pattern" --type ts` — search TypeScript files with line numbers',
160
+ '- `rg -C 3 "pattern"` — show 3 lines of context around matches',
161
+ '- `rg -l "pattern"` — list only filenames that match',
162
+ '- `rg "TODO|FIXME" --type ts --count` — count matches per file',
163
+ '',
164
+ '**`cat` — read files.** Use `cat -n` for line numbers. For large files, use `sed -n "10,30p"` to read a range.',
165
+ '',
166
+ '**`ls` — orient yourself.** `ls -la src/` for details, `ls -R` for recursive listing.',
167
+ '',
168
+ '**`sed` — extract line ranges.** `sed -n "50,80p" file.ts` reads lines 50-80.',
169
+ '',
170
+ '**`awk` — structured text processing.** Extract columns, summarize, transform.',
171
+ '',
172
+ '**Workflow:** `rg` to find → `cat -n` to read → `editFile` to change → `runCommand` to verify.',
173
+ ].join('\n')
174
+
175
+ export default CodingTools
@@ -1,8 +1,8 @@
1
1
  import { z } from 'zod'
2
2
  import { FeatureStateSchema, FeatureOptionsSchema, FeatureEventsSchema } from '../../schemas/base.js'
3
3
  import { type AvailableFeatures } from '@soederpop/luca/feature'
4
- import { Feature } from '@soederpop/luca/feature'
5
- import { NodeContainer, type DiskCache, type NodeFeatures } from '@soederpop/luca/node/container'
4
+ import { Feature } from '../feature.js'
5
+ import type { DiskCache } from '@soederpop/luca/node/container'
6
6
  import type { Message } from './conversation'
7
7
 
8
8
  declare module '@soederpop/luca/feature' {
@@ -95,10 +95,6 @@ export class ConversationHistory extends Feature<ConversationHistoryState, Conve
95
95
  }
96
96
  }
97
97
 
98
- /** @returns The parent NodeContainer, narrowed from the base Container type. */
99
- override get container() {
100
- return super.container as NodeContainer<NodeFeatures, any>
101
- }
102
98
 
103
99
  /** @returns The diskCache feature instance used for persistence, configured with the optional cachePath. */
104
100
  get diskCache(): DiskCache {
@@ -1,7 +1,7 @@
1
1
  import { z } from 'zod'
2
2
  import { FeatureStateSchema, FeatureOptionsSchema, FeatureEventsSchema } from '../../schemas/base.js'
3
3
  import { type AvailableFeatures } from '@soederpop/luca/feature'
4
- import { Feature } from '@soederpop/luca/feature'
4
+ import { Feature } from '../feature.js'
5
5
  import type { OpenAIClient } from '../../clients/openai';
6
6
  import type OpenAI from 'openai';
7
7
  import type { ConversationHistory } from './conversation-history';
@@ -212,9 +212,12 @@ export class Conversation extends Feature<ConversationState, ConversationOptions
212
212
  /** The active structured output schema for the current ask() call, if any. */
213
213
  private _activeSchema: z.ZodType | null = null
214
214
 
215
- /** Resolved max tokens: per-call override > options-level > default 512. */
215
+ /** Registered stubs: matched against user input to short-circuit the API with a canned response. */
216
+ private _stubs: Array<{ matcher: string | RegExp; response: string | (() => string) }> = []
217
+
218
+ /** Resolved max tokens: per-call override > options-level. Undefined means no limit (model default). */
216
219
  private get maxTokens(): number | undefined {
217
- return (this.state.get('callMaxTokens') as number | null) ?? this.options.maxTokens ?? 512
220
+ return (this.state.get('callMaxTokens') as number | null) ?? this.options.maxTokens ?? undefined
218
221
  }
219
222
 
220
223
  /** @returns Default state seeded from options: id, thread, model, initial history, and zero token usage. */
@@ -276,6 +279,22 @@ export class Conversation extends Feature<ConversationState, ConversationOptions
276
279
  return this
277
280
  }
278
281
 
282
+ /**
283
+ * Register a hardcoded stub response that bypasses the API when the user's message matches.
284
+ * Streaming is still simulated — chunk/preview events fire word-by-word.
285
+ *
286
+ * @param matcher - Exact string match, substring, or RegExp tested against user input
287
+ * @param response - The text to stream back, or a zero-arg function that returns it
288
+ *
289
+ * @example
290
+ * conversation.stub('hello', 'Hi there!')
291
+ * conversation.stub(/weather/i, () => 'Sunny and 72°F.')
292
+ */
293
+ stub(matcher: string | RegExp, response: string | (() => string)): this {
294
+ this._stubs.push({ matcher, response })
295
+ return this
296
+ }
297
+
279
298
  /** Returns configured remote MCP servers keyed by server label. */
280
299
  get mcpServers(): Record<string, ConversationMCPServer> {
281
300
  return (this.options.mcpServers || {}) as Record<string, ConversationMCPServer>
@@ -286,6 +305,30 @@ export class Conversation extends Feature<ConversationState, ConversationOptions
286
305
  return this.state.get('messages') || []
287
306
  }
288
307
 
308
+ /**
309
+ * Fork the conversation into a new independent instance.
310
+ * The fork inherits the same system prompt, tools, and full message history,
311
+ * but has its own identity and state — changes in either direction do not affect the other.
312
+ *
313
+ * @param overrides - Optional option overrides for the forked conversation (e.g. different model or title)
314
+ *
315
+ * @example
316
+ * ```typescript
317
+ * const fork = conversation.fork()
318
+ * await fork.ask('What if we took a different approach?')
319
+ * // original conversation is unchanged
320
+ * ```
321
+ */
322
+ fork(overrides: Partial<ConversationOptions> = {}): Conversation {
323
+ return this.container.feature('conversation', {
324
+ ...this.options,
325
+ id: undefined,
326
+ history: JSON.parse(JSON.stringify(this.messages)),
327
+ tools: { ...this.tools },
328
+ ...overrides,
329
+ })
330
+ }
331
+
289
332
  /** Returns the OpenAI model name being used for completions. */
290
333
  get model(): string {
291
334
  return this.state.get('model')!
@@ -518,6 +561,11 @@ export class Conversation extends Feature<ConversationState, ConversationOptions
518
561
  this.emit('userMessage', content)
519
562
 
520
563
  try {
564
+ const stubText = this._matchStub(typeof content === 'string' ? content : '')
565
+ if (stubText !== null) {
566
+ return await this._streamStub(stubText)
567
+ }
568
+
521
569
  let raw: string
522
570
 
523
571
  if (this.apiMode === 'responses') {
@@ -764,6 +812,50 @@ export class Conversation extends Feature<ConversationState, ConversationOptions
764
812
  }
765
813
  }
766
814
 
815
+ /** Check registered stubs against user input. Returns the response text, or null if no match. */
816
+ private _matchStub(input: string): string | null {
817
+ for (const { matcher, response } of this._stubs) {
818
+ const matched = typeof matcher === 'string'
819
+ ? input === matcher || input.includes(matcher)
820
+ : matcher.test(input)
821
+ if (matched) {
822
+ return typeof response === 'function' ? response() : response
823
+ }
824
+ }
825
+ return null
826
+ }
827
+
828
+ /**
829
+ * Simulate a streaming response for a hardcoded stub text.
830
+ * Emits chunk/preview events word-by-word, yielding between each to keep the event loop alive.
831
+ */
832
+ private async _streamStub(text: string): Promise<string> {
833
+ this.state.set('streaming', true)
834
+ this.emit('turnStart', { turn: 1, isFollowUp: false })
835
+
836
+ let accumulated = ''
837
+ const chunks = text.match(/\S+\s*/g) ?? [text]
838
+
839
+ try {
840
+ for (const chunk of chunks) {
841
+ accumulated += chunk
842
+ this.emit('chunk', chunk)
843
+ this.emit('preview', accumulated)
844
+ await Promise.resolve()
845
+ }
846
+ } finally {
847
+ this.state.set('streaming', false)
848
+ }
849
+
850
+ const trimmed = text
851
+ this.pushMessage({ role: 'assistant', content: trimmed })
852
+ this.state.set('lastResponse', trimmed)
853
+ this.emit('turnEnd', { turn: 1, hasToolCalls: false })
854
+ this.emit('response', trimmed)
855
+
856
+ return trimmed
857
+ }
858
+
767
859
  /**
768
860
  * Runs the streaming Responses API loop. Handles local function calls by
769
861
  * executing handlers and submitting `function_call_output` items until
@@ -1,6 +1,7 @@
1
1
  import { z } from 'zod'
2
2
  import { FeatureStateSchema, FeatureOptionsSchema, FeatureEventsSchema } from '../../schemas/base.js'
3
- import { type AvailableFeatures, Feature } from '@soederpop/luca/feature'
3
+ import { type AvailableFeatures } from '@soederpop/luca/feature'
4
+ import { Feature } from '../feature.js'
4
5
  import type { ContentDb } from '@/node.js'
5
6
  import type Assistant from './assistant.js'
6
7
 
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod'
2
2
  import { FeatureStateSchema, FeatureOptionsSchema, FeatureEventsSchema } from '../../schemas/base.js'
3
- import { Feature } from '@soederpop/luca/feature'
3
+ import { Feature } from '../feature.js'
4
4
  import type { FS } from '../../node/features/fs.js'
5
5
  import type { Grep, GrepMatch } from '../../node/features/grep.js'
6
6
  import type { Helper } from '../../helper.js'
@@ -38,7 +38,7 @@ export class FileTools extends Feature {
38
38
 
39
39
  static { Feature.register(this, 'fileTools') }
40
40
 
41
- static tools: Record<string, { schema: z.ZodType; description?: string }> = {
41
+ static override tools: Record<string, { schema: z.ZodType; description?: string }> = {
42
42
  readFile: {
43
43
  description: 'Read the contents of a file. Returns the text content. Use offset/limit to read portions of large files.',
44
44
  schema: z.object({
@@ -48,20 +48,20 @@ export class FileTools extends Feature {
48
48
  }).describe('Read the contents of a file. Returns the text content. Use offset/limit to read portions of large files.'),
49
49
  },
50
50
  writeFile: {
51
- description: 'Create a new file or overwrite an existing file with the given content. Prefer editFile for modifying existing files.',
51
+ description: 'Create a new file or completely overwrite an existing file. WARNING: this replaces the entire file use editFile instead for modifying existing files. Use writeFile only for creating new files or intentional full rewrites.',
52
52
  schema: z.object({
53
- path: z.string().describe('File path relative to the project root'),
54
- content: z.string().describe('The full content to write'),
55
- }).describe('Create a new file or overwrite an existing file with the given content. Prefer editFile for modifying existing files.'),
53
+ path: z.string().describe('File path relative to the project root. Parent directories are created automatically.'),
54
+ content: z.string().describe('The complete file content. This replaces everything in the file — there is no merge or append.'),
55
+ }).describe('Create a new file or completely overwrite an existing file. WARNING: this replaces the entire file use editFile instead for modifying existing files. Use writeFile only for creating new files or intentional full rewrites.'),
56
56
  },
57
57
  editFile: {
58
- description: 'Make a surgical edit to a file by replacing an exact string match. The oldString must appear exactly once in the file (unless replaceAll is true). This is the preferred way to modify existing files.',
58
+ description: 'Make a surgical edit to a file by replacing an exact string match. The preferred way to modify existing files always use this over writeFile for changes to existing code.',
59
59
  schema: z.object({
60
60
  path: z.string().describe('File path relative to the project root'),
61
- oldString: z.string().describe('The exact text to find and replace'),
62
- newString: z.string().describe('The replacement text'),
63
- replaceAll: z.boolean().optional().describe('Replace all occurrences instead of requiring uniqueness (default: false)'),
64
- }).describe('Make a surgical edit to a file by replacing an exact string match. The oldString must appear exactly once in the file (unless replaceAll is true).'),
61
+ oldString: z.string().describe('The EXACT text to find, copied verbatim from the file — including whitespace and indentation. Must appear exactly once in the file (unless replaceAll is true). If the match fails, read the file again and copy the exact text.'),
62
+ newString: z.string().describe('The replacement text. Preserve the same indentation style as the surrounding code.'),
63
+ replaceAll: z.boolean().optional().describe('Replace all occurrences instead of requiring uniqueness. Use for renaming a variable across a file. Default: false.'),
64
+ }).describe('Make a surgical edit to a file by replacing an exact string match. The preferred way to modify existing files always use this over writeFile for changes to existing code.'),
65
65
  },
66
66
  listDirectory: {
67
67
  description: 'List files and directories at a path. Returns arrays of file and directory names.',
@@ -73,23 +73,23 @@ export class FileTools extends Feature {
73
73
  }).describe('List files and directories at a path. Returns arrays of file and directory names.'),
74
74
  },
75
75
  searchFiles: {
76
- description: 'Search file contents for a pattern using ripgrep. Returns structured matches with file, line number, and content.',
76
+ description: 'Search inside file contents for a pattern (like grep/ripgrep). Returns matching lines with file path and line number. Use this to find where code is defined, where a function is called, or any text pattern across the codebase.',
77
77
  schema: z.object({
78
- pattern: z.string().describe('Search pattern (regex supported)'),
79
- path: z.string().optional().describe('Directory to search in (defaults to project root)'),
80
- include: z.string().optional().describe('Glob pattern to filter files (e.g. "*.ts")'),
81
- exclude: z.string().optional().describe('Glob pattern to exclude (e.g. "node_modules")'),
82
- ignoreCase: z.boolean().optional().describe('Case insensitive search'),
83
- maxResults: z.number().optional().describe('Maximum number of results to return'),
84
- }).describe('Search file contents for a pattern using ripgrep. Returns structured matches with file, line number, and content.'),
78
+ pattern: z.string().describe('Search pattern — supports regex. Examples: "function handleAuth", "TODO|FIXME", "import.*from.*react"'),
79
+ path: z.string().optional().describe('Directory to search in (defaults to project root). Narrow this to avoid searching node_modules or irrelevant directories.'),
80
+ include: z.string().optional().describe('Glob to filter which files to search (e.g. "*.ts", "*.tsx"). Use this to scope to specific file types.'),
81
+ exclude: z.string().optional().describe('Glob to exclude files (e.g. "node_modules", "dist"). node_modules is excluded by default.'),
82
+ ignoreCase: z.boolean().optional().describe('Case insensitive search. Default: false.'),
83
+ maxResults: z.number().optional().describe('Maximum results to return. Default: 50. Use a smaller number for broad patterns.'),
84
+ }).describe('Search inside file contents for a pattern (like grep/ripgrep). Returns matching lines with file path and line number. Use this to find where code is defined, where a function is called, or any text pattern across the codebase.'),
85
85
  },
86
86
  findFiles: {
87
- description: 'Find files by name/glob pattern. Returns matching file paths.',
87
+ description: 'Find files by name or glob pattern. Returns file paths, not contents. Use this to locate files ("where is the config?"), not to search inside them (use searchFiles for that).',
88
88
  schema: z.object({
89
- pattern: z.string().describe('Glob pattern to match (e.g. "**/*.test.ts", "src/**/*.tsx")'),
89
+ pattern: z.string().describe('Glob pattern to match file names. Examples: "**/*.test.ts", "src/**/*.tsx", "**/config.*"'),
90
90
  path: z.string().optional().describe('Directory to search from (defaults to project root)'),
91
- exclude: z.string().optional().describe('Glob pattern to exclude'),
92
- }).describe('Find files by name/glob pattern. Returns matching file paths.'),
91
+ exclude: z.string().optional().describe('Glob pattern to exclude. node_modules and .git are excluded by default.'),
92
+ }).describe('Find files by name or glob pattern. Returns file paths, not contents. Use this to locate files ("where is the config?"), not to search inside them (use searchFiles for that).'),
93
93
  },
94
94
  fileInfo: {
95
95
  description: 'Get information about a file or directory: whether it exists, its type (file/directory), size, and modification time.',
@@ -273,11 +273,18 @@ export class FileTools extends Feature {
273
273
  if (typeof (consumer as any).addSystemPromptExtension === 'function') {
274
274
  (consumer as any).addSystemPromptExtension('fileTools', [
275
275
  '## File Tools',
276
- '- All file paths are relative to the project root unless they start with /',
277
- '- Use `searchFiles` to understand code before modifying it',
278
- '- Use `editFile` for surgical changes to existing files — prefer it over `writeFile`',
279
- '- Use `listDirectory` to explore before assuming paths exist',
280
- '- Use `readFile` with offset/limit for large files instead of reading the entire file',
276
+ '',
277
+ 'All paths are relative to the project root unless they start with /.',
278
+ '',
279
+ '**Before modifying code:** Always read the file first. Use `searchFiles` to find where something is defined before making changes. Use `listDirectory` to verify paths exist before assuming.',
280
+ '',
281
+ '**Editing files:** Prefer `editFile` over `writeFile` for existing files — it makes surgical replacements. The `oldString` must appear exactly once in the file (unless using `replaceAll`). If your match isn\'t unique, include more surrounding context to make it unique. Never guess at file contents — read first, then edit.',
282
+ '',
283
+ '**Finding things:** Use `findFiles` to locate files by name or glob pattern (e.g. "**/*.test.ts"). Use `searchFiles` to find specific content inside files (grep). These are different tools for different questions: "where is the file?" vs "where is this code?".',
284
+ '',
285
+ '**Large files:** Use `readFile` with `offset` and `limit` to read portions. Don\'t load a 5000-line file when you only need lines 100-150.',
286
+ '',
287
+ '**`writeFile` is destructive** — it overwrites the entire file. Only use it for creating new files or when you intend a complete rewrite.',
281
288
  ].join('\n'))
282
289
  }
283
290
  }
@@ -1,7 +1,6 @@
1
1
  import { z } from 'zod'
2
2
  import { FeatureStateSchema, FeatureOptionsSchema, FeatureEventsSchema } from '../../schemas/base.js'
3
- import { Feature } from '@soederpop/luca/feature'
4
- import type { AGIContainer } from '../container.server.js'
3
+ import { Feature } from '../feature.js'
5
4
  import type { Assistant } from './assistant.js'
6
5
  import type { ToolCallCtx } from '../lib/interceptor-chain.js'
7
6
 
@@ -214,9 +213,6 @@ export class LucaCoder extends Feature<LucaCoderState, LucaCoderOptions> {
214
213
  }
215
214
  }
216
215
 
217
- override get container(): AGIContainer {
218
- return super.container as AGIContainer
219
- }
220
216
 
221
217
  /** The inner assistant. Throws if not started. */
222
218
  get assistant(): Assistant {
@@ -2,7 +2,7 @@
2
2
  import { z } from 'zod'
3
3
  import { FeatureStateSchema, FeatureOptionsSchema, FeatureEventsSchema } from '../../schemas/base.js'
4
4
  import { type AvailableFeatures } from '@soederpop/luca/feature'
5
- import { Feature } from '@soederpop/luca/feature'
5
+ import { Feature } from '../feature.js'
6
6
 
7
7
  declare module '@soederpop/luca/feature' {
8
8
  interface AvailableFeatures {
@@ -1,4 +1,4 @@
1
- import { Feature } from '../../feature.js'
1
+ import { Feature } from '../feature.js'
2
2
  import { FeatureStateSchema, FeatureOptionsSchema, FeatureEventsSchema } from '../../schemas/base.js'
3
3
  import { z } from 'zod'
4
4
  import { camelCase } from 'lodash-es'
@@ -95,7 +95,7 @@ export interface OpenAIToolDef {
95
95
  * api.endpoint('getPetById')
96
96
  *
97
97
  * // Convert to OpenAI tool definitions
98
- * api.toTools()
98
+ * api.toOpenAITools()
99
99
  *
100
100
  * // Convert a single endpoint to a function definition
101
101
  * api.toFunction('getPetById')
@@ -205,7 +205,7 @@ export class OpenAPI extends Feature<OpenAPIState, OpenAPIOptions> {
205
205
  * @param {Function} [filter] - Optional predicate to select which endpoints to include
206
206
  * @returns {OpenAIToolDef[]} Array of tool definitions ready for the OpenAI tools parameter
207
207
  */
208
- toTools(filter?: (ep: EndpointInfo) => boolean): OpenAIToolDef[] {
208
+ toOpenAITools(filter?: (ep: EndpointInfo) => boolean): OpenAIToolDef[] {
209
209
  const eps = filter ? this.endpoints.filter(filter) : this.endpoints
210
210
  return eps.map((ep) => ({
211
211
  type: 'function' as const,