@inneranimalmedia/agentsam-sdk 2.6.3 → 2.6.4

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 (233) hide show
  1. package/AGENTSAM.md +6 -0
  2. package/README.md +16 -1
  3. package/bin/agentsam +16 -1
  4. package/docs/BRAND_INTELLIGENCE.md +1 -1
  5. package/docs/architecture/AGENTSAM_DISTRIBUTION_OWNERSHIP.md +176 -0
  6. package/docs/architecture/AGENTSAM_GO_RUNTIME.md +282 -0
  7. package/docs/architecture/CODEBASEINDEX_GUIDED_PATH.md +202 -0
  8. package/docs/architecture/FS_E2E_CLOSURE_RECEIPT.md +59 -0
  9. package/docs/architecture/LOCAL_FS_AUTHORITY.md +38 -0
  10. package/docs/architecture/LOCAL_STUDIO_CLOUDFLARE_OAUTH.md +28 -0
  11. package/docs/architecture/PLAN_CLI_AND_LOCAL_STUDIO_DESKTOP.md +96 -0
  12. package/docs/architecture/SAM_ACTIVITY_RECOVERY_RECEIPT.md +39 -0
  13. package/docs/architecture/SAM_DECISION_WORK_RECEIPT.md +54 -0
  14. package/docs/architecture/SAM_KERNEL.md +181 -0
  15. package/docs/architecture/SAM_MACHINE_NORMALIZATION_PRECOMMIT_REPORT.md +208 -0
  16. package/docs/architecture/SLASH_SKILLS_PORTABLE.md +116 -0
  17. package/docs/architecture/fs-e2e-receipt.latest.json +42 -0
  18. package/docs/architecture/previews/codebaseindex-guided-path/CODEBASEINDEX_GUIDED_PATH.md +202 -0
  19. package/docs/architecture/previews/codebaseindex-guided-path/index.html +321 -0
  20. package/migrations/d1/0010_portable_tickets_memory.sql +140 -0
  21. package/migrations/d1/0011_agentsam_skill_v2.sql +185 -0
  22. package/migrations/d1/0011b_agentsam_skill_v2_cutover.sql +22 -0
  23. package/migrations/d1/0011c_agentsam_skill_v2_backfill.sql +76 -0
  24. package/migrations/d1/0011d_agentsam_skill_v2_retrieval_revisions.sql +50 -0
  25. package/migrations/d1/0012_agentsam_tools_required_seed.sql +67 -0
  26. package/migrations/d1/0013_identity_oauth_states.sql +15 -0
  27. package/migrations/d1/0014_auth_event_log.sql +20 -0
  28. package/migrations/d1/0015_identity_oauth_state_app_id.sql +3 -0
  29. package/migrations/d1/README_PORTABLE_CONTROL_PLANE.md +16 -0
  30. package/migrations/sqlite/agentsam_skill_retrieval.portable.sql +42 -0
  31. package/package.json +19 -4
  32. package/packages/agentsam-contracts/src/errors.ts +16 -0
  33. package/packages/agentsam-errors/src/envelope.js +53 -0
  34. package/packages/agentsam-errors/src/index.js +1 -0
  35. package/packages/agentsam-errors/src/recovery.js +301 -0
  36. package/packages/agentsam-knowledge/src/providers/index.js +18 -6
  37. package/packages/connectors/cloudflare/src/routes.js +9 -0
  38. package/packages/connectors/cloudflare/tests/connector.test.mjs +26 -1
  39. package/packages/identity/.agentsam/features/oauth-login-portal/agentsam.feature.json +1 -1
  40. package/packages/identity/.agentsam/features/oauth-login-portal/routes.json +11 -2
  41. package/packages/identity/docs/PORTABLE_IDENTITY_ARCHITECTURE.md +50 -0
  42. package/packages/identity/migrations/D1_SCHEMA_MAPPING.md +31 -0
  43. package/packages/identity/migrations/sqlite/001_identity_core.sql +99 -0
  44. package/packages/identity/migrations/sqlite/002_identity_oauth_client.sql +38 -0
  45. package/packages/identity/migrations/sqlite/003_identity_oauth_server.sql +64 -0
  46. package/packages/identity/package.json +2 -2
  47. package/packages/identity/src/adapters/cloudflare-d1/index.js +122 -22
  48. package/packages/identity/src/adapters/sqlite/index.js +319 -0
  49. package/packages/identity/src/app/verify-app.js +95 -0
  50. package/packages/identity/src/contracts/identity-store.js +115 -0
  51. package/packages/identity/src/contracts/route-ids.js +30 -0
  52. package/packages/identity/src/contracts/route-projection.js +218 -0
  53. package/packages/identity/src/contracts/routes.js +11 -0
  54. package/packages/identity/src/core/browser-paths.js +4 -5
  55. package/packages/identity/src/core/constants.js +13 -8
  56. package/packages/identity/src/core/session-policy.js +32 -0
  57. package/packages/identity/src/frontend/auth-portal/pages/login.html +10 -10
  58. package/packages/identity/src/frontend/auth-portal/pages/reset.html +3 -3
  59. package/packages/identity/src/frontend/auth-portal/pages/signup.html +3 -3
  60. package/packages/identity/src/frontend/auth-portal/preview/dashboard-stub.html +1 -1
  61. package/packages/identity/src/index.js +25 -0
  62. package/packages/identity/src/oauth/README.md +10 -4
  63. package/packages/identity/src/oauth/credentials.js +20 -13
  64. package/packages/identity/src/oauth/finalize-inbound.js +1 -1
  65. package/packages/identity/src/oauth/iam-platform.js +8 -7
  66. package/packages/identity/src/oauth/redirect-paths.js +27 -36
  67. package/packages/identity/src/server/identity-service.js +30 -13
  68. package/packages/identity/src/server/mount-policy.js +30 -0
  69. package/packages/identity/src/server/post-auth.js +79 -0
  70. package/packages/identity/src/server/worker-router.js +104 -72
  71. package/packages/identity/tests/finalize-inbound-oauth.test.mjs +6 -6
  72. package/packages/identity/tests/iam-provider.test.mjs +1 -1
  73. package/packages/identity/tests/identity-service.test.mjs +36 -5
  74. package/packages/identity/tests/oauth-credentials.test.mjs +3 -1
  75. package/packages/identity/tests/portable-identity-architecture.test.mjs +157 -0
  76. package/packages/identity/tests/session-routes-policy.test.mjs +21 -0
  77. package/packages/theme-church-site/package.json +2 -1
  78. package/packages/theme-church-site/src/index.js +1 -0
  79. package/packages/theme-companions-site/package.json +2 -1
  80. package/packages/theme-companions-site/src/index.js +1 -0
  81. package/packages/theme-floors-site/package.json +2 -1
  82. package/packages/theme-floors-site/src/index.js +1 -0
  83. package/packages/theme-fuelnfree-site/package.json +2 -1
  84. package/packages/theme-fuelnfree-site/src/index.js +1 -0
  85. package/packages/theme-handyman-site/package.json +2 -1
  86. package/packages/theme-handyman-site/src/index.js +1 -0
  87. package/packages/theme-insurance-site/package.json +2 -1
  88. package/packages/theme-insurance-site/src/index.js +1 -0
  89. package/packages/theme-shinshu-site/package.json +2 -1
  90. package/packages/theme-shinshu-site/src/index.js +1 -0
  91. package/protocol/apps/agentsam.app.v1.schema.json +51 -0
  92. package/protocol/brand/brandpack.v1.schema.json +43 -0
  93. package/protocol/credentials/issue.v1.schema.json +38 -0
  94. package/protocol/database/connection.v1.schema.json +41 -0
  95. package/protocol/embeddings/embedding-profile.v1.schema.json +20 -0
  96. package/protocol/errors/error-envelope.schema.json +135 -1
  97. package/protocol/errors/recovery.v1.schema.json +50 -0
  98. package/protocol/runtime/workspace-fs.v1.schema.json +71 -0
  99. package/protocol/sam/activity.v1.schema.json +48 -0
  100. package/protocol/sam/answer.v1.schema.json +35 -0
  101. package/protocol/sam/calibration.v1.schema.json +21 -0
  102. package/protocol/sam/decision-receipt.v1.schema.json +29 -0
  103. package/protocol/sam/evaluation.v1.schema.json +19 -0
  104. package/protocol/sam/operation.schema.json +66 -0
  105. package/protocol/sam/outcome.v1.schema.json +36 -0
  106. package/protocol/sam/question.v1.schema.json +26 -0
  107. package/protocol/sam/registry.seed.json +153 -0
  108. package/protocol/sam/result.schema.json +53 -0
  109. package/protocol/sam/state.v1.schema.json +23 -0
  110. package/protocol/skills/agentsam.interaction.v1.schema.json +50 -0
  111. package/protocol/skills/agentsam.skill.v1.schema.json +57 -0
  112. package/protocol/ui/icon-registry.mjs +226 -0
  113. package/protocol/ui/icon.v1.schema.json +51 -0
  114. package/skills/README.md +22 -9
  115. package/skills/agentsam-codebaseindex/SKILL.md +225 -0
  116. package/skills/catalog.json +14 -0
  117. package/src/cli/command-catalog.js +130 -0
  118. package/src/cli/dispatch.js +48 -0
  119. package/src/cli.js +43 -1
  120. package/src/commands/api-key.js +244 -0
  121. package/src/commands/app.js +60 -28
  122. package/src/commands/brand.js +17 -19
  123. package/src/commands/codebaseindex.js +688 -0
  124. package/src/commands/env.js +152 -25
  125. package/src/commands/go.js +366 -53
  126. package/src/commands/interaction-clack.js +115 -0
  127. package/src/commands/models.js +1 -1
  128. package/src/commands/providers.js +62 -14
  129. package/src/commands/shell.js +43 -2
  130. package/src/commands/skill.js +248 -0
  131. package/src/commands/skills.js +1 -1
  132. package/src/commands/start-local.js +4 -0
  133. package/src/commands/whoami.js +90 -18
  134. package/src/go/build.js +229 -39
  135. package/src/go/cloudflare.js +506 -105
  136. package/src/go/container.js +120 -0
  137. package/src/go/contract.js +9 -4
  138. package/src/go/discover.js +149 -33
  139. package/src/go/index.js +15 -3
  140. package/src/go/native-probe-runner.mjs +119 -0
  141. package/src/go/{registry.js → official-registry.js} +64 -7
  142. package/src/go/official-release.js +10 -0
  143. package/src/go/receipts.js +77 -10
  144. package/src/go/verify.js +9 -2
  145. package/src/index.js +27 -0
  146. package/src/indexing/ingest/discover-models.js +298 -0
  147. package/src/indexing/ingest/inventory.js +243 -0
  148. package/src/indexing/ingest/job-graph.js +181 -0
  149. package/src/indexing/ingest/materials.js +210 -0
  150. package/src/lib/provider-credentials.js +63 -21
  151. package/src/lib/slash-commands.js +1 -0
  152. package/src/local-fs/capability.js +121 -0
  153. package/src/local-fs/freshness.js +75 -0
  154. package/src/local-fs/index.js +385 -0
  155. package/src/local-fs/paths.js +100 -0
  156. package/src/local-pty/server.js +295 -19
  157. package/src/mcp/client.js +2 -2
  158. package/src/models/ai-access-onboarding.js +112 -0
  159. package/src/models/discovery.js +10 -2
  160. package/src/models/inventory-core.js +9 -1
  161. package/src/sam/activity/index.js +183 -0
  162. package/src/sam/client.js +252 -0
  163. package/src/sam/decision/calibration.js +109 -0
  164. package/src/sam/decision/confidence.js +126 -0
  165. package/src/sam/decision/evaluate.js +157 -0
  166. package/src/sam/decision/evaluators/deterministic.js +341 -0
  167. package/src/sam/decision/evaluators/heuristic.js +61 -0
  168. package/src/sam/decision/evaluators/select.js +50 -0
  169. package/src/sam/decision/evaluators/semantic.js +149 -0
  170. package/src/sam/decision/hierarchical.js +61 -0
  171. package/src/sam/decision/index.js +53 -0
  172. package/src/sam/decision/policy.js +86 -0
  173. package/src/sam/decision/questions.js +120 -0
  174. package/src/sam/decision/receipt.js +148 -0
  175. package/src/sam/decision/state.js +117 -0
  176. package/src/sam/decision/types.js +22 -0
  177. package/src/sam/decision/validate.js +200 -0
  178. package/src/sam/define.js +51 -0
  179. package/src/sam/index.js +65 -0
  180. package/src/sam/operations/brand-scan.js +62 -0
  181. package/src/sam/operations/cad-blender-inspect.js +36 -0
  182. package/src/sam/operations/codebaseindex-ingest.js +49 -0
  183. package/src/sam/operations/decision-evaluate.js +59 -0
  184. package/src/sam/operations/planning-astar.js +77 -0
  185. package/src/sam/operations/planning-goap.js +60 -0
  186. package/src/sam/operations/repository-inspect.js +72 -0
  187. package/src/sam/operations/security-scan.js +33 -0
  188. package/src/sam/operations/terminal-exec.js +29 -0
  189. package/src/sam/planning/astar.js +311 -0
  190. package/src/sam/planning/goap.js +177 -0
  191. package/src/sam/planning/index.js +21 -0
  192. package/src/sam/planning/state.js +84 -0
  193. package/src/sam/registry.js +48 -0
  194. package/src/sam/result.js +77 -0
  195. package/src/sam/seed.js +44 -0
  196. package/src/sam/types.js +91 -0
  197. package/src/skills/catalog.js +64 -0
  198. package/src/skills/content-resolver.js +124 -0
  199. package/src/skills/hosted-store.js +37 -0
  200. package/src/skills/index.js +29 -64
  201. package/src/skills/interaction.js +102 -0
  202. package/src/skills/local-store.js +228 -0
  203. package/src/skills/manifest.js +104 -0
  204. package/src/skills/metrics.js +31 -0
  205. package/src/skills/registry.js +184 -0
  206. package/src/skills/runtime.js +287 -0
  207. package/src/skills/slash.js +44 -0
  208. package/src/ui/cli/help.js +94 -101
  209. package/test/cli/api-key-env-whoami.test.mjs +129 -0
  210. package/test/cli/codebaseindex-plan-ux.test.mjs +37 -0
  211. package/test/cli/go.test.mjs +62 -5
  212. package/test/cli/skill-npm-and-env.test.mjs +52 -0
  213. package/test/cli/wireframes-go-registry.test.mjs +87 -2
  214. package/test/go/build-source-identity.test.mjs +31 -0
  215. package/test/go/cloudflare-probe.test.mjs +274 -10
  216. package/test/go/distribution.test.mjs +28 -0
  217. package/test/integration/ai-access-onboarding.test.mjs +47 -0
  218. package/test/integration/cli-help.test.mjs +1 -1
  219. package/test/integration/cms-site-tenancy-contract.test.mjs +6 -6
  220. package/test/integration/codebaseindex-ingest.test.mjs +166 -0
  221. package/test/integration/icon-registry.test.mjs +67 -0
  222. package/test/integration/ingest-discover-models.test.mjs +30 -0
  223. package/test/integration/install-script.test.mjs +12 -9
  224. package/test/integration/local-fs.test.mjs +113 -0
  225. package/test/integration/provider-env-cli.test.mjs +2 -1
  226. package/test/integration/sam-activity-recovery.test.mjs +147 -0
  227. package/test/integration/sam-decision.test.mjs +584 -0
  228. package/test/integration/sam-kernel.test.mjs +99 -0
  229. package/test/integration/sam-planning-astar.test.mjs +279 -0
  230. package/test/integration/skill-runtime.test.mjs +240 -0
  231. package/test/integration/studio-fs-pty-e2e.test.mjs +294 -0
  232. package/test/models.test.mjs +14 -7
  233. package/test/shell.test.mjs +4 -4
@@ -0,0 +1,10 @@
1
+ export const INNERANIMALMEDIA_OFFICIAL_RELEASE_ENV =
2
+ 'AGENTSAM_INNERANIMALMEDIA_OFFICIAL_RELEASE';
3
+
4
+ export const LEGACY_IAM_OFFICIAL_RELEASE_ENV =
5
+ 'AGENTSAM_IAM_OFFICIAL_RELEASE';
6
+
7
+ export function innerAnimalMediaOfficialReleaseEnabled(env = process.env) {
8
+ return env?.[INNERANIMALMEDIA_OFFICIAL_RELEASE_ENV] === '1'
9
+ || env?.[LEGACY_IAM_OFFICIAL_RELEASE_ENV] === '1';
10
+ }
@@ -10,18 +10,40 @@ export function goStateDir(productRoot) {
10
10
  export function writeGoBuildReceipt(productRoot, receipt) {
11
11
  const dir = goStateDir(productRoot);
12
12
  const file = path.join(dir, 'latest.build-receipt.json');
13
- fs.writeFileSync(file, `${JSON.stringify(receipt, null, 2)}\n`);
13
+ fs.writeFileSync(file, JSON.stringify(receipt, null, 2) + '\n');
14
14
  return file;
15
15
  }
16
16
 
17
17
  export function writeDeploymentReceipt(productRoot, receipt) {
18
18
  const dir = goStateDir(productRoot);
19
19
  const file = path.join(dir, 'latest.deployment-receipt.json');
20
+ const payload = { schema: 'agentsam.deployment-receipt.v1', ...receipt };
21
+ fs.writeFileSync(file, JSON.stringify(payload, null, 2) + '\n');
22
+ return file;
23
+ }
24
+
25
+ export function writeDeploymentValidationReceipt(productRoot, receipt) {
26
+ const dir = goStateDir(productRoot);
27
+ const file = path.join(dir, 'latest.deployment-validation-receipt.json');
20
28
  const payload = {
21
- schema: 'agentsam.deployment-receipt.v1',
29
+ schema: 'agentsam.deployment-validation-receipt.v1',
22
30
  ...receipt,
23
31
  };
24
- fs.writeFileSync(file, `${JSON.stringify(payload, null, 2)}\n`);
32
+ fs.writeFileSync(file, JSON.stringify(payload, null, 2) + '\n');
33
+ return file;
34
+ }
35
+
36
+ export function writeProductValidationLocal(productRoot, row) {
37
+ const dir = goStateDir(productRoot);
38
+ const file = path.join(dir, 'product.validation-registry.json');
39
+ const payload = {
40
+ schema: 'agentsam.product-validation-registry.v1',
41
+ registry: 'agentsam_products',
42
+ authority: 'local_validation',
43
+ row,
44
+ written_at: new Date().toISOString(),
45
+ };
46
+ fs.writeFileSync(file, JSON.stringify(payload, null, 2) + '\n');
25
47
  return file;
26
48
  }
27
49
 
@@ -31,11 +53,11 @@ export function writeProductRegistryLocal(productRoot, row) {
31
53
  const payload = {
32
54
  schema: 'agentsam.product-local-registry.v1',
33
55
  registry: 'agentsam_products',
34
- note: 'Local projection + optional remote D1 upsert into agentsam_products / asset_relationships.',
56
+ note: 'Local AgentSam projection. InnerAnimalMedia D1 registration is a separate explicit official-release operation.',
35
57
  row,
36
58
  written_at: new Date().toISOString(),
37
59
  };
38
- fs.writeFileSync(file, `${JSON.stringify(payload, null, 2)}\n`);
60
+ fs.writeFileSync(file, JSON.stringify(payload, null, 2) + '\n');
39
61
  return file;
40
62
  }
41
63
 
@@ -44,20 +66,43 @@ export function readLatestStatus(productRoot) {
44
66
  const buildPath = path.join(dir, 'latest.build-receipt.json');
45
67
  const deployPath = path.join(dir, 'latest.deployment-receipt.json');
46
68
  const productPath = path.join(dir, 'product.registry.json');
69
+ const validationPath = path.join(dir, 'latest.deployment-validation-receipt.json');
70
+ const validationProductPath = path.join(dir, 'product.validation-registry.json');
47
71
  return {
48
72
  build: fs.existsSync(buildPath) ? JSON.parse(fs.readFileSync(buildPath, 'utf8')) : null,
49
73
  deployment: fs.existsSync(deployPath) ? JSON.parse(fs.readFileSync(deployPath, 'utf8')) : null,
50
74
  product: fs.existsSync(productPath) ? JSON.parse(fs.readFileSync(productPath, 'utf8')) : null,
75
+ validation: fs.existsSync(validationPath) ? JSON.parse(fs.readFileSync(validationPath, 'utf8')) : null,
76
+ validation_product: fs.existsSync(validationProductPath)
77
+ ? JSON.parse(fs.readFileSync(validationProductPath, 'utf8'))
78
+ : null,
51
79
  };
52
80
  }
53
81
 
54
- export function buildProductRow({ product, repositoryId, commit, url, health }) {
82
+ export function buildProductRow({
83
+ product,
84
+ repositoryId,
85
+ commit,
86
+ sourceIdentity = null,
87
+ packageName = '@inneranimalmedia/agentsam-go-worker',
88
+ packageVersion = '0.1.0',
89
+ cloudflareAccount = null,
90
+ url,
91
+ health,
92
+ workerDeploymentId = null,
93
+ workerVersionId = null,
94
+ artifactDigest = null,
95
+ containerDigest = null,
96
+ }) {
55
97
  return {
56
98
  slug: product,
57
99
  kind: 'service',
58
100
  name: product,
59
101
  status: health === 'healthy' ? 'deployed' : (health === 'pending' ? 'built' : 'degraded'),
60
102
  repository_id: repositoryId || null,
103
+ canonical_path: 'apps/agentsam-go-worker',
104
+ package_name: packageName,
105
+ version: packageVersion,
61
106
  metadata: {
62
107
  runtime: 'go',
63
108
  deployment: {
@@ -65,12 +110,34 @@ export function buildProductRow({ product, repositoryId, commit, url, health })
65
110
  mode: 'worker-container',
66
111
  url: url || null,
67
112
  health: health || null,
113
+ worker_deployment_id: workerDeploymentId,
114
+ worker_version_id: workerVersionId,
115
+ artifact_digest: artifactDigest,
116
+ container_image_digest: containerDigest,
117
+ cloudflare_account: cloudflareAccount,
118
+ },
119
+ source: {
120
+ identity: sourceIdentity,
121
+ commit: commit || null,
122
+ package_name: packageName,
123
+ package_version: packageVersion,
68
124
  },
69
- source: { commit: commit || null },
70
125
  relationships: [
71
- { type: 'source_repository', target: repositoryId || null },
72
- { type: 'runtime', target: 'go' },
73
- { type: 'edge', target: 'cloudflare-worker' },
126
+ repositoryId
127
+ ? { type: 'source_repository', target: repositoryId }
128
+ : { type: 'source_package', target: packageName },
129
+ {
130
+ type: 'runtime',
131
+ target: 'go',
132
+ target_type: 'runtime',
133
+ relationship_type: 'runs_on',
134
+ },
135
+ {
136
+ type: 'edge',
137
+ target: product,
138
+ target_type: 'cloudflare_worker',
139
+ relationship_type: 'deployed_as',
140
+ },
74
141
  ],
75
142
  },
76
143
  };
package/src/go/verify.js CHANGED
@@ -4,18 +4,25 @@ import { runGoTests, runGoVet } from './build.js';
4
4
 
5
5
  export async function verifyGoProduct({
6
6
  productRoot,
7
+ stateRoot = productRoot,
7
8
  runtimeRoot,
8
9
  url = null,
9
10
  fetchImpl = globalThis.fetch,
10
11
  skipLive = false,
11
12
  } = {}) {
12
- const status = readLatestStatus(productRoot);
13
+ const status = readLatestStatus(stateRoot);
13
14
  const tests = runtimeRoot ? runGoTests(runtimeRoot) : { ok: false, error: 'no_runtime' };
14
15
  const vet = runtimeRoot ? runGoVet(runtimeRoot) : { ok: false, error: 'no_runtime' };
15
16
  const liveUrl = url || status.deployment?.url || null;
16
17
  let live = { skipped: true, ok: false };
17
18
  if (!skipLive && liveUrl) {
18
- live = await probeGoDeployment(liveUrl, { fetchImpl });
19
+ live = await probeGoDeployment(liveUrl, {
20
+ fetchImpl,
21
+ expectedSource: status.deployment?.source_identity || status.build?.source?.identity || null,
22
+ expectedSourceCommit: status.deployment?.source_commit || status.build?.source?.commit || null,
23
+ expectedTarget: 'cloudflare',
24
+ edge: true,
25
+ });
19
26
  }
20
27
 
21
28
  const ok = Boolean(tests.ok && vet.ok && (skipLive || !liveUrl || live.ok));
package/src/index.js CHANGED
@@ -3,6 +3,27 @@
3
3
  import pkg from '../package.json' with { type: 'json' };
4
4
 
5
5
  export { AgentSam } from './AgentSam.js';
6
+ export {
7
+ SAM_RESULT_SCHEMA,
8
+ SAM_EXPANSION,
9
+ defineSamOperation,
10
+ registerSamOperation,
11
+ getSamOperation,
12
+ listSamOperations,
13
+ toSamOperationCard,
14
+ buildSamResult,
15
+ AgentSamClient,
16
+ createAgentSamClient,
17
+ ensureSeedOperations,
18
+ SEED_OPERATIONS,
19
+ } from './sam/index.js';
20
+ export {
21
+ CLI_COMMAND_CATALOG,
22
+ getCliCommand,
23
+ listCliCommands,
24
+ printAssistTip,
25
+ suggestCliCommands,
26
+ } from './cli/command-catalog.js';
6
27
  export { routeIntent } from './lib/router.js';
7
28
  export { searchToolCards, toToolCard, hydrateToolSchemas } from './tools/index.js';
8
29
  export {
@@ -130,6 +151,12 @@ export {
130
151
  fingerprintError,
131
152
  shouldRetry,
132
153
  retryDelayMs,
154
+ planRecovery,
155
+ inferFailureClass,
156
+ inferSideEffectState,
157
+ FAILURE_CLASS,
158
+ SIDE_EFFECT_STATE,
159
+ RECOVERY_SCHEMA,
133
160
  toHttpError,
134
161
  fromHttpError,
135
162
  renderError,
@@ -0,0 +1,298 @@
1
+ /**
2
+ * Discover embedding models from the user's configured credentials.
3
+ *
4
+ * Authority order for the picker:
5
+ * 1. Credential-scoped cloud providers (OpenAI, Gemini, Cloudflare Workers AI)
6
+ * 2. Optional local Ollama inventory (offer only — never required, never SSOT)
7
+ * 3. Always "none" (AST/text only)
8
+ *
9
+ * Dimensions are profile fingerprints for the chosen provider/model — not "Ollama truth."
10
+ * Regex/name heuristics are hints until a real embed/adapter reports length.
11
+ */
12
+
13
+ import { collectModelsStatus } from '../../commands/models.js';
14
+ import { resolveOllamaConfig, probeOllama, probeOllamaModel } from '../../commands/ollama.js';
15
+ import { resolveProviderCredential } from '../../lib/provider-credentials.js';
16
+ import { createProviderRegistry } from '../../../packages/agentsam-knowledge/src/providers/index.js';
17
+
18
+ function clean(value) {
19
+ return value == null ? '' : String(value).trim();
20
+ }
21
+
22
+ /** Known Workers AI / Vectorize-friendly embed dims (hint until first embed probes). */
23
+ const WORKERS_AI_EMBED_DIMS = Object.freeze({
24
+ '@cf/baai/bge-small-en-v1.5': 384,
25
+ '@cf/baai/bge-base-en-v1.5': 768,
26
+ '@cf/baai/bge-large-en-v1.5': 1024,
27
+ '@cf/baai/bge-m3': 1024,
28
+ '@cf/google/embeddinggemma-300m': 768,
29
+ });
30
+
31
+ function looksLikeEmbedModel(name) {
32
+ const id = clean(name).toLowerCase();
33
+ if (!id) return false;
34
+ return /embed|bge-|e5-|gte-|minilm|mxbai-embed|nomic-embed|snowflake-arctic-embed/i.test(id);
35
+ }
36
+
37
+ /**
38
+ * Hint dimensions for a provider/model. Not authoritative — adapters may probe.
39
+ */
40
+ function defaultDimensions(provider, model) {
41
+ const id = clean(model).toLowerCase();
42
+ if (provider === 'openai') {
43
+ if (id.includes('large')) return 3072;
44
+ if (id.includes('small')) return 1536;
45
+ return 1536;
46
+ }
47
+ if (provider === 'gemini') {
48
+ return 768;
49
+ }
50
+ if (provider === 'workers-ai' || provider === 'cloudflare') {
51
+ if (WORKERS_AI_EMBED_DIMS[clean(model)]) return WORKERS_AI_EMBED_DIMS[clean(model)];
52
+ if (id.includes('small')) return 384;
53
+ if (id.includes('large') || id.includes('bge-m3')) return 1024;
54
+ return 768;
55
+ }
56
+ if (provider === 'ollama') {
57
+ if (id.includes('mxbai-embed-large')) return 1024;
58
+ if (id.includes('nomic-embed')) return 768;
59
+ return 1024;
60
+ }
61
+ return 768;
62
+ }
63
+
64
+ /**
65
+ * Encode a selectable embedding profile for clack / CLI.
66
+ * Format: provider|model|dimensions (pipe — models may contain colons)
67
+ */
68
+ export function encodeEmbeddingChoice(provider, model, dimensions) {
69
+ return `${provider}|${model}|${dimensions}`;
70
+ }
71
+
72
+ /**
73
+ * @param {string} value
74
+ */
75
+ export function parseEmbeddingChoice(value) {
76
+ if (!value || value === 'none') {
77
+ return { provider: 'none', model: 'none', revision: '1', dimensions: 0, parameters: {} };
78
+ }
79
+ // New encoding: provider|model|dims
80
+ if (String(value).includes('|')) {
81
+ const [provider, model, dims] = String(value).split('|');
82
+ return {
83
+ provider: clean(provider),
84
+ model: clean(model),
85
+ revision: '1',
86
+ dimensions: Number(dims) || defaultDimensions(provider, model),
87
+ parameters: provider === 'gemini' ? { task: 'code retrieval' } : {},
88
+ };
89
+ }
90
+ // Legacy encoding used briefly: provider:model:dims (breaks on model ids with colons)
91
+ const parts = String(value).split(':');
92
+ if (parts.length >= 3) {
93
+ const provider = parts[0];
94
+ const dims = parts[parts.length - 1];
95
+ const model = parts.slice(1, -1).join(':');
96
+ return {
97
+ provider: clean(provider),
98
+ model: clean(model),
99
+ revision: '1',
100
+ dimensions: Number(dims) || defaultDimensions(provider, model),
101
+ parameters: provider === 'gemini' ? { task: 'code retrieval' } : {},
102
+ };
103
+ }
104
+ throw new Error(`invalid_embedding_choice:${value}`);
105
+ }
106
+
107
+ /**
108
+ * Build embedding select options from live discovery.
109
+ * Always offers "none" (AST/text only). Ollama entries appear only when online (optional).
110
+ *
111
+ * @param {object} [options]
112
+ * @returns {Promise<{ options: object[], inventory: object, assistModels: object[] }>}
113
+ */
114
+ export async function discoverIngestModelOptions(options = {}) {
115
+ const env = options.env || process.env;
116
+ const status = await collectModelsStatus({
117
+ env,
118
+ home: options.home,
119
+ discoverRemote: options.discoverRemote !== false,
120
+ includeLocal: true,
121
+ // Keep CF embed models; chat allowlist must not hide Vectorize options.
122
+ curateWorkersAi: options.curateWorkersAi !== false,
123
+ fetchImpl: options.fetchImpl,
124
+ providerFetchImpl: options.providerFetchImpl,
125
+ });
126
+
127
+ /** @type {Map<string, object>} */
128
+ const byValue = new Map();
129
+ const push = (row) => {
130
+ if (!row?.value || byValue.has(row.value)) return;
131
+ byValue.set(row.value, row);
132
+ };
133
+
134
+ push({
135
+ value: 'none',
136
+ label: 'None — AST/text only ($0 embeddings)',
137
+ hint: 'deterministic · no provider spend',
138
+ provider: 'none',
139
+ source: 'builtin',
140
+ });
141
+
142
+ // Credential-scoped OpenAI embedding models from live /v1/models
143
+ for (const row of status.providerModels?.openai || []) {
144
+ const caps = row.capabilities || {};
145
+ const id = row.provider_model_id || '';
146
+ if (caps.embeddings === true || /^text-embedding-/i.test(id)) {
147
+ const dims = defaultDimensions('openai', id);
148
+ push({
149
+ value: encodeEmbeddingChoice('openai', id, dims),
150
+ label: `OpenAI · ${id}`,
151
+ hint: `credential · ${dims}d`,
152
+ provider: 'openai',
153
+ source: 'provider_api',
154
+ model: id,
155
+ dimensions: dims,
156
+ });
157
+ }
158
+ }
159
+
160
+ // Gemini: if key configured, offer models from knowledge adapter + any discovered embed ids
161
+ const geminiCred = resolveProviderCredential('gemini', { env, home: options.home });
162
+ if (geminiCred?.configured) {
163
+ const registry = createProviderRegistry({
164
+ gemini: { apiKey: geminiCred.value || env.GEMINI_API_KEY },
165
+ });
166
+ const caps = registry.get('gemini').capabilities();
167
+ for (const id of caps.models || []) {
168
+ const dims = defaultDimensions('gemini', id);
169
+ push({
170
+ value: encodeEmbeddingChoice('gemini', id, dims),
171
+ label: `Gemini · ${id}`,
172
+ hint: `credential · ${dims}d`,
173
+ provider: 'gemini',
174
+ source: 'provider_credential',
175
+ model: id,
176
+ dimensions: dims,
177
+ });
178
+ }
179
+ }
180
+
181
+ // Cloudflare Workers AI embedding models — required for Vectorize / CF lanes.
182
+ // Uses live account discovery (Text Embeddings). Provider id = workers-ai (knowledge adapter).
183
+ for (const row of status.providerModels?.cloudflare || []) {
184
+ const caps = row.capabilities || {};
185
+ const id = row.provider_model_id || '';
186
+ const task = String(row.metadata?.task || '').toLowerCase();
187
+ const isEmbed = caps.embeddings === true || task === 'text embeddings' || looksLikeEmbedModel(id);
188
+ if (!isEmbed || !id) continue;
189
+ const dims = defaultDimensions('workers-ai', id);
190
+ push({
191
+ value: encodeEmbeddingChoice('workers-ai', id, dims),
192
+ label: `Workers AI · ${id}`,
193
+ hint: `cloudflare · vectorize-ready · ${dims}d`,
194
+ provider: 'workers-ai',
195
+ source: 'provider_api',
196
+ model: id,
197
+ dimensions: dims,
198
+ });
199
+ }
200
+
201
+ // Optional local Ollama — never required; only offered when online.
202
+ /** @type {object[]} */
203
+ const assistModels = [];
204
+ if (status.local?.online) {
205
+ const ollamaConfig = resolveOllamaConfig({}, env);
206
+ for (const row of status.local.models || []) {
207
+ const name = clean(row.name || row.model);
208
+ if (!name) continue;
209
+ const probe = options.skipOllamaProbe
210
+ ? { ok: true, capabilities: [] }
211
+ : await probeOllamaModel(name, ollamaConfig, options.fetchImpl || fetch);
212
+ const caps = Array.isArray(probe.capabilities) ? probe.capabilities : [];
213
+ const isEmbed = looksLikeEmbedModel(name) || caps.includes('embedding') || caps.includes('embed');
214
+ if (isEmbed) {
215
+ // Prefer probed dim length when the adapter returns it; else name hint.
216
+ const probedDims = Number(probe.dimensions) || Number(probe.embedding_length) || 0;
217
+ const dims = probedDims > 0 ? probedDims : defaultDimensions('ollama', name);
218
+ push({
219
+ value: encodeEmbeddingChoice('ollama', name, dims),
220
+ label: `Ollama · ${name}`,
221
+ hint: `local optional · ${dims}d`,
222
+ provider: 'ollama',
223
+ source: 'ollama_tags',
224
+ model: name,
225
+ dimensions: dims,
226
+ });
227
+ } else {
228
+ assistModels.push({
229
+ value: `ollama|${name}`,
230
+ label: `Ollama · ${name}`,
231
+ hint: 'local assist (allowlist suggestions)',
232
+ provider: 'ollama',
233
+ model: name,
234
+ source: 'ollama_tags',
235
+ });
236
+ }
237
+ }
238
+ }
239
+
240
+ return {
241
+ options: [...byValue.values()],
242
+ inventory: status,
243
+ assistModels,
244
+ ollama: status.local,
245
+ };
246
+ }
247
+
248
+ /**
249
+ * Ask a local Ollama chat model to suggest include/exclude paths.
250
+ * Optional — never required for ingest.
251
+ *
252
+ * @param {{ root: string, model: string, topLevel: string[], fetchImpl?: typeof fetch, env?: object }} opts
253
+ */
254
+ export async function suggestScopeWithLocalModel(opts) {
255
+ const env = opts.env || process.env;
256
+ const config = resolveOllamaConfig({}, env);
257
+ const endpoint = new URL('/api/generate', config.baseUrl);
258
+ const listing = (opts.topLevel || []).slice(0, 80).join('\n');
259
+ const prompt = [
260
+ 'You help configure a repository knowledge allowlist/denylist for AgentSam codebaseindex.',
261
+ 'Return ONLY compact JSON: {"include":["..."],"exclude":["..."],"rationale":"..."}',
262
+ 'include/exclude must be relative path segments (no globs). Prefer source dirs; exclude deps/build caches.',
263
+ 'Machine inventory already classified top-level paths — prefer refining those categories, do not invent unrelated roots.',
264
+ `Repository root: ${opts.root}`,
265
+ opts.categories ? `Categories JSON: ${JSON.stringify(opts.categories)}` : '',
266
+ 'Top-level entries:',
267
+ listing || '(empty)',
268
+ ].filter(Boolean).join('\n');
269
+
270
+ const response = await (opts.fetchImpl || fetch)(endpoint, {
271
+ method: 'POST',
272
+ headers: { 'content-type': 'application/json' },
273
+ body: JSON.stringify({ model: opts.model, prompt, stream: false, format: 'json' }),
274
+ signal: AbortSignal.timeout(60_000),
275
+ });
276
+ if (!response.ok) {
277
+ throw new Error(`ollama_assist_failed:HTTP ${response.status}`);
278
+ }
279
+ const body = await response.json();
280
+ const raw = clean(body?.response);
281
+ let parsed;
282
+ try {
283
+ parsed = JSON.parse(raw);
284
+ } catch {
285
+ throw new Error('ollama_assist_invalid_json');
286
+ }
287
+ const include = Array.isArray(parsed.include) ? parsed.include.map(clean).filter(Boolean) : [];
288
+ const exclude = Array.isArray(parsed.exclude) ? parsed.exclude.map(clean).filter(Boolean) : [];
289
+ return {
290
+ include,
291
+ exclude,
292
+ rationale: clean(parsed.rationale) || null,
293
+ model: opts.model,
294
+ provider: 'ollama',
295
+ };
296
+ }
297
+
298
+ export { probeOllama, resolveOllamaConfig, looksLikeEmbedModel, defaultDimensions, WORKERS_AI_EMBED_DIMS };