@neurocode-ai/core 1.18.8

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 (490) hide show
  1. package/bin/neurocode +199 -0
  2. package/bunfig.toml +2 -0
  3. package/drizzle.config.ts +10 -0
  4. package/package.json +131 -0
  5. package/schema.json +2071 -0
  6. package/script/fix-node-pty.ts +28 -0
  7. package/script/migration.ts +196 -0
  8. package/src/account/sql.ts +39 -0
  9. package/src/account.ts +101 -0
  10. package/src/agent.ts +111 -0
  11. package/src/aisdk.ts +235 -0
  12. package/src/background-job.ts +365 -0
  13. package/src/catalog.ts +301 -0
  14. package/src/command.ts +64 -0
  15. package/src/config/agent.ts +25 -0
  16. package/src/config/attachments.ts +15 -0
  17. package/src/config/command.ts +12 -0
  18. package/src/config/compaction.ts +15 -0
  19. package/src/config/experimental.ts +18 -0
  20. package/src/config/formatter.ts +12 -0
  21. package/src/config/lsp.ts +18 -0
  22. package/src/config/markdown.ts +36 -0
  23. package/src/config/mcp.ts +48 -0
  24. package/src/config/plugin/agent.ts +179 -0
  25. package/src/config/plugin/command.ts +83 -0
  26. package/src/config/plugin/external.ts +91 -0
  27. package/src/config/plugin/provider.ts +113 -0
  28. package/src/config/plugin/reference.ts +70 -0
  29. package/src/config/plugin/skill.ts +50 -0
  30. package/src/config/plugin.ts +13 -0
  31. package/src/config/provider.ts +71 -0
  32. package/src/config/reference.ts +22 -0
  33. package/src/config/tool-output.ts +9 -0
  34. package/src/config/watcher.ts +7 -0
  35. package/src/config.ts +227 -0
  36. package/src/control-plane/move-session.ts +148 -0
  37. package/src/control-plane/workspace.sql.ts +20 -0
  38. package/src/credential/sql.ts +14 -0
  39. package/src/credential.ts +138 -0
  40. package/src/cross-spawn-spawner.ts +507 -0
  41. package/src/data-migration.sql.ts +6 -0
  42. package/src/database/database.ts +57 -0
  43. package/src/database/migration/20260127222353_familiar_lady_ursula.ts +107 -0
  44. package/src/database/migration/20260211171708_add_project_commands.ts +11 -0
  45. package/src/database/migration/20260213144116_wakeful_the_professor.ts +23 -0
  46. package/src/database/migration/20260225215848_workspace.ts +19 -0
  47. package/src/database/migration/20260227213759_add_session_workspace_id.ts +12 -0
  48. package/src/database/migration/20260228203230_blue_harpoon.ts +30 -0
  49. package/src/database/migration/20260303231226_add_workspace_fields.ts +15 -0
  50. package/src/database/migration/20260309230000_move_org_to_state.ts +15 -0
  51. package/src/database/migration/20260312043431_session_message_cursor.ts +16 -0
  52. package/src/database/migration/20260323234822_events.ts +26 -0
  53. package/src/database/migration/20260410174513_workspace-name.ts +29 -0
  54. package/src/database/migration/20260413175956_chief_energizer.ts +24 -0
  55. package/src/database/migration/20260423070820_add_icon_url_override.ts +14 -0
  56. package/src/database/migration/20260427172553_slow_nightmare.ts +30 -0
  57. package/src/database/migration/20260428004200_add_session_path.ts +11 -0
  58. package/src/database/migration/20260501142318_next_venus.ts +12 -0
  59. package/src/database/migration/20260504145000_add_sync_owner.ts +11 -0
  60. package/src/database/migration/20260507164347_add_workspace_time.ts +11 -0
  61. package/src/database/migration/20260510033149_session_usage.ts +56 -0
  62. package/src/database/migration/20260511000411_data_migration_state.ts +16 -0
  63. package/src/database/migration/20260511173437_session-metadata.ts +16 -0
  64. package/src/database/migration/20260601010001_normalize_storage_paths.ts +22 -0
  65. package/src/database/migration/20260601202201_amazing_prowler.ts +11 -0
  66. package/src/database/migration/20260602002951_lowly_union_jack.ts +24 -0
  67. package/src/database/migration/20260602182828_add_project_directories.ts +20 -0
  68. package/src/database/migration/20260603001617_session_message_projection_indexes.ts +19 -0
  69. package/src/database/migration/20260603040000_session_message_projection_order.ts +19 -0
  70. package/src/database/migration/20260603141458_session_input_inbox.ts +25 -0
  71. package/src/database/migration/20260603160727_jittery_ezekiel_stane.ts +20 -0
  72. package/src/database/migration/20260604172448_event_sourced_session_input.ts +47 -0
  73. package/src/database/migration/20260605003541_add_session_context_snapshot.ts +21 -0
  74. package/src/database/migration/20260605042240_add_context_epoch_agent.ts +11 -0
  75. package/src/database/migration/20260611035744_credential.ts +25 -0
  76. package/src/database/migration/20260611192811_lush_chimera.ts +25 -0
  77. package/src/database/migration/20260612174303_project_dir_strategy.ts +29 -0
  78. package/src/database/migration/20260622142730_simplify_session_context_epoch.ts +13 -0
  79. package/src/database/migration/20260622170816_reset_v2_session_state.ts +17 -0
  80. package/src/database/migration/20260622202450_simplify_session_input.ts +17 -0
  81. package/src/database/migration.gen.ts +44 -0
  82. package/src/database/migration.ts +81 -0
  83. package/src/database/path.ts +91 -0
  84. package/src/database/schema.gen.ts +274 -0
  85. package/src/database/schema.sql.ts +10 -0
  86. package/src/database/sqlite.bun.ts +183 -0
  87. package/src/database/sqlite.node.ts +178 -0
  88. package/src/database/sqlite.ts +8 -0
  89. package/src/effect/app-node-builder.ts +23 -0
  90. package/src/effect/app-node-platform.ts +18 -0
  91. package/src/effect/app-node.ts +14 -0
  92. package/src/effect/dfdf +1 -0
  93. package/src/effect/keyed-mutex.ts +45 -0
  94. package/src/effect/layer-node.ts +333 -0
  95. package/src/effect/memo-map.ts +3 -0
  96. package/src/effect/runtime.ts +21 -0
  97. package/src/effect/service-use.ts +43 -0
  98. package/src/event/sql.ts +25 -0
  99. package/src/event.ts +638 -0
  100. package/src/file-mutation.ts +207 -0
  101. package/src/file.ts +6 -0
  102. package/src/filesystem/fff.bun.ts +140 -0
  103. package/src/filesystem/fff.node.ts +138 -0
  104. package/src/filesystem/ignore.ts +67 -0
  105. package/src/filesystem/protected.ts +53 -0
  106. package/src/filesystem/search.ts +239 -0
  107. package/src/filesystem/watcher.ts +140 -0
  108. package/src/filesystem.ts +118 -0
  109. package/src/flag/flag.ts +78 -0
  110. package/src/fs-util.ts +274 -0
  111. package/src/git.ts +987 -0
  112. package/src/github-copilot/README.md +5 -0
  113. package/src/github-copilot/chat/convert-to-openai-compatible-chat-messages.ts +170 -0
  114. package/src/github-copilot/chat/get-response-metadata.ts +15 -0
  115. package/src/github-copilot/chat/map-openai-compatible-finish-reason.ts +19 -0
  116. package/src/github-copilot/chat/openai-compatible-api-types.ts +64 -0
  117. package/src/github-copilot/chat/openai-compatible-chat-language-model.ts +815 -0
  118. package/src/github-copilot/chat/openai-compatible-chat-options.ts +28 -0
  119. package/src/github-copilot/chat/openai-compatible-metadata-extractor.ts +44 -0
  120. package/src/github-copilot/chat/openai-compatible-prepare-tools.ts +83 -0
  121. package/src/github-copilot/copilot-provider.ts +100 -0
  122. package/src/github-copilot/openai-compatible-error.ts +27 -0
  123. package/src/github-copilot/responses/convert-to-openai-responses-input.ts +335 -0
  124. package/src/github-copilot/responses/map-openai-responses-finish-reason.ts +22 -0
  125. package/src/github-copilot/responses/openai-config.ts +18 -0
  126. package/src/github-copilot/responses/openai-error.ts +22 -0
  127. package/src/github-copilot/responses/openai-responses-api-types.ts +214 -0
  128. package/src/github-copilot/responses/openai-responses-language-model.ts +1770 -0
  129. package/src/github-copilot/responses/openai-responses-prepare-tools.ts +173 -0
  130. package/src/github-copilot/responses/openai-responses-settings.ts +1 -0
  131. package/src/github-copilot/responses/tool/code-interpreter.ts +87 -0
  132. package/src/github-copilot/responses/tool/file-search.ts +127 -0
  133. package/src/github-copilot/responses/tool/image-generation.ts +114 -0
  134. package/src/github-copilot/responses/tool/local-shell.ts +64 -0
  135. package/src/github-copilot/responses/tool/web-search-preview.ts +103 -0
  136. package/src/github-copilot/responses/tool/web-search.ts +102 -0
  137. package/src/global.ts +87 -0
  138. package/src/id/id.ts +47 -0
  139. package/src/image/photon.ts +94 -0
  140. package/src/image.ts +81 -0
  141. package/src/installation/version.ts +8 -0
  142. package/src/instruction-context.ts +101 -0
  143. package/src/integration/connection.ts +12 -0
  144. package/src/integration.ts +520 -0
  145. package/src/location-mutation.ts +162 -0
  146. package/src/location-service-map.ts +18 -0
  147. package/src/location-services.ts +115 -0
  148. package/src/location.ts +39 -0
  149. package/src/markdown.d.ts +4 -0
  150. package/src/model.ts +41 -0
  151. package/src/models-dev.ts +260 -0
  152. package/src/npm-config.ts +40 -0
  153. package/src/npm.ts +269 -0
  154. package/src/oauth/page.ts +276 -0
  155. package/src/observability/logging.ts +71 -0
  156. package/src/observability/otlp.ts +79 -0
  157. package/src/observability/shared.ts +1 -0
  158. package/src/observability.ts +24 -0
  159. package/src/patch.ts +197 -0
  160. package/src/permission/saved.ts +79 -0
  161. package/src/permission/sql.ts +20 -0
  162. package/src/permission.ts +310 -0
  163. package/src/plugin/agent.ts +206 -0
  164. package/src/plugin/command/initialize.txt +65 -0
  165. package/src/plugin/command/review.txt +100 -0
  166. package/src/plugin/command.ts +25 -0
  167. package/src/plugin/host.ts +219 -0
  168. package/src/plugin/internal.ts +153 -0
  169. package/src/plugin/layer-map.example.ts +94 -0
  170. package/src/plugin/models-dev.ts +183 -0
  171. package/src/plugin/promise.ts +93 -0
  172. package/src/plugin/provider/alibaba.ts +15 -0
  173. package/src/plugin/provider/amazon-bedrock.ts +126 -0
  174. package/src/plugin/provider/anthropic.ts +27 -0
  175. package/src/plugin/provider/azure.ts +82 -0
  176. package/src/plugin/provider/cerebras.ts +26 -0
  177. package/src/plugin/provider/cloudflare-ai-gateway.ts +81 -0
  178. package/src/plugin/provider/cloudflare-workers-ai.ts +81 -0
  179. package/src/plugin/provider/cohere.ts +15 -0
  180. package/src/plugin/provider/deepinfra.ts +15 -0
  181. package/src/plugin/provider/dynamic.ts +31 -0
  182. package/src/plugin/provider/gateway.ts +15 -0
  183. package/src/plugin/provider/github-copilot.ts +52 -0
  184. package/src/plugin/provider/gitlab.ts +65 -0
  185. package/src/plugin/provider/google-vertex.ts +173 -0
  186. package/src/plugin/provider/google.ts +15 -0
  187. package/src/plugin/provider/groq.ts +15 -0
  188. package/src/plugin/provider/kilo.ts +21 -0
  189. package/src/plugin/provider/llmgateway.ts +26 -0
  190. package/src/plugin/provider/mistral.ts +15 -0
  191. package/src/plugin/provider/nvidia.ts +22 -0
  192. package/src/plugin/provider/openai-compatible.ts +17 -0
  193. package/src/plugin/provider/openai.ts +292 -0
  194. package/src/plugin/provider/opencode.ts +311 -0
  195. package/src/plugin/provider/openrouter.ts +36 -0
  196. package/src/plugin/provider/perplexity.ts +15 -0
  197. package/src/plugin/provider/sap-ai-core.ts +46 -0
  198. package/src/plugin/provider/snowflake-cortex.ts +89 -0
  199. package/src/plugin/provider/togetherai.ts +15 -0
  200. package/src/plugin/provider/venice.ts +15 -0
  201. package/src/plugin/provider/vercel.ts +27 -0
  202. package/src/plugin/provider/xai.ts +22 -0
  203. package/src/plugin/provider/zenmux.ts +21 -0
  204. package/src/plugin/provider.ts +71 -0
  205. package/src/plugin/skill/customize-neurocode.md +452 -0
  206. package/src/plugin/skill.ts +31 -0
  207. package/src/plugin/variant.ts +39 -0
  208. package/src/plugin.ts +167 -0
  209. package/src/policy.ts +49 -0
  210. package/src/process.ts +261 -0
  211. package/src/project/copy-strategies.ts +35 -0
  212. package/src/project/copy.ts +292 -0
  213. package/src/project/directories.ts +158 -0
  214. package/src/project/schema.ts +16 -0
  215. package/src/project/sql.ts +35 -0
  216. package/src/project.ts +136 -0
  217. package/src/provider.ts +25 -0
  218. package/src/pty/protocol.ts +37 -0
  219. package/src/pty/pty.bun.ts +26 -0
  220. package/src/pty/pty.node.ts +29 -0
  221. package/src/pty/pty.ts +25 -0
  222. package/src/pty/schema.ts +1 -0
  223. package/src/pty/ticket.ts +56 -0
  224. package/src/pty.ts +318 -0
  225. package/src/public-event-manifest.ts +7 -0
  226. package/src/question.ts +153 -0
  227. package/src/reference/guidance.ts +69 -0
  228. package/src/reference.ts +125 -0
  229. package/src/repository-cache.ts +259 -0
  230. package/src/repository.ts +214 -0
  231. package/src/ripgrep/binary.ts +132 -0
  232. package/src/ripgrep.ts +281 -0
  233. package/src/schema.ts +79 -0
  234. package/src/session/compaction.ts +241 -0
  235. package/src/session/context-epoch.ts +174 -0
  236. package/src/session/error.ts +24 -0
  237. package/src/session/event.ts +2 -0
  238. package/src/session/execution/local.ts +46 -0
  239. package/src/session/execution.ts +34 -0
  240. package/src/session/history.ts +101 -0
  241. package/src/session/info.ts +50 -0
  242. package/src/session/input.ts +288 -0
  243. package/src/session/message-updater.ts +397 -0
  244. package/src/session/message.ts +2 -0
  245. package/src/session/projector.ts +458 -0
  246. package/src/session/prompt.ts +1 -0
  247. package/src/session/revert.ts +121 -0
  248. package/src/session/run-coordinator.ts +104 -0
  249. package/src/session/runner/index.ts +28 -0
  250. package/src/session/runner/llm.ts +432 -0
  251. package/src/session/runner/max-steps.ts +16 -0
  252. package/src/session/runner/model.ts +218 -0
  253. package/src/session/runner/publish-llm-event.ts +423 -0
  254. package/src/session/runner/to-llm-message.ts +171 -0
  255. package/src/session/schema.ts +9 -0
  256. package/src/session/sql.ts +176 -0
  257. package/src/session/store.ts +63 -0
  258. package/src/session/todo.ts +78 -0
  259. package/src/session.ts +486 -0
  260. package/src/share/sql.ts +13 -0
  261. package/src/shell.ts +226 -0
  262. package/src/skill/discovery.ts +213 -0
  263. package/src/skill/guidance.ts +76 -0
  264. package/src/skill.ts +132 -0
  265. package/src/snapshot.ts +266 -0
  266. package/src/state.ts +128 -0
  267. package/src/system-context/builtins.ts +50 -0
  268. package/src/system-context/index.ts +320 -0
  269. package/src/system-context/registry.ts +49 -0
  270. package/src/tool/AGENTS.md +59 -0
  271. package/src/tool/application-tools.ts +57 -0
  272. package/src/tool/apply-patch.ts +219 -0
  273. package/src/tool/bash.ts +207 -0
  274. package/src/tool/builtins.ts +48 -0
  275. package/src/tool/edit.ts +223 -0
  276. package/src/tool/glob.ts +105 -0
  277. package/src/tool/grep.ts +137 -0
  278. package/src/tool/http-body.ts +30 -0
  279. package/src/tool/question.ts +94 -0
  280. package/src/tool/read-filesystem.ts +366 -0
  281. package/src/tool/read.ts +117 -0
  282. package/src/tool/registry.ts +147 -0
  283. package/src/tool/skill.ts +109 -0
  284. package/src/tool/todowrite.ts +62 -0
  285. package/src/tool/tool.ts +162 -0
  286. package/src/tool/tools.ts +13 -0
  287. package/src/tool/webfetch.ts +218 -0
  288. package/src/tool/websearch.ts +260 -0
  289. package/src/tool/write.ts +101 -0
  290. package/src/tool-output-store.ts +211 -0
  291. package/src/util/array.ts +10 -0
  292. package/src/util/binary.ts +41 -0
  293. package/src/util/effect-flock.ts +284 -0
  294. package/src/util/encode.ts +51 -0
  295. package/src/util/error.ts +70 -0
  296. package/src/util/flock.ts +358 -0
  297. package/src/util/glob.ts +34 -0
  298. package/src/util/hash.ts +11 -0
  299. package/src/util/identifier.ts +1 -0
  300. package/src/util/iife.ts +3 -0
  301. package/src/util/lazy.ts +11 -0
  302. package/src/util/module.ts +10 -0
  303. package/src/util/path.ts +37 -0
  304. package/src/util/retry.ts +42 -0
  305. package/src/util/slug.ts +74 -0
  306. package/src/util/token.ts +5 -0
  307. package/src/util/which.ts +14 -0
  308. package/src/util/wildcard.ts +14 -0
  309. package/src/v1/config/agent.ts +89 -0
  310. package/src/v1/config/attachment.ts +25 -0
  311. package/src/v1/config/command.ts +13 -0
  312. package/src/v1/config/config.ts +192 -0
  313. package/src/v1/config/console-state.ts +16 -0
  314. package/src/v1/config/error.ts +39 -0
  315. package/src/v1/config/formatter.ts +13 -0
  316. package/src/v1/config/layout.ts +6 -0
  317. package/src/v1/config/lsp.ts +80 -0
  318. package/src/v1/config/mcp.ts +63 -0
  319. package/src/v1/config/migrate.ts +254 -0
  320. package/src/v1/config/permission.ts +50 -0
  321. package/src/v1/config/plugin.ts +9 -0
  322. package/src/v1/config/provider-options.ts +227 -0
  323. package/src/v1/config/provider.ts +121 -0
  324. package/src/v1/config/server.ts +19 -0
  325. package/src/v1/config/skills.ts +13 -0
  326. package/src/v1/permission.ts +33 -0
  327. package/src/v1/session.ts +68 -0
  328. package/src/v2-schema.ts +3 -0
  329. package/src/workspace.ts +6 -0
  330. package/sst-env.d.ts +10 -0
  331. package/test/agent.test.ts +131 -0
  332. package/test/application-tools.test.ts +287 -0
  333. package/test/background-job.test.ts +106 -0
  334. package/test/catalog.test.ts +353 -0
  335. package/test/command.test.ts +56 -0
  336. package/test/config/agent.test.ts +349 -0
  337. package/test/config/command.test.ts +83 -0
  338. package/test/config/config.test.ts +798 -0
  339. package/test/config/fixtures/plugin/directory-plugin.ts +13 -0
  340. package/test/config/plugin.test.ts +248 -0
  341. package/test/config/provider-options.test.ts +224 -0
  342. package/test/config/provider.test.ts +269 -0
  343. package/test/config/skill.test.ts +80 -0
  344. package/test/credential.test.ts +36 -0
  345. package/test/database-migration.test.ts +644 -0
  346. package/test/effect/cross-spawn-spawner.test.ts +426 -0
  347. package/test/effect/keyed-mutex.test.ts +73 -0
  348. package/test/effect/layer-node/layer-node-types.test.ts +143 -0
  349. package/test/effect/layer-node/layer-node.test.ts +261 -0
  350. package/test/effect/layer-node/node-build.test.ts +125 -0
  351. package/test/effect/observability.test.ts +109 -0
  352. package/test/event.test.ts +1124 -0
  353. package/test/file-mutation.test.ts +368 -0
  354. package/test/filesystem/filesystem.test.ts +387 -0
  355. package/test/filesystem/ignore.test.ts +10 -0
  356. package/test/filesystem/search.test.ts +44 -0
  357. package/test/filesystem/watcher.test.ts +266 -0
  358. package/test/fixture/effect-flock-worker.ts +60 -0
  359. package/test/fixture/flock-worker.ts +72 -0
  360. package/test/fixture/git.ts +49 -0
  361. package/test/fixture/location.ts +26 -0
  362. package/test/fixture/tmpdir.ts +25 -0
  363. package/test/fixtures/recordings/session-runner/openai-chat-streams-text.json +27 -0
  364. package/test/git.test.ts +164 -0
  365. package/test/github-copilot/convert-to-copilot-messages.test.ts +523 -0
  366. package/test/github-copilot/copilot-chat-model.test.ts +592 -0
  367. package/test/github-copilot/openai-responses-language-model.test.ts +206 -0
  368. package/test/global.test.ts +16 -0
  369. package/test/instruction-context.test.ts +323 -0
  370. package/test/integration.test.ts +349 -0
  371. package/test/legacy-event-schema.test.ts +16 -0
  372. package/test/lib/effect.ts +53 -0
  373. package/test/lib/tool.ts +20 -0
  374. package/test/location-filesystem.test.ts +69 -0
  375. package/test/location-layer.test.ts +226 -0
  376. package/test/location-mutation.test.ts +178 -0
  377. package/test/location.test.ts +42 -0
  378. package/test/model.test.ts +23 -0
  379. package/test/models.test.ts +290 -0
  380. package/test/move-session.test.ts +235 -0
  381. package/test/npm-config.test.ts +51 -0
  382. package/test/npm.test.ts +84 -0
  383. package/test/oauth-page.test.ts +15 -0
  384. package/test/patch.test.ts +68 -0
  385. package/test/permission.test.ts +315 -0
  386. package/test/plugin/command.test.ts +47 -0
  387. package/test/plugin/fixture.ts +52 -0
  388. package/test/plugin/fixtures/config-effect-plugin.ts +15 -0
  389. package/test/plugin/fixtures/config-promise-plugin.ts +13 -0
  390. package/test/plugin/fixtures/invalid-plugin.ts +1 -0
  391. package/test/plugin/fixtures/models-dev.json +14 -0
  392. package/test/plugin/fixtures/provider-factory.ts +9 -0
  393. package/test/plugin/host.ts +303 -0
  394. package/test/plugin/models-dev.test.ts +170 -0
  395. package/test/plugin/promise.test.ts +67 -0
  396. package/test/plugin/provider-alibaba.test.ts +92 -0
  397. package/test/plugin/provider-amazon-bedrock.test.ts +622 -0
  398. package/test/plugin/provider-anthropic.test.ts +94 -0
  399. package/test/plugin/provider-azure-cognitive-services.test.ts +199 -0
  400. package/test/plugin/provider-azure.test.ts +293 -0
  401. package/test/plugin/provider-cerebras.test.ts +136 -0
  402. package/test/plugin/provider-cloudflare-ai-gateway.test.ts +426 -0
  403. package/test/plugin/provider-cloudflare-workers-ai.test.ts +279 -0
  404. package/test/plugin/provider-cohere.test.ts +123 -0
  405. package/test/plugin/provider-deepinfra.test.ts +159 -0
  406. package/test/plugin/provider-dynamic.test.ts +184 -0
  407. package/test/plugin/provider-gateway.test.ts +115 -0
  408. package/test/plugin/provider-github-copilot.test.ts +278 -0
  409. package/test/plugin/provider-gitlab.test.ts +308 -0
  410. package/test/plugin/provider-google-vertex-anthropic.test.ts +264 -0
  411. package/test/plugin/provider-google-vertex.test.ts +387 -0
  412. package/test/plugin/provider-google.test.ts +80 -0
  413. package/test/plugin/provider-groq.test.ts +121 -0
  414. package/test/plugin/provider-kilo.test.ts +99 -0
  415. package/test/plugin/provider-llmgateway.test.ts +80 -0
  416. package/test/plugin/provider-mistral.test.ts +129 -0
  417. package/test/plugin/provider-nvidia.test.ts +97 -0
  418. package/test/plugin/provider-openai-compatible.test.ts +107 -0
  419. package/test/plugin/provider-openai.test.ts +176 -0
  420. package/test/plugin/provider-opencode.test.ts +423 -0
  421. package/test/plugin/provider-openrouter.test.ts +113 -0
  422. package/test/plugin/provider-perplexity.test.ts +122 -0
  423. package/test/plugin/provider-sap-ai-core.test.ts +159 -0
  424. package/test/plugin/provider-snowflake-cortex.test.ts +261 -0
  425. package/test/plugin/provider-togetherai.test.ts +129 -0
  426. package/test/plugin/provider-venice.test.ts +115 -0
  427. package/test/plugin/provider-vercel.test.ts +83 -0
  428. package/test/plugin/provider-xai.test.ts +125 -0
  429. package/test/plugin/provider-zenmux.test.ts +110 -0
  430. package/test/plugin/skill.test.ts +25 -0
  431. package/test/plugin/variant.test.ts +67 -0
  432. package/test/plugin.test.ts +71 -0
  433. package/test/policy.test.ts +85 -0
  434. package/test/preload.ts +5 -0
  435. package/test/process/process.test.ts +368 -0
  436. package/test/project-copy.test.ts +400 -0
  437. package/test/project-directories.test.ts +61 -0
  438. package/test/project.test.ts +221 -0
  439. package/test/provider-mistral.test.ts +282 -0
  440. package/test/provider-xai-responses.test.ts +32 -0
  441. package/test/pty/info-schema.test.ts +32 -0
  442. package/test/pty/protocol.test.ts +27 -0
  443. package/test/pty/pty-session.test.ts +240 -0
  444. package/test/pty/ticket.test.ts +62 -0
  445. package/test/question.test.ts +114 -0
  446. package/test/reference-guidance.test.ts +76 -0
  447. package/test/reference.test.ts +78 -0
  448. package/test/repository-cache.test.ts +153 -0
  449. package/test/repository.test.ts +71 -0
  450. package/test/ripgrep.test.ts +65 -0
  451. package/test/session-compaction.test.ts +27 -0
  452. package/test/session-create.test.ts +425 -0
  453. package/test/session-history.test.ts +165 -0
  454. package/test/session-projector.test.ts +533 -0
  455. package/test/session-prompt.test.ts +584 -0
  456. package/test/session-run-coordinator.test.ts +418 -0
  457. package/test/session-runner-message.test.ts +501 -0
  458. package/test/session-runner-model.test.ts +347 -0
  459. package/test/session-runner-recorded.test.ts +193 -0
  460. package/test/session-runner-tool-events.test.ts +136 -0
  461. package/test/session-runner-tool-registry.test.ts +452 -0
  462. package/test/session-runner.test.ts +3365 -0
  463. package/test/session-todo.test.ts +94 -0
  464. package/test/session-tool-progress.test.ts +158 -0
  465. package/test/shared-schema.test.ts +206 -0
  466. package/test/shell.test.ts +108 -0
  467. package/test/skill/guidance.test.ts +144 -0
  468. package/test/skill-discovery.test.ts +165 -0
  469. package/test/skill.test.ts +125 -0
  470. package/test/snapshot.test.ts +178 -0
  471. package/test/state.test.ts +115 -0
  472. package/test/system-context/builtins.test.ts +129 -0
  473. package/test/system-context/index.test.ts +307 -0
  474. package/test/system-context/registry.test.ts +114 -0
  475. package/test/tool-apply-patch.test.ts +436 -0
  476. package/test/tool-bash.test.ts +437 -0
  477. package/test/tool-edit.test.ts +434 -0
  478. package/test/tool-output-store.test.ts +247 -0
  479. package/test/tool-question.test.ts +162 -0
  480. package/test/tool-read-filesystem.test.ts +118 -0
  481. package/test/tool-read.test.ts +674 -0
  482. package/test/tool-skill.test.ts +149 -0
  483. package/test/tool-todowrite.test.ts +125 -0
  484. package/test/tool-webfetch.test.ts +281 -0
  485. package/test/tool-websearch.test.ts +316 -0
  486. package/test/tool-write.test.ts +305 -0
  487. package/test/util/effect-flock.test.ts +392 -0
  488. package/test/util/flock.test.ts +428 -0
  489. package/test/util/which.test.ts +100 -0
  490. package/tsconfig.json +7 -0
@@ -0,0 +1,93 @@
1
+ export * as PluginPromise from "./promise"
2
+
3
+ import { define } from "@neurocode-ai/plugin/v2/effect"
4
+ import type { Plugin, PluginContext, Registration } from "@neurocode-ai/plugin/v2/promise"
5
+ import { Effect, Scope } from "effect"
6
+
7
+ // The Effect host hands back this registration shape; mirror it structurally so
8
+ // we do not have to alias the Effect package's `Registration` against the Promise one.
9
+ type HostRegistration = { readonly dispose: Effect.Effect<void> }
10
+
11
+ /**
12
+ * Adapts a Promise plugin into an Effect plugin so the existing Effect-only
13
+ * loader (`PluginV2` / `PluginInternal`) can run it unchanged.
14
+ *
15
+ * Hook registrations created during the async `setup` attach to the plugin's
16
+ * scope, so unloading the plugin disposes them. The captured fiber context
17
+ * preserves boot-time batching, so Promise-plugin transforms still coalesce
18
+ * into one reload per domain.
19
+ */
20
+ export function fromPromise(plugin: Plugin) {
21
+ return define({
22
+ id: plugin.id,
23
+ effect: (host) =>
24
+ Effect.gen(function* () {
25
+ const scope = yield* Scope.Scope
26
+ const context = yield* Effect.context<Scope.Scope>()
27
+
28
+ // Run a hook registration on the plugin scope and resolve once it is registered.
29
+ const register = (effect: Effect.Effect<HostRegistration, never, Scope.Scope>): Promise<Registration> =>
30
+ Effect.runPromiseWith(context)(Scope.provide(scope)(effect)).then((registration) => ({
31
+ dispose: () => Effect.runPromiseWith(context)(registration.dispose),
32
+ }))
33
+
34
+ const run = (effect: Effect.Effect<void>) => Effect.runPromiseWith(context)(effect)
35
+
36
+ const transform =
37
+ <Draft>(domain: {
38
+ transform: (
39
+ callback: (draft: Draft) => Effect.Effect<void> | void,
40
+ ) => Effect.Effect<HostRegistration, never, Scope.Scope>
41
+ }) =>
42
+ (callback: (draft: Draft) => Promise<void> | void) =>
43
+ register(domain.transform((draft) => Effect.promise(() => Promise.resolve(callback(draft)))))
44
+
45
+ const context2: PluginContext = {
46
+ options: host.options,
47
+ agent: {
48
+ transform: transform(host.agent),
49
+ reload: () => run(host.agent.reload()),
50
+ },
51
+ aisdk: {
52
+ sdk: (callback) =>
53
+ register(host.aisdk.sdk((event) => Effect.promise(() => Promise.resolve(callback(event))))),
54
+ language: (callback) =>
55
+ register(host.aisdk.language((event) => Effect.promise(() => Promise.resolve(callback(event))))),
56
+ },
57
+ catalog: {
58
+ transform: transform(host.catalog),
59
+ reload: () => run(host.catalog.reload()),
60
+ },
61
+ command: {
62
+ transform: transform(host.command),
63
+ reload: () => run(host.command.reload()),
64
+ },
65
+ integration: {
66
+ transform: transform(host.integration),
67
+ reload: () => run(host.integration.reload()),
68
+ connection: {
69
+ active: (id) => Effect.runPromiseWith(context)(host.integration.connection.active(id)),
70
+ resolve: (connection) => Effect.runPromiseWith(context)(host.integration.connection.resolve(connection)),
71
+ },
72
+ },
73
+ plugin: {
74
+ add: (input) => {
75
+ const child = fromPromise(input)
76
+ return run(host.plugin.add(child))
77
+ },
78
+ remove: (id) => run(host.plugin.remove(id)),
79
+ },
80
+ reference: {
81
+ transform: transform(host.reference),
82
+ reload: () => run(host.reference.reload()),
83
+ },
84
+ skill: {
85
+ transform: transform(host.skill),
86
+ reload: () => run(host.skill.reload()),
87
+ },
88
+ }
89
+
90
+ yield* Effect.promise(() => Promise.resolve(plugin.setup(context2)))
91
+ }),
92
+ })
93
+ }
@@ -0,0 +1,15 @@
1
+ import { Effect } from "effect"
2
+ import { define } from "../internal"
3
+
4
+ export const AlibabaPlugin = define({
5
+ id: "alibaba",
6
+ effect: Effect.fn(function* (ctx) {
7
+ yield* ctx.aisdk.sdk(
8
+ Effect.fn(function* (evt) {
9
+ if (evt.package !== "@ai-sdk/alibaba") return
10
+ const mod = yield* Effect.promise(() => import("@ai-sdk/alibaba"))
11
+ evt.sdk = mod.createAlibaba(evt.options)
12
+ }),
13
+ )
14
+ }),
15
+ })
@@ -0,0 +1,126 @@
1
+ import { Effect } from "effect"
2
+ import type { LanguageModelV3 } from "@ai-sdk/provider"
3
+ import { define } from "../internal"
4
+ import { ProviderV2 } from "../../provider"
5
+
6
+ type MantleSDK = {
7
+ languageModel: (modelID: string) => LanguageModelV3
8
+ chat: (modelID: string) => LanguageModelV3
9
+ responses: (modelID: string) => LanguageModelV3
10
+ }
11
+
12
+ // Bedrock cross-region inference profiles require regional prefixes only for
13
+ // specific model/region combinations. Keep the mapping narrow and avoid
14
+ // double-prefixing model IDs that models.dev already marks as global/us/eu/etc.
15
+ function resolveModelID(modelID: string, region: string | undefined) {
16
+ const crossRegionPrefixes = ["global.", "us.", "eu.", "jp.", "apac.", "au."]
17
+ if (crossRegionPrefixes.some((prefix) => modelID.startsWith(prefix))) return modelID
18
+
19
+ const resolvedRegion = region ?? "us-east-1"
20
+ const regionPrefix = resolvedRegion.split("-")[0]
21
+ if (regionPrefix === "us") {
22
+ const requiresPrefix = ["nova-micro", "nova-lite", "nova-pro", "nova-premier", "nova-2", "claude", "deepseek"].some(
23
+ (item) => modelID.includes(item),
24
+ )
25
+ if (requiresPrefix && !resolvedRegion.startsWith("us-gov")) return `${regionPrefix}.${modelID}`
26
+ return modelID
27
+ }
28
+ if (regionPrefix === "eu") {
29
+ const regionRequiresPrefix = [
30
+ "eu-west-1",
31
+ "eu-west-2",
32
+ "eu-west-3",
33
+ "eu-north-1",
34
+ "eu-central-1",
35
+ "eu-south-1",
36
+ "eu-south-2",
37
+ ].some((item) => resolvedRegion.includes(item))
38
+ const modelRequiresPrefix = ["claude", "nova-lite", "nova-micro", "llama3", "pixtral"].some((item) =>
39
+ modelID.includes(item),
40
+ )
41
+ return regionRequiresPrefix && modelRequiresPrefix ? `${regionPrefix}.${modelID}` : modelID
42
+ }
43
+ if (regionPrefix !== "ap") return modelID
44
+
45
+ const australia = ["ap-southeast-2", "ap-southeast-4"].includes(resolvedRegion)
46
+ if (australia && ["anthropic.claude-sonnet-4-5", "anthropic.claude-haiku"].some((item) => modelID.includes(item))) {
47
+ return `au.${modelID}`
48
+ }
49
+
50
+ const prefix = resolvedRegion === "ap-northeast-1" ? "jp" : "apac"
51
+ return ["claude", "nova-lite", "nova-micro", "nova-pro"].some((item) => modelID.includes(item))
52
+ ? `${prefix}.${modelID}`
53
+ : modelID
54
+ }
55
+
56
+ function selectMantleModel(sdk: MantleSDK, modelID: string) {
57
+ if (modelID === "openai.gpt-oss-safeguard-20b" || modelID === "openai.gpt-oss-safeguard-120b")
58
+ return sdk.chat(modelID)
59
+ return sdk.responses(modelID)
60
+ }
61
+
62
+ export const AmazonBedrockPlugin = define({
63
+ id: "amazon-bedrock",
64
+ effect: Effect.fn(function* (ctx) {
65
+ yield* ctx.catalog.transform(
66
+ Effect.fn(function* (evt) {
67
+ for (const item of evt.provider.list()) {
68
+ if (item.provider.api.type !== "aisdk") continue
69
+ if (item.provider.api.package !== "@ai-sdk/amazon-bedrock") continue
70
+ evt.provider.update(item.provider.id, (provider) => {
71
+ if (provider.api.type !== "aisdk") return
72
+ if (typeof provider.request.body.endpoint !== "string") return
73
+ // The AI SDK expects a base URL, but users configure Bedrock private/VPC
74
+ // endpoints as `endpoint`; move it into the catalog endpoint URL once.
75
+ provider.api.url = provider.request.body.endpoint
76
+ delete provider.request.body.endpoint
77
+ })
78
+ }
79
+ }),
80
+ )
81
+ yield* ctx.aisdk.sdk(
82
+ Effect.fn(function* (evt) {
83
+ if (!["@ai-sdk/amazon-bedrock", "@ai-sdk/amazon-bedrock/mantle"].includes(evt.package)) return
84
+ const options = { ...evt.options }
85
+ const profile = typeof options.profile === "string" ? options.profile : process.env.AWS_PROFILE
86
+ const region = typeof options.region === "string" ? options.region : (process.env.AWS_REGION ?? "us-east-1")
87
+ const bearerToken =
88
+ process.env.AWS_BEARER_TOKEN_BEDROCK ??
89
+ (typeof options.bearerToken === "string" ? options.bearerToken : undefined)
90
+ if (bearerToken && !process.env.AWS_BEARER_TOKEN_BEDROCK) process.env.AWS_BEARER_TOKEN_BEDROCK = bearerToken
91
+ const containerCreds = Boolean(
92
+ process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI || process.env.AWS_CONTAINER_CREDENTIALS_FULL_URI,
93
+ )
94
+
95
+ options.region = region
96
+ if (typeof options.endpoint === "string") options.baseURL = options.endpoint
97
+ if (!bearerToken && options.credentialProvider === undefined) {
98
+ // Do not gate SDK creation on explicit AWS env vars. The default chain
99
+ // also handles ~/.aws/credentials, SSO, process creds, and instance roles.
100
+ const { fromNodeProviderChain } = yield* Effect.promise(() => import("@aws-sdk/credential-providers"))
101
+ options.credentialProvider = fromNodeProviderChain(profile ? { profile } : {})
102
+ }
103
+
104
+ if (evt.package === "@ai-sdk/amazon-bedrock/mantle") {
105
+ const mod = yield* Effect.promise(() => import("@ai-sdk/amazon-bedrock/mantle"))
106
+ evt.sdk = mod.createBedrockMantle(options)
107
+ return
108
+ }
109
+
110
+ const mod = yield* Effect.promise(() => import("@ai-sdk/amazon-bedrock"))
111
+ evt.sdk = mod.createAmazonBedrock(options)
112
+ }),
113
+ )
114
+ yield* ctx.aisdk.language(
115
+ Effect.fn(function* (evt) {
116
+ if (evt.model.providerID !== ProviderV2.ID.amazonBedrock) return
117
+ if (evt.model.api.type === "aisdk" && evt.model.api.package === "@ai-sdk/amazon-bedrock/mantle") {
118
+ evt.language = selectMantleModel(evt.sdk, evt.model.api.id)
119
+ return
120
+ }
121
+ const region = typeof evt.options.region === "string" ? evt.options.region : process.env.AWS_REGION
122
+ evt.language = evt.sdk.languageModel(resolveModelID(evt.model.api.id, region))
123
+ }),
124
+ )
125
+ }),
126
+ })
@@ -0,0 +1,27 @@
1
+ import { Effect } from "effect"
2
+ import { define } from "../internal"
3
+
4
+ export const AnthropicPlugin = define({
5
+ id: "anthropic",
6
+ effect: Effect.fn(function* (ctx) {
7
+ yield* ctx.catalog.transform(
8
+ Effect.fn(function* (evt) {
9
+ for (const item of evt.provider.list()) {
10
+ if (item.provider.api.type !== "aisdk") continue
11
+ if (item.provider.api.package !== "@ai-sdk/anthropic") continue
12
+ evt.provider.update(item.provider.id, (provider) => {
13
+ provider.request.headers["anthropic-beta"] =
14
+ "interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14"
15
+ })
16
+ }
17
+ }),
18
+ )
19
+ yield* ctx.aisdk.sdk(
20
+ Effect.fn(function* (evt) {
21
+ if (evt.package !== "@ai-sdk/anthropic") return
22
+ const mod = yield* Effect.promise(() => import("@ai-sdk/anthropic"))
23
+ evt.sdk = mod.createAnthropic(evt.options)
24
+ }),
25
+ )
26
+ }),
27
+ })
@@ -0,0 +1,82 @@
1
+ import { Effect } from "effect"
2
+ import { define } from "../internal"
3
+ import { ProviderV2 } from "../../provider"
4
+
5
+ function selectLanguage(sdk: any, modelID: string, useChat: boolean) {
6
+ if (useChat && sdk.chat) return sdk.chat(modelID)
7
+ if (sdk.responses) return sdk.responses(modelID)
8
+ if (sdk.messages) return sdk.messages(modelID)
9
+ if (sdk.chat) return sdk.chat(modelID)
10
+ return sdk.languageModel(modelID)
11
+ }
12
+
13
+ export const AzurePlugin = define({
14
+ id: "azure",
15
+ effect: Effect.fn(function* (ctx) {
16
+ yield* ctx.catalog.transform(
17
+ Effect.fn(function* (evt) {
18
+ for (const item of evt.provider.list()) {
19
+ if (item.provider.api.type !== "aisdk") continue
20
+ if (item.provider.api.package !== "@ai-sdk/azure") continue
21
+ const configured = item.provider.request.body.resourceName
22
+ const resourceName =
23
+ typeof configured === "string" && configured.trim() !== "" ? configured : process.env.AZURE_RESOURCE_NAME
24
+ if (!resourceName) continue
25
+ evt.provider.update(item.provider.id, (provider) => {
26
+ provider.request.body.resourceName = resourceName
27
+ })
28
+ }
29
+ }),
30
+ )
31
+ yield* ctx.aisdk.sdk(
32
+ Effect.fn(function* (evt) {
33
+ if (evt.package !== "@ai-sdk/azure") return
34
+ if (evt.model.providerID === ProviderV2.ID.azure) {
35
+ if (
36
+ !evt.options.resourceName &&
37
+ !evt.options.baseURL &&
38
+ (evt.model.api.type !== "aisdk" || !evt.model.api.url)
39
+ ) {
40
+ throw new Error(
41
+ "AZURE_RESOURCE_NAME is missing, set it using env var or reconnecting the azure provider and setting it",
42
+ )
43
+ }
44
+ }
45
+ const mod = yield* Effect.promise(() => import("@ai-sdk/azure"))
46
+ evt.sdk = mod.createAzure(evt.options)
47
+ }),
48
+ )
49
+ yield* ctx.aisdk.language(
50
+ Effect.fn(function* (evt) {
51
+ if (evt.model.providerID !== ProviderV2.ID.azure) return
52
+ evt.language = selectLanguage(evt.sdk, evt.model.api.id, Boolean(evt.options.useCompletionUrls))
53
+ }),
54
+ )
55
+ }),
56
+ })
57
+
58
+ export const AzureCognitiveServicesPlugin = define({
59
+ id: "azure-cognitive-services",
60
+ effect: Effect.fn(function* (ctx) {
61
+ yield* ctx.catalog.transform(
62
+ Effect.fn(function* (evt) {
63
+ const resourceName = process.env.AZURE_COGNITIVE_SERVICES_RESOURCE_NAME
64
+ if (!resourceName) return
65
+ for (const item of evt.provider.list()) {
66
+ if (item.provider.api.type !== "aisdk") continue
67
+ if (item.provider.api.package !== "@ai-sdk/openai-compatible") continue
68
+ if (!item.provider.id.includes("azure-cognitive-services")) continue
69
+ evt.provider.update(item.provider.id, (provider) => {
70
+ provider.request.body.baseURL = `https://${resourceName}.cognitiveservices.azure.com/openai`
71
+ })
72
+ }
73
+ }),
74
+ )
75
+ yield* ctx.aisdk.language(
76
+ Effect.fn(function* (evt) {
77
+ if (evt.model.providerID !== ProviderV2.ID.make("azure-cognitive-services")) return
78
+ evt.language = selectLanguage(evt.sdk, evt.model.api.id, Boolean(evt.options.useCompletionUrls))
79
+ }),
80
+ )
81
+ }),
82
+ })
@@ -0,0 +1,26 @@
1
+ import { Effect } from "effect"
2
+ import { define } from "../internal"
3
+
4
+ export const CerebrasPlugin = define({
5
+ id: "cerebras",
6
+ effect: Effect.fn(function* (ctx) {
7
+ yield* ctx.catalog.transform(
8
+ Effect.fn(function* (evt) {
9
+ for (const item of evt.provider.list()) {
10
+ if (item.provider.api.type !== "aisdk") continue
11
+ if (item.provider.api.package !== "@ai-sdk/cerebras") continue
12
+ evt.provider.update(item.provider.id, (provider) => {
13
+ provider.request.headers["X-Cerebras-3rd-Party-Integration"] = "opencode"
14
+ })
15
+ }
16
+ }),
17
+ )
18
+ yield* ctx.aisdk.sdk(
19
+ Effect.fn(function* (evt) {
20
+ if (evt.package !== "@ai-sdk/cerebras") return
21
+ const mod = yield* Effect.promise(() => import("@ai-sdk/cerebras"))
22
+ evt.sdk = mod.createCerebras(evt.options)
23
+ }),
24
+ )
25
+ }),
26
+ })
@@ -0,0 +1,81 @@
1
+ import os from "os"
2
+ import { InstallationVersion } from "../../installation/version"
3
+ import { Effect, Option, Schema } from "effect"
4
+ import { define } from "../internal"
5
+
6
+ export const CloudflareAIGatewayPlugin = define({
7
+ id: "cloudflare-ai-gateway",
8
+ effect: Effect.fn(function* (ctx) {
9
+ yield* ctx.aisdk.sdk(
10
+ Effect.fn(function* (evt) {
11
+ if (evt.package !== "ai-gateway-provider") return
12
+ if (evt.options.baseURL) return
13
+
14
+ const config = gatewayConfig(evt.options)
15
+ if (!config) return
16
+ const metadata = gatewayMetadata(evt.options)
17
+ const { createAiGateway } = yield* Effect.promise(() => import("ai-gateway-provider")).pipe(Effect.orDie)
18
+ const { createUnified } = yield* Effect.promise(() => import("ai-gateway-provider/providers/unified")).pipe(
19
+ Effect.orDie,
20
+ )
21
+ const gateway = createAiGateway({
22
+ accountId: config.accountId,
23
+ gateway: config.gatewayId,
24
+ apiKey: config.apiKey,
25
+ options: gatewayOptions(evt.options, metadata),
26
+ } as any)
27
+ const unified = createUnified({ apiKey: config.apiKey })
28
+ evt.sdk = {
29
+ languageModel(modelID: string) {
30
+ return gateway(unified(modelID))
31
+ },
32
+ }
33
+ }),
34
+ )
35
+ }),
36
+ })
37
+
38
+ type GatewayConfig = {
39
+ accountId: string
40
+ gatewayId: string
41
+ apiKey: string
42
+ }
43
+
44
+ const decodeJson = Schema.decodeUnknownOption(Schema.UnknownFromJsonString)
45
+
46
+ function gatewayConfig(options: Record<string, unknown>): GatewayConfig | undefined {
47
+ const accountId = process.env.CLOUDFLARE_ACCOUNT_ID ?? stringOption(options, "accountId")
48
+ // Credential projection copies key metadata into options. The prompt stores the
49
+ // gateway as gatewayId, while older config examples may use gateway.
50
+ const gatewayId =
51
+ process.env.CLOUDFLARE_GATEWAY_ID ?? stringOption(options, "gatewayId") ?? stringOption(options, "gateway")
52
+ const apiKey = process.env.CLOUDFLARE_API_TOKEN ?? process.env.CF_AIG_TOKEN ?? stringOption(options, "apiKey")
53
+ if (!accountId || !gatewayId || !apiKey) return undefined
54
+
55
+ return { accountId, gatewayId, apiKey }
56
+ }
57
+
58
+ function gatewayMetadata(options: Record<string, unknown>) {
59
+ // Preserve the legacy cf-aig-metadata header escape hatch for gateway logging
60
+ // metadata, but prefer the typed metadata option when present.
61
+ if (options.metadata !== undefined) return options.metadata
62
+ const raw = (options.headers as Record<string, string> | undefined)?.["cf-aig-metadata"]
63
+ return raw ? Option.getOrUndefined(decodeJson(raw)) : undefined
64
+ }
65
+
66
+ function gatewayOptions(options: Record<string, unknown>, metadata: unknown) {
67
+ return {
68
+ metadata,
69
+ cacheTtl: options.cacheTtl,
70
+ cacheKey: options.cacheKey,
71
+ skipCache: options.skipCache,
72
+ collectLog: options.collectLog,
73
+ headers: {
74
+ "User-Agent": `opencode/${InstallationVersion} cloudflare-ai-gateway (${os.platform()} ${os.release()}; ${os.arch()})`,
75
+ },
76
+ }
77
+ }
78
+
79
+ function stringOption(options: Record<string, unknown>, key: string) {
80
+ return typeof options[key] === "string" ? options[key] : undefined
81
+ }
@@ -0,0 +1,81 @@
1
+ import os from "os"
2
+ import { InstallationVersion } from "../../installation/version"
3
+ import { Effect } from "effect"
4
+ import { define } from "../internal"
5
+ import { ProviderV2 } from "../../provider"
6
+
7
+ const providerID = ProviderV2.ID.make("cloudflare-workers-ai")
8
+
9
+ export const CloudflareWorkersAIPlugin = define({
10
+ id: "cloudflare-workers-ai",
11
+ effect: Effect.fn(function* (ctx) {
12
+ yield* ctx.catalog.transform(
13
+ Effect.fn(function* (evt) {
14
+ const item = evt.provider.get(providerID)
15
+ if (!item) return
16
+ evt.provider.update(item.provider.id, (provider) => {
17
+ if (provider.api.type !== "aisdk") return
18
+ if (provider.api.url) return
19
+ const accountId = resolveAccountId(provider.request.body)
20
+ if (accountId) provider.api.url = workersEndpoint(accountId)
21
+ })
22
+ }),
23
+ )
24
+ yield* ctx.aisdk.sdk(
25
+ Effect.fn(function* (evt) {
26
+ if (evt.model.providerID !== providerID) return
27
+ if (evt.package !== "@ai-sdk/openai-compatible") return
28
+
29
+ const accountId = resolveAccountId(evt.options)
30
+ if (!hasWorkersEndpoint(evt.model.api) && !accountId) return
31
+ const mod = yield* Effect.promise(() => import("@ai-sdk/openai-compatible"))
32
+ evt.sdk = mod.createOpenAICompatible(
33
+ sdkOptions({
34
+ ...evt.options,
35
+ baseURL: evt.options.baseURL ?? (accountId ? workersEndpoint(accountId) : undefined),
36
+ }) as any,
37
+ )
38
+ }),
39
+ )
40
+ yield* ctx.aisdk.language(
41
+ Effect.fn(function* (evt) {
42
+ if (evt.model.providerID !== providerID) return
43
+ evt.language = evt.sdk.languageModel(evt.model.api.id)
44
+ }),
45
+ )
46
+ }),
47
+ })
48
+
49
+ function resolveAccountId(options: Record<string, unknown>) {
50
+ return process.env.CLOUDFLARE_ACCOUNT_ID ?? stringOption(options, "accountId")
51
+ }
52
+
53
+ function workersEndpoint(accountId: string) {
54
+ return `https://api.cloudflare.com/client/v4/accounts/${accountId}/ai/v1`
55
+ }
56
+
57
+ function hasWorkersEndpoint(api: ProviderV2.Api) {
58
+ return api.type === "aisdk" && Boolean(api.url)
59
+ }
60
+
61
+ function sdkOptions(options: Record<string, any>) {
62
+ return {
63
+ ...options,
64
+ baseURL: expandAccountId(options.baseURL),
65
+ apiKey: process.env.CLOUDFLARE_API_KEY ?? options.apiKey,
66
+ headers: {
67
+ "User-Agent": `opencode/${InstallationVersion} cloudflare-workers-ai (${os.platform()} ${os.release()}; ${os.arch()})`,
68
+ ...options.headers,
69
+ },
70
+ name: providerID,
71
+ }
72
+ }
73
+
74
+ function expandAccountId(baseURL: unknown) {
75
+ if (typeof baseURL !== "string") return baseURL
76
+ return baseURL.replaceAll("${CLOUDFLARE_ACCOUNT_ID}", process.env.CLOUDFLARE_ACCOUNT_ID ?? "${CLOUDFLARE_ACCOUNT_ID}")
77
+ }
78
+
79
+ function stringOption(options: Record<string, unknown>, key: string) {
80
+ return typeof options[key] === "string" ? options[key] : undefined
81
+ }
@@ -0,0 +1,15 @@
1
+ import { Effect } from "effect"
2
+ import { define } from "../internal"
3
+
4
+ export const CoherePlugin = define({
5
+ id: "cohere",
6
+ effect: Effect.fn(function* (ctx) {
7
+ yield* ctx.aisdk.sdk(
8
+ Effect.fn(function* (evt) {
9
+ if (evt.package !== "@ai-sdk/cohere") return
10
+ const mod = yield* Effect.promise(() => import("@ai-sdk/cohere"))
11
+ evt.sdk = mod.createCohere(evt.options)
12
+ }),
13
+ )
14
+ }),
15
+ })
@@ -0,0 +1,15 @@
1
+ import { Effect } from "effect"
2
+ import { define } from "../internal"
3
+
4
+ export const DeepInfraPlugin = define({
5
+ id: "deepinfra",
6
+ effect: Effect.fn(function* (ctx) {
7
+ yield* ctx.aisdk.sdk(
8
+ Effect.fn(function* (evt) {
9
+ if (evt.package !== "@ai-sdk/deepinfra") return
10
+ const mod = yield* Effect.promise(() => import("@ai-sdk/deepinfra"))
11
+ evt.sdk = mod.createDeepInfra(evt.options)
12
+ }),
13
+ )
14
+ }),
15
+ })
@@ -0,0 +1,31 @@
1
+ import { Effect } from "effect"
2
+ import { pathToFileURL } from "url"
3
+ import { define } from "../internal"
4
+ import { Npm } from "../../npm"
5
+
6
+ export const DynamicProviderPlugin = define({
7
+ id: "dynamic-provider",
8
+ effect: Effect.fn(function* (ctx) {
9
+ const npm = yield* Npm.Service
10
+ yield* ctx.aisdk.sdk(
11
+ Effect.fn(function* (evt) {
12
+ if (evt.sdk) return
13
+
14
+ const installedPath = evt.package.startsWith("file://")
15
+ ? evt.package
16
+ : (yield* npm.add(evt.package).pipe(Effect.orDie)).entrypoint
17
+ if (!installedPath) throw new Error(`Package ${evt.package} has no import entrypoint`)
18
+
19
+ const mod = yield* Effect.promise(async () => {
20
+ return (await import(
21
+ installedPath.startsWith("file://") ? installedPath : pathToFileURL(installedPath).href
22
+ )) as Record<string, (options: any) => any>
23
+ }).pipe(Effect.orDie)
24
+ const match = Object.keys(mod).find((name) => name.startsWith("create"))
25
+ if (!match) throw new Error(`Package ${evt.package} has no provider factory export`)
26
+
27
+ evt.sdk = mod[match](evt.options)
28
+ }),
29
+ )
30
+ }),
31
+ })
@@ -0,0 +1,15 @@
1
+ import { Effect } from "effect"
2
+ import { define } from "../internal"
3
+
4
+ export const GatewayPlugin = define({
5
+ id: "gateway",
6
+ effect: Effect.fn(function* (ctx) {
7
+ yield* ctx.aisdk.sdk(
8
+ Effect.fn(function* (evt) {
9
+ if (evt.package !== "@ai-sdk/gateway") return
10
+ const mod = yield* Effect.promise(() => import("@ai-sdk/gateway"))
11
+ evt.sdk = mod.createGateway(evt.options)
12
+ }),
13
+ )
14
+ }),
15
+ })
@@ -0,0 +1,52 @@
1
+ import { Effect } from "effect"
2
+ import { ModelV2 } from "../../model"
3
+ import { ProviderV2 } from "../../provider"
4
+ import type { PluginContext } from "@neurocode-ai/plugin/v2/effect"
5
+
6
+ export const GithubCopilotPlugin = {
7
+ id: "github-copilot",
8
+ effect: Effect.fn(function* (ctx: PluginContext) {
9
+ yield* ctx.catalog.transform(
10
+ Effect.fn(function* (evt) {
11
+ const item = evt.provider.get(ProviderV2.ID.githubCopilot)
12
+ if (!item || !item.models.has(ModelV2.ID.make("gpt-5-chat-latest"))) return
13
+ evt.model.update(item.provider.id, ModelV2.ID.make("gpt-5-chat-latest"), (model) => {
14
+ // This chat-only alias conflicts with the Copilot GPT-5 Responses route,
15
+ // so hide it only for Copilot rather than for every provider catalog.
16
+ model.enabled = false
17
+ })
18
+ }),
19
+ )
20
+ yield* ctx.aisdk.sdk(
21
+ Effect.fn(function* (evt) {
22
+ if (evt.package !== "@ai-sdk/github-copilot") return
23
+ const mod = yield* Effect.promise(() => import("../../github-copilot/copilot-provider"))
24
+ evt.sdk = mod.createOpenaiCompatible(evt.options)
25
+ }),
26
+ )
27
+ yield* ctx.aisdk.language(
28
+ Effect.fn(function* (evt) {
29
+ if (evt.model.providerID !== ProviderV2.ID.githubCopilot) return
30
+ if (evt.sdk.responses === undefined && evt.sdk.chat === undefined) {
31
+ evt.language = evt.sdk.languageModel(evt.model.api.id)
32
+ return
33
+ }
34
+ if (evt.options.endpoint === "responses" && evt.sdk.responses) {
35
+ evt.language = evt.sdk.responses(evt.model.api.id)
36
+ return
37
+ }
38
+ if (evt.options.endpoint === "chat" && evt.sdk.chat) {
39
+ evt.language = evt.sdk.chat(evt.model.api.id)
40
+ return
41
+ }
42
+ const match = /^gpt-(\d+)/.exec(evt.model.api.id)
43
+ // Copilot supports Responses for GPT-5 class models, except mini variants
44
+ // which still need the chat-completions endpoint.
45
+ evt.language =
46
+ match && Number(match[1]) >= 5 && !evt.model.api.id.startsWith("gpt-5-mini") && evt.sdk.responses
47
+ ? evt.sdk.responses(evt.model.api.id)
48
+ : evt.sdk.chat(evt.model.api.id)
49
+ }),
50
+ )
51
+ }),
52
+ }