@inneranimalmedia/agentsam-sdk 2.6.9 → 2.6.10

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 (176) hide show
  1. package/README.md +18 -0
  2. package/apps/cad-creator/shared/cad/package.json +1 -1
  3. package/apps/client-cms-editor/backend/package.json +3 -3
  4. package/apps/client-cms-editor/frontend/package.json +4 -4
  5. package/apps/client-cms-editor/package-lock.json +8 -8
  6. package/apps/client-cms-editor/package.json +1 -1
  7. package/apps/client-cms-editor/shared/cms/package.json +2 -2
  8. package/docs/architecture/HOOKS-MODELS-SELF-HOSTING-PLAN.md +199 -0
  9. package/examples/hyperspace-demo/index.html +16 -0
  10. package/examples/hyperspace-demo/package.json +21 -0
  11. package/examples/hyperspace-demo/src/main.tsx +160 -0
  12. package/examples/hyperspace-demo/tsconfig.json +9 -0
  13. package/examples/hyperspace-demo/vite.config.ts +24 -0
  14. package/migrations/runtime/0005_agentsam_hooks.sql +87 -0
  15. package/package.json +23 -7
  16. package/packages/agentsam-brand/package.json +1 -1
  17. package/packages/agentsam-brand/src/core/v2/compile.js +1 -1
  18. package/packages/agentsam-brand/src/core/v2/schema.js +1 -1
  19. package/packages/agentsam-contracts/package.json +1 -1
  20. package/packages/agentsam-contracts/src/errors.ts +19 -10
  21. package/packages/agentsam-errors/package.json +11 -3
  22. package/packages/agentsam-errors/protocol/agentsam.error.v2.schema.json +821 -0
  23. package/packages/agentsam-errors/protocol/error-catalog.json +3512 -0
  24. package/packages/agentsam-errors/src/envelope.js +63 -11
  25. package/packages/agentsam-errors/src/error.js +6 -0
  26. package/packages/agentsam-errors/src/fingerprint.js +9 -1
  27. package/packages/agentsam-errors/src/normalize.js +51 -6
  28. package/packages/agentsam-errors/src/recovery.js +9 -35
  29. package/packages/agentsam-errors/src/transport.js +6 -1
  30. package/packages/agentsam-errors/src/vocabulary.js +515 -126
  31. package/packages/agentsam-errors/test/catalog-v2.test.mjs +106 -0
  32. package/packages/agentsam-errors/types/index.d.ts +157 -0
  33. package/packages/agentsam-goap/package.json +2 -2
  34. package/packages/agentsam-hooks/README.md +206 -0
  35. package/packages/agentsam-hooks/bin/agentsam-hooks.mjs +64 -0
  36. package/packages/agentsam-hooks/bindings/go/command.go +55 -0
  37. package/packages/agentsam-hooks/bindings/go/errors_generated.go +402 -0
  38. package/packages/agentsam-hooks/bindings/go/go.mod +3 -0
  39. package/packages/agentsam-hooks/bindings/go/hooks.go +285 -0
  40. package/packages/agentsam-hooks/bindings/go/hooks_test.go +48 -0
  41. package/packages/agentsam-hooks/bindings/rust/Cargo.toml +11 -0
  42. package/packages/agentsam-hooks/bindings/rust/src/errors_generated.rs +396 -0
  43. package/packages/agentsam-hooks/bindings/rust/src/lib.rs +397 -0
  44. package/packages/agentsam-hooks/package.json +69 -0
  45. package/packages/agentsam-hooks/schema/manifest.json +54 -0
  46. package/packages/agentsam-hooks/scripts/clean-protocol.mjs +17 -0
  47. package/packages/agentsam-hooks/scripts/sync-protocol.mjs +27 -0
  48. package/packages/agentsam-hooks/src/adapters/agents.js +82 -0
  49. package/packages/agentsam-hooks/src/adapters/callback.js +4 -0
  50. package/packages/agentsam-hooks/src/adapters/capability.js +122 -0
  51. package/packages/agentsam-hooks/src/adapters/command.js +104 -0
  52. package/packages/agentsam-hooks/src/adapters/composite.js +31 -0
  53. package/packages/agentsam-hooks/src/adapters/http.js +58 -0
  54. package/packages/agentsam-hooks/src/adapters/lsp.js +116 -0
  55. package/packages/agentsam-hooks/src/adapters/mcp.js +76 -0
  56. package/packages/agentsam-hooks/src/adapters/provider.js +129 -0
  57. package/packages/agentsam-hooks/src/config.js +143 -0
  58. package/packages/agentsam-hooks/src/contracts.js +284 -0
  59. package/packages/agentsam-hooks/src/errors-generated.js +2732 -0
  60. package/packages/agentsam-hooks/src/index.d.ts +193 -0
  61. package/packages/agentsam-hooks/src/index.js +14 -0
  62. package/packages/agentsam-hooks/src/policy.js +34 -0
  63. package/packages/agentsam-hooks/src/runtime.js +312 -0
  64. package/packages/agentsam-hooks/src/store.js +264 -0
  65. package/packages/agentsam-hooks/test/adapters.test.mjs +216 -0
  66. package/packages/agentsam-hooks/test/runtime.test.mjs +258 -0
  67. package/packages/agentsam-knowledge/package.json +1 -1
  68. package/packages/agentsam-nav/dist/Nav.d.ts +43 -0
  69. package/packages/agentsam-nav/dist/NavCollapsible.d.ts +10 -0
  70. package/packages/agentsam-nav/dist/NavContent.d.ts +2 -0
  71. package/packages/agentsam-nav/dist/NavFooter.d.ts +2 -0
  72. package/packages/agentsam-nav/dist/NavGroup.d.ts +3 -0
  73. package/packages/agentsam-nav/dist/NavHeader.d.ts +2 -0
  74. package/packages/agentsam-nav/dist/NavMenu.d.ts +22 -0
  75. package/packages/agentsam-nav/dist/NavProvider.d.ts +35 -0
  76. package/packages/agentsam-nav/dist/NavTrigger.d.ts +2 -0
  77. package/packages/agentsam-nav/dist/Surfaces.d.ts +41 -0
  78. package/packages/agentsam-nav/dist/browser.d.ts +11 -0
  79. package/packages/agentsam-nav/dist/browser.global.js +135 -0
  80. package/packages/agentsam-nav/dist/browser.js +7290 -0
  81. package/packages/agentsam-nav/dist/contracts.d.ts +76 -0
  82. package/packages/agentsam-nav/dist/index.d.ts +11 -0
  83. package/packages/agentsam-nav/dist/index.js +7291 -0
  84. package/packages/agentsam-nav/dist/legacy.css +83 -0
  85. package/packages/agentsam-nav/dist/shell.css +113 -0
  86. package/packages/agentsam-nav/dist/theme.css +113 -0
  87. package/packages/agentsam-nav/dist/utils.d.ts +1 -0
  88. package/packages/agentsam-nav/package.json +1 -1
  89. package/packages/agentsam-queue-control/package.json +1 -1
  90. package/packages/agentsam-repository/package.json +1 -1
  91. package/packages/agentsam-repository/src/goap.js.bak-20260922011251 +670 -0
  92. package/packages/agentsam-vault/package.json +1 -1
  93. package/packages/agentsam-workbench/package.json +3 -3
  94. package/packages/connectors/cloudflare/package.json +1 -1
  95. package/packages/heuristic-theme/package.json +1 -1
  96. package/packages/identity/package.json +2 -2
  97. package/packages/providers/completeful/package.json +1 -1
  98. package/packages/theme-church-site/package.json +2 -2
  99. package/packages/theme-companions-site/package.json +2 -2
  100. package/packages/theme-floors-site/package.json +2 -2
  101. package/packages/theme-fuelnfree-site/package.json +2 -2
  102. package/packages/theme-handyman-site/package.json +2 -2
  103. package/packages/theme-insurance-site/package.json +2 -2
  104. package/packages/theme-scenes/package.json +1 -1
  105. package/packages/theme-shinshu-site/package.json +2 -2
  106. package/packages/work-graph/package.json +1 -1
  107. package/protocol/apps/agentsam.app.v1.schema.json +1 -1
  108. package/protocol/apps/agentsam.host-install.v1.schema.json +1 -1
  109. package/protocol/assets/asset-record.v1.schema.json +1 -1
  110. package/protocol/brand/brandpack.v1.schema.json +1 -1
  111. package/protocol/capabilities/capability-manifest.schema.json +1 -1
  112. package/protocol/capabilities/knowledge-search-input.schema.json +1 -0
  113. package/protocol/credentials/issue.v1.schema.json +1 -1
  114. package/protocol/database/agentsam.schema-pack.v1.schema.json +1 -1
  115. package/protocol/database/connection.v1.schema.json +1 -1
  116. package/protocol/embeddings/embedding-profile.v1.schema.json +1 -1
  117. package/protocol/errors/README.md +36 -0
  118. package/protocol/errors/agentsam.error.v2.schema.json +821 -0
  119. package/protocol/errors/error-catalog.json +3506 -158
  120. package/protocol/errors/error-envelope.schema.json +195 -52
  121. package/protocol/errors/recovery.v1.schema.json +1 -1
  122. package/protocol/features/agentsam.feature.v1.schema.json +1 -1
  123. package/protocol/hooks/README.md +18 -0
  124. package/protocol/hooks/agentsam.hook.output.v1.schema.json +27 -0
  125. package/protocol/hooks/agentsam.hook.receipt.v1.schema.json +61 -0
  126. package/protocol/hooks/agentsam.hook.v1.schema.json +35 -0
  127. package/protocol/hooks/agentsam.hooks.config.v1.schema.json +78 -0
  128. package/protocol/local-engine/benchmark.v1.schema.json +1 -1
  129. package/protocol/local-engine/engine.v1.schema.json +1 -1
  130. package/protocol/models/model-inventory-v2.schema.json +1 -1
  131. package/protocol/models/provider-model-snapshot.v1.schema.json +22 -0
  132. package/protocol/rpc/v1/errors.proto +1 -0
  133. package/protocol/runtime/agentsam.runtime.v1.schema.json +1 -1
  134. package/protocol/runtime/workspace-fs.v1.schema.json +1 -1
  135. package/protocol/sam/activity.v1.schema.json +1 -1
  136. package/protocol/sam/answer.v1.schema.json +1 -1
  137. package/protocol/sam/calibration.v1.schema.json +1 -1
  138. package/protocol/sam/decision-receipt.v1.schema.json +1 -1
  139. package/protocol/sam/evaluation.v1.schema.json +1 -1
  140. package/protocol/sam/operation.schema.json +1 -1
  141. package/protocol/sam/outcome.v1.schema.json +1 -1
  142. package/protocol/sam/question.v1.schema.json +1 -1
  143. package/protocol/sam/result.schema.json +1 -1
  144. package/protocol/sam/state.v1.schema.json +1 -1
  145. package/protocol/scoring/scorecard.v1.schema.json +1 -1
  146. package/protocol/skills/agentsam.interaction.v1.schema.json +1 -1
  147. package/protocol/skills/agentsam.skill.v1.schema.json +1 -1
  148. package/protocol/theme-refinery/product-metadata.schema.json +1 -1
  149. package/protocol/theme-refinery/reconciliation-receipt.schema.json +1 -1
  150. package/protocol/ui/icon.v1.schema.json +1 -1
  151. package/python/README.md +20 -0
  152. package/python/agentsam_sdk/errors/__init__.py +4 -0
  153. package/python/agentsam_sdk/errors/vocabulary.py +2730 -0
  154. package/python/agentsam_sdk/hooks/__init__.py +32 -0
  155. package/python/agentsam_sdk/hooks/adapters.py +132 -0
  156. package/python/agentsam_sdk/hooks/contracts.py +121 -0
  157. package/python/agentsam_sdk/hooks/runtime.py +253 -0
  158. package/python/tests/test_hooks.py +115 -0
  159. package/src/agent/responses-runner.js +145 -1
  160. package/src/cli/command-catalog.js +1 -0
  161. package/src/cli.js +9 -0
  162. package/src/commands/cheat-sheet.js +1 -0
  163. package/src/commands/hooks.js +260 -0
  164. package/src/commands/models.js +1 -1
  165. package/src/commands/shell.js +114 -9
  166. package/src/errors/diagnostic.js +9 -9
  167. package/src/index.js +32 -0
  168. package/src/knowledge/service/grpc-codec.js +2 -0
  169. package/src/lib/slash-commands.js +1 -0
  170. package/src/local/runtime-store.js +46 -0
  171. package/src/models/catalog.js +0 -49
  172. package/src/models/inventory-core.js +69 -0
  173. package/src/plugins/index.js +8 -1
  174. package/src/plugins/registry.js +56 -0
  175. package/src/rpc/generated/errors_pb.js +49 -1
  176. package/src/tools/runtime.js +13 -5
@@ -181,16 +181,16 @@ export function diagnosticFromError(error, fallback = {}) {
181
181
  if (error?.diagnostic) return error.diagnostic;
182
182
  const envelope = error?.envelope || (error?.ok === false && error?.schema_version ? error : null);
183
183
  if (envelope) return legacyDiagnosticFromEnvelope(envelope, fallback);
184
- return Object.freeze({
185
- schema_version: 1,
186
- source: fallback.source || 'agentsam',
187
- kind: fallback.kind || 'runtime_error',
188
- code: clean(error?.code || fallback.code) || 'runtime_error',
189
- message: redactString(error?.message || error || fallback.message || 'Unknown error', 4_000),
190
- http_status: Number(error?.status || fallback.status || 0) || null,
191
- retriable: Boolean(fallback.retriable),
192
- retry_strategy: fallback.retry_strategy || 'inspect_error',
184
+ const canonical = normalizeError(error, {
185
+ reason: fallback.reason,
186
+ domain: fallback.domain || 'runtime',
187
+ stage: fallback.stage,
188
+ feature: fallback.feature,
189
+ failure_behavior: fallback.failure_behavior,
190
+ side_effect_state: fallback.side_effect_state,
191
+ source: { kind: 'runtime', name: fallback.source || 'agentsam-sdk' },
193
192
  });
193
+ return legacyDiagnosticFromEnvelope(canonical, fallback);
194
194
  }
195
195
 
196
196
  export function renderDiagnosticError(error) {
package/src/index.js CHANGED
@@ -25,6 +25,37 @@ export {
25
25
  suggestCliCommands,
26
26
  } from './cli/command-catalog.js';
27
27
  export { routeIntent } from './lib/router.js';
28
+ export {
29
+ HOOK_PROTOCOL_SCHEMA,
30
+ HOOK_CONFIG_SCHEMA,
31
+ HOOK_RECEIPT_SCHEMA,
32
+ HOOK_EVENTS,
33
+ PERMISSION_DECISIONS,
34
+ ERROR_HANDLING_DECISIONS,
35
+ HOOK_FAILURE_MODES,
36
+ AgentSamHooks,
37
+ HookExecutionError,
38
+ HookPermissionError,
39
+ normalizeHookEvent,
40
+ normalizeHookOutput,
41
+ createHookEnvelope,
42
+ createHookRuntime,
43
+ createHookRuntimeFromConfig,
44
+ createHookStore,
45
+ registerStoredHooks,
46
+ ensureHookRuntime,
47
+ findHookConfig,
48
+ loadHookConfig,
49
+ createCallbackHookAdapter,
50
+ createCommandHookAdapter,
51
+ createHttpHookAdapter,
52
+ createHookedProviderAdapter,
53
+ createHookedCapabilityAdapter,
54
+ createCompositeCapabilityAdapter,
55
+ createMcpCapabilityAdapter,
56
+ createLspCapabilityAdapter,
57
+ createAgentCapabilityAdapter,
58
+ } from '../packages/agentsam-hooks/src/index.js';
28
59
  export { searchToolCards, toToolCard, hydrateToolSchemas } from './tools/index.js';
29
60
  export {
30
61
  AGENTSAM_PLUGIN_SCHEMA_VERSION,
@@ -36,6 +67,7 @@ export {
36
67
  listPlugins,
37
68
  listPluginTools,
38
69
  recordPluginHealthCheck,
70
+ recordAiPluginModelDiscovery,
39
71
  recordToolCall,
40
72
  createPluginRuntime,
41
73
  createPluginCapabilityAdapter,
@@ -77,6 +77,7 @@ export function encodeErrorDetail(value) {
77
77
  detail.setDomain(envelope.domain);
78
78
  if (envelope.tool) detail.setTool(envelope.tool);
79
79
  if (envelope.stage) detail.setStage(envelope.stage);
80
+ if (envelope.native_stage) detail.setNativeStage(envelope.native_stage);
80
81
  detail.setRemediationAction(envelope.remediation.action);
81
82
  if (envelope.remediation.message) detail.setRemediationMessage(envelope.remediation.message);
82
83
  detail.setFingerprint(envelope.fingerprint);
@@ -115,6 +116,7 @@ export function decodeErrorDetail(detail) {
115
116
  domain: detail.hasDomain?.() ? detail.getDomain() : 'runtime',
116
117
  tool: detail.hasTool?.() ? detail.getTool() : null,
117
118
  stage: detail.hasStage?.() ? detail.getStage() : null,
119
+ native_stage: detail.hasNativeStage?.() ? detail.getNativeStage() : null,
118
120
  remediation: {
119
121
  action: detail.hasRemediationAction?.() ? detail.getRemediationAction() : undefined,
120
122
  message: detail.hasRemediationMessage?.() ? detail.getRemediationMessage() : null,
@@ -12,6 +12,7 @@ export const SLASH_COMMANDS = [
12
12
  { cmd: '/context', description: 'Show model context economics; add repo for Git bridge context', lane: 'context' },
13
13
  { cmd: '/status', description: 'Honest project awareness: account, models, terminal, live deploy', lane: 'local' },
14
14
  { cmd: '/models', description: 'Probe providers and provider-verified known models', lane: 'model' },
15
+ { cmd: '/hooks', description: 'Inspect lifecycle hook sources, order, and execution receipts', lane: 'agent' },
15
16
  { cmd: '/providers', description: 'Configure and verify machine provider credentials', lane: 'model' },
16
17
  { cmd: '/credentials', description: 'Audit credentials, drift, and remediation (never prints secrets)', lane: 'identity' },
17
18
  { cmd: '/cheat-sheet', description: 'Organized Agent Sam command groups', lane: 'local' },
@@ -4,6 +4,7 @@ import { createLocalSqliteDatabase } from './sqlite.js';
4
4
  import { applyRuntimeMigrations } from './migrations.js';
5
5
  import { findCliProjectRoot } from '../lib/cli-preferences.js';
6
6
  import { getLocalDatabasePath, tryReadProjectConfig } from '../lib/project-config.js';
7
+ import { createHookStore } from '../../packages/agentsam-hooks/src/store.js';
7
8
 
8
9
  function clean(value) { return value == null ? '' : String(value).trim(); }
9
10
  function hash(value) { return createHash('sha256').update(String(value || '')).digest('hex'); }
@@ -187,3 +188,48 @@ export async function pruneExpiredRuntimeState(value = {}) {
187
188
  return { digests: Number(digests.changes || 0), compactions: Number(compactions.changes || 0), approvals_expired: Number(approvals.changes || 0) };
188
189
  });
189
190
  }
191
+
192
+ function hookStore(db, value = {}) {
193
+ return createHookStore(db, { ownerId: clean(value.owner_id || value.account_id) || 'local' });
194
+ }
195
+
196
+ export async function listRuntimeHooks(value = {}) {
197
+ return withStore(value.projectRoot || value.cwd, (db) => hookStore(db, value).listHooks({
198
+ activeOnly: value.activeOnly,
199
+ event_type: value.event_type,
200
+ context: value.context,
201
+ }));
202
+ }
203
+
204
+ export async function upsertRuntimeHook(value = {}) {
205
+ return withStore(value.projectRoot || value.cwd, (db) => hookStore(db, value).upsertHook(value));
206
+ }
207
+
208
+ export async function setRuntimeHookActive(value = {}) {
209
+ return withStore(value.projectRoot || value.cwd, (db) => hookStore(db, value).setHookActive(value.hook_id || value.hook_key, value.active));
210
+ }
211
+
212
+ export async function removeRuntimeHook(value = {}) {
213
+ return withStore(value.projectRoot || value.cwd, (db) => hookStore(db, value).removeHook(value.hook_id || value.hook_key));
214
+ }
215
+
216
+ export async function recordRuntimeHookReceipt(value = {}) {
217
+ if (!value.receipt) return null;
218
+ return withStore(value.projectRoot || value.cwd, (db) => hookStore(db, value).recordExecution(value.receipt, {
219
+ source_kind: value.source_kind,
220
+ hook_id: value.hook_id,
221
+ invocation_id: value.invocation_id,
222
+ agent_run_id: value.agent_run_id,
223
+ session_id: value.session_id,
224
+ conversation_id: value.conversation_id,
225
+ context: value.context,
226
+ }));
227
+ }
228
+
229
+ export async function listRuntimeHookExecutions(value = {}) {
230
+ return withStore(value.projectRoot || value.cwd, (db) => hookStore(db, value).listExecutions({
231
+ hook_key: value.hook_key,
232
+ status: value.status,
233
+ limit: value.limit,
234
+ }));
235
+ }
@@ -7,7 +7,6 @@ const DOCS = Object.freeze({
7
7
  gpt56Sol: 'https://developers.openai.com/api/docs/models/gpt-5.6-sol',
8
8
  gpt56Terra: 'https://developers.openai.com/api/docs/models/gpt-5.6-terra',
9
9
  gpt56Luna: 'https://developers.openai.com/api/docs/models/gpt-5.6-luna',
10
- gpt53Codex: 'https://developers.openai.com/api/docs/models/gpt-5.3-codex',
11
10
  embeddingLarge: 'https://developers.openai.com/api/docs/models/text-embedding-3-large',
12
11
  embeddingSmall: 'https://developers.openai.com/api/docs/models/text-embedding-3-small',
13
12
  });
@@ -226,53 +225,6 @@ const GPT_56_LUNA = openAiAgentModel({
226
225
  pricing: freezePricing({ input: 0.2, cachedInput: 0.02, cacheWrite: 0.25, output: 1.2, source: DOCS.gpt56Luna }),
227
226
  });
228
227
 
229
- const GPT_53_CODEX = openAiAgentModel({
230
- id: 'gpt-5.3-codex',
231
- label: 'GPT-5.3-Codex',
232
- source: DOCS.gpt53Codex,
233
- reasoning: ['low', 'medium', 'high', 'xhigh'],
234
- contextWindow: 400_000,
235
- maxOutputTokens: 128_000,
236
- knowledgeCutoff: '2025-08-31',
237
- description: 'Agentic coding model for Codex-style software workflows.',
238
- pricing: freezePricing({
239
- input: 1.75,
240
- cachedInput: 0.175,
241
- cacheWrite: 0,
242
- output: 14,
243
- source: DOCS.gpt53Codex,
244
- longContext: false,
245
- processing: false,
246
- }),
247
- capabilities: {
248
- web_search: false,
249
- file_search: false,
250
- image_generation: false,
251
- code_interpreter: false,
252
- hosted_shell: false,
253
- apply_patch: false,
254
- skills: false,
255
- computer_use: false,
256
- mcp: false,
257
- tool_search: false,
258
- async_tool_calls: false,
259
- mid_turn_steering: false,
260
- configuration_update: false,
261
- fast: false,
262
- flex: false,
263
- },
264
- serviceTiers: ['default'],
265
- contextPolicy: Object.freeze({
266
- target_input_tokens: 100_000,
267
- compact_at_tokens: 160_000,
268
- intervene_at_tokens: 210_000,
269
- max_normal_input_tokens: 240_000,
270
- pricing_threshold_tokens: null,
271
- max_cumulative_input_tokens: 400_000,
272
- safety_margin_tokens: 20_000,
273
- }),
274
- });
275
-
276
228
  const TEXT_EMBEDDING_3_LARGE = openAiEmbeddingModel({
277
229
  id: 'text-embedding-3-large',
278
230
  label: 'text-embedding-3-large',
@@ -296,7 +248,6 @@ export const MODEL_CATALOG = Object.freeze([
296
248
  GPT_56_LUNA,
297
249
  GPT_56_TERRA,
298
250
  GPT_56_SOL,
299
- GPT_53_CODEX,
300
251
  TEXT_EMBEDDING_3_LARGE,
301
252
  TEXT_EMBEDDING_3_SMALL,
302
253
  ]);
@@ -24,6 +24,75 @@ export const WORKERS_AI_CURATED_MODEL_IDS = Object.freeze([
24
24
  ]);
25
25
 
26
26
  const CURATED = new Set(WORKERS_AI_CURATED_MODEL_IDS);
27
+ export const PROVIDER_MODEL_SNAPSHOT_SCHEMA = 'agentsam.provider-model-snapshot.v1';
28
+
29
+ function modelSnapshotHash(modelIds) {
30
+ const source = modelIds.join('\n');
31
+ let hash = 2166136261;
32
+ for (let index = 0; index < source.length; index += 1) {
33
+ hash ^= source.charCodeAt(index);
34
+ hash = Math.imul(hash, 16777619);
35
+ }
36
+ return `fnv1a32:${(hash >>> 0).toString(16).padStart(8, '0')}`;
37
+ }
38
+
39
+ /**
40
+ * Compact credential-scoped availability evidence for an existing
41
+ * `agentsam_plugins` AI installation. The global catalog remains curated
42
+ * reference data; discovery never creates one model row per user.
43
+ */
44
+ export function createProviderModelSnapshot(provider, models = [], options = {}) {
45
+ const providerId = String(provider || '').trim().toLowerCase();
46
+ if (!providerId) throw new TypeError('provider_required');
47
+ const modelIds = [...new Set(models.map((row) => String(
48
+ typeof row === 'string' ? row : row?.provider_model_id || row?.model_id || '',
49
+ ).trim()).filter(Boolean))].sort();
50
+ const fetchedAtUnix = Number.isFinite(Number(options.fetchedAtUnix))
51
+ ? Math.max(0, Math.floor(Number(options.fetchedAtUnix)))
52
+ : Math.floor(Date.now() / 1000);
53
+ return Object.freeze({
54
+ schema: PROVIDER_MODEL_SNAPSHOT_SCHEMA,
55
+ provider: providerId,
56
+ model_ids: Object.freeze(modelIds),
57
+ model_count: modelIds.length,
58
+ models_hash: modelSnapshotHash(modelIds),
59
+ fetched_at_unix: fetchedAtUnix,
60
+ authority: 'credential_scoped_provider_discovery',
61
+ });
62
+ }
63
+
64
+ /**
65
+ * Produce fields for the existing `agentsam_plugins` row. Failed probes keep
66
+ * the last good snapshot while updating health evidence; no secret or model
67
+ * catalog rows are written.
68
+ */
69
+ export function createAiPluginProbePatch(previousMetadata = {}, discovery = {}, options = {}) {
70
+ const now = Number.isFinite(Number(options.fetchedAtUnix))
71
+ ? Math.max(0, Math.floor(Number(options.fetchedAtUnix)))
72
+ : Math.floor(Date.now() / 1000);
73
+ const metadata = previousMetadata && typeof previousMetadata === 'object' && !Array.isArray(previousMetadata)
74
+ ? { ...previousMetadata }
75
+ : {};
76
+ if (discovery.ok === true) {
77
+ metadata.model_snapshot = createProviderModelSnapshot(
78
+ options.provider || discovery.provider,
79
+ discovery.models || [],
80
+ { fetchedAtUnix: now },
81
+ );
82
+ }
83
+ const error = String(discovery.error || '').trim();
84
+ const authFailure = /\b(?:401|403)\b|unauthoriz|forbidden|invalid[_ -]?(?:api[_ -]?)?key|credential.*reject/i.test(error);
85
+ return Object.freeze({
86
+ metadata,
87
+ health_status: discovery.ok === true ? 'healthy' : authFailure ? 'auth_error' : 'unreachable',
88
+ last_health_at: now,
89
+ ...(discovery.ok === true ? { last_healthy_at: now, consecutive_failures: 0, last_error_code: null, last_error_message: null } : {
90
+ consecutive_failures_delta: 1,
91
+ last_error_code: authFailure ? 'provider_credential_rejected' : 'provider_discovery_failed',
92
+ last_error_message: authFailure ? 'Provider credential rejected' : 'Provider model discovery failed',
93
+ }),
94
+ });
95
+ }
27
96
 
28
97
  const SERVICE_TO_PROVIDER = Object.freeze({
29
98
  openai: 'openai',
@@ -5,7 +5,14 @@ export {
5
5
  INNERANIMALMEDIA_CLOUDFLARE_OAUTH_PLUGIN_MANIFEST,
6
6
  } from './cloudflare.js';
7
7
  export { COMPLETEFUL_PLUGIN_MANIFEST } from './completeful.js';
8
- export { installPlugin, listPlugins, listPluginTools, recordPluginHealthCheck, recordToolCall } from './registry.js';
8
+ export {
9
+ installPlugin,
10
+ listPlugins,
11
+ listPluginTools,
12
+ recordPluginHealthCheck,
13
+ recordAiPluginModelDiscovery,
14
+ recordToolCall,
15
+ } from './registry.js';
9
16
  export { createPluginRuntime, createPluginCapabilityAdapter, executeAgentSamTool } from './runtime.js';
10
17
  export { resolveProjectPluginScope, resolveProjectPluginResources, resolveProjectRuntimeResources, resolveProjectVectorizeScope } from './resource-scope.js';
11
18
  export { resolveVectorizeConfig, executeVectorizeTool } from './vectorize.js';
@@ -1,4 +1,5 @@
1
1
  import { normalizePluginManifest } from './contracts.js';
2
+ import { createAiPluginProbePatch } from '../models/inventory-core.js';
2
3
 
3
4
  function clean(value) { return value == null ? '' : String(value).trim(); }
4
5
  function json(value, fallback) { try { return JSON.parse(String(value ?? '')); } catch { return fallback; } }
@@ -188,6 +189,61 @@ export async function recordPluginHealthCheck(db, value = {}) {
188
189
  return { id: checkId, status: value.status };
189
190
  }
190
191
 
192
+ /**
193
+ * Persist credential-verified AI model availability in the existing plugin
194
+ * installation metadata. A failed probe records health evidence but preserves
195
+ * the last successful model snapshot.
196
+ */
197
+ export async function recordAiPluginModelDiscovery(db, value = {}) {
198
+ if (!db?.prepare) throw new TypeError('D1-compatible database binding required');
199
+ const pluginId = clean(value.pluginId);
200
+ const accountId = clean(value.accountId);
201
+ if (!pluginId) throw new Error('plugin_id_required');
202
+ if (!accountId) throw new Error('plugin_account_id_required');
203
+ const plugin = await db.prepare(`
204
+ SELECT id, plugin_key, provider_key, environment, plugin_kind, metadata_json
205
+ FROM agentsam_plugins WHERE id = ? AND account_id = ? LIMIT 1
206
+ `).bind(pluginId, accountId).first();
207
+ if (!plugin) throw new Error(`plugin_not_found:${pluginId}`);
208
+ if (clean(plugin.plugin_kind) !== 'ai') throw new Error(`plugin_not_ai:${pluginId}`);
209
+
210
+ const probe = createAiPluginProbePatch(json(plugin.metadata_json, {}), value.discovery || {}, {
211
+ provider: value.provider || plugin.provider_key,
212
+ fetchedAtUnix: value.completedAt,
213
+ });
214
+ await runMutation(db, `
215
+ UPDATE agentsam_plugins SET metadata_json = ?, updated_at = unixepoch()
216
+ WHERE id = ? AND account_id = ?
217
+ `, [JSON.stringify(probe.metadata), pluginId, accountId]);
218
+
219
+ const snapshot = probe.metadata.model_snapshot || null;
220
+ const health = await recordPluginHealthCheck(db, {
221
+ pluginId,
222
+ pluginKey: plugin.plugin_key,
223
+ accountId,
224
+ environment: plugin.environment,
225
+ checkKind: 'model_inventory',
226
+ checkSource: value.checkSource || 'provider_discovery',
227
+ status: probe.health_status,
228
+ startedAt: value.startedAt,
229
+ completedAt: probe.last_health_at,
230
+ latencyMs: value.latencyMs,
231
+ httpStatus: value.httpStatus,
232
+ providerRequestId: value.providerRequestId,
233
+ errorCode: probe.last_error_code,
234
+ errorMessage: probe.last_error_message,
235
+ details: snapshot ? {
236
+ schema: snapshot.schema,
237
+ provider: snapshot.provider,
238
+ model_count: snapshot.model_count,
239
+ models_hash: snapshot.models_hash,
240
+ fetched_at_unix: snapshot.fetched_at_unix,
241
+ ...(value.discovery?.ok === true ? {} : { snapshot_preserved: true }),
242
+ } : { provider: clean(value.provider || plugin.provider_key), snapshot_preserved: true },
243
+ });
244
+ return Object.freeze({ ...health, plugin_id: pluginId, health_status: probe.health_status, model_snapshot: snapshot });
245
+ }
246
+
191
247
  export async function recordToolCall(db, value = {}) {
192
248
  const callId = clean(value.id) || id('atcl');
193
249
  await runMutation(db, `
@@ -103,7 +103,8 @@ proto.agentsam.knowledge.v1.ErrorDetail.toObject = function(includeInstance, msg
103
103
  detailsJson: jspb.Message.getFieldWithDefault(msg, 25, ""),
104
104
  occurrenceCount: jspb.Message.getFieldWithDefault(msg, 26, 0),
105
105
  requestId: jspb.Message.getFieldWithDefault(msg, 27, ""),
106
- schemaVersion: jspb.Message.getFieldWithDefault(msg, 28, 0)
106
+ schemaVersion: jspb.Message.getFieldWithDefault(msg, 28, 0),
107
+ nativeStage: jspb.Message.getFieldWithDefault(msg, 29, "")
107
108
  };
108
109
 
109
110
  if (includeInstance) {
@@ -252,6 +253,10 @@ proto.agentsam.knowledge.v1.ErrorDetail.deserializeBinaryFromReader = function(m
252
253
  var value = /** @type {number} */ (reader.readUint32());
253
254
  msg.setSchemaVersion(value);
254
255
  break;
256
+ case 29:
257
+ var value = /** @type {string} */ (reader.readString());
258
+ msg.setNativeStage(value);
259
+ break;
255
260
  default:
256
261
  reader.skipField();
257
262
  break;
@@ -477,6 +482,13 @@ proto.agentsam.knowledge.v1.ErrorDetail.serializeBinaryToWriter = function(messa
477
482
  f
478
483
  );
479
484
  }
485
+ f = /** @type {string} */ (jspb.Message.getField(message, 29));
486
+ if (f != null) {
487
+ writer.writeString(
488
+ 29,
489
+ f
490
+ );
491
+ }
480
492
  };
481
493
 
482
494
 
@@ -1416,6 +1428,42 @@ proto.agentsam.knowledge.v1.ErrorDetail.prototype.hasSchemaVersion = function()
1416
1428
  };
1417
1429
 
1418
1430
 
1431
+ /**
1432
+ * optional string native_stage = 29;
1433
+ * @return {string}
1434
+ */
1435
+ proto.agentsam.knowledge.v1.ErrorDetail.prototype.getNativeStage = function() {
1436
+ return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 29, ""));
1437
+ };
1438
+
1439
+
1440
+ /**
1441
+ * @param {string} value
1442
+ * @return {!proto.agentsam.knowledge.v1.ErrorDetail} returns this
1443
+ */
1444
+ proto.agentsam.knowledge.v1.ErrorDetail.prototype.setNativeStage = function(value) {
1445
+ return jspb.Message.setField(this, 29, value);
1446
+ };
1447
+
1448
+
1449
+ /**
1450
+ * Clears the field making it undefined.
1451
+ * @return {!proto.agentsam.knowledge.v1.ErrorDetail} returns this
1452
+ */
1453
+ proto.agentsam.knowledge.v1.ErrorDetail.prototype.clearNativeStage = function() {
1454
+ return jspb.Message.setField(this, 29, undefined);
1455
+ };
1456
+
1457
+
1458
+ /**
1459
+ * Returns whether this field is set.
1460
+ * @return {boolean}
1461
+ */
1462
+ proto.agentsam.knowledge.v1.ErrorDetail.prototype.hasNativeStage = function() {
1463
+ return jspb.Message.getField(this, 29) != null;
1464
+ };
1465
+
1466
+
1419
1467
  /**
1420
1468
  * @enum {number}
1421
1469
  */
@@ -1,4 +1,4 @@
1
- import { ERROR_REASON_POLICY, normalizeError } from '../errors/index.js';
1
+ import { ERROR_REASON_POLICY, canonicalizeErrorReason, normalizeError } from '../errors/index.js';
2
2
  import { receiptPayload, redactToolValue } from './redact.js';
3
3
 
4
4
  function defaultId(prefix) {
@@ -6,6 +6,11 @@ function defaultId(prefix) {
6
6
  }
7
7
 
8
8
  function reasonForError(error) {
9
+ const nativeReason = canonicalizeErrorReason(error);
10
+ if (/^(hook|mcp|lsp|tool|provider)_/.test(nativeReason || '')) return nativeReason;
11
+ const message = String(error?.message || error || '').toLowerCase();
12
+ if (message.includes('provider adapter not registered') || message.includes('no registered execution target')) return 'tool_handler_unavailable';
13
+ if (/timeout|timed out|deadline/.test(message)) return 'tool_timeout';
9
14
  const status = Number(error?.status || error?.http_status || 0);
10
15
  if (status === 401) return 'provider_credential_invalid';
11
16
  if (status === 403) return 'provider_scope_insufficient';
@@ -16,12 +21,12 @@ function reasonForError(error) {
16
21
  if (status === 400 || status === 422) return 'provider_request_invalid';
17
22
  if (error?.code === 'completeful_idempotency_required') return 'input_invalid';
18
23
  if (error instanceof TypeError) return 'input_invalid';
19
- return 'execution_failed';
24
+ return nativeReason || 'tool_execution_failed';
20
25
  }
21
26
 
22
- function normalizeToolError(error, definition) {
27
+ function normalizeToolError(error, definition, sideEffectState = 'unknown') {
23
28
  const reason = reasonForError(error);
24
- const policy = ERROR_REASON_POLICY[reason] || ERROR_REASON_POLICY.execution_failed;
29
+ const policy = ERROR_REASON_POLICY[reason] || ERROR_REASON_POLICY.tool_execution_failed;
25
30
  return normalizeError(error, {
26
31
  code: policy.code,
27
32
  reason,
@@ -29,6 +34,9 @@ function normalizeToolError(error, definition) {
29
34
  ? { kind: 'provider', name: definition.provider, service: definition.provider }
30
35
  : { kind: 'runtime', name: 'agentsam-tool-runtime' },
31
36
  domain: 'tool',
37
+ stage: 'execute',
38
+ feature: 'tool.execute',
39
+ side_effect_state: sideEffectState,
32
40
  tool: definition.toolKey,
33
41
  provider: definition.provider || null,
34
42
  provider_code: error?.code || null,
@@ -132,7 +140,7 @@ export function createToolExecutor({
132
140
  try {
133
141
  invoke = await resolveExecutionTarget(registry, definition);
134
142
  } catch (error) {
135
- const normalized = normalizeToolError(error, definition);
143
+ const normalized = normalizeToolError(error, definition, 'not_started');
136
144
  const completedAt = now();
137
145
  const receipt = {
138
146
  invocationId: invocation.id,