@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
@@ -2,11 +2,15 @@ import {
2
2
  DEFAULT_HTTP_STATUS,
3
3
  ERROR_CODE,
4
4
  ERROR_DOMAIN,
5
+ ERROR_FAILURE_BEHAVIOR,
6
+ ERROR_FAILURE_CLASS,
5
7
  ERROR_REASON_POLICY,
6
8
  ERROR_RESOLUTION_OWNER,
7
9
  ERROR_SCHEMA_VERSION,
8
10
  ERROR_SEVERITY,
11
+ ERROR_SIDE_EFFECT_STATE,
9
12
  ERROR_SOURCE_KIND,
13
+ ERROR_STAGE,
10
14
  GRPC_STATUS,
11
15
  REMEDIATION_ACTION,
12
16
  } from './vocabulary.js';
@@ -20,7 +24,19 @@ const SEVERITY_VALUES = VALUES(ERROR_SEVERITY);
20
24
  const SOURCE_VALUES = VALUES(ERROR_SOURCE_KIND);
21
25
  const OWNER_VALUES = VALUES(ERROR_RESOLUTION_OWNER);
22
26
  const DOMAIN_VALUES = VALUES(ERROR_DOMAIN);
27
+ const FAILURE_CLASS_VALUES = VALUES(ERROR_FAILURE_CLASS);
28
+ const STAGE_VALUES = VALUES(ERROR_STAGE);
29
+ const FAILURE_BEHAVIOR_VALUES = VALUES(ERROR_FAILURE_BEHAVIOR);
30
+ const SIDE_EFFECT_STATE_VALUES = VALUES(ERROR_SIDE_EFFECT_STATE);
23
31
  const ACTION_VALUES = VALUES(REMEDIATION_ACTION);
32
+ const FEATURE_PATTERN = /^[a-z][a-z0-9]*(?:[._-][a-z0-9]+)*$/;
33
+ const STAGE_ALIASES = new Map([
34
+ ['discovery', 'discover'], ['configuration', 'configure'], ['request', 'execute'], ['run', 'execute'],
35
+ ['dispatch', 'execute'], ['adapter', 'execute'], ['spawn', 'start'], ['parse', 'transform'],
36
+ ['render', 'transform'], ['compaction', 'transform'], ['persistence', 'persist'],
37
+ ['persistence_read', 'load'], ['persistence_write', 'persist'], ['search', 'discover'],
38
+ ['inventory', 'discover'], ['approve', 'authorize'],
39
+ ]);
24
40
  const GRPC_CODE_BY_NUMBER = new Map(Object.entries(GRPC_STATUS).map(([name, value]) => [value, ERROR_CODE[name]]));
25
41
  const HTTP_OVERRIDES = new Map([
26
42
  [400, ERROR_CODE.INVALID_ARGUMENT], [401, ERROR_CODE.UNAUTHENTICATED], [403, ERROR_CODE.PERMISSION_DENIED],
@@ -51,6 +67,11 @@ const USER_ACTIONS = new Set([
51
67
  REMEDIATION_ACTION.SELECT_MODEL,
52
68
  REMEDIATION_ACTION.CHANGE_REGION,
53
69
  REMEDIATION_ACTION.RESTART_RUNTIME,
70
+ REMEDIATION_ACTION.RESTART_SERVICE,
71
+ REMEDIATION_ACTION.REPAIR_SCHEMA,
72
+ REMEDIATION_ACTION.RUN_MIGRATION,
73
+ REMEDIATION_ACTION.UPDATE_LOCKFILE,
74
+ REMEDIATION_ACTION.REINSTALL_WORKSPACE,
54
75
  ]);
55
76
 
56
77
  function clean(value) { return value == null ? '' : String(value).trim(); }
@@ -107,6 +128,21 @@ export function canonicalCodeFromGrpcStatus(status) { return GRPC_CODE_BY_NUMBER
107
128
  export function defaultHttpStatusForCode(code) { return DEFAULT_HTTP_STATUS[code] ?? 500; }
108
129
  export function grpcStatusForCode(code) { return GRPC_STATUS[code] ?? GRPC_STATUS.UNKNOWN; }
109
130
 
131
+ function normalizeStage(value, fallback) {
132
+ const requested = clean(value);
133
+ if (!requested) return { stage: fallback, nativeStage: null };
134
+ if (STAGE_VALUES.has(requested)) return { stage: requested, nativeStage: null };
135
+ const generic = STAGE_ALIASES.get(requested);
136
+ return { stage: generic || fallback, nativeStage: requested };
137
+ }
138
+
139
+ function vocabularyValue(value, allowed, label, fallback = null) {
140
+ const normalized = clean(value || fallback);
141
+ if (!normalized && fallback == null) return null;
142
+ if (!allowed.has(normalized)) throw new TypeError(`Unknown AgentSam error ${label}: ${normalized}`);
143
+ return normalized;
144
+ }
145
+
110
146
  export function createErrorEnvelope(input = {}) {
111
147
  const reason = clean(input.reason || 'unknown');
112
148
  if (!REASON_PATTERN.test(reason)) throw new TypeError(`Invalid AgentSam error reason: ${reason}`);
@@ -121,8 +157,19 @@ export function createErrorEnvelope(input = {}) {
121
157
  const retryable = input.retryable == null ? Boolean(policy.retryable) : Boolean(input.retryable);
122
158
  const resolutionOwner = clean(input.resolution_owner || policy.resolution_owner);
123
159
  if (!OWNER_VALUES.has(resolutionOwner)) throw new TypeError(`Unknown AgentSam error resolution owner: ${resolutionOwner}`);
124
- const domain = clean(input.domain || ERROR_DOMAIN.RUNTIME);
125
- if (!DOMAIN_VALUES.has(domain)) throw new TypeError(`Unknown AgentSam error domain: ${domain}`);
160
+ const domain = vocabularyValue(input.domain, DOMAIN_VALUES, 'domain', policy.domain || ERROR_DOMAIN.RUNTIME);
161
+ const failureClass = vocabularyValue(input.failure_class, FAILURE_CLASS_VALUES, 'failure class', policy.failure_class || 'internal');
162
+ const normalizedStage = normalizeStage(input.stage, policy.default_stage || ERROR_STAGE.EXECUTE);
163
+ const nativeStage = optional(input.native_stage, 256) || normalizedStage.nativeStage;
164
+ const feature = optional(input.feature, 256);
165
+ if (feature && !FEATURE_PATTERN.test(feature)) throw new TypeError(`Invalid AgentSam error feature: ${feature}`);
166
+ const failureBehavior = vocabularyValue(input.failure_behavior, FAILURE_BEHAVIOR_VALUES, 'failure behavior');
167
+ const sideEffectState = vocabularyValue(
168
+ input.side_effect_state || input.operation?.side_effect_state,
169
+ SIDE_EFFECT_STATE_VALUES,
170
+ 'side effect state',
171
+ input.operation ? ERROR_SIDE_EFFECT_STATE.UNKNOWN : ERROR_SIDE_EFFECT_STATE.NONE,
172
+ );
126
173
  const remediation = normalizeRemediation(input.remediation, policy);
127
174
  if (severity === ERROR_SEVERITY.TRANSIENT && !retryable) throw new TypeError('transient AgentSam errors must be retryable');
128
175
  if ((remediation.action === REMEDIATION_ACTION.RETRY || remediation.action === REMEDIATION_ACTION.RETRY_LATER) && !retryable) {
@@ -139,14 +186,22 @@ export function createErrorEnvelope(input = {}) {
139
186
  schema_version: ERROR_SCHEMA_VERSION,
140
187
  code,
141
188
  reason,
189
+ domain,
190
+ failure_class: failureClass,
191
+ stage: normalizedStage.stage,
192
+ native_stage: nativeStage,
193
+ feature,
194
+ failure_behavior: failureBehavior,
142
195
  severity,
143
- source,
196
+ retryable,
197
+ side_effect_state: sideEffectState,
144
198
  resolution_owner: resolutionOwner,
145
- domain,
199
+ source,
200
+ adapter: optional(input.adapter, 256),
201
+ protocol: optional(input.protocol, 256),
202
+ transport: optional(input.transport, 256),
146
203
  tool: optional(input.tool, 256),
147
- stage: optional(input.stage, 256),
148
204
  message: redactString(input.message || 'Operation failed', 4_000),
149
- retryable,
150
205
  retry_after_ms: input.retry_after_ms == null ? null : Math.max(0, Math.round(Number(input.retry_after_ms) || 0)),
151
206
  remediation,
152
207
  resource: normalizeResource(input.resource),
@@ -154,7 +209,6 @@ export function createErrorEnvelope(input = {}) {
154
209
  environment,
155
210
  http_status: input.http_status == null ? defaultHttpStatusForCode(code) : Number(input.http_status),
156
211
  grpc_status: input.grpc_status == null ? grpcStatusForCode(code) : Number(input.grpc_status),
157
- transport: optional(input.transport, 256),
158
212
  provider: optional(input.provider, 256),
159
213
  provider_code: optional(input.provider_code, 512),
160
214
  request_id: optional(input.request_id, 512),
@@ -167,9 +221,7 @@ export function createErrorEnvelope(input = {}) {
167
221
  if (!Number.isInteger(envelope.grpc_status) || envelope.grpc_status < 0 || envelope.grpc_status > 16) envelope.grpc_status = null;
168
222
  envelope.fingerprint = optional(input.fingerprint, 128) || fingerprintError(envelope);
169
223
 
170
- // Optional recovery dimensions (v1-compatible extras — orthogonal to reason enum)
171
- const failureClass = input.failure_class || null;
172
- if (failureClass) envelope.failure_class = clean(failureClass);
224
+ // Optional recovery plans remain orthogonal to the canonical v2 failure dimensions.
173
225
  if (input.operation && typeof input.operation === 'object') {
174
226
  envelope.operation = Object.freeze({
175
227
  kind: optional(input.operation.kind, 256),
@@ -178,7 +230,7 @@ export function createErrorEnvelope(input = {}) {
178
230
  resource_id: optional(input.operation.resource_id, 512),
179
231
  read_only: input.operation.read_only === true,
180
232
  idempotent: input.operation.idempotent === true,
181
- side_effect_state: optional(input.operation.side_effect_state, 64) || 'unknown',
233
+ side_effect_state: sideEffectState,
182
234
  });
183
235
  }
184
236
  if (input.retry && typeof input.retry === 'object') {
@@ -11,8 +11,14 @@ export class AgentSamError extends Error {
11
11
  this.diagnostic = normalized;
12
12
  this.code = normalized.code;
13
13
  this.reason = normalized.reason;
14
+ this.domain = normalized.domain;
15
+ this.failure_class = normalized.failure_class;
16
+ this.stage = normalized.stage;
17
+ this.feature = normalized.feature;
18
+ this.failure_behavior = normalized.failure_behavior;
14
19
  this.severity = normalized.severity;
15
20
  this.retryable = normalized.retryable;
21
+ this.side_effect_state = normalized.side_effect_state;
16
22
  this.status = normalized.http_status;
17
23
  this.fingerprint = normalized.fingerprint;
18
24
  }
@@ -10,8 +10,16 @@ function stableFields(value = {}) {
10
10
  value.source?.service,
11
11
  value.resolution_owner,
12
12
  value.domain,
13
- value.tool,
13
+ value.failure_class,
14
14
  value.stage,
15
+ value.native_stage,
16
+ value.feature,
17
+ value.failure_behavior,
18
+ value.side_effect_state,
19
+ value.adapter,
20
+ value.protocol,
21
+ value.transport,
22
+ value.tool,
15
23
  value.provider,
16
24
  value.provider_code,
17
25
  value.native?.code,
@@ -1,8 +1,47 @@
1
1
  import { AgentSamError } from './error.js';
2
2
  import { canonicalCodeFromHttpStatus, createErrorEnvelope, isErrorEnvelope } from './envelope.js';
3
- import { ERROR_REASON } from './vocabulary.js';
3
+ import { ERROR_REASON, ERROR_REASON_ALIASES, ERROR_REASON_POLICY } from './vocabulary.js';
4
4
 
5
5
  function clean(value) { return value == null ? '' : String(value).trim(); }
6
+ function token(value) { return clean(value).split(':', 1)[0]; }
7
+
8
+ /**
9
+ * Resolves canonical reasons and legacy/native aliases without discarding the
10
+ * original evidence. Adapter context disambiguates old generic hook codes.
11
+ */
12
+ export function canonicalizeErrorReason(value, context = {}) {
13
+ const values = value && typeof value === 'object'
14
+ ? [value.reason, value.code, value.message]
15
+ : [value];
16
+ for (const raw of values) {
17
+ const candidate = token(raw);
18
+ if (!candidate) continue;
19
+ if (ERROR_REASON_POLICY[candidate]) return candidate;
20
+ const lowered = candidate.toLowerCase();
21
+ if (ERROR_REASON_POLICY[lowered]) return lowered;
22
+ if (candidate === 'AGENTSAM_HOOK_TIMEOUT' && context.adapter) {
23
+ const specific = `hook_${clean(context.adapter).toLowerCase()}_timeout`;
24
+ if (ERROR_REASON_POLICY[specific]) return specific;
25
+ }
26
+ const alias = ERROR_REASON_ALIASES[candidate] || ERROR_REASON_ALIASES[lowered] || ERROR_REASON_ALIASES[candidate.toUpperCase()];
27
+ if (alias) return alias;
28
+ }
29
+ return null;
30
+ }
31
+
32
+ function reasonFromHttpStatus(status) {
33
+ if (status === 400 || status === 422) return ERROR_REASON.INPUT_INVALID;
34
+ if (status === 401) return ERROR_REASON.AUTH_INVALID;
35
+ if (status === 403) return ERROR_REASON.PERMISSION_DENIED;
36
+ if (status === 404) return ERROR_REASON.TARGET_NOT_FOUND;
37
+ if (status === 408 || status === 504) return ERROR_REASON.TRANSPORT_TIMEOUT;
38
+ if (status === 409) return ERROR_REASON.CONFLICT;
39
+ if (status === 412) return ERROR_REASON.PRECONDITION_FAILED;
40
+ if (status === 429) return ERROR_REASON.RATE_LIMITED;
41
+ if (status === 501) return ERROR_REASON.UNSUPPORTED_OPERATION;
42
+ if ([502, 503, 520, 521, 522, 523, 525, 526, 530].includes(status)) return ERROR_REASON.TRANSPORT_UNREACHABLE;
43
+ return ERROR_REASON.INTERNAL;
44
+ }
6
45
 
7
46
  export function normalizeError(error, context = {}) {
8
47
  if (isErrorEnvelope(error)) return error;
@@ -10,11 +49,17 @@ export function normalizeError(error, context = {}) {
10
49
  if (isErrorEnvelope(error?.envelope)) return error.envelope;
11
50
  if (isErrorEnvelope(error?.error)) return error.error;
12
51
  const status = Number(error?.status || error?.http_status || context.http_status || 0) || null;
13
- const canonical = clean(context.code) || (status ? canonicalCodeFromHttpStatus(status) : undefined);
52
+ const recoveredReason = canonicalizeErrorReason(context.reason, context)
53
+ || canonicalizeErrorReason(error, context);
54
+ const reason = recoveredReason || (status ? reasonFromHttpStatus(status) : ERROR_REASON.INTERNAL);
55
+ // A known reason owns its broad canonical code. HTTP status only selects a
56
+ // broad fallback reason when no machine reason or alias was recovered.
57
+ const canonical = clean(context.code)
58
+ || (ERROR_REASON_POLICY[reason] ? undefined : (status ? canonicalCodeFromHttpStatus(status) : undefined));
14
59
  return createErrorEnvelope({
15
60
  ...context,
16
61
  code: canonical,
17
- reason: context.reason || ERROR_REASON.INTERNAL,
62
+ reason,
18
63
  message: context.message || error?.message || String(error || 'Unknown error'),
19
64
  http_status: status,
20
65
  native: context.native || {
@@ -23,8 +68,8 @@ export function normalizeError(error, context = {}) {
23
68
  stack: error?.stack || null,
24
69
  },
25
70
  source: context.source || { kind: 'agentsam', name: 'agentsam-sdk' },
26
- resolution_owner: context.resolution_owner || 'agentsam',
27
- severity: context.severity || 'blocking_internal',
28
- remediation: context.remediation || { action: 'inspect_platform' },
71
+ resolution_owner: context.resolution_owner,
72
+ severity: context.severity,
73
+ remediation: context.remediation,
29
74
  });
30
75
  }
@@ -1,3 +1,5 @@
1
+ import { ERROR_FAILURE_CLASS, ERROR_SIDE_EFFECT_STATE } from './vocabulary.js';
2
+
1
3
  /**
2
4
  * Recovery policy — separates "what failed" from "what to do".
3
5
  *
@@ -6,39 +8,10 @@
6
8
  * Critical rule: unknown side_effect_state ⇒ reconcile before retry.
7
9
  */
8
10
 
9
- export const FAILURE_CLASS = Object.freeze({
10
- INPUT: 'input',
11
- AUTHENTICATION: 'authentication',
12
- AUTHORIZATION: 'authorization',
13
- POLICY: 'policy',
14
- DISCOVERY: 'discovery',
15
- RESOLUTION: 'resolution',
16
- TRANSPORT: 'transport',
17
- PROTOCOL: 'protocol',
18
- TIMEOUT: 'timeout',
19
- RATE_LIMIT: 'rate_limit',
20
- CAPACITY: 'capacity',
21
- RESOURCE: 'resource',
22
- FILESYSTEM: 'filesystem',
23
- PERSISTENCE: 'persistence',
24
- CONSISTENCY: 'consistency',
25
- CONFLICT: 'conflict',
26
- DEPENDENCY: 'dependency',
27
- PROCESS: 'process',
28
- IPC: 'ipc',
29
- DATA_INTEGRITY: 'data_integrity',
30
- CANCELLED: 'cancelled',
31
- UNKNOWN: 'unknown',
32
- });
33
-
34
- export const SIDE_EFFECT_STATE = Object.freeze({
35
- NONE: 'none',
36
- NOT_STARTED: 'not_started',
37
- CONFIRMED_NOT_APPLIED: 'confirmed_not_applied',
38
- CONFIRMED_APPLIED: 'confirmed_applied',
39
- PARTIALLY_APPLIED: 'partially_applied',
40
- UNKNOWN: 'unknown',
41
- });
11
+ // Compatibility names now project the generated v2 vocabulary instead of
12
+ // maintaining a second recovery-only taxonomy.
13
+ export const FAILURE_CLASS = ERROR_FAILURE_CLASS;
14
+ export const SIDE_EFFECT_STATE = ERROR_SIDE_EFFECT_STATE;
42
15
 
43
16
  export const RECOVERY_SCHEMA = 'agentsam.recovery.v1';
44
17
 
@@ -85,6 +58,7 @@ export function inferFailureClass(error = {}) {
85
58
  * @param {object} [operationContext]
86
59
  */
87
60
  export function inferSideEffectState(error = {}, operationContext = {}) {
61
+ if (error.side_effect_state && Object.values(SIDE_EFFECT_STATE).includes(error.side_effect_state)) return error.side_effect_state;
88
62
  const op = error.operation || operationContext.operation || {};
89
63
  if (op.side_effect_state) return op.side_effect_state;
90
64
  if (op.read_only === true || op.side_effect_state === SIDE_EFFECT_STATE.NONE) {
@@ -148,7 +122,7 @@ export function planRecovery(error = {}, operationContext = {}) {
148
122
  };
149
123
 
150
124
  // Cancellations are not defects
151
- if (failure_class === FAILURE_CLASS.CANCELLED) {
125
+ if (failure_class === FAILURE_CLASS.CANCELLED || failure_class === FAILURE_CLASS.CANCELLATION) {
152
126
  return freezePlan({
153
127
  ...plan,
154
128
  disposition: 'abort',
@@ -195,7 +169,7 @@ export function planRecovery(error = {}, operationContext = {}) {
195
169
  });
196
170
  }
197
171
 
198
- if (failure_class === FAILURE_CLASS.INPUT || failure_class === FAILURE_CLASS.CONFLICT) {
172
+ if ([FAILURE_CLASS.INPUT, FAILURE_CLASS.VALIDATION, FAILURE_CLASS.CONFLICT].includes(failure_class)) {
199
173
  const disposition = failure_class === FAILURE_CLASS.CONFLICT && error.retryable
200
174
  ? 'retry'
201
175
  : 'await_user';
@@ -30,7 +30,12 @@ export function fromHttpError({ status, body, headers, source, provider, domain
30
30
  : code === 'RESOURCE_EXHAUSTED' ? ERROR_REASON.RATE_LIMITED
31
31
  : code === 'UNAVAILABLE' ? ERROR_REASON.TRANSPORT_UNREACHABLE
32
32
  : code === 'DEADLINE_EXCEEDED' ? ERROR_REASON.TRANSPORT_TIMEOUT
33
- : ERROR_REASON.UNKNOWN,
33
+ : code === 'INTERNAL' ? ERROR_REASON.INTERNAL
34
+ : code === 'INVALID_ARGUMENT' ? ERROR_REASON.INPUT_INVALID
35
+ : code === 'NOT_FOUND' ? ERROR_REASON.TARGET_NOT_FOUND
36
+ : code === 'FAILED_PRECONDITION' ? ERROR_REASON.PRECONDITION_FAILED
37
+ : code === 'UNIMPLEMENTED' ? ERROR_REASON.UNSUPPORTED_OPERATION
38
+ : ERROR_REASON.UNKNOWN,
34
39
  message: candidate?.message || candidate?.error || `HTTP ${status || 500} request failed`,
35
40
  retryable: Number(status) === 429 || Number(status) >= 500,
36
41
  retry_after_ms: (() => {