@inneranimalmedia/agentsam-sdk 2.4.1 → 2.6.0

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 +55 -0
  2. package/README.md +17 -12
  3. package/bin/agentsam +2 -0
  4. package/docs/AGENTSAM_ASTRA_OPENAI_INTEGRATION.md +1363 -0
  5. package/docs/AGENTSAM_WORKBENCH.md +30 -0
  6. package/docs/AUTH_IDENTITY_CONTRACT.md +52 -0
  7. package/docs/CAPABILITIES.md +5 -3
  8. package/docs/CLI_SHELL.md +167 -80
  9. package/docs/CMS_STUDIO.md +101 -0
  10. package/docs/CONTEXT.md +170 -0
  11. package/docs/LOCAL_OLLAMA.md +58 -0
  12. package/docs/MERKLE.md +19 -19
  13. package/docs/PORTABLE_CONTEXT.md +4 -3
  14. package/docs/PROJECT_CONFIG.md +72 -0
  15. package/docs/RELEASES.md +35 -2
  16. package/docs/REPOSITORY_INTELLIGENCE.md +1 -1
  17. package/docs/REPOSITORY_KNOWLEDGE.md +114 -0
  18. package/docs/SDK_WORKER.md +86 -0
  19. package/docs/SECURITY.md +59 -22
  20. package/docs/client-cms-editor.md +15 -0
  21. package/docs/local-studio/WORKMODE_DONOR_NOTES.md +485 -0
  22. package/package.json +35 -10
  23. package/packages/connectors/cloudflare/package.json +10 -0
  24. package/packages/connectors/cloudflare/src/index.js +127 -0
  25. package/packages/connectors/cloudflare/src/owner.js +76 -0
  26. package/packages/connectors/cloudflare/src/routes.js +223 -0
  27. package/packages/connectors/cloudflare/src/vault.js +80 -0
  28. package/packages/connectors/cloudflare/tests/connector.test.mjs +44 -0
  29. package/packages/identity/package.json +10 -1
  30. package/packages/identity/src/contracts/auth-config.js +109 -0
  31. package/packages/identity/src/index.js +1 -0
  32. package/packages/identity/src/oauth/README.md +2 -2
  33. package/packages/identity/src/oauth/credentials.js +11 -4
  34. package/packages/identity/src/oauth/iam-platform.js +3 -3
  35. package/packages/identity/src/providers/iam/index.js +7 -7
  36. package/packages/identity/src/providers/iam/oauth.js +6 -4
  37. package/packages/identity/src/providers/iam/profile.js +5 -5
  38. package/packages/identity/tests/auth-config.test.mjs +61 -0
  39. package/packages/identity/tests/oauth-credentials.test.mjs +13 -2
  40. package/protocol/FILEMETA_V1.md +95 -0
  41. package/protocol/INSPECT_VIEWS_V1.md +40 -0
  42. package/protocol/MERKLE_PERSISTENCE_V1.md +50 -0
  43. package/protocol/MERKLE_V1.md +3 -1
  44. package/protocol/README.md +1 -0
  45. package/protocol/capabilities/cloudflare-cpu-audit-input.schema.json +19 -0
  46. package/protocol/capabilities/cloudflare-cpu-profile-input.schema.json +13 -0
  47. package/protocol/capabilities/cloudflare-wrangler-native-input.schema.json +19 -0
  48. package/protocol/capabilities/manifest.json +79 -3
  49. package/protocol/capabilities/repository-snapshot.schema.json +1 -0
  50. package/protocol/context/context-budget.schema.json +36 -0
  51. package/protocol/context/context-item.schema.json +19 -0
  52. package/protocol/context/resolved-context-pack.schema.json +47 -0
  53. package/protocol/context/result-policy.schema.json +17 -0
  54. package/protocol/knowledge/context-pack.schema.json +33 -0
  55. package/protocol/knowledge/retrieval-query.schema.json +68 -13
  56. package/protocol/models/README.md +373 -0
  57. package/protocol/models/model-inventory-v2.schema.json +212 -0
  58. package/python/README.md +15 -7
  59. package/python/agentsam_sdk/cli.py +0 -21
  60. package/python/agentsam_sdk/tui/README.md +17 -12
  61. package/python/agentsam_sdk/tui/bootstrap.py +2 -2
  62. package/python/agentsam_sdk/tui/demo.py +25 -10
  63. package/python/agentsam_sdk/tui/onboarding.py +208 -0
  64. package/python/tests/test_tui_cli.py +7 -6
  65. package/skills/README.md +21 -0
  66. package/skills/agentsam-app-fundamentals/SKILL.md +165 -0
  67. package/skills/agentsam-app-fundamentals/references/graphs-contracts-ast-merkle.md +89 -0
  68. package/skills/agentsam-app-fundamentals/references/trust-credentials-and-destinations.md +99 -0
  69. package/skills/agentsam-cloudflare-workers/SKILL.md +53 -0
  70. package/skills/agentsam-cloudflare-workers/references/cpu-profiling.md +16 -0
  71. package/skills/agentsam-cloudflare-workers/references/errors-and-observability.md +29 -0
  72. package/skills/agentsam-cloudflare-workers/references/wrangler-native-map.md +28 -0
  73. package/skills/agentsam-jr-dev/SKILL.md +232 -0
  74. package/skills/agentsam-jr-dev/references/real-application-logic.md +156 -0
  75. package/skills/agentsam-jr-dev/references/web-application-fundamentals.md +240 -0
  76. package/skills/agentsam-progression-guard/SKILL.md +197 -0
  77. package/skills/agentsam-progression-guard/references/checkpoint-chain.md +111 -0
  78. package/skills/agentsam-progression-guard/references/hooks-operational-io.md +96 -0
  79. package/skills/catalog.json +71 -0
  80. package/src/agent/capability-adapter.js +25 -13
  81. package/src/agent/index.js +1 -0
  82. package/src/agent/responses-runner.js +325 -0
  83. package/src/capabilities/index.js +7 -0
  84. package/src/capabilities/repository-snapshot-view.js +238 -0
  85. package/src/capabilities/repository-snapshot.js +28 -14
  86. package/src/cli.js +198 -76
  87. package/src/cloudflare/cpu-profile.js +115 -0
  88. package/src/cloudflare/index.js +14 -0
  89. package/src/cloudflare/wrangler.js +132 -0
  90. package/src/commands/account-auth.js +47 -0
  91. package/src/commands/cloudflare.js +58 -0
  92. package/src/commands/connections.js +93 -0
  93. package/src/commands/context-economics.js +114 -0
  94. package/src/commands/context.js +14 -2
  95. package/src/commands/db.js +4 -7
  96. package/src/commands/deploy.js +54 -32
  97. package/src/commands/eval.js +63 -0
  98. package/src/commands/interactive.js +18 -0
  99. package/src/commands/knowledge.js +27 -4
  100. package/src/commands/merkle-persist.js +118 -0
  101. package/src/commands/merkle.js +32 -17
  102. package/src/commands/models.js +152 -0
  103. package/src/commands/ollama.js +259 -0
  104. package/src/commands/preferences.js +144 -0
  105. package/src/commands/product.js +86 -16
  106. package/src/commands/resume.js +67 -0
  107. package/src/commands/security.js +8 -6
  108. package/src/commands/shell.js +405 -100
  109. package/src/commands/skills.js +66 -0
  110. package/src/commands/start-local.js +1 -1
  111. package/src/commands/tunnel.js +5 -4
  112. package/src/commands/whoami.js +86 -0
  113. package/src/context/budget.js +120 -0
  114. package/src/context/compact.js +28 -0
  115. package/src/context/index.js +7 -0
  116. package/src/context/rehydrate.js +35 -0
  117. package/src/context/resolve.js +116 -0
  118. package/src/context/result-policy.js +66 -0
  119. package/src/errors/diagnostic.js +160 -0
  120. package/src/errors/index.js +9 -0
  121. package/src/eval/context.js +191 -0
  122. package/src/eval/index.js +1 -0
  123. package/src/index.js +70 -0
  124. package/src/indexing/execution-boundary.js +144 -0
  125. package/src/indexing/index.js +8 -0
  126. package/src/indexing/provider.js +41 -0
  127. package/src/knowledge/config.js +2 -2
  128. package/src/knowledge/context-pack.js +12 -1
  129. package/src/knowledge/contracts.js +9 -4
  130. package/src/knowledge/engine.js +7 -3
  131. package/src/knowledge/service/server.js +1 -1
  132. package/src/lib/account-session.js +98 -0
  133. package/src/lib/agent-instructions.js +73 -0
  134. package/src/lib/auth.js +4 -0
  135. package/src/lib/bridge-client.js +7 -5
  136. package/src/lib/cli-preferences.js +78 -0
  137. package/src/lib/core-client.js +8 -8
  138. package/src/lib/deploy/git-guard.js +69 -0
  139. package/src/lib/deploy/health.js +57 -0
  140. package/src/lib/deploy/local-studio.js +283 -0
  141. package/src/lib/deploy/secret-scan.js +65 -0
  142. package/src/lib/deploy-receipt/index.js +5 -2
  143. package/src/lib/detect-context.js +6 -5
  144. package/src/lib/execution-approvals.js +59 -0
  145. package/src/lib/identity-scaffold.js +1 -1
  146. package/src/lib/local-scaffold.js +35 -33
  147. package/src/lib/local-sessions.js +127 -0
  148. package/src/lib/local-status.js +9 -17
  149. package/src/lib/merkle/cloudflare-persistence.js +321 -0
  150. package/src/lib/merkle/filemeta.js +43 -0
  151. package/src/lib/merkle/git-ignore.js +24 -0
  152. package/src/lib/merkle/hash.js +1 -0
  153. package/src/lib/merkle/index.js +22 -0
  154. package/src/lib/merkle/persistence.js +72 -0
  155. package/src/lib/merkle/semantic.js +359 -0
  156. package/src/lib/merkle/snapshot.js +9 -3
  157. package/src/lib/merkle/tree.js +11 -6
  158. package/src/lib/project-config.js +227 -0
  159. package/src/lib/project-rules.js +68 -0
  160. package/src/lib/provider-credentials.js +83 -0
  161. package/src/lib/save-sdk-token.js +1 -1
  162. package/src/lib/scaffold/templates/worker-api/index.js +101 -20
  163. package/src/lib/scaffold/wizards/worker-api.js +27 -11
  164. package/src/lib/slash-commands.js +22 -15
  165. package/src/lib/tools.js +11 -5
  166. package/src/models/catalog.js +135 -0
  167. package/src/models/index.js +7 -0
  168. package/src/providers/index.js +5 -0
  169. package/src/providers/openai-responses.js +275 -0
  170. package/src/security/index.js +1 -0
  171. package/src/security/inventory.js +4 -1
  172. package/src/security/process.js +35 -9
  173. package/src/security/render.js +27 -5
  174. package/src/security/scan.js +24 -9
  175. package/src/security/trust-boundary.js +24 -0
  176. package/src/skills/index.js +64 -0
  177. package/src/telemetry/contracts.js +203 -0
  178. package/src/telemetry/events.js +48 -0
  179. package/src/telemetry/index.js +8 -0
  180. package/src/tools/hydrate.js +35 -0
  181. package/src/tools/index.js +2 -0
  182. package/src/tools/search.js +70 -0
  183. package/src/ui/ansi.js +1 -1
  184. package/src/ui/boot.js +54 -0
  185. package/src/ui/merkle/render.js +1 -0
  186. package/src/ui/runtime-activity.js +192 -0
  187. package/src/ui/theme.js +19 -18
  188. package/test/account-session.test.mjs +36 -0
  189. package/test/app-building-skills.test.mjs +61 -0
  190. package/test/apps-scaffold-contract.test.mjs +56 -0
  191. package/test/capabilities.test.mjs +53 -4
  192. package/test/cli-preferences.test.mjs +46 -0
  193. package/test/cloudflare-connector.test.mjs +96 -0
  194. package/test/cloudflare-runtime.test.mjs +75 -0
  195. package/test/context.test.mjs +144 -0
  196. package/test/deploy-health-scan.test.mjs +67 -0
  197. package/test/error-diagnostics.test.mjs +59 -0
  198. package/test/eval-context.test.mjs +37 -0
  199. package/test/execution-approvals.test.mjs +27 -0
  200. package/test/indexing-provider.test.mjs +29 -0
  201. package/test/jr-dev-skill.test.mjs +26 -0
  202. package/test/knowledge-context-pack.test.mjs +19 -0
  203. package/test/knowledge.test.mjs +1 -1
  204. package/test/local-sessions.test.mjs +42 -0
  205. package/test/local-studio-deploy.test.mjs +83 -0
  206. package/test/merkle-persistence.test.mjs +91 -0
  207. package/test/merkle.test.mjs +77 -3
  208. package/test/model-catalog.test.mjs +43 -0
  209. package/test/models.test.mjs +51 -0
  210. package/test/npm10-lock.test.mjs +29 -0
  211. package/test/ollama.test.mjs +94 -0
  212. package/test/openai-responses.test.mjs +95 -0
  213. package/test/project-config.test.mjs +81 -0
  214. package/test/project-rules.test.mjs +44 -0
  215. package/test/provider-credentials.test.mjs +52 -0
  216. package/test/rehydrate.test.mjs +25 -0
  217. package/test/release-hygiene.test.mjs +34 -0
  218. package/test/repository-snapshot-view.test.mjs +112 -0
  219. package/test/responses-runner.test.mjs +148 -0
  220. package/test/runtime-activity.test.mjs +98 -0
  221. package/test/sdk-worker-contract.test.mjs +68 -0
  222. package/test/security.test.mjs +46 -0
  223. package/test/shell.test.mjs +55 -21
  224. package/test/skills.test.mjs +22 -0
  225. package/test/smoke.mjs +5 -2
  226. package/test/telemetry.test.mjs +79 -0
  227. package/test/theme-portability.test.mjs +14 -0
  228. package/test/tools-search.test.mjs +40 -0
  229. package/test/whoami-resume.test.mjs +56 -0
  230. package/examples/agentsam-tui-ansi.mjs +0 -149
  231. package/src/commands/tui.js +0 -120
  232. package/src/ui/splash-xterm.js +0 -290
  233. package/src/ui/splash.js +0 -426
@@ -0,0 +1,71 @@
1
+ {
2
+ "schema_version": 1,
3
+ "skills": [
4
+ {
5
+ "id": "agentsam-jr-dev",
6
+ "aliases": [
7
+ "agentsam_jr_dev",
8
+ "jr-dev"
9
+ ],
10
+ "title": "AgentSam Jr Dev",
11
+ "description": "Teach, inspect, build, and revise real software using beginner-friendly language grounded in repository and runtime evidence.",
12
+ "entry": "agentsam-jr-dev/SKILL.md",
13
+ "references": [
14
+ "agentsam-jr-dev/references/web-application-fundamentals.md",
15
+ "agentsam-jr-dev/references/real-application-logic.md"
16
+ ],
17
+ "user_invocable": true
18
+ },
19
+ {
20
+ "id": "agentsam-app-fundamentals",
21
+ "aliases": [
22
+ "app-fundamentals",
23
+ "application-fundamentals",
24
+ "quick-bytes"
25
+ ],
26
+ "title": "AgentSam Application Fundamentals",
27
+ "description": "Build and review applications using explicit execution ownership, contracts, credentialed destinations, dependency graphs, AST evidence, and Merkle evidence.",
28
+ "entry": "agentsam-app-fundamentals/SKILL.md",
29
+ "references": [
30
+ "agentsam-app-fundamentals/references/trust-credentials-and-destinations.md",
31
+ "agentsam-app-fundamentals/references/graphs-contracts-ast-merkle.md"
32
+ ],
33
+ "user_invocable": true
34
+ },
35
+ {
36
+ "id": "agentsam-progression-guard",
37
+ "aliases": [
38
+ "progression-guard",
39
+ "no-regress",
40
+ "ship-guard",
41
+ "release-guard"
42
+ ],
43
+ "title": "AgentSam Progression Guard",
44
+ "description": "Prevent silent regression with explicit local, CI, predeploy, deploy, postdeploy, promotion, and runtime evidence gates.",
45
+ "entry": "agentsam-progression-guard/SKILL.md",
46
+ "references": [
47
+ "agentsam-progression-guard/references/checkpoint-chain.md",
48
+ "agentsam-progression-guard/references/hooks-operational-io.md"
49
+ ],
50
+ "user_invocable": true
51
+ },
52
+ {
53
+ "id": "agentsam-cloudflare-workers",
54
+ "aliases": [
55
+ "cloudflare",
56
+ "workers",
57
+ "wrangler",
58
+ "cf-native"
59
+ ],
60
+ "title": "AgentSam Cloudflare Workers",
61
+ "description": "Operate and debug Cloudflare Workers with typed Wrangler operations, runtime-aware observability, structured errors, and CPU profiling discipline.",
62
+ "entry": "agentsam-cloudflare-workers/SKILL.md",
63
+ "references": [
64
+ "agentsam-cloudflare-workers/references/wrangler-native-map.md",
65
+ "agentsam-cloudflare-workers/references/errors-and-observability.md",
66
+ "agentsam-cloudflare-workers/references/cpu-profiling.md"
67
+ ],
68
+ "user_invocable": true
69
+ }
70
+ ]
71
+ }
@@ -1,14 +1,32 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
1
4
  import { getCapability, listCapabilities } from '../capabilities/manifest.js';
2
5
  import { repositorySnapshot } from '../capabilities/repository-snapshot.js';
6
+ import { runWranglerNative, summarizeCloudflareCpuProfileFile, runCloudflareCpuAudit } from '../cloudflare/index.js';
3
7
  import { runRepositoryAudit } from './repository-audit.js';
4
8
 
9
+ const PACKAGE_ROOT = path.resolve(fileURLToPath(new URL('../../', import.meta.url)));
10
+
11
+ function loadSchema(value) {
12
+ if (!value) return { type: 'object', properties: {} };
13
+ if (typeof value === 'object' && !Array.isArray(value)) return structuredClone(value);
14
+ const filename = path.resolve(PACKAGE_ROOT, String(value));
15
+ if (filename !== PACKAGE_ROOT && !filename.startsWith(`${PACKAGE_ROOT}${path.sep}`)) throw new Error(`capability_schema_outside_package:${value}`);
16
+ try { return JSON.parse(fs.readFileSync(filename, 'utf8')); }
17
+ catch (error) { throw new Error(`capability_schema_unreadable:${value}:${error?.message || error}`); }
18
+ }
19
+
5
20
  export function createCapabilityAdapter({ handlers = {}, reasoner } = {}) {
6
21
  const executable = new Map([
7
22
  ['repository.snapshot', (input) => repositorySnapshot(input)],
23
+ ['cloudflare.wrangler.native', (input = {}) => runWranglerNative(input.command, input)],
24
+ ['cloudflare.cpu.profile', (input = {}) => summarizeCloudflareCpuProfileFile(input)],
8
25
  ...Object.entries(handlers),
9
26
  ]);
10
27
  if (typeof reasoner === 'function') {
11
28
  executable.set('repository.audit', (input = {}) => runRepositoryAudit({ ...input, reasoner }));
29
+ executable.set('cloudflare.cpu.audit', (input = {}) => runCloudflareCpuAudit({ ...input, reasoner }));
12
30
  }
13
31
 
14
32
  function describe(id) {
@@ -18,33 +36,27 @@ export function createCapabilityAdapter({ handlers = {}, reasoner } = {}) {
18
36
  }
19
37
 
20
38
  return Object.freeze({
21
- list(options = {}) {
22
- return listCapabilities(options);
23
- },
39
+ list(options = {}) { return listCapabilities(options); },
24
40
  describe,
25
41
  toolDescriptors({ domain, kind, includeUnavailable = false } = {}) {
26
- return listCapabilities({ domain, kind }).filter((row) => includeUnavailable || executable.has(row.id)).map((row) => ({
42
+ return listCapabilities({ domain, kind, status: null }).filter((row) => includeUnavailable || executable.has(row.id)).map((row) => ({
27
43
  name: row.id,
28
44
  description: row.description,
29
- input_schema: row.input_schema || null,
45
+ category: row.domain,
46
+ risk: row.side_effects === 'none' || row.side_effects === 'network-read' ? 'read' : 'write',
47
+ input_schema: loadSchema(row.input_schema),
30
48
  side_effects: row.side_effects,
31
49
  deterministic: row.deterministic,
32
50
  model_required: row.model_required,
33
51
  }));
34
52
  },
35
- canInvoke(id) {
36
- return executable.has(String(id || '').trim());
37
- },
53
+ canInvoke(id) { return executable.has(String(id || '').trim()); },
38
54
  async invoke(id, input = {}) {
39
55
  const capability = describe(id);
40
56
  const handler = executable.get(capability.id);
41
57
  if (!handler) throw new Error(`capability_handler_unavailable:${capability.id}`);
42
58
  const value = await handler(input);
43
- return {
44
- capability_id: capability.id,
45
- capability_version: capability.version,
46
- result: value,
47
- };
59
+ return { capability_id: capability.id, capability_version: capability.version, result: value };
48
60
  },
49
61
  });
50
62
  }
@@ -1,2 +1,3 @@
1
1
  export { createCapabilityAdapter } from './capability-adapter.js';
2
2
  export { buildRepositoryAuditPacket, renderRepositoryAuditMarkdown, runRepositoryAudit } from './repository-audit.js';
3
+ export { buildAgentToolSurface, capabilityFunctionName, runResponsesAgent } from './responses-runner.js';
@@ -0,0 +1,325 @@
1
+ import { createHash } from 'node:crypto';
2
+ import path from 'node:path';
3
+ import { assessContextUsage, compileAgentInstructions, createContextBudget, estimateContextTokens, truncateResultText } from '../context/index.js';
4
+ import { getModelRecord, calculateModelCost } from '../models/index.js';
5
+ import { searchToolCards, hydrateToolSchemas } from '../tools/index.js';
6
+ import { createAgentEvent } from '../telemetry/index.js';
7
+ import { diagnosticFromError } from '../errors/index.js';
8
+
9
+ const RUNTIME_OWNED_KEYS = new Set(['account_id', 'user_id', 'tenant_id', 'workspace_id', 'connection_id', 'runtime_lease_id', 'execution_id']);
10
+
11
+ function clean(value) { return value == null ? '' : String(value).trim(); }
12
+ function hash(value) { return `sha256:${createHash('sha256').update(String(value)).digest('hex')}`; }
13
+ function event(emit, type, payload, runId) { if (typeof emit === 'function') emit(createAgentEvent(type, payload, { runId })); }
14
+
15
+ export function capabilityFunctionName(id) {
16
+ const source = clean(id).replace(/[^A-Za-z0-9_-]+/g, '_').replace(/^_+|_+$/g, '') || 'capability';
17
+ if (source.length <= 58) return `as_${source}`;
18
+ return `as_${source.slice(0, 45)}_${createHash('sha256').update(source).digest('hex').slice(0, 10)}`;
19
+ }
20
+
21
+ function userMessage(text) {
22
+ return { role: 'user', content: [{ type: 'input_text', text: String(text) }] };
23
+ }
24
+
25
+ function modelBudget(record) {
26
+ const policy = record.context_policy || {};
27
+ return createContextBudget({
28
+ windowTokens: record.context_window,
29
+ targetInputTokens: policy.target_input_tokens,
30
+ compactAtTokens: policy.compact_at_tokens,
31
+ interveneAtTokens: policy.intervene_at_tokens,
32
+ maxNormalInputTokens: policy.max_normal_input_tokens,
33
+ pricingThresholdTokens: policy.pricing_threshold_tokens,
34
+ safetyMarginTokens: policy.safety_margin_tokens,
35
+ });
36
+ }
37
+
38
+ export function buildAgentToolSurface(capabilityAdapter, objective, options = {}) {
39
+ if (!capabilityAdapter?.toolDescriptors) throw new TypeError('capabilityAdapter.toolDescriptors is required');
40
+ const catalog = capabilityAdapter.toolDescriptors({ includeUnavailable: false });
41
+ const searched = searchToolCards(catalog, objective, { maxItems: options.maxTools ?? 8, maxChars: options.maxCardChars ?? 24_000 });
42
+ const selected = searched.cards.map((card) => card.tool);
43
+ const hydrated = hydrateToolSchemas(catalog, selected, { maxTools: options.maxTools ?? 8, maxChars: options.maxSchemaChars ?? 40_000 });
44
+ const aliases = new Map();
45
+ const tools = hydrated.tools.map((descriptor) => {
46
+ const alias = capabilityFunctionName(descriptor.name);
47
+ aliases.set(alias, descriptor.name);
48
+ return Object.freeze({
49
+ type: 'function',
50
+ name: alias,
51
+ description: descriptor.description,
52
+ parameters: descriptor.input_schema || { type: 'object', properties: {} },
53
+ strict: true,
54
+ });
55
+ });
56
+ return Object.freeze({
57
+ tools: Object.freeze(tools),
58
+ aliases,
59
+ descriptors: Object.freeze(hydrated.tools),
60
+ receipt: Object.freeze({
61
+ catalog_tools: catalog.length,
62
+ cards_returned: searched.receipt.returned_items,
63
+ card_chars: searched.receipt.chars,
64
+ hydrated_tools: hydrated.receipt.hydrated_tools,
65
+ hydrated_schema_chars: hydrated.receipt.schema_chars,
66
+ deferred_tools: Object.freeze(hydrated.receipt.deferred_tools),
67
+ }),
68
+ });
69
+ }
70
+
71
+ function sanitizeToolInput(value, descriptor, cwd) {
72
+ const parsed = value && typeof value === 'object' && !Array.isArray(value) ? { ...value } : {};
73
+ for (const key of RUNTIME_OWNED_KEYS) delete parsed[key];
74
+ const properties = descriptor?.input_schema?.properties || {};
75
+ if (Object.hasOwn(properties, 'cwd')) parsed.cwd = cwd;
76
+ return parsed;
77
+ }
78
+
79
+ function parseArguments(value) {
80
+ if (!clean(value)) return {};
81
+ try {
82
+ const parsed = JSON.parse(value);
83
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error('arguments must be an object');
84
+ return parsed;
85
+ } catch (error) { throw new Error(`invalid_tool_arguments:${error?.message || error}`); }
86
+ }
87
+
88
+ function boundedToolOutput(value, callId, maxChars) {
89
+ const serialized = typeof value === 'string' ? value : JSON.stringify(value);
90
+ const ref = `tool:${callId}`;
91
+ const digest = hash(serialized);
92
+ if (serialized.length <= maxChars) return Object.freeze({ ref, hash: digest, source_chars: serialized.length, chars: serialized.length, truncated: false, output: serialized });
93
+ const bounded = truncateResultText(serialized, maxChars);
94
+ return Object.freeze({
95
+ ref,
96
+ hash: digest,
97
+ source_chars: serialized.length,
98
+ chars: bounded.chars,
99
+ truncated: true,
100
+ output: JSON.stringify({ ref, hash: digest, truncated: true, source_chars: serialized.length, excerpt: bounded.text }),
101
+ });
102
+ }
103
+
104
+ function toolResultCharBudget(activeTokens, budget) {
105
+ if (!Number.isFinite(activeTokens) || activeTokens < 0) return budget.maxToolResultChars;
106
+ const reserveTokens = 4_000;
107
+ const headroomTokens = Math.max(256, budget.maxNormalInputTokens - Math.ceil(activeTokens) - reserveTokens);
108
+ return Math.max(1_024, Math.min(budget.maxToolResultChars, Math.floor(headroomTokens * budget.charsPerToken)));
109
+ }
110
+
111
+ function projectedInputTokens({ instructions, input, toolSurface, priorActiveTokens, budget }) {
112
+ const inputChars = typeof input === 'string' ? input.length : JSON.stringify(input ?? '').length;
113
+ const newTokens = estimateContextTokens(String(instructions || '').length + inputChars + toolSurface.receipt.hydrated_schema_chars, budget.charsPerToken);
114
+ return Math.max(newTokens, Number.isFinite(priorActiveTokens) ? Math.ceil(priorActiveTokens) + newTokens : newTokens);
115
+ }
116
+
117
+ function assertEconomicPreflight(projectedTokens, budget, allowOverride) {
118
+ if (allowOverride) return;
119
+ if (budget.pricingThresholdTokens != null && projectedTokens > budget.pricingThresholdTokens) {
120
+ throw new Error(`context_preflight_pricing_threshold:${projectedTokens}>${budget.pricingThresholdTokens}`);
121
+ }
122
+ if (projectedTokens >= budget.maxNormalInputTokens) throw new Error(`context_preflight_max_normal:${projectedTokens}>=${budget.maxNormalInputTokens}`);
123
+ if (projectedTokens >= budget.compactAtTokens) throw new Error(`context_preflight_compaction_required:${projectedTokens}>=${budget.compactAtTokens}`);
124
+ }
125
+
126
+ export async function runResponsesAgent(options = {}) {
127
+ const provider = options.provider;
128
+ if (!provider?.create || !provider?.continueWithToolOutputs) throw new TypeError('Responses provider adapter is required');
129
+ if (!options.capabilityAdapter) throw new TypeError('capabilityAdapter is required');
130
+ const cwd = path.resolve(options.cwd || process.cwd());
131
+ const objective = clean(options.prompt);
132
+ if (!objective) throw new TypeError('prompt is required');
133
+ const record = getModelRecord(options.model);
134
+ if (!record) throw new RangeError(`unknown model: ${options.model}`);
135
+ const reasoningEffort = clean(options.reasoningEffort || 'low');
136
+ const serviceTier = clean(options.serviceTier || 'default');
137
+ const budget = modelBudget(record);
138
+ const instructionSet = options.instructions == null ? compileAgentInstructions(cwd, { maxChars: budget.maxSystemChars }) : null;
139
+ const instructions = options.instructions == null ? instructionSet.content : String(options.instructions);
140
+ const toolSurface = buildAgentToolSurface(options.capabilityAdapter, objective, options);
141
+ const emit = options.emit;
142
+ const runId = options.runId;
143
+ event(emit, 'tool.search', toolSurface.receipt, runId);
144
+
145
+ let previousResponseId = clean(options.previousResponseId) || null;
146
+ let priorActiveTokens = options.previousUsageSnapshot?.current_context?.input_tokens;
147
+ let input = objective;
148
+ let compacted = null;
149
+ let projected = projectedInputTokens({ instructions, input, toolSurface, priorActiveTokens, budget });
150
+
151
+ if (projected >= budget.compactAtTokens && previousResponseId && options.autoCompact !== false && typeof provider.compact === 'function') {
152
+ compacted = await provider.compact({
153
+ model: record.provider_model_id,
154
+ previousResponseId,
155
+ instructions,
156
+ promptCacheKey: options.promptCacheKey,
157
+ emit,
158
+ runId,
159
+ });
160
+ input = [...(compacted.output || []), userMessage(objective)];
161
+ previousResponseId = null;
162
+ priorActiveTokens = null;
163
+ projected = projectedInputTokens({ instructions, input, toolSurface, priorActiveTokens, budget });
164
+ }
165
+
166
+ assertEconomicPreflight(projected, budget, options.allowEconomicOverride === true);
167
+ const pressure = assessContextUsage(projected, budget);
168
+ const maxOutputTokens = Number.isInteger(options.maxOutputTokens) && options.maxOutputTokens > 0
169
+ ? Math.min(options.maxOutputTokens, record.max_output_tokens)
170
+ : Math.min(32_768, record.max_output_tokens);
171
+ const projectedCost = calculateModelCost(record, { input_tokens: projected, output_tokens: maxOutputTokens }, { serviceTier });
172
+ if (Number.isFinite(options.maxCallCostUsd) && projectedCost.total_usd > options.maxCallCostUsd) {
173
+ throw new Error(`projected_call_cost_exceeds_budget:${projectedCost.total_usd.toFixed(6)}>${Number(options.maxCallCostUsd).toFixed(6)}`);
174
+ }
175
+ const preflight = Object.freeze({
176
+ model: record.provider_model_id,
177
+ reasoning_effort: reasoningEffort,
178
+ service_tier: serviceTier,
179
+ estimated_input_tokens: projected,
180
+ max_output_tokens: maxOutputTokens,
181
+ projected_max_call_cost_usd: projectedCost.total_usd,
182
+ pricing_threshold_tokens: budget.pricingThresholdTokens,
183
+ tokens_until_pricing_threshold: pressure.tokensUntilPricingThreshold,
184
+ compacted_before_turn: Boolean(compacted),
185
+ estimate_kind: 'local',
186
+ });
187
+ if (typeof options.beforeRequest === 'function') {
188
+ const approved = await options.beforeRequest(preflight);
189
+ if (approved === false) throw new Error('model_request_not_approved');
190
+ }
191
+ event(emit, 'context.snapshot', {
192
+ estimate_kind: 'local',
193
+ estimated_input_tokens: projected,
194
+ window_tokens: budget.windowTokens,
195
+ utilization_ratio: pressure.utilizationRatio,
196
+ pricing_threshold_tokens: budget.pricingThresholdTokens,
197
+ tokens_until_pricing_threshold: pressure.tokensUntilPricingThreshold,
198
+ pressure: pressure.stage,
199
+ projected_max_call_cost_usd: projectedCost.total_usd,
200
+ tool_surface: toolSurface.receipt,
201
+ }, runId);
202
+
203
+ let cumulativeUsage = options.cumulativeUsage || null;
204
+ let totalCostUsd = 0;
205
+ let response = await provider.create({
206
+ model: record.provider_model_id,
207
+ input,
208
+ instructions,
209
+ reasoningEffort,
210
+ serviceTier,
211
+ tools: toolSurface.tools,
212
+ previousResponseId: previousResponseId || undefined,
213
+ maxOutputTokens,
214
+ promptCacheKey: options.promptCacheKey,
215
+ cumulativeUsage,
216
+ emit,
217
+ runId,
218
+ });
219
+ totalCostUsd += response.cost?.total_usd || 0;
220
+ cumulativeUsage = response.usage_snapshot?.cumulative || cumulativeUsage;
221
+
222
+ const toolReceipts = [];
223
+ const maxToolRounds = Number.isInteger(options.maxToolRounds) && options.maxToolRounds > 0 ? options.maxToolRounds : 8;
224
+ let rounds = 0;
225
+ while (response.tool_calls?.length) {
226
+ rounds += 1;
227
+ if (rounds > maxToolRounds) throw new Error(`tool_round_limit_exceeded:${maxToolRounds}`);
228
+ const outputs = [];
229
+ const activeTokens = response.usage_snapshot?.current_context?.input_tokens;
230
+ const maxToolChars = toolResultCharBudget(activeTokens, budget);
231
+ for (const call of response.tool_calls) {
232
+ const capabilityId = toolSurface.aliases.get(call.name);
233
+ if (!capabilityId) throw new Error(`unrecognized_tool_call:${call.name}`);
234
+ const descriptor = toolSurface.descriptors.find((row) => row.name === capabilityId);
235
+ const args = sanitizeToolInput(parseArguments(call.arguments), descriptor, cwd);
236
+ if (typeof options.beforeTool === 'function') {
237
+ const approved = await options.beforeTool({
238
+ call_id: call.call_id,
239
+ capability_id: capabilityId,
240
+ descriptor: descriptor ? { ...descriptor, input_schema: undefined } : null,
241
+ input: args,
242
+ cwd,
243
+ });
244
+ if (approved === false) {
245
+ const denied = new Error(`tool_execution_not_approved:${capabilityId}`);
246
+ denied.code = 'AGENTSAM_TOOL_NOT_APPROVED';
247
+ const diagnostic = diagnosticFromError(denied, { source: 'tool', kind: 'tool_execution_denied' });
248
+ event(emit, 'tool.failed', { call_id: call.call_id, capability_id: capabilityId, error: diagnostic }, runId);
249
+ event(emit, 'error.observed', { ...diagnostic, call_id: call.call_id, capability_id: capabilityId }, runId);
250
+ throw denied;
251
+ }
252
+ }
253
+ event(emit, 'tool.started', { call_id: call.call_id, capability_id: capabilityId }, runId);
254
+ try {
255
+ const value = await options.capabilityAdapter.invoke(capabilityId, args);
256
+ const bounded = boundedToolOutput(value, call.call_id, maxToolChars);
257
+ toolReceipts.push(Object.freeze({ call_id: call.call_id, capability_id: capabilityId, ...bounded, output: undefined }));
258
+ outputs.push({ call_id: call.call_id, output: bounded.output });
259
+ event(emit, 'tool.completed', {
260
+ call_id: call.call_id,
261
+ capability_id: capabilityId,
262
+ result_ref: bounded.ref,
263
+ result_hash: bounded.hash,
264
+ result_chars: bounded.chars,
265
+ source_chars: bounded.source_chars,
266
+ truncated: bounded.truncated,
267
+ }, runId);
268
+ } catch (error) {
269
+ const diagnostic = diagnosticFromError(error, { source: 'tool', kind: 'tool_execution_error' });
270
+ event(emit, 'tool.failed', { call_id: call.call_id, capability_id: capabilityId, error: diagnostic }, runId);
271
+ event(emit, 'error.observed', { ...diagnostic, call_id: call.call_id, capability_id: capabilityId }, runId);
272
+ outputs.push({ call_id: call.call_id, output: JSON.stringify({ ok: false, error: diagnostic }) });
273
+ }
274
+ }
275
+ response = await provider.continueWithToolOutputs({
276
+ model: record.provider_model_id,
277
+ previousResponseId: response.response_id,
278
+ toolOutputs: outputs,
279
+ instructions,
280
+ reasoningEffort,
281
+ serviceTier,
282
+ tools: toolSurface.tools,
283
+ maxOutputTokens,
284
+ promptCacheKey: options.promptCacheKey,
285
+ cumulativeUsage,
286
+ emit,
287
+ runId,
288
+ });
289
+ totalCostUsd += response.cost?.total_usd || 0;
290
+ cumulativeUsage = response.usage_snapshot?.cumulative || cumulativeUsage;
291
+ }
292
+
293
+ const active = response.usage_snapshot?.current_context?.input_tokens ?? 0;
294
+ const finalPressure = assessContextUsage(active, budget);
295
+ event(emit, 'context.snapshot', {
296
+ estimate_kind: 'provider',
297
+ active_input_tokens: active,
298
+ window_tokens: budget.windowTokens,
299
+ utilization_ratio: finalPressure.utilizationRatio,
300
+ pricing_threshold_tokens: budget.pricingThresholdTokens,
301
+ tokens_until_pricing_threshold: finalPressure.tokensUntilPricingThreshold,
302
+ pressure: finalPressure.stage,
303
+ compact_before_next_turn: finalPressure.shouldCompact,
304
+ }, runId);
305
+
306
+ return Object.freeze({
307
+ output_text: response.output_text || '',
308
+ response_id: response.response_id,
309
+ model: record.provider_model_id,
310
+ reasoning_effort: reasoningEffort,
311
+ requested_service_tier: serviceTier,
312
+ actual_service_tier: response.actual_service_tier,
313
+ usage_snapshot: response.usage_snapshot,
314
+ cumulative_usage: cumulativeUsage,
315
+ total_cost_usd: totalCostUsd,
316
+ tool_surface: toolSurface.receipt,
317
+ tool_receipts: Object.freeze(toolReceipts),
318
+ compacted_before_turn: Boolean(compacted),
319
+ continuation: Object.freeze({
320
+ previous_response_id: response.response_id,
321
+ usage_snapshot: response.usage_snapshot,
322
+ compact_before_next_turn: finalPressure.shouldCompact,
323
+ }),
324
+ });
325
+ }
@@ -5,3 +5,10 @@ export {
5
5
  listCapabilities,
6
6
  } from './manifest.js';
7
7
  export { repositorySnapshot } from './repository-snapshot.js';
8
+ export {
9
+ REPOSITORY_SNAPSHOT_VIEWS,
10
+ buildRepositorySnapshotFacets,
11
+ normalizeRepositorySnapshotFilters,
12
+ projectRepositorySnapshot,
13
+ repositoryFileMatches,
14
+ } from './repository-snapshot-view.js';