@inneranimalmedia/agentsam-sdk 2.6.2 → 2.6.3

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 (497) hide show
  1. package/AGENTSAM.md +45 -1
  2. package/README.md +80 -0
  3. package/apps/README.md +34 -0
  4. package/apps/cad-creator/README.md +728 -0
  5. package/apps/cad-creator/shared/cad/package.json +19 -0
  6. package/apps/cad-creator/shared/cad/src/domain/operations.ts +7 -0
  7. package/apps/cad-creator/shared/cad/src/domain/project-contract.d.ts +3 -0
  8. package/apps/cad-creator/shared/cad/src/domain/project-contract.js +75 -0
  9. package/apps/cad-creator/shared/cad/src/domain/project-tools.d.ts +1 -0
  10. package/apps/cad-creator/shared/cad/src/domain/project-tools.js +24 -0
  11. package/apps/cad-creator/shared/cad/src/domain/validation.ts +191 -0
  12. package/apps/cad-creator/shared/cad/src/index.ts +4 -0
  13. package/apps/cad-creator/shared/cad/src/robotics/types.ts +232 -0
  14. package/apps/cad-creator/shared/cad/src/types.ts +507 -0
  15. package/apps/cad-creator/shared/cad/tsconfig.json +14 -0
  16. package/docs/AUTORAG.md +58 -0
  17. package/docs/BRAND_INTELLIGENCE.md +30 -0
  18. package/docs/CLI_SHELL.md +4 -2
  19. package/docs/CMS_CONTEXTUAL_COMPOSER.md +38 -0
  20. package/docs/MERKLE.md +4 -0
  21. package/docs/PROJECT_CONFIG.md +3 -0
  22. package/docs/REPOSITORY_KNOWLEDGE.md +2 -0
  23. package/docs/THEME_REFINERY.md +120 -0
  24. package/docs/architecture/PROVIDER-TOOLS-AND-COMPACTION.md +60 -0
  25. package/docs/architecture/STORAGE.md +87 -0
  26. package/docs/cad-project-tools.md +69 -0
  27. package/docs/cms-scaffolding-pattern-reference.md +73 -0
  28. package/docs/plans/AGENTSAM-INTERACTIVE-UI-REQUIREMENTS-codex-tui-20260919.md +113 -0
  29. package/docs/plans/AGENTSAM-INTERACTIVE-UI-REQUIREMENTS.md +85 -0
  30. package/docs/plans/AGENTSAM-MCP-CLIENT-2026-09-19.md +181 -0
  31. package/docs/plans/ASBD-PORTABLE-WORKGRAPH-UI-DEFERRED.md +34 -0
  32. package/docs/plans/ASTRA-BRIEF-2026-09-18.md +258 -0
  33. package/docs/plans/MULTI-AGENT-SPRINTS-2026-09-19.md +373 -0
  34. package/docs/plans/NEXT-AGENT-HANDOFF.md +167 -0
  35. package/docs/plans/RECONCILIATION-2026-09-19.md +178 -0
  36. package/docs/plugins.md +43 -0
  37. package/docs/tools/README.md +57 -0
  38. package/docs/tools/agent-and-orchestration.md +49 -0
  39. package/docs/tools/browser-and-research.md +46 -0
  40. package/docs/tools/cloudflare-platform.md +32 -0
  41. package/docs/tools/cms.md +25 -0
  42. package/docs/tools/communications.md +41 -0
  43. package/docs/tools/database-and-storage.md +62 -0
  44. package/docs/tools/design-and-media.md +64 -0
  45. package/docs/tools/filesystem-and-code.md +55 -0
  46. package/docs/tools/github.md +56 -0
  47. package/docs/tools/integrations-and-misc.md +16 -0
  48. package/docs/tools/memory.md +21 -0
  49. package/docs/tools/terminal-and-execution.md +29 -0
  50. package/docs/tools/tickets-and-platform.md +30 -0
  51. package/migrations/d1/0001_agentsam_plugin_runtime.sql +177 -0
  52. package/migrations/d1/0002_agentsam_ticket_ownership.sql +8 -0
  53. package/migrations/d1/0002_dynamic_model_policies.sql +23 -0
  54. package/migrations/d1/0003_expand_tool_handler_families.sql +18 -0
  55. package/migrations/d1/0004_project_aware_retrieval_lanes.sql +24 -0
  56. package/migrations/d1/0005_portable_knowledge_identity.sql +104 -0
  57. package/migrations/d1/0006_repair_ops_trail_account_scope.sql +14 -0
  58. package/migrations/d1/0007_repair_ops_trail_agent_run_account.sql +13 -0
  59. package/migrations/d1/0008_backfill_knowledge_run_legacy_tenant.sql +14 -0
  60. package/migrations/d1/0009_normalize_cloudflare_plugin_installations.sql +137 -0
  61. package/migrations/runtime/0001_cli_runtime.sql +67 -0
  62. package/migrations/runtime/0002_project_sessions.sql +15 -0
  63. package/migrations/runtime/0003_provider_continuations.sql +8 -0
  64. package/package.json +92 -12
  65. package/packages/agentsam-brand/README.md +21 -0
  66. package/packages/agentsam-brand/package.json +22 -0
  67. package/packages/agentsam-brand/src/contract.js +59 -0
  68. package/packages/agentsam-brand/src/extract.js +126 -0
  69. package/packages/agentsam-brand/src/goap-actions.js +73 -0
  70. package/packages/agentsam-brand/src/index.js +48 -0
  71. package/packages/agentsam-brand/src/plan.js +115 -0
  72. package/packages/agentsam-brand/src/resolve.js +139 -0
  73. package/packages/agentsam-brand/src/scan.js +250 -0
  74. package/packages/agentsam-brand/test/brand-scan.test.mjs +106 -0
  75. package/packages/agentsam-contracts/README.md +23 -0
  76. package/packages/agentsam-contracts/package.json +32 -0
  77. package/packages/agentsam-contracts/src/adapter.ts +25 -0
  78. package/packages/agentsam-contracts/src/agent.ts +35 -0
  79. package/packages/agentsam-contracts/src/artifacts.ts +33 -0
  80. package/packages/agentsam-contracts/src/authority.ts +29 -0
  81. package/packages/agentsam-contracts/src/context.ts +16 -0
  82. package/packages/agentsam-contracts/src/errors.ts +46 -0
  83. package/packages/agentsam-contracts/src/events.ts +47 -0
  84. package/packages/agentsam-contracts/src/execution.ts +50 -0
  85. package/packages/agentsam-contracts/src/hooks.ts +40 -0
  86. package/packages/agentsam-contracts/src/identity.ts +16 -0
  87. package/packages/agentsam-contracts/src/index.ts +14 -0
  88. package/packages/agentsam-contracts/src/models.ts +9 -0
  89. package/packages/agentsam-contracts/src/providers.ts +33 -0
  90. package/packages/agentsam-contracts/src/repository.ts +64 -0
  91. package/packages/agentsam-contracts/src/tools.ts +98 -0
  92. package/packages/agentsam-contracts/test/contracts.test.mjs +16 -0
  93. package/packages/agentsam-contracts/test/errors-catalog.test.mjs +25 -0
  94. package/packages/agentsam-contracts/test/repository.test.mjs +18 -0
  95. package/packages/agentsam-contracts/tsconfig.json +12 -0
  96. package/packages/agentsam-errors/package.json +17 -0
  97. package/packages/agentsam-errors/src/adapters/anthropic.js +15 -0
  98. package/packages/agentsam-errors/src/adapters/cad.js +109 -0
  99. package/packages/agentsam-errors/src/adapters/cloudflare.js +21 -0
  100. package/packages/agentsam-errors/src/adapters/cursor.js +4 -0
  101. package/packages/agentsam-errors/src/adapters/device.js +38 -0
  102. package/packages/agentsam-errors/src/adapters/docker.js +28 -0
  103. package/packages/agentsam-errors/src/adapters/gcp.js +14 -0
  104. package/packages/agentsam-errors/src/adapters/github.js +22 -0
  105. package/packages/agentsam-errors/src/adapters/google.js +17 -0
  106. package/packages/agentsam-errors/src/adapters/index.js +55 -0
  107. package/packages/agentsam-errors/src/adapters/internal.js +40 -0
  108. package/packages/agentsam-errors/src/adapters/oauth.js +24 -0
  109. package/packages/agentsam-errors/src/adapters/openai.js +17 -0
  110. package/packages/agentsam-errors/src/adapters/process.js +35 -0
  111. package/packages/agentsam-errors/src/adapters/provider.js +114 -0
  112. package/packages/agentsam-errors/src/envelope.js +186 -0
  113. package/packages/agentsam-errors/src/error.js +24 -0
  114. package/packages/agentsam-errors/src/fingerprint.js +35 -0
  115. package/packages/agentsam-errors/src/index.js +10 -0
  116. package/packages/agentsam-errors/src/normalize.js +30 -0
  117. package/packages/agentsam-errors/src/redaction.js +52 -0
  118. package/packages/agentsam-errors/src/render.js +16 -0
  119. package/packages/agentsam-errors/src/retry.js +10 -0
  120. package/packages/agentsam-errors/src/transport.js +52 -0
  121. package/packages/agentsam-errors/src/vocabulary.js +320 -0
  122. package/packages/agentsam-errors/test/envelope.test.mjs +70 -0
  123. package/packages/agentsam-errors/test/providers.test.mjs +99 -0
  124. package/packages/agentsam-errors/test/redaction.test.mjs +21 -0
  125. package/packages/agentsam-errors/test/runtime-cad-device.test.mjs +76 -0
  126. package/packages/agentsam-errors/test/transport.test.mjs +46 -0
  127. package/packages/agentsam-knowledge/package.json +15 -0
  128. package/packages/agentsam-knowledge/src/autorag/index.js +64 -0
  129. package/packages/agentsam-knowledge/src/backends/index.js +26 -0
  130. package/packages/agentsam-knowledge/src/index.js +3 -0
  131. package/packages/agentsam-knowledge/src/providers/index.js +95 -0
  132. package/packages/agentsam-knowledge/test/autorag.test.mjs +42 -0
  133. package/packages/agentsam-nav/README.md +40 -0
  134. package/packages/agentsam-nav/dist/Nav.d.ts +43 -0
  135. package/packages/agentsam-nav/dist/NavCollapsible.d.ts +10 -0
  136. package/packages/agentsam-nav/dist/NavContent.d.ts +2 -0
  137. package/packages/agentsam-nav/dist/NavFooter.d.ts +2 -0
  138. package/packages/agentsam-nav/dist/NavGroup.d.ts +3 -0
  139. package/packages/agentsam-nav/dist/NavHeader.d.ts +2 -0
  140. package/packages/agentsam-nav/dist/NavMenu.d.ts +22 -0
  141. package/packages/agentsam-nav/dist/NavProvider.d.ts +35 -0
  142. package/packages/agentsam-nav/dist/NavTrigger.d.ts +2 -0
  143. package/packages/agentsam-nav/dist/Surfaces.d.ts +41 -0
  144. package/packages/agentsam-nav/dist/browser.d.ts +11 -0
  145. package/packages/agentsam-nav/dist/browser.global.js +132 -0
  146. package/packages/agentsam-nav/dist/browser.js +613 -0
  147. package/packages/agentsam-nav/dist/contracts.d.ts +76 -0
  148. package/packages/agentsam-nav/dist/index.d.ts +11 -0
  149. package/packages/agentsam-nav/dist/index.js +614 -0
  150. package/packages/agentsam-nav/dist/legacy.css +83 -0
  151. package/packages/agentsam-nav/dist/shell.css +113 -0
  152. package/packages/agentsam-nav/dist/theme.css +113 -0
  153. package/packages/agentsam-nav/dist/utils.d.ts +1 -0
  154. package/packages/agentsam-nav/package.json +43 -0
  155. package/packages/agentsam-queue-control/README.md +107 -0
  156. package/packages/agentsam-queue-control/package.json +31 -0
  157. package/packages/agentsam-queue-control/schemas/job-envelope.schema.json +56 -0
  158. package/packages/agentsam-queue-control/src/adapters/cloudflare.js +152 -0
  159. package/packages/agentsam-queue-control/src/adapters/memory.js +38 -0
  160. package/packages/agentsam-queue-control/src/contracts.js +130 -0
  161. package/packages/agentsam-queue-control/src/control-plane.js +141 -0
  162. package/packages/agentsam-queue-control/src/dispatch.js +43 -0
  163. package/packages/agentsam-queue-control/src/index.js +7 -0
  164. package/packages/agentsam-queue-control/src/policy.js +88 -0
  165. package/packages/agentsam-queue-control/src/topology.js +66 -0
  166. package/packages/agentsam-queue-control/test/queue-control.test.mjs +100 -0
  167. package/packages/agentsam-repository/src/goap.js +718 -0
  168. package/packages/agentsam-repository/src/goap.js.bak-20260922011251 +670 -0
  169. package/packages/agentsam-repository/src/index.js +5 -0
  170. package/packages/agentsam-repository/src/merkle/cloudflare-persistence.js +2 -2
  171. package/packages/agentsam-repository/src/tickets.js +184 -0
  172. package/packages/agentsam-repository/src/work-tracking.js +199 -0
  173. package/packages/agentsam-repository/src/workspace-state.js +176 -0
  174. package/packages/agentsam-repository/test/goap-tickets-workspace-state.test.mjs +152 -0
  175. package/packages/connectors/cloudflare/src/index.js +297 -15
  176. package/packages/connectors/cloudflare/src/owner.js +43 -40
  177. package/packages/connectors/cloudflare/src/routes.js +167 -26
  178. package/packages/connectors/cloudflare/tests/connector.test.mjs +112 -2
  179. package/packages/heuristic-theme/README.md +11 -0
  180. package/packages/heuristic-theme/package.json +25 -0
  181. package/packages/heuristic-theme/src/index.js +2 -0
  182. package/packages/heuristic-theme/src/registry.js +36 -0
  183. package/packages/heuristic-theme/src/theme.js +41 -0
  184. package/packages/heuristic-theme/test/theme.test.mjs +26 -0
  185. package/packages/identity/.agentsam/features/oauth-login-portal/agentsam.feature.json +64 -0
  186. package/packages/identity/.agentsam/features/oauth-login-portal/providers.json +96 -0
  187. package/packages/identity/.agentsam/features/oauth-login-portal/resources.json +47 -0
  188. package/packages/identity/.agentsam/features/oauth-login-portal/routes.json +74 -0
  189. package/packages/identity/.agentsam/features/oauth-login-portal/ui.json +35 -0
  190. package/packages/identity/package.json +3 -2
  191. package/packages/identity/src/adapters/cloudflare-d1/ids.js +4 -0
  192. package/packages/identity/src/adapters/cloudflare-d1/index.js +39 -1
  193. package/packages/identity/src/contracts/provider.js +3 -2
  194. package/packages/identity/src/frontend/auth-portal/pages/login.html +7 -0
  195. package/packages/identity/src/index.js +2 -0
  196. package/packages/identity/src/oauth/credentials.js +13 -0
  197. package/packages/identity/src/oauth/iam-platform.js +5 -5
  198. package/packages/identity/src/providers/cloudflare/index.js +19 -0
  199. package/packages/identity/src/providers/cloudflare/mapper.js +21 -0
  200. package/packages/identity/src/providers/cloudflare/oauth.js +48 -0
  201. package/packages/identity/src/providers/cloudflare/profile.js +28 -0
  202. package/packages/identity/src/providers/index.js +18 -2
  203. package/packages/identity/src/server/identity-service.js +13 -3
  204. package/packages/identity/src/server/worker-router.js +63 -8
  205. package/packages/identity/tests/identity-service.test.mjs +15 -0
  206. package/packages/providers/completeful/README.md +38 -0
  207. package/packages/providers/completeful/package.json +29 -0
  208. package/packages/providers/completeful/src/client.js +162 -0
  209. package/packages/providers/completeful/src/events.js +49 -0
  210. package/packages/providers/completeful/src/index.js +22 -0
  211. package/packages/providers/completeful/src/tools.js +579 -0
  212. package/packages/providers/completeful/src/webhooks.js +55 -0
  213. package/packages/providers/completeful/test/provider.test.mjs +196 -0
  214. package/packages/theme-church-site/README.md +10 -0
  215. package/packages/theme-church-site/package.json +30 -0
  216. package/packages/theme-church-site/src/harvest.json +14 -0
  217. package/packages/theme-church-site/src/index.js +84 -0
  218. package/packages/theme-church-site/test/theme.test.mjs +19 -0
  219. package/packages/theme-companions-site/README.md +10 -0
  220. package/packages/theme-companions-site/package.json +30 -0
  221. package/packages/theme-companions-site/src/harvest.json +12 -0
  222. package/packages/theme-companions-site/src/index.js +82 -0
  223. package/packages/theme-companions-site/test/theme.test.mjs +19 -0
  224. package/packages/theme-floors-site/README.md +10 -0
  225. package/packages/theme-floors-site/package.json +30 -0
  226. package/packages/theme-floors-site/src/harvest.json +14 -0
  227. package/packages/theme-floors-site/src/index.js +82 -0
  228. package/packages/theme-floors-site/test/theme.test.mjs +19 -0
  229. package/packages/theme-fuelnfree-site/README.md +10 -0
  230. package/packages/theme-fuelnfree-site/package.json +30 -0
  231. package/packages/theme-fuelnfree-site/src/harvest.json +13 -0
  232. package/packages/theme-fuelnfree-site/src/index.js +81 -0
  233. package/packages/theme-fuelnfree-site/test/theme.test.mjs +19 -0
  234. package/packages/theme-handyman-site/README.md +10 -0
  235. package/packages/theme-handyman-site/package.json +30 -0
  236. package/packages/theme-handyman-site/src/harvest.json +10 -0
  237. package/packages/theme-handyman-site/src/index.js +83 -0
  238. package/packages/theme-handyman-site/test/theme.test.mjs +19 -0
  239. package/packages/theme-insurance-site/README.md +10 -0
  240. package/packages/theme-insurance-site/package.json +30 -0
  241. package/packages/theme-insurance-site/src/harvest.json +10 -0
  242. package/packages/theme-insurance-site/src/index.js +83 -0
  243. package/packages/theme-insurance-site/test/theme.test.mjs +19 -0
  244. package/packages/theme-shinshu-site/README.md +10 -0
  245. package/packages/theme-shinshu-site/package.json +30 -0
  246. package/packages/theme-shinshu-site/src/harvest.json +12 -0
  247. package/packages/theme-shinshu-site/src/index.js +83 -0
  248. package/packages/theme-shinshu-site/test/theme.test.mjs +19 -0
  249. package/packages/work-graph/README.md +49 -0
  250. package/packages/work-graph/package.json +19 -0
  251. package/packages/work-graph/prototype/README.md +32 -0
  252. package/packages/work-graph/prototype/data/demo-workgraph.js +47 -0
  253. package/packages/work-graph/prototype/renderers/timeline-model.js +21 -0
  254. package/packages/work-graph/prototype/renderers/workgraph-runtime.js +38 -0
  255. package/packages/work-graph/prototype-gnantt.html +655 -0
  256. package/packages/work-graph/src/adapters/business/projects.js +23 -0
  257. package/packages/work-graph/src/adapters/engineering/git.js +22 -0
  258. package/packages/work-graph/src/adapters/engineering/mcp.js +22 -0
  259. package/packages/work-graph/src/index.js +76 -0
  260. package/packages/work-graph/src/renderers/gantt-model.js +11 -0
  261. package/packages/work-graph/src/renderers/timeline.js +16 -0
  262. package/packages/work-graph/test/work-graph.test.mjs +37 -0
  263. package/protocol/README.md +12 -0
  264. package/protocol/capabilities/cloudflare-cpu-audit-input.schema.json +30 -6
  265. package/protocol/capabilities/cloudflare-cpu-profile-input.schema.json +18 -4
  266. package/protocol/capabilities/cloudflare-wrangler-native-input.schema.json +59 -10
  267. package/protocol/capabilities/knowledge-search-input.schema.json +35 -0
  268. package/protocol/capabilities/manifest.json +163 -1
  269. package/protocol/capabilities/repository-audit-input.schema.json +39 -6
  270. package/protocol/capabilities/repository-snapshot-input.schema.json +15 -3
  271. package/protocol/capabilities/terminal-exec-input.schema.json +55 -0
  272. package/protocol/commerce/catalog.v1.json +50 -0
  273. package/protocol/errors/error-catalog.json +164 -0
  274. package/protocol/errors/error-envelope.schema.json +544 -0
  275. package/protocol/features/README.md +57 -0
  276. package/protocol/features/agentsam.feature.v1.schema.json +290 -0
  277. package/protocol/features/catalog.json +65 -0
  278. package/protocol/features/examples/provider-resend.feature.json +17 -0
  279. package/protocol/go/agentsam-go-runtime.v1.json +17 -0
  280. package/protocol/knowledge/LIFECYCLE.md +140 -0
  281. package/protocol/knowledge/README.md +4 -0
  282. package/protocol/presets/catalog.json +128 -19
  283. package/protocol/rpc/v1/errors.proto +24 -0
  284. package/protocol/theme-refinery/d1-reconciliation.md +48 -0
  285. package/protocol/theme-refinery/product-metadata.schema.json +27 -0
  286. package/protocol/theme-refinery/receipts/products-registry-batch-20260924.json +318 -0
  287. package/protocol/theme-refinery/receipts/theme-harvest-20260924.json +472 -0
  288. package/protocol/theme-refinery/reconciliation-receipt.schema.json +83 -0
  289. package/services/cad/server.py +249 -2
  290. package/src/agent/capability-adapter.js +15 -5
  291. package/src/agent/index.js +2 -1
  292. package/src/agent/model-turn.js +51 -0
  293. package/src/agent/responses-runner.js +304 -38
  294. package/src/capabilities/index.js +1 -0
  295. package/src/capabilities/terminal-exec.js +78 -0
  296. package/src/cli.js +117 -9
  297. package/src/cloudflare/index.js +6 -0
  298. package/src/cloudflare/runtime-status.js +393 -0
  299. package/src/cloudflare/wrangler.js +17 -1
  300. package/src/commands/app.js +106 -0
  301. package/src/commands/autorag.js +77 -0
  302. package/src/commands/brand.js +293 -0
  303. package/src/commands/cad.js +1 -0
  304. package/src/commands/connections.js +126 -29
  305. package/src/commands/context-economics.js +8 -0
  306. package/src/commands/db.js +7 -0
  307. package/src/commands/env.js +5 -4
  308. package/src/commands/eval.js +209 -14
  309. package/src/commands/go.js +365 -0
  310. package/src/commands/goap.js +176 -0
  311. package/src/commands/identity-init.js +27 -3
  312. package/src/commands/identity-protocol.js +195 -0
  313. package/src/commands/knowledge.js +64 -5
  314. package/src/commands/mcp.js +341 -0
  315. package/src/commands/merkle-persist.js +3 -1
  316. package/src/commands/merkle.js +18 -3
  317. package/src/commands/models.js +109 -23
  318. package/src/commands/plugins.js +175 -0
  319. package/src/commands/preferences.js +28 -8
  320. package/src/commands/product.js +53 -10
  321. package/src/commands/providers.js +118 -37
  322. package/src/commands/resume.js +9 -5
  323. package/src/commands/runtime-status.js +154 -0
  324. package/src/commands/shell.js +466 -55
  325. package/src/commands/status.js +82 -7
  326. package/src/commands/tunnel.js +228 -195
  327. package/src/commands/whoami.js +78 -6
  328. package/src/context/budget.js +6 -0
  329. package/src/context/index.js +2 -1
  330. package/src/context/project-card.js +75 -0
  331. package/src/errors/contract.js +34 -211
  332. package/src/errors/diagnostic.js +95 -51
  333. package/src/errors/index.js +6 -13
  334. package/src/eval/index.js +6 -0
  335. package/src/eval/live.js +439 -0
  336. package/src/features/resolve.js +242 -0
  337. package/src/go/build.js +108 -0
  338. package/src/go/cloudflare.js +207 -0
  339. package/src/go/contract.js +139 -0
  340. package/src/go/discover.js +96 -0
  341. package/src/go/index.js +13 -0
  342. package/src/go/receipts.js +77 -0
  343. package/src/go/registry.js +223 -0
  344. package/src/go/verify.js +31 -0
  345. package/src/index.js +100 -1
  346. package/src/knowledge/config.js +13 -5
  347. package/src/knowledge/engine.js +23 -8
  348. package/src/knowledge/index.js +1 -0
  349. package/src/knowledge/lane-registry.js +46 -0
  350. package/src/knowledge/providers/gemini.js +48 -8
  351. package/src/knowledge/service/client.js +13 -1
  352. package/src/knowledge/service/grpc-codec.js +156 -53
  353. package/src/knowledge/service/job-engine.js +133 -11
  354. package/src/knowledge/service/job-worker.js +34 -5
  355. package/src/knowledge/service/server.js +10 -1
  356. package/src/knowledge/store-discovery.js +77 -0
  357. package/src/lib/account-session.js +8 -2
  358. package/src/lib/agent-instructions.js +3 -0
  359. package/src/lib/auth.js +7 -3
  360. package/src/lib/cad/blender.js +42 -3
  361. package/src/lib/cad/d1-project-store.js +43 -0
  362. package/src/lib/cad/discovery.js +616 -0
  363. package/src/lib/cad/docker-executor.js +352 -0
  364. package/src/lib/cad/freecad.js +253 -0
  365. package/src/lib/cad/index.js +40 -0
  366. package/src/lib/cad/openscad.js +198 -0
  367. package/src/lib/cad/project-cli.d.ts +2 -0
  368. package/src/lib/cad/project-cli.js +21 -0
  369. package/src/lib/cad/project-contract.d.ts +3 -0
  370. package/src/lib/cad/project-contract.js +1 -0
  371. package/src/lib/cad/project-recipe.js +30 -0
  372. package/src/lib/cad/project-runtime.d.ts +2 -0
  373. package/src/lib/cad/project-runtime.js +53 -0
  374. package/src/lib/cad/project-store.js +25 -0
  375. package/src/lib/cad/project-workflows.js +31 -0
  376. package/src/lib/cad-docker.js +21 -2
  377. package/src/lib/cli-preferences.js +17 -2
  378. package/src/lib/core-client.js +37 -18
  379. package/src/lib/deploy/local-studio.js +6 -5
  380. package/src/lib/dockerize.js +3 -0
  381. package/src/lib/execution-approvals.js +1 -0
  382. package/src/lib/identity-scaffold.js +4 -1
  383. package/src/lib/knowledge-docker.js +9 -1
  384. package/src/lib/local-sessions.js +124 -34
  385. package/src/lib/local-status.js +35 -14
  386. package/src/lib/project-config.js +9 -0
  387. package/src/lib/provider-credentials.js +73 -11
  388. package/src/lib/scaffold/resolve-cloudflare-account.js +37 -0
  389. package/src/lib/scaffold/wizards/cms.js +2 -8
  390. package/src/lib/scaffold/wizards/worker-api.js +2 -8
  391. package/src/lib/slash-commands.js +9 -2
  392. package/src/local/migrations.js +109 -1
  393. package/src/local/runtime-store.js +31 -5
  394. package/src/local/sqlite.js +36 -1
  395. package/src/mcp/authority.js +348 -0
  396. package/src/mcp/client-adapters.js +431 -0
  397. package/src/mcp/client.js +172 -0
  398. package/src/mcp/index.js +47 -0
  399. package/src/mcp/telemetry.js +103 -0
  400. package/src/models/catalog.js +329 -51
  401. package/src/models/discovery.js +24 -4
  402. package/src/models/index.js +2 -0
  403. package/src/models/inventory-core.js +182 -0
  404. package/src/models/policy.js +20 -0
  405. package/src/plugins/cloudflare.js +103 -0
  406. package/src/plugins/completeful.js +69 -0
  407. package/src/plugins/contracts.js +86 -0
  408. package/src/plugins/index.js +11 -0
  409. package/src/plugins/registry.js +207 -0
  410. package/src/plugins/resource-scope.js +45 -0
  411. package/src/plugins/runtime.js +118 -0
  412. package/src/plugins/vectorize.js +31 -0
  413. package/src/progression/engine.js +171 -0
  414. package/src/progression/index.js +1 -0
  415. package/src/providers/cloudflare-chat.js +1 -1
  416. package/src/providers/gemini-generate-content.js +2 -1
  417. package/src/providers/openai-responses.js +45 -16
  418. package/src/providers/tool-schema.js +85 -0
  419. package/src/repository/index.js +29 -0
  420. package/src/rpc/generated/errors_pb.js +961 -1
  421. package/src/security/local-vault.js +415 -0
  422. package/src/security/process.js +20 -4
  423. package/src/status/actions.js +192 -0
  424. package/src/tools/hydrate.js +5 -1
  425. package/src/tools/index.js +7 -0
  426. package/src/tools/redact.js +64 -0
  427. package/src/tools/registry.js +83 -0
  428. package/src/tools/runtime.js +257 -0
  429. package/src/tools/search.js +21 -8
  430. package/src/ui/ansi.js +117 -3
  431. package/src/ui/cli/activity.js +76 -7
  432. package/src/ui/cli/footer.js +110 -9
  433. package/src/ui/cli/help.js +11 -4
  434. package/src/ui/wireframes.js +166 -0
  435. package/test/account-session.test.mjs +28 -0
  436. package/test/apps-scaffold-contract.test.mjs +16 -1
  437. package/test/capabilities.test.mjs +1 -1
  438. package/test/cli/eval-live.test.mjs +219 -0
  439. package/test/cli/go.test.mjs +71 -0
  440. package/test/cli/local-vault-and-provider-setup.test.mjs +268 -0
  441. package/test/cli/mcp-client.test.mjs +245 -0
  442. package/test/cli/runtime-ui.test.mjs +69 -2
  443. package/test/cli/status-actions.test.mjs +88 -0
  444. package/test/cli/wireframes-go-registry.test.mjs +54 -0
  445. package/test/cloudflare-connector.test.mjs +3 -6
  446. package/test/cloudflare-runtime.test.mjs +8 -1
  447. package/test/context.test.mjs +15 -0
  448. package/test/error-diagnostics.test.mjs +9 -0
  449. package/test/fixtures/cad/courtyard-house.json +208 -0
  450. package/test/go/cloudflare-probe.test.mjs +53 -0
  451. package/test/integration/app-command.test.mjs +55 -0
  452. package/test/integration/cad-discovery.test.mjs +158 -0
  453. package/test/integration/cad-docker-executor.test.mjs +249 -0
  454. package/test/integration/cad-execution.test.mjs +184 -0
  455. package/test/integration/cad-project-app.test.mjs +31 -0
  456. package/test/integration/cad-project-d1.test.mjs +25 -0
  457. package/test/integration/cad-project-native.test.mjs +24 -0
  458. package/test/integration/cad-project-workflow.test.mjs +9 -0
  459. package/test/integration/cad-project.test.mjs +82 -0
  460. package/test/integration/cli-help.test.mjs +4 -0
  461. package/test/integration/cms-site-tenancy-contract.test.mjs +256 -0
  462. package/test/integration/core-client.integration.test.mjs +55 -0
  463. package/test/integration/error-runtime-rpc.test.mjs +71 -0
  464. package/test/integration/features-resolve.test.mjs +128 -0
  465. package/test/integration/install-script.test.mjs +107 -0
  466. package/test/integration/inventory-core.test.mjs +53 -0
  467. package/test/integration/plugins-cloudflare.integration.test.mjs +28 -0
  468. package/test/integration/provider-env-cli.test.mjs +1 -1
  469. package/test/integration/runtime-migrations.test.mjs +6 -1
  470. package/test/integration/runtime-status.integration.test.mjs +211 -0
  471. package/test/integration/scaffold-cloudflare.test.mjs +46 -0
  472. package/test/integration/storage-architecture.test.mjs +154 -0
  473. package/test/integration/store-discovery.test.mjs +44 -0
  474. package/test/integration/terminal-exec.integration.test.mjs +86 -0
  475. package/test/integration/tool-runtime.test.mjs +124 -0
  476. package/test/integration/tool-schema.test.mjs +59 -0
  477. package/test/knowledge-service.test.mjs +4 -0
  478. package/test/local-sessions.test.mjs +11 -2
  479. package/test/local-studio-deploy.test.mjs +1 -1
  480. package/test/model-catalog.test.mjs +28 -1
  481. package/test/models.test.mjs +159 -5
  482. package/test/openai-responses.test.mjs +60 -0
  483. package/test/provider-credentials.test.mjs +15 -5
  484. package/test/responses-runner.test.mjs +321 -6
  485. package/test/shell.test.mjs +149 -4
  486. package/test/smoke.mjs +2 -2
  487. package/test/tools-search.test.mjs +33 -0
  488. package/test/unit/website-assets-bindings.test.mjs +60 -0
  489. package/test/whoami-resume.test.mjs +82 -3
  490. package/examples/gorilla-shell/README.md +0 -15
  491. package/src/lib/gorilla-template.js +0 -54
  492. package/templates/gorilla-shell/App.tsx +0 -639
  493. package/templates/gorilla-shell/README.md +0 -34
  494. package/templates/gorilla-shell/index.html +0 -15
  495. package/templates/gorilla-shell/main.jsx +0 -9
  496. package/templates/gorilla-shell/package.json +0 -19
  497. package/templates/gorilla-shell/vite.config.js +0 -21
@@ -0,0 +1,124 @@
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+
4
+ import {
5
+ createToolExecutor,
6
+ createToolRegistry,
7
+ } from '../../src/tools/index.js';
8
+ import {
9
+ COMPLETEFUL_TOOL_DEFINITIONS,
10
+ createCompletefulClient,
11
+ createCompletefulProviderAdapter,
12
+ } from '../../packages/providers/completeful/src/index.js';
13
+
14
+ test('tool runtime owns idempotency, redacts durable receipts, and emits safe events', async () => {
15
+ let captured = null;
16
+ const client = createCompletefulClient({
17
+ apiKey: 'capp_test_example',
18
+ fetchImpl: async (url, init) => {
19
+ captured = { url, init };
20
+ return new Response(
21
+ JSON.stringify({
22
+ id: 'ord_1',
23
+ email: 'customer@example.com',
24
+ shipping_address: { line1: 'private street' },
25
+ notes: 'private note',
26
+ }),
27
+ { status: 201, headers: { 'x-request-id': 'req_order_1' } },
28
+ );
29
+ },
30
+ });
31
+
32
+ const registry = createToolRegistry({
33
+ tools: COMPLETEFUL_TOOL_DEFINITIONS,
34
+ adapters: [createCompletefulProviderAdapter(client)],
35
+ });
36
+
37
+ const recorded = [];
38
+ const observed = [];
39
+ let sequence = 0;
40
+ const executor = createToolExecutor({
41
+ registry,
42
+ makeId: (prefix) => `${prefix}_test_${++sequence}`,
43
+ now: (() => {
44
+ let value = 1_800_000_000_000;
45
+ return () => ++value;
46
+ })(),
47
+ recordReceipt: (receipt) => recorded.push(receipt),
48
+ onEvent: (event) => observed.push(event),
49
+ });
50
+
51
+ const result = await executor.execute({
52
+ toolKey: 'completeful.order.create',
53
+ accountId: 'acct_1',
54
+ correlationId: 'corr_1',
55
+ input: {
56
+ shop_id: 'shop_1',
57
+ body: {
58
+ shipping_address: { line1: 'private street' },
59
+ email: 'customer@example.com',
60
+ notes: 'private note',
61
+ line_items: [{ product_id: 'prod_1', quantity: 1 }],
62
+ },
63
+ },
64
+ });
65
+
66
+ assert.equal(result.ok, true);
67
+ assert.equal(result.output.email, 'customer@example.com');
68
+ assert.equal(captured.init.headers.get('Idempotency-Key'), result.invocation.id);
69
+ assert.equal(result.receipt.input.body.email, '[REDACTED]');
70
+ assert.equal(result.receipt.input.body.shipping_address, '[REDACTED]');
71
+ assert.equal(result.receipt.output.email, '[REDACTED]');
72
+ assert.equal(result.receipt.output.shipping_address, '[REDACTED]');
73
+ assert.equal(recorded.length, 1);
74
+ assert.equal(observed.length, 1);
75
+ assert.equal(observed[0].eventKey, 'completeful.order.created');
76
+ assert.equal(observed[0].payload.output.email, '[REDACTED]');
77
+ assert.equal(observed[0].causationId, result.invocation.id);
78
+ assert.equal(observed[0].correlationId, 'corr_1');
79
+ });
80
+
81
+ test('tool runtime converts provider errors into the canonical AgentSam envelope', async () => {
82
+ const client = createCompletefulClient({
83
+ apiKey: 'capp_test_example',
84
+ fetchImpl: async () =>
85
+ new Response(
86
+ JSON.stringify({
87
+ error: 'too many requests',
88
+ code: 'rate_limited',
89
+ request_id: 'req_rate',
90
+ }),
91
+ { status: 429 },
92
+ ),
93
+ });
94
+
95
+ const registry = createToolRegistry({
96
+ tools: COMPLETEFUL_TOOL_DEFINITIONS,
97
+ adapters: [createCompletefulProviderAdapter(client)],
98
+ });
99
+ const executor = createToolExecutor({
100
+ registry,
101
+ makeId: (prefix) => `${prefix}_failure`,
102
+ });
103
+
104
+ const result = await executor.execute({
105
+ toolKey: 'completeful.catalog.list',
106
+ input: { limit: 1 },
107
+ });
108
+
109
+ assert.equal(result.ok, false);
110
+ assert.equal(result.error.reason, 'provider_rate_limited');
111
+ assert.equal(result.error.code, 'RESOURCE_EXHAUSTED');
112
+ assert.equal(result.error.provider, 'completeful');
113
+ assert.equal(result.error.provider_code, 'rate_limited');
114
+ assert.equal(result.error.request_id, 'req_rate');
115
+ assert.equal(result.receipt.status, 'failed');
116
+ });
117
+
118
+ test('registry rejects duplicate tool keys instead of silently shadowing definitions', () => {
119
+ const definition = COMPLETEFUL_TOOL_DEFINITIONS[0];
120
+ assert.throws(
121
+ () => createToolRegistry({ tools: [definition, definition] }),
122
+ /duplicate tool definition/,
123
+ );
124
+ });
@@ -0,0 +1,59 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { compileToolSchema, restoreOptionalArguments } from '../../src/providers/tool-schema.js';
4
+ import { createCapabilityAdapter } from '../../src/agent/capability-adapter.js';
5
+ import { createOpenAIResponsesAdapter } from '../../src/providers/openai-responses.js';
6
+ import { createGeminiGenerateContentAdapter } from '../../src/providers/gemini-generate-content.js';
7
+
8
+ const canonical = { $schema: 'https://json-schema.org/draft/2020-12/schema', $id: 'sample', type: 'object', properties: {
9
+ text: { type: 'string' }, rows: { type: 'array', items: { type: 'object', properties: { label: { type: 'string', enum: ['x'] } } } },
10
+ additionalProperties: { type: 'string' },
11
+ }, required: ['text'] };
12
+
13
+ test('strict compiler recursively closes objects and makes omitted fields nullable without mutating canonical input', () => {
14
+ const original = structuredClone(canonical);
15
+ const { providerSchema: s } = compileToolSchema({ provider: 'openai', canonicalSchema: canonical });
16
+ assert.equal(s.additionalProperties, false);
17
+ assert.deepEqual(s.required, ['text', 'rows', 'additionalProperties']);
18
+ assert.equal(s.properties.rows.anyOf[0].items.additionalProperties, false);
19
+ assert.deepEqual(s.properties.rows.anyOf[0].items.required, ['label']);
20
+ assert.deepEqual(s.properties.rows.anyOf[0].items.properties.label.anyOf, [{ type: 'string', enum: ['x'] }, { type: 'null' }]);
21
+ assert.deepEqual(canonical, original);
22
+ assert.deepEqual(restoreOptionalArguments({ text: 'x', rows: [{ label: null }], additionalProperties: null }, canonical), { text: 'x', rows: [{}] });
23
+ });
24
+
25
+ test('all executable capability schemas compile for both providers, including actual knowledge.search arguments', () => {
26
+ for (const descriptor of createCapabilityAdapter().toolDescriptors()) {
27
+ for (const provider of ['openai', 'gemini']) assert.ok(compileToolSchema({ provider, canonicalSchema: descriptor.input_schema, strict: descriptor.strict !== false, name: descriptor.name }).hash);
28
+ if (descriptor.name === 'knowledge.search') assert.equal(descriptor.input_schema.properties.text.type, 'string');
29
+ }
30
+ });
31
+
32
+ test('bad schemas fail before provider fetch, with actionable paths', async () => {
33
+ for (const schema of [
34
+ { type: 'object', properties: {}, required: ['missing'] },
35
+ { type: 'object', properties: { x: { $ref: 'https://remote/schema' } } },
36
+ { type: 'object', properties: { x: { type: 'array' } } },
37
+ { type: 'object', properties: { x: { type: 'invalid' } } },
38
+ ]) {
39
+ let requests = 0;
40
+ const adapter = createOpenAIResponsesAdapter({ apiKey: 'test', fetchImpl: async () => { requests++; } });
41
+ await assert.rejects(adapter.create({ model: 'gpt-6-astra', input: 'test', tools: [{ type: 'function', name: 'broken', parameters: schema }] }), /tool_schema_invalid:openai:broken:/);
42
+ assert.equal(requests, 0);
43
+ }
44
+ });
45
+
46
+ test('Gemini uses JSON Schema declaration field and preserves canonical optionality', async () => {
47
+ let body;
48
+ const adapter = createGeminiGenerateContentAdapter({ apiKey: 'test', fetchImpl: async (_, init) => {
49
+ body = JSON.parse(init.body);
50
+ return { ok: true, json: async () => ({ candidates: [{ content: { role: 'model', parts: [{ text: 'ok' }] } }] }) };
51
+ } });
52
+ await adapter.create({ modelRecord: { provider: 'gemini', provider_model_id: 'fixture' }, input: 'test', tools: [{ name: 'sample', parameters: canonical }] });
53
+ const declaration = body.tools[0].functionDeclarations[0];
54
+ assert.equal(declaration.parameters, undefined);
55
+ assert.equal(declaration.parametersJsonSchema.$schema, undefined);
56
+ assert.equal(declaration.parametersJsonSchema.$id, undefined);
57
+ assert.deepEqual(declaration.parametersJsonSchema.required, ['text']);
58
+ assert.equal(declaration.parametersJsonSchema.properties.additionalProperties.type, 'string');
59
+ });
@@ -93,6 +93,10 @@ test('portable dockerize stages only SDK runtime, preserves identities/tokens, a
93
93
  assert.equal(fs.existsSync(path.join(context, 'src/rpc/generated/knowledge_grpc_pb.js')), true);
94
94
  assert.equal(fs.existsSync(path.join(context, 'src/rpc/generated/package.json')), true);
95
95
  assert.equal(fs.existsSync(path.join(context, 'src/errors/contract.js')), true);
96
+ assert.equal(fs.existsSync(path.join(context, 'packages/agentsam-errors/src/index.js')), true);
97
+ assert.equal(fs.existsSync(path.join(context, 'packages/agentsam-errors/package.json')), true);
98
+ assert.equal(fs.existsSync(path.join(context, 'packages/agentsam-repository/src/merkle/hash.js')), true);
99
+ assert.match(result.plan.files.dockerfile, /COPY packages \.\/packages/);
96
100
  assert.equal(fs.existsSync(path.join(context, 'package-lock.json')), true);
97
101
  const token = fs.readFileSync(result.tokenFile, 'utf8');
98
102
  assert.equal(fs.statSync(result.tokenFile).mode & 0o777, 0o600);
@@ -12,12 +12,14 @@ function tempHome(t) {
12
12
  return home;
13
13
  }
14
14
 
15
- test('local sessions persist provider-neutral continuation, usage, cost, and last-input title', t => {
15
+ test('local sessions persist safe continuation, usage, cost, and an explicit title', t => {
16
16
  const home = tempHome(t);
17
17
  const cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-session-project-'));
18
18
  t.after(() => fs.rmSync(cwd, { recursive: true, force: true }));
19
19
  let session = createLocalSession({ cwd, last_input: 'Run wrangler whoami' }, { home });
20
20
  assert.match(session.id, /^asess_[0-9a-f-]{36}$/i);
21
+ assert.equal(session.title, 'Agent Sam session');
22
+ assert.equal(session.last_input, null);
21
23
  session = saveLocalSession({
22
24
  ...session,
23
25
  title: sessionTitleFromInput('Run wrangler whoami'),
@@ -33,10 +35,17 @@ test('local sessions persist provider-neutral continuation, usage, cost, and las
33
35
  active_started_at: null,
34
36
  }, { home });
35
37
 
36
- const loaded = loadLocalSession(session.id, { home });
38
+ const loaded = loadLocalSession(session.id, { home, cwd });
37
39
  assert.equal(loaded.provider_state.previous_response_id, 'resp_123');
38
40
  assert.equal(loaded.cumulative_usage.cached_input_tokens, 60_544);
39
41
  assert.equal(listLocalSessions({ home, cwd })[0].id, session.id);
42
+ assert.equal(loaded.project_root, cwd);
43
+ assert.equal(loaded.storage.runtime, 'sqlite');
44
+ assert.equal(loaded.storage.path, '.agentsam/data/agentsam.sqlite');
45
+ assert.equal(loaded.storage.remote, null);
46
+ assert.equal(loaded.storage.capabilities.local_only, true);
47
+ assert.equal(fs.existsSync(path.join(home, '.agentsam', 'sessions', `${session.id}.json`)), false);
48
+ assert.equal(fs.existsSync(path.join(cwd, '.agentsam', 'data', 'agentsam.sqlite')), true);
40
49
 
41
50
  const receipt = renderSessionReceipt(loaded);
42
51
  assert.match(receipt, /Token usage: total=21,463 input=21,244 \(\+ 60,544 cached\) output=219 reasoning=31/);
@@ -25,7 +25,7 @@ describe('local-studio deploy resolver', () => {
25
25
  assert.deepEqual(target.wranglerArgs, ['deploy', '-c', 'backend/wrangler.jsonc']);
26
26
  assert.equal(isLocalStudioCheckout(root), true);
27
27
  const cmd = wranglerDeployCommand(target, { dryRun: true });
28
- assert.equal(cmd.bin, 'npx');
28
+ assert.equal(cmd.bin, process.platform === 'win32' ? 'npx.cmd' : 'npx');
29
29
  assert.equal(cmd.cwd, target.appRoot);
30
30
  assert.deepEqual(cmd.args, ['wrangler', 'deploy', '-c', 'backend/wrangler.jsonc', '--dry-run']);
31
31
  });
@@ -1,6 +1,6 @@
1
1
  import assert from 'node:assert/strict';
2
2
  import test from 'node:test';
3
- import { calculateModelCost, getModelRecord } from '../src/models/index.js';
3
+ import { calculateModelCost, getModelRecord, mergeModelReference } from '../src/models/index.js';
4
4
 
5
5
  test('Astra catalog separates technical window, reasoning controls, service tiers, and economics', () => {
6
6
  const model = getModelRecord('gpt-6-astra');
@@ -41,3 +41,30 @@ test('service tier and cache pricing stay explicit rather than hidden in prompts
41
41
  assert.equal(standard.rates_per_million.cached_input, 1);
42
42
  assert.equal(standard.rates_per_million.cache_write, 12.5);
43
43
  });
44
+
45
+
46
+ test('GPT-6 Luna reference hydrates a stale provider-verified snapshot without changing availability authority', () => {
47
+ const merged = mergeModelReference({
48
+ model_key: 'openai:gpt-6-luna',
49
+ provider: 'openai',
50
+ provider_model_id: 'gpt-6-luna',
51
+ availability: 'available',
52
+ availability_source: 'provider_api',
53
+ context_window: null,
54
+ context_window_source: 'unknown',
55
+ max_output_tokens: null,
56
+ max_output_tokens_source: 'unknown',
57
+ reasoning_efforts: ['auto'],
58
+ service_tiers: ['default'],
59
+ capabilities: { responses: true },
60
+ });
61
+ assert.equal(merged.availability, 'available');
62
+ assert.equal(merged.availability_source, 'provider_api');
63
+ assert.equal(merged.context_window, 1_050_000);
64
+ assert.equal(merged.context_window_source, 'sdk_reference');
65
+ assert.equal(merged.max_output_tokens, 128_000);
66
+ assert.deepEqual(merged.reasoning_efforts, ['none', 'low', 'medium', 'high', 'xhigh', 'max']);
67
+ assert.equal(merged.default_reasoning_effort, 'medium');
68
+ assert.equal(merged.capabilities.responses, true);
69
+ assert.equal(merged.capabilities.function_calling, true);
70
+ });
@@ -21,7 +21,7 @@ test('model inventory reports configured API providers without exposing credenti
21
21
  home,
22
22
  discoverRemote: false,
23
23
  env: {
24
- OPENAI_API_KEY: 'secret-openai', GEMINI_API_KEY: '', XAI_API_KEY: 'secret-xai', ANTHROPIC_API_KEY: 'secret-anthropic', CLOUDFLARE_API_TOKEN: 'secret-cf', ACCOUNT_ID: '33333333333333333333333333333333',
24
+ OPENAI_API_KEY: 'secret-openai', GEMINI_API_KEY: '', XAI_API_KEY: 'secret-xai', ANTHROPIC_API_KEY: 'secret-anthropic', CLOUDFLARE_API_TOKEN: 'secret-cf', CLOUDFLARE_ACCOUNT_ID: '33333333333333333333333333333333',
25
25
  OLLAMA_BASE_URL: 'http://127.0.0.1:11434', OLLAMA_MODEL: 'qwen:test', OLLAMA_EMBED_MODEL: 'embed:test',
26
26
  },
27
27
  fetchImpl: async () => response({ models: [{ name: 'qwen:test' }, { name: 'embed:test' }] }),
@@ -39,8 +39,10 @@ test('model inventory reports configured API providers without exposing credenti
39
39
  assert.doesNotMatch(rendered, /secret-openai|secret-xai|secret-anthropic|secret-cf/);
40
40
  });
41
41
 
42
- test('static/reference metadata never invents hosted model availability', async () => {
42
+ test('static/reference metadata never invents hosted model availability', async t => {
43
+ const home = tempHome(t);
43
44
  const status = await collectModelsStatus({
45
+ home,
44
46
  env: { OPENAI_API_KEY: 'secret-openai', OLLAMA_BASE_URL: 'http://127.0.0.1:11434' },
45
47
  fetchImpl: async () => response({ models: [] }),
46
48
  providerFetchImpl: async () => response({ data: [{ id: 'some-other-model' }] }),
@@ -52,8 +54,10 @@ test('static/reference metadata never invents hosted model availability', async
52
54
  assert.equal(referenceOnly?.availability_source, 'sdk_reference');
53
55
  });
54
56
 
55
- test('exact hosted model availability is verified against the provider inventory', async () => {
57
+ test('exact hosted model availability is verified against the provider inventory', async t => {
58
+ const home = tempHome(t);
56
59
  const status = await collectModelsStatus({
60
+ home,
57
61
  env: { OPENAI_API_KEY: 'secret-openai', OLLAMA_BASE_URL: 'http://127.0.0.1:11434' },
58
62
  fetchImpl: async () => response({ models: [] }),
59
63
  providerFetchImpl: async () => response({ data: [{ id: 'gpt-6-astra' }, { id: 'some-other-model' }] }),
@@ -68,9 +72,11 @@ test('exact hosted model availability is verified against the provider inventory
68
72
 
69
73
 
70
74
 
71
- test('Gemini and xAI discovery keep per-key limits from provider metadata', async () => {
75
+ test('Gemini and xAI discovery keep per-key limits from provider metadata', async t => {
76
+ const home = tempHome(t);
72
77
  const seen = [];
73
78
  const status = await collectModelsStatus({
79
+ home,
74
80
  env: {
75
81
  GEMINI_API_KEY: 'gem-key',
76
82
  XAI_API_KEY: 'xai-key',
@@ -124,7 +130,8 @@ test('Cloudflare discovery is scoped to the loaded account and surfaces text-gen
124
130
  const home = tempHome(t);
125
131
  const status = await collectModelsStatus({
126
132
  home,
127
- env: { CLOUDFLARE_API_TOKEN: 'secret-cf', ACCOUNT_ID: '44444444444444444444444444444444', OLLAMA_BASE_URL: 'http://127.0.0.1:11434' },
133
+ curateWorkersAi: false,
134
+ env: { CLOUDFLARE_API_TOKEN: 'secret-cf', CLOUDFLARE_ACCOUNT_ID: '44444444444444444444444444444444', OLLAMA_BASE_URL: 'http://127.0.0.1:11434' },
128
135
  fetchImpl: async () => response({ models: [] }),
129
136
  providerFetchImpl: async (url, options) => {
130
137
  seen.push({ url, auth: options.headers.authorization });
@@ -146,3 +153,150 @@ test('Cloudflare discovery is scoped to the loaded account and surfaces text-gen
146
153
  assert.doesNotMatch(rendered, /@cf\/baai\/embed/);
147
154
  assert.doesNotMatch(rendered, /secret-cf/);
148
155
  });
156
+
157
+ test('Cursor participates in machine inventory when CURSOR_API_KEY is configured', async t => {
158
+ const home = tempHome(t);
159
+ const seen = [];
160
+ const status = await collectModelsStatus({
161
+ home,
162
+ env: {
163
+ CURSOR_API_KEY: 'cursor-secret-key',
164
+ OLLAMA_BASE_URL: 'http://127.0.0.1:11434',
165
+ },
166
+ fetchImpl: async () => response({ models: [] }),
167
+ providerFetchImpl: async (url, options) => {
168
+ seen.push({ url, auth: options?.headers?.authorization });
169
+ if (String(url).includes('api.cursor.com')) {
170
+ return response({
171
+ items: [
172
+ { id: 'composer-2.5', displayName: 'Composer 2.5', parameters: [] },
173
+ { id: 'gpt-5.6-sol', displayName: 'GPT-5.6 Sol', parameters: [{ id: 'reasoning', values: [{ value: 'high' }] }] },
174
+ ],
175
+ });
176
+ }
177
+ throw new Error('unexpected URL ' + url);
178
+ },
179
+ });
180
+
181
+ const cursor = status.providers.find((row) => row.id === 'cursor');
182
+ assert.equal(cursor?.configured, true);
183
+ assert.equal(status.discovery.cursor.ok, true);
184
+ assert.equal(status.discovery.cursor.returnedModelCount, 2);
185
+ assert.equal(seen.length, 1);
186
+ assert.match(seen[0].url, /api\.cursor\.com\/v1\/models/);
187
+ assert.match(seen[0].auth, /Bearer cursor-secret-key/);
188
+ assert.deepEqual(
189
+ status.availableModels.filter((row) => row.provider === 'cursor').map((row) => row.provider_model_id),
190
+ ['composer-2.5', 'gpt-5.6-sol'],
191
+ );
192
+ const rendered = renderModelsStatus(status);
193
+ assert.match(rendered, /Cursor/);
194
+ assert.match(rendered, /composer-2\.5/);
195
+ assert.doesNotMatch(rendered, /cursor-secret-key/);
196
+ });
197
+
198
+ test('missing Cursor credential skips discovery and does not fall back to another provider', async t => {
199
+ const home = tempHome(t);
200
+ const seen = [];
201
+ const status = await collectModelsStatus({
202
+ home,
203
+ env: {
204
+ OPENAI_API_KEY: 'secret-openai',
205
+ OLLAMA_BASE_URL: 'http://127.0.0.1:11434',
206
+ },
207
+ fetchImpl: async () => response({ models: [] }),
208
+ providerFetchImpl: async (url) => {
209
+ seen.push(url);
210
+ if (String(url).includes('api.openai.com')) return response({ data: [{ id: 'gpt-test' }] });
211
+ if (String(url).includes('api.cursor.com')) throw new Error('cursor must not be called');
212
+ return response({ data: [] });
213
+ },
214
+ });
215
+ assert.equal(status.providers.find((row) => row.id === 'cursor')?.configured, false);
216
+ assert.equal(status.discovery.cursor.attempted, false);
217
+ assert.equal(seen.some((url) => String(url).includes('api.cursor.com')), false);
218
+ assert.equal(status.availableModels.some((row) => row.provider === 'cursor'), false);
219
+ assert.equal(status.availableModels.some((row) => row.provider === 'openai'), true);
220
+ });
221
+
222
+ test('Cursor discovery failure stays attached to Cursor and does not invent OpenAI models', async t => {
223
+ const home = tempHome(t);
224
+ const status = await collectModelsStatus({
225
+ home,
226
+ env: {
227
+ CURSOR_API_KEY: 'bad-cursor-key',
228
+ OLLAMA_BASE_URL: 'http://127.0.0.1:11434',
229
+ },
230
+ fetchImpl: async () => response({ models: [] }),
231
+ providerFetchImpl: async (url) => {
232
+ if (String(url).includes('api.cursor.com')) {
233
+ return { ok: false, status: 401, async json() { return { error: 'unauthorized' }; } };
234
+ }
235
+ throw new Error('unexpected URL ' + url);
236
+ },
237
+ });
238
+ assert.equal(status.providers.find((row) => row.id === 'cursor')?.configured, true);
239
+ assert.equal(status.discovery.cursor.ok, false);
240
+ assert.ok(status.discovery.cursor.error);
241
+ assert.equal((status.providerModels.cursor || []).length, 0);
242
+ assert.equal(status.availableModels.some((row) => row.provider === 'openai'), false);
243
+ });
244
+
245
+ test('Workers AI curated allowlist intersects live Cloudflare discovery', async t => {
246
+ const home = tempHome(t);
247
+ const status = await collectModelsStatus({
248
+ home,
249
+ curateWorkersAi: true,
250
+ env: { CLOUDFLARE_API_TOKEN: 'secret-cf', CLOUDFLARE_ACCOUNT_ID: '44444444444444444444444444444444', OLLAMA_BASE_URL: 'http://127.0.0.1:11434' },
251
+ fetchImpl: async () => response({ models: [] }),
252
+ providerFetchImpl: async () => response({
253
+ success: true,
254
+ result: [
255
+ { name: '@cf/qwen/qwen2.5-coder-32b-instruct', task: { name: 'Text Generation' } },
256
+ { name: '@cf/meta/llama-3.2-1b-instruct', task: { name: 'Text Generation' } },
257
+ { name: '@cf/openai/gpt-oss-120b', task: { name: 'Text Generation' } },
258
+ ],
259
+ }),
260
+ });
261
+ assert.deepEqual(
262
+ status.providerModels.cloudflare.map((row) => row.provider_model_id).sort(),
263
+ ['@cf/openai/gpt-oss-120b', '@cf/qwen/qwen2.5-coder-32b-instruct'],
264
+ );
265
+ assert.equal(status.discovery.cloudflare.curation, 'agentsam_workers_ai_allowlist');
266
+ });
267
+
268
+ test('studio vault credential plane never reads machine env when resolver is injected', async t => {
269
+ const home = tempHome(t);
270
+ const status = await collectModelsStatus({
271
+ home,
272
+ credentialPlane: 'studio_vault',
273
+ includeLocal: false,
274
+ env: { OPENAI_API_KEY: 'machine-must-not-be-used', CURSOR_API_KEY: 'machine-cursor' },
275
+ resolveCredential: async (providerId) => {
276
+ if (providerId === 'gemini') {
277
+ return { configured: true, value: 'vault-gemini', source: 'user_vault', env: 'GEMINI_API_KEY' };
278
+ }
279
+ return { configured: false, value: '', source: null, error: null };
280
+ },
281
+ fetchImpl: async () => response({ models: [] }),
282
+ providerFetchImpl: async (url) => {
283
+ if (String(url).includes('generativelanguage.googleapis.com') && String(url).includes('vault-gemini')) {
284
+ return response({
285
+ models: [{
286
+ name: 'models/gemini-vault',
287
+ baseModelId: 'gemini-vault',
288
+ displayName: 'Vault Gemini',
289
+ inputTokenLimit: 1000,
290
+ supportedGenerationMethods: ['generateContent'],
291
+ }],
292
+ });
293
+ }
294
+ throw new Error('machine providers must not be discovered: ' + url);
295
+ },
296
+ });
297
+ assert.equal(status.credential_plane, 'studio_vault');
298
+ assert.equal(status.providers.find((row) => row.id === 'openai')?.configured, false);
299
+ assert.equal(status.providers.find((row) => row.id === 'gemini')?.configured, true);
300
+ assert.equal(status.providers.find((row) => row.id === 'gemini')?.source, 'user_vault');
301
+ assert.deepEqual(status.availableModels.map((row) => row.provider_model_id), ['gemini-vault']);
302
+ });
@@ -41,6 +41,51 @@ test('Responses adapter sends reasoning/service tier without legacy sampling par
41
41
  assert.deepEqual(events.map(event => event.type), ['model.started', 'usage.snapshot', 'cost.snapshot', 'model.completed']);
42
42
  });
43
43
 
44
+ test('Responses adapter carries hosted built-ins and function tools through /v1/responses with model capability checks', async () => {
45
+ let request = null;
46
+ const adapter = createOpenAIResponsesAdapter({
47
+ apiKey: 'test-key',
48
+ fetchImpl: async (url, options) => {
49
+ request = { url, body: JSON.parse(options.body) };
50
+ return jsonResponse({
51
+ id: 'resp_tools',
52
+ status: 'completed',
53
+ service_tier: 'default',
54
+ output: [{ type: 'message', content: [{ type: 'output_text', text: 'done' }] }],
55
+ usage: { input_tokens: 100, output_tokens: 10 },
56
+ });
57
+ },
58
+ });
59
+
60
+ await adapter.create({
61
+ model: 'gpt-6-luna',
62
+ input: 'research and summarize',
63
+ reasoningEffort: 'medium',
64
+ serviceTier: 'default',
65
+ tools: [
66
+ { type: 'web_search' },
67
+ { type: 'function', name: 'repository_snapshot', description: 'Snapshot repo', parameters: { type: 'object', properties: {} } },
68
+ ],
69
+ });
70
+
71
+ assert.equal(request.url, 'https://api.openai.com/v1/responses');
72
+ assert.equal(request.body.reasoning.effort, 'medium');
73
+ assert.deepEqual(request.body.tools[0], { type: 'web_search' });
74
+ assert.equal(request.body.tools[1].type, 'function');
75
+ assert.equal(request.body.tools[1].name, 'repository_snapshot');
76
+
77
+ await assert.rejects(
78
+ () => adapter.create({
79
+ model: 'gpt-5.3-codex',
80
+ input: 'search',
81
+ reasoningEffort: 'medium',
82
+ serviceTier: 'default',
83
+ tools: [{ type: 'web_search' }],
84
+ }),
85
+ /does not declare Responses tool support: web_search/,
86
+ );
87
+ });
88
+
44
89
  test('Responses adapter preserves function call_id when returning tool output', async () => {
45
90
  const bodies = [];
46
91
  const adapter = createOpenAIResponsesAdapter({
@@ -93,3 +138,18 @@ test('compaction is an explicit provider operation and has no arbitrary default
93
138
  assert.equal(body.previous_response_id, 'resp_previous');
94
139
  assert.equal(compacted.compaction_id, 'cmp_1');
95
140
  });
141
+
142
+ test('OpenAI server-side compaction uses canonical policy and honors disable with previous_response_id', async () => {
143
+ const { getModelRecord } = await import('../src/models/index.js');
144
+ const bodies = [];
145
+ const adapter = createOpenAIResponsesAdapter({ apiKey: 'test', fetchImpl: async (_, init) => {
146
+ bodies.push(JSON.parse(init.body));
147
+ return jsonResponse({ id: 'resp_1', output: [], usage: {} });
148
+ } });
149
+ await adapter.create({ model: 'gpt-6-astra', previousResponseId: 'resp_previous', input: 'new message' });
150
+ assert.deepEqual(bodies[0].context_management, [{ type: 'compaction', compact_threshold: getModelRecord('gpt-6-astra').context_policy.compact_at_tokens }]);
151
+ assert.equal(bodies[0].input, 'new message');
152
+ assert.equal(bodies[0].previous_response_id, 'resp_previous');
153
+ await adapter.create({ model: 'gpt-6-astra', input: 'test', autoCompact: false });
154
+ assert.equal(bodies[1].context_management, undefined);
155
+ });
@@ -63,14 +63,24 @@ test('provider env profiles create a secure reusable source loader without embed
63
63
 
64
64
  const cloudflare = ensureProviderEnvProfile('cloudflare', { home });
65
65
  const source = fs.readFileSync(cloudflare.file, 'utf8');
66
- assert.match(source, /ACCOUNT_ID=""/);
66
+ assert.match(source, /CLOUDFLARE_ACCOUNT_ID=""/);
67
67
  assert.match(source, /CLOUDFLARE_API_TOKEN=""/);
68
68
  });
69
69
 
70
+ test('Cloudflare credential identity never falls back to generic ACCOUNT_ID', t => {
71
+ const home = fixtureHome(t);
72
+ const resolved = resolveProviderCredential('cloudflare', {
73
+ env: { CLOUDFLARE_API_TOKEN: 'token-secret', ACCOUNT_ID: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' },
74
+ home,
75
+ });
76
+ assert.equal(resolved.configured, true);
77
+ assert.equal(resolved.account_id, null);
78
+ });
79
+
70
80
  test('Cloudflare credential status carries non-secret account identity from the provider profile', t => {
71
81
  const home = fixtureHome(t);
72
82
  const profile = path.join(home, '.agentsam', 'env.d', 'cloudflare.env');
73
- fs.writeFileSync(profile, 'export ACCOUNT_ID="0123456789abcdef0123456789abcdef"\nexport CLOUDFLARE_API_TOKEN="token-secret"\n', { mode: 0o600 });
83
+ fs.writeFileSync(profile, 'export CLOUDFLARE_ACCOUNT_ID="0123456789abcdef0123456789abcdef"\nexport CLOUDFLARE_API_TOKEN="token-secret"\n', { mode: 0o600 });
74
84
  if (process.platform !== 'win32') fs.chmodSync(profile, 0o600);
75
85
  const resolved = resolveProviderCredential('cloudflare', { env: {}, home });
76
86
  assert.equal(resolved.account_id, '0123456789abcdef0123456789abcdef');
@@ -83,14 +93,14 @@ test('Cloudflare credential status carries non-secret account identity from the
83
93
  test('Cloudflare profile account backfill never overwrites an existing token or account choice', t => {
84
94
  const home = fixtureHome(t);
85
95
  const profile = path.join(home, '.agentsam', 'env.d', 'cloudflare.env');
86
- fs.writeFileSync(profile, 'export ACCOUNT_ID=""\nexport CLOUDFLARE_API_TOKEN="keep-me"\n', { mode: 0o600 });
96
+ fs.writeFileSync(profile, 'export CLOUDFLARE_ACCOUNT_ID=""\nexport CLOUDFLARE_API_TOKEN="keep-me"\n', { mode: 0o600 });
87
97
  ensureProviderEnvProfile('cloudflare', { home, accountId: '11111111111111111111111111111111' });
88
98
  let source = fs.readFileSync(profile, 'utf8');
89
- assert.match(source, /ACCOUNT_ID="11111111111111111111111111111111"/);
99
+ assert.match(source, /CLOUDFLARE_ACCOUNT_ID="11111111111111111111111111111111"/);
90
100
  assert.match(source, /CLOUDFLARE_API_TOKEN="keep-me"/);
91
101
 
92
102
  ensureProviderEnvProfile('cloudflare', { home, accountId: '22222222222222222222222222222222' });
93
103
  source = fs.readFileSync(profile, 'utf8');
94
- assert.match(source, /ACCOUNT_ID="11111111111111111111111111111111"/);
104
+ assert.match(source, /CLOUDFLARE_ACCOUNT_ID="11111111111111111111111111111111"/);
95
105
  assert.doesNotMatch(source, /22222222222222222222222222222222/);
96
106
  });