nexus-ai-pro 2.2.0 → 2.4.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 (298) hide show
  1. package/API_STABILITY.md +225 -0
  2. package/CHANGELOG.md +325 -1
  3. package/README.md +20 -6
  4. package/SECURITY.md +140 -0
  5. package/dist/adapter-kit/contracts.d.ts +87 -0
  6. package/dist/adapter-kit/contracts.js +237 -0
  7. package/dist/adapter-kit/errors.d.ts +39 -0
  8. package/dist/adapter-kit/errors.js +52 -0
  9. package/dist/adapter-kit/index.d.ts +144 -0
  10. package/dist/adapter-kit/index.js +178 -0
  11. package/dist/adapter-kit/semver.d.ts +12 -0
  12. package/dist/adapter-kit/semver.js +55 -0
  13. package/dist/agent/capabilities.d.ts +39 -0
  14. package/dist/agent/capabilities.js +36 -0
  15. package/dist/agent/create-agent.d.ts +61 -11
  16. package/dist/agent/create-agent.js +136 -22
  17. package/dist/agent/index.d.ts +3 -2
  18. package/dist/agent/index.js +1 -1
  19. package/dist/agent/middleware/approval.d.ts +26 -0
  20. package/dist/agent/middleware/approval.js +23 -0
  21. package/dist/agent/{middleware.d.ts → middleware/basic.d.ts} +5 -4
  22. package/dist/agent/{middleware.js → middleware/basic.js} +3 -5
  23. package/dist/agent/middleware/context-editor.d.ts +52 -0
  24. package/dist/agent/middleware/context-editor.js +66 -0
  25. package/dist/agent/middleware/filesystem.d.ts +44 -0
  26. package/dist/agent/middleware/filesystem.js +83 -0
  27. package/dist/agent/middleware/index.d.ts +19 -0
  28. package/dist/agent/middleware/index.js +9 -0
  29. package/dist/agent/middleware/limits.d.ts +42 -0
  30. package/dist/agent/middleware/limits.js +52 -0
  31. package/dist/agent/middleware/models.d.ts +48 -0
  32. package/dist/agent/middleware/models.js +44 -0
  33. package/dist/agent/middleware/pii.d.ts +67 -0
  34. package/dist/agent/middleware/pii.js +142 -0
  35. package/dist/agent/middleware/retry.d.ts +66 -0
  36. package/dist/agent/middleware/retry.js +59 -0
  37. package/dist/agent/middleware/shared.d.ts +41 -0
  38. package/dist/agent/middleware/shared.js +73 -0
  39. package/dist/agent/middleware/tool-selector.d.ts +64 -0
  40. package/dist/agent/middleware/tool-selector.js +106 -0
  41. package/dist/agent/permissions.d.ts +113 -0
  42. package/dist/agent/permissions.js +180 -0
  43. package/dist/agent/sandbox.d.ts +151 -0
  44. package/dist/agent/sandbox.js +257 -0
  45. package/dist/agent/tool.d.ts +8 -3
  46. package/dist/agent/tool.js +14 -3
  47. package/dist/core/secure-stream.js +4 -3
  48. package/dist/deep-agent/index.d.ts +109 -0
  49. package/dist/deep-agent/index.js +216 -0
  50. package/dist/embeddings/adapters.js +2 -1
  51. package/dist/evals/judge.js +2 -5
  52. package/dist/evaluate/cache.d.ts +0 -14
  53. package/dist/evaluate/cache.js +0 -30
  54. package/dist/evaluate/file-cache.d.ts +15 -0
  55. package/dist/evaluate/file-cache.js +30 -0
  56. package/dist/evaluate/index.d.ts +2 -1
  57. package/dist/evaluate/index.js +2 -1
  58. package/dist/evaluate/review.js +2 -2
  59. package/dist/evaluate/run.js +2 -2
  60. package/dist/evaluate/version.js +3 -3
  61. package/dist/graph/functional.d.ts +9 -0
  62. package/dist/graph/functional.js +20 -3
  63. package/dist/graph/graph.js +27 -6
  64. package/dist/graph/lint.d.ts +4 -1
  65. package/dist/graph/lint.js +35 -0
  66. package/dist/graph/node-cache.js +3 -3
  67. package/dist/hallucination/rag.d.ts +4 -1
  68. package/dist/hallucination/rag.js +6 -1
  69. package/dist/images/asset-stores.js +2 -3
  70. package/dist/images/asset-support.js +2 -2
  71. package/dist/images/assets.js +1 -2
  72. package/dist/images/evals.js +4 -4
  73. package/dist/insights/proposals.js +1 -2
  74. package/dist/insights/regressions.d.ts +26 -2
  75. package/dist/insights/regressions.js +129 -3
  76. package/dist/loaders/git.js +8 -1
  77. package/dist/loaders/web.js +7 -1
  78. package/dist/mcp/client.d.ts +14 -0
  79. package/dist/mcp/client.js +59 -1
  80. package/dist/mcp/registry.d.ts +6 -0
  81. package/dist/mcp/registry.js +7 -0
  82. package/dist/postgres/fulltext.d.ts +67 -0
  83. package/dist/postgres/fulltext.js +91 -0
  84. package/dist/prompts/file.js +28 -11
  85. package/dist/protocols/a2a.d.ts +235 -0
  86. package/dist/protocols/a2a.js +386 -0
  87. package/dist/protocols/acp.d.ts +87 -0
  88. package/dist/protocols/acp.js +322 -0
  89. package/dist/protocols/ag-ui.d.ts +120 -0
  90. package/dist/protocols/ag-ui.js +180 -0
  91. package/dist/protocols/shared.d.ts +80 -0
  92. package/dist/protocols/shared.js +49 -0
  93. package/dist/providers/anthropic.js +1 -0
  94. package/dist/providers/cohere.js +2 -2
  95. package/dist/providers/google.js +2 -11
  96. package/dist/providers/openai.js +1 -0
  97. package/dist/rag/elasticsearch.d.ts +71 -0
  98. package/dist/rag/elasticsearch.js +130 -0
  99. package/dist/rag/file-ingestion.js +15 -9
  100. package/dist/rag/pipeline.d.ts +140 -0
  101. package/dist/rag/pipeline.js +187 -0
  102. package/dist/rag/rerankers.d.ts +92 -0
  103. package/dist/rag/rerankers.js +97 -0
  104. package/dist/rag/retrievers.d.ts +12 -1
  105. package/dist/runtime/detect.d.ts +17 -0
  106. package/dist/runtime/detect.js +16 -0
  107. package/dist/runtime/index.d.ts +19 -0
  108. package/dist/runtime/index.js +7 -0
  109. package/dist/security/injection-detector.d.ts +2 -0
  110. package/dist/security/injection-detector.js +7 -1
  111. package/dist/security/input-guard.js +5 -2
  112. package/dist/security/output-guard.js +8 -4
  113. package/dist/security/pii-detector.js +22 -6
  114. package/dist/security/prompt-hardening.js +6 -2
  115. package/dist/security/semantic-injection-classifier.d.ts +2 -1
  116. package/dist/security/semantic-injection-classifier.js +31 -35
  117. package/dist/security/upload-scanner.d.ts +8 -0
  118. package/dist/security/upload-scanner.js +51 -9
  119. package/dist/server/assistant.d.ts +5 -1
  120. package/dist/server/assistant.js +4 -2
  121. package/dist/server/auth.d.ts +250 -0
  122. package/dist/server/auth.js +392 -0
  123. package/dist/server/deployments.d.ts +63 -1
  124. package/dist/server/deployments.js +75 -2
  125. package/dist/server/runs.d.ts +9 -0
  126. package/dist/server/runs.js +20 -0
  127. package/dist/server/server.js +5 -0
  128. package/dist/store/memory.d.ts +10 -0
  129. package/dist/store/memory.js +10 -0
  130. package/dist/testing/record.js +2 -2
  131. package/dist/tracing/stores.js +2 -1
  132. package/dist/tracing/tracer.js +2 -2
  133. package/dist/types/config.d.ts +20 -0
  134. package/dist/types/graph.d.ts +38 -0
  135. package/dist/types/messages.d.ts +36 -2
  136. package/dist/types/principal.d.ts +21 -0
  137. package/dist/types/principal.js +1 -0
  138. package/dist/types/server.d.ts +8 -9
  139. package/dist/utils/base64.d.ts +4 -0
  140. package/dist/utils/base64.js +21 -0
  141. package/dist/utils/checksums.d.ts +22 -0
  142. package/dist/utils/checksums.js +39 -0
  143. package/dist/utils/ids.d.ts +8 -0
  144. package/dist/utils/ids.js +26 -2
  145. package/dist/utils/sha256.d.ts +22 -0
  146. package/dist/utils/sha256.js +120 -0
  147. package/dist/utils/tenant.d.ts +11 -0
  148. package/dist/utils/tenant.js +14 -0
  149. package/dist/version.d.ts +1 -1
  150. package/dist/version.js +1 -1
  151. package/dist-cjs/adapter-kit/contracts.d.ts +87 -0
  152. package/dist-cjs/adapter-kit/contracts.js +243 -0
  153. package/dist-cjs/adapter-kit/errors.d.ts +39 -0
  154. package/dist-cjs/adapter-kit/errors.js +57 -0
  155. package/dist-cjs/adapter-kit/index.d.ts +144 -0
  156. package/dist-cjs/adapter-kit/index.js +194 -0
  157. package/dist-cjs/adapter-kit/semver.d.ts +12 -0
  158. package/dist-cjs/adapter-kit/semver.js +59 -0
  159. package/dist-cjs/agent/capabilities.d.ts +39 -0
  160. package/dist-cjs/agent/capabilities.js +41 -0
  161. package/dist-cjs/agent/create-agent.d.ts +61 -11
  162. package/dist-cjs/agent/create-agent.js +136 -22
  163. package/dist-cjs/agent/index.d.ts +3 -2
  164. package/dist-cjs/agent/index.js +4 -4
  165. package/dist-cjs/agent/middleware/approval.d.ts +26 -0
  166. package/dist-cjs/agent/middleware/approval.js +26 -0
  167. package/dist-cjs/agent/{middleware.d.ts → middleware/basic.d.ts} +5 -4
  168. package/dist-cjs/agent/{middleware.js → middleware/basic.js} +3 -5
  169. package/dist-cjs/agent/middleware/context-editor.d.ts +52 -0
  170. package/dist-cjs/agent/middleware/context-editor.js +70 -0
  171. package/dist-cjs/agent/middleware/filesystem.d.ts +44 -0
  172. package/dist-cjs/agent/middleware/filesystem.js +86 -0
  173. package/dist-cjs/agent/middleware/index.d.ts +19 -0
  174. package/dist-cjs/agent/middleware/index.js +28 -0
  175. package/dist-cjs/agent/middleware/limits.d.ts +42 -0
  176. package/dist-cjs/agent/middleware/limits.js +57 -0
  177. package/dist-cjs/agent/middleware/models.d.ts +48 -0
  178. package/dist-cjs/agent/middleware/models.js +48 -0
  179. package/dist-cjs/agent/middleware/pii.d.ts +67 -0
  180. package/dist-cjs/agent/middleware/pii.js +147 -0
  181. package/dist-cjs/agent/middleware/retry.d.ts +66 -0
  182. package/dist-cjs/agent/middleware/retry.js +63 -0
  183. package/dist-cjs/agent/middleware/shared.d.ts +41 -0
  184. package/dist-cjs/agent/middleware/shared.js +83 -0
  185. package/dist-cjs/agent/middleware/tool-selector.d.ts +64 -0
  186. package/dist-cjs/agent/middleware/tool-selector.js +109 -0
  187. package/dist-cjs/agent/permissions.d.ts +113 -0
  188. package/dist-cjs/agent/permissions.js +189 -0
  189. package/dist-cjs/agent/sandbox.d.ts +151 -0
  190. package/dist-cjs/agent/sandbox.js +297 -0
  191. package/dist-cjs/agent/tool.d.ts +8 -3
  192. package/dist-cjs/agent/tool.js +14 -3
  193. package/dist-cjs/core/secure-stream.js +4 -3
  194. package/dist-cjs/deep-agent/index.d.ts +109 -0
  195. package/dist-cjs/deep-agent/index.js +219 -0
  196. package/dist-cjs/embeddings/adapters.js +2 -1
  197. package/dist-cjs/evals/judge.js +2 -5
  198. package/dist-cjs/evaluate/cache.d.ts +0 -14
  199. package/dist-cjs/evaluate/cache.js +1 -65
  200. package/dist-cjs/evaluate/file-cache.d.ts +15 -0
  201. package/dist-cjs/evaluate/file-cache.js +67 -0
  202. package/dist-cjs/evaluate/index.d.ts +2 -1
  203. package/dist-cjs/evaluate/index.js +3 -2
  204. package/dist-cjs/evaluate/review.js +2 -2
  205. package/dist-cjs/evaluate/run.js +2 -2
  206. package/dist-cjs/evaluate/version.js +3 -3
  207. package/dist-cjs/graph/functional.d.ts +9 -0
  208. package/dist-cjs/graph/functional.js +20 -3
  209. package/dist-cjs/graph/graph.js +27 -6
  210. package/dist-cjs/graph/lint.d.ts +4 -1
  211. package/dist-cjs/graph/lint.js +35 -0
  212. package/dist-cjs/graph/node-cache.js +3 -3
  213. package/dist-cjs/hallucination/rag.d.ts +4 -1
  214. package/dist-cjs/hallucination/rag.js +6 -1
  215. package/dist-cjs/images/asset-stores.js +2 -3
  216. package/dist-cjs/images/asset-support.js +2 -2
  217. package/dist-cjs/images/assets.js +1 -2
  218. package/dist-cjs/images/evals.js +4 -4
  219. package/dist-cjs/insights/proposals.js +1 -2
  220. package/dist-cjs/insights/regressions.d.ts +26 -2
  221. package/dist-cjs/insights/regressions.js +129 -3
  222. package/dist-cjs/loaders/git.js +8 -1
  223. package/dist-cjs/loaders/web.js +7 -1
  224. package/dist-cjs/mcp/client.d.ts +14 -0
  225. package/dist-cjs/mcp/client.js +60 -1
  226. package/dist-cjs/mcp/registry.d.ts +6 -0
  227. package/dist-cjs/mcp/registry.js +7 -0
  228. package/dist-cjs/postgres/fulltext.d.ts +67 -0
  229. package/dist-cjs/postgres/fulltext.js +129 -0
  230. package/dist-cjs/prompts/file.js +28 -11
  231. package/dist-cjs/protocols/a2a.d.ts +235 -0
  232. package/dist-cjs/protocols/a2a.js +393 -0
  233. package/dist-cjs/protocols/acp.d.ts +87 -0
  234. package/dist-cjs/protocols/acp.js +326 -0
  235. package/dist-cjs/protocols/ag-ui.d.ts +120 -0
  236. package/dist-cjs/protocols/ag-ui.js +186 -0
  237. package/dist-cjs/protocols/shared.d.ts +80 -0
  238. package/dist-cjs/protocols/shared.js +59 -0
  239. package/dist-cjs/providers/anthropic.js +1 -0
  240. package/dist-cjs/providers/cohere.js +2 -2
  241. package/dist-cjs/providers/google.js +3 -12
  242. package/dist-cjs/providers/openai.js +1 -0
  243. package/dist-cjs/rag/elasticsearch.d.ts +71 -0
  244. package/dist-cjs/rag/elasticsearch.js +135 -0
  245. package/dist-cjs/rag/file-ingestion.js +14 -8
  246. package/dist-cjs/rag/pipeline.d.ts +140 -0
  247. package/dist-cjs/rag/pipeline.js +191 -0
  248. package/dist-cjs/rag/rerankers.d.ts +92 -0
  249. package/dist-cjs/rag/rerankers.js +107 -0
  250. package/dist-cjs/rag/retrievers.d.ts +12 -1
  251. package/dist-cjs/runtime/detect.d.ts +17 -0
  252. package/dist-cjs/runtime/detect.js +19 -0
  253. package/dist-cjs/runtime/index.d.ts +19 -0
  254. package/dist-cjs/runtime/index.js +31 -0
  255. package/dist-cjs/security/injection-detector.d.ts +2 -0
  256. package/dist-cjs/security/injection-detector.js +7 -1
  257. package/dist-cjs/security/input-guard.js +5 -2
  258. package/dist-cjs/security/output-guard.js +8 -4
  259. package/dist-cjs/security/pii-detector.js +22 -6
  260. package/dist-cjs/security/prompt-hardening.js +6 -2
  261. package/dist-cjs/security/semantic-injection-classifier.d.ts +2 -1
  262. package/dist-cjs/security/semantic-injection-classifier.js +31 -35
  263. package/dist-cjs/security/upload-scanner.d.ts +8 -0
  264. package/dist-cjs/security/upload-scanner.js +53 -9
  265. package/dist-cjs/server/assistant.d.ts +5 -1
  266. package/dist-cjs/server/assistant.js +4 -2
  267. package/dist-cjs/server/auth.d.ts +250 -0
  268. package/dist-cjs/server/auth.js +402 -0
  269. package/dist-cjs/server/deployments.d.ts +63 -1
  270. package/dist-cjs/server/deployments.js +75 -2
  271. package/dist-cjs/server/runs.d.ts +9 -0
  272. package/dist-cjs/server/runs.js +20 -0
  273. package/dist-cjs/server/server.js +5 -0
  274. package/dist-cjs/store/memory.d.ts +10 -0
  275. package/dist-cjs/store/memory.js +10 -0
  276. package/dist-cjs/testing/record.js +2 -2
  277. package/dist-cjs/tracing/stores.js +2 -1
  278. package/dist-cjs/tracing/tracer.js +2 -2
  279. package/dist-cjs/types/config.d.ts +20 -0
  280. package/dist-cjs/types/graph.d.ts +38 -0
  281. package/dist-cjs/types/messages.d.ts +36 -2
  282. package/dist-cjs/types/principal.d.ts +21 -0
  283. package/dist-cjs/types/principal.js +2 -0
  284. package/dist-cjs/types/server.d.ts +8 -9
  285. package/dist-cjs/utils/base64.d.ts +4 -0
  286. package/dist-cjs/utils/base64.js +25 -0
  287. package/dist-cjs/utils/checksums.d.ts +22 -0
  288. package/dist-cjs/utils/checksums.js +46 -0
  289. package/dist-cjs/utils/ids.d.ts +8 -0
  290. package/dist-cjs/utils/ids.js +28 -2
  291. package/dist-cjs/utils/sha256.d.ts +22 -0
  292. package/dist-cjs/utils/sha256.js +125 -0
  293. package/dist-cjs/utils/tenant.d.ts +11 -0
  294. package/dist-cjs/utils/tenant.js +15 -0
  295. package/dist-cjs/version.d.ts +1 -1
  296. package/dist-cjs/version.js +1 -1
  297. package/llms.txt +7 -3
  298. package/package.json +193 -6
@@ -0,0 +1,144 @@
1
+ /**
2
+ * The adapter kit: how a package outside this repository builds an adapter — a provider, an
3
+ * embeddings backend, a vector store, a retriever, or a long-term store — and proves it works.
4
+ *
5
+ * Each `define*()` takes what the adapter is, the releases of `nexus-ai-pro` it supports, what it
6
+ * can do, and how to create it, and returns an adapter whose instances normalize every failure into
7
+ * an `AdapterError` and report every call for telemetry. Its `verify()` runs the same contract suite
8
+ * this package runs on its own adapters, skipping only what the adapter declares it cannot do, with a
9
+ * small benchmark held to the budgets it declares.
10
+ */
11
+ import type { EmbeddingProvider, VectorStore } from '../hallucination/retrieval.js';
12
+ import type { BaseProvider } from '../providers/base.js';
13
+ import type { Retriever } from '../rag/retrievers.js';
14
+ import { type EmbeddingProviderConformanceOptions } from '../testing/embedding-provider-conformance.js';
15
+ import { type ProviderConformanceOptions } from '../testing/provider-conformance.js';
16
+ import type { EmbeddingsProvider } from '../types/embeddings.js';
17
+ import type { Store } from '../types/store.js';
18
+ import { type AdapterCheck, type RetrieverCapabilities, type RetrieverContractOptions, type StoreCapabilities, type VectorStoreCapabilities } from './contracts.js';
19
+ import { type AdapterErrorClass } from './errors.js';
20
+ export { ADAPTER_FIXTURE_PASSAGES, type AdapterCheck, type RetrieverCapabilities, type RetrieverContractOptions, runRetrieverContract, runStoreContract, runVectorStoreContract, type StoreCapabilities, type VectorStoreCapabilities, type VectorStoreContractOptions, } from './contracts.js';
21
+ export { AdapterError, type AdapterErrorClass, type AdapterErrorCode, classifyAdapterError } from './errors.js';
22
+ export { parseVersion, satisfiesRange } from './semver.js';
23
+ /** The kinds of adapter the kit builds. */
24
+ export type AdapterKind = 'provider' | 'embeddings' | 'vector-store' | 'retriever' | 'store';
25
+ /** What every adapter declares about itself. */
26
+ export interface AdapterDefinition<Config, Instance, Capabilities> {
27
+ /** Its name, usually its package name, such as `@acme/nexus-milvus`. */
28
+ name: string;
29
+ /** Its own version. */
30
+ version: string;
31
+ /** The releases of `nexus-ai-pro` it works with, as a range: `>=2.4.0 <3`. */
32
+ nexus: string;
33
+ /** What it can do. The contract skips what it declares it cannot, and fails what it claims and cannot. */
34
+ capabilities: Capabilities;
35
+ /** Creates an instance from its configuration. */
36
+ create(config: Config): Instance | Promise<Instance>;
37
+ /**
38
+ * Classifies a failure from the service behind the adapter, when the kit's own reading of statuses
39
+ * and network codes is not enough. Returning nothing falls back to that reading.
40
+ */
41
+ normalizeError?(error: unknown, operation: string): AdapterErrorClass | undefined;
42
+ /** The p95 latency each operation must stay within in `verify()`'s benchmark, in milliseconds. */
43
+ budgets?: Readonly<Record<string, number>>;
44
+ }
45
+ /** One call through an adapter, for telemetry. */
46
+ export interface AdapterCallEvent {
47
+ /** The adapter. */
48
+ adapter: string;
49
+ /** Its kind. */
50
+ kind: AdapterKind;
51
+ /** The method called, such as `search`. */
52
+ operation: string;
53
+ /** How long the call took, in milliseconds. */
54
+ durationMs: number;
55
+ /** Whether it succeeded. */
56
+ ok: boolean;
57
+ /** How it failed, when it did. */
58
+ error?: AdapterErrorClass;
59
+ }
60
+ /** Options for an adapter's `create()`. */
61
+ export interface AdapterCreateOptions {
62
+ /** Receives every call: the hook a tracer, a metrics exporter, or a log subscribes with. */
63
+ onCall?: (event: AdapterCallEvent) => void;
64
+ }
65
+ /** What `verify()` measured for one operation over the contract's calls. */
66
+ export interface AdapterBenchmarkEntry {
67
+ /** Successful calls measured. */
68
+ calls: number;
69
+ /** Median latency, in milliseconds. */
70
+ p50Ms: number;
71
+ /** 95th-percentile latency, in milliseconds. */
72
+ p95Ms: number;
73
+ }
74
+ /** What `verify()` found. */
75
+ export interface AdapterReport {
76
+ /** The adapter. */
77
+ adapter: string;
78
+ /** Its version. */
79
+ version: string;
80
+ /** Its kind. */
81
+ kind: AdapterKind;
82
+ /** The `nexus-ai-pro` release it was verified against. */
83
+ nexusVersion: string;
84
+ /** Whether that release is inside the adapter's declared range. */
85
+ compatible: boolean;
86
+ /** True when it is compatible and every check that ran held. */
87
+ passed: boolean;
88
+ /** Every check, in order, with skipped ones marked. */
89
+ checks: AdapterCheck[];
90
+ /** Latency per operation over the contract's calls. */
91
+ benchmark: Record<string, AdapterBenchmarkEntry>;
92
+ }
93
+ /** An adapter built with the kit. */
94
+ export interface Adapter<Config, Instance, Capabilities, VerifyOptions> extends Readonly<Omit<AdapterDefinition<Config, Instance, Capabilities>, 'create'>> {
95
+ /** Its kind. */
96
+ readonly kind: AdapterKind;
97
+ /** Creates an instance whose every call normalizes its failures and reports itself. */
98
+ create(config: Config, options?: AdapterCreateOptions): Promise<Instance>;
99
+ /** Whether a release of `nexus-ai-pro` is inside the declared range. Defaults to the installed one. */
100
+ compatible(nexusVersion?: string): boolean;
101
+ /** Runs the contract suite for its kind against a fresh instance, with a benchmark. */
102
+ verify(config: Config, options: VerifyOptions): Promise<AdapterReport>;
103
+ }
104
+ /** What a chat provider supports, which decides the conformance cases it runs. */
105
+ export interface ProviderAdapterCapabilities {
106
+ /** `stream()`. */
107
+ streaming: boolean;
108
+ /** JSON output through `responseFormat`. */
109
+ json: boolean;
110
+ /** Tool calls. */
111
+ tools: boolean;
112
+ /** `healthCheck()`. */
113
+ health: boolean;
114
+ }
115
+ /** Options for a provider adapter's `verify()`: the model and, if you like, cases of your own. */
116
+ export type ProviderVerifyOptions = Pick<ProviderConformanceOptions, 'model' | 'fixtures'>;
117
+ /** Builds a chat-provider adapter, verified by the provider conformance suite. */
118
+ export declare function defineProviderAdapter<Config, Instance extends BaseProvider>(definition: AdapterDefinition<Config, Instance, ProviderAdapterCapabilities>): Adapter<Config, Instance, ProviderAdapterCapabilities, ProviderVerifyOptions>;
119
+ /** What an embeddings backend supports. */
120
+ export interface EmbeddingsAdapterCapabilities {
121
+ /** Stops an embedding call when its signal aborts. */
122
+ abort: boolean;
123
+ /** Returns the same vectors for the same input. */
124
+ deterministic: boolean;
125
+ }
126
+ /** Options for an embeddings adapter's `verify()`. */
127
+ export type EmbeddingsVerifyOptions = Pick<EmbeddingProviderConformanceOptions, 'model' | 'fixtures'>;
128
+ /** Builds an embeddings adapter, verified by the embeddings conformance suite. */
129
+ export declare function defineEmbeddingsAdapter<Config, Instance extends EmbeddingsProvider>(definition: AdapterDefinition<Config, Instance, EmbeddingsAdapterCapabilities>): Adapter<Config, Instance, EmbeddingsAdapterCapabilities, EmbeddingsVerifyOptions>;
130
+ /** Options for a vector-store adapter's `verify()`. */
131
+ export interface VectorStoreVerifyOptions {
132
+ /** The embedding function the store embeds with, to compute a query vector. */
133
+ embed: EmbeddingProvider;
134
+ /** Waits for writes to become searchable, for an eventually consistent index. */
135
+ settle?: () => Promise<void>;
136
+ }
137
+ /** Builds a vector-store adapter, verified by the `VectorStore` contract. */
138
+ export declare function defineVectorStoreAdapter<Config, Instance extends VectorStore>(definition: AdapterDefinition<Config, Instance, VectorStoreCapabilities>): Adapter<Config, Instance, VectorStoreCapabilities, VectorStoreVerifyOptions>;
139
+ /** Options for a retriever adapter's `verify()`. */
140
+ export type RetrieverVerifyOptions = Omit<RetrieverContractOptions, 'capabilities'>;
141
+ /** Builds a retriever adapter, verified by the `Retriever` contract, and the `SparseRetriever` one when it takes writes. */
142
+ export declare function defineRetrieverAdapter<Config, Instance extends Retriever>(definition: AdapterDefinition<Config, Instance, RetrieverCapabilities>): Adapter<Config, Instance, RetrieverCapabilities, RetrieverVerifyOptions>;
143
+ /** Builds a long-term store adapter, verified by the `Store` contract. */
144
+ export declare function defineStoreAdapter<Config, Instance extends Store>(definition: AdapterDefinition<Config, Instance, StoreCapabilities>): Adapter<Config, Instance, StoreCapabilities, Record<string, never>>;
@@ -0,0 +1,178 @@
1
+ import { runEmbeddingProviderConformance, } from '../testing/embedding-provider-conformance.js';
2
+ import { runProviderConformance } from '../testing/provider-conformance.js';
3
+ import { NEXUS_VERSION } from '../version.js';
4
+ import { runRetrieverContract, runStoreContract, runVectorStoreContract, } from './contracts.js';
5
+ import { AdapterError, classifyAdapterError } from './errors.js';
6
+ import { satisfiesRange } from './semver.js';
7
+ export { ADAPTER_FIXTURE_PASSAGES, runRetrieverContract, runStoreContract, runVectorStoreContract, } from './contracts.js';
8
+ export { AdapterError, classifyAdapterError } from './errors.js';
9
+ export { parseVersion, satisfiesRange } from './semver.js';
10
+ const OPERATIONS = {
11
+ provider: ['complete', 'healthCheck'],
12
+ embeddings: ['embed'],
13
+ 'vector-store': ['add', 'search', 'searchVector', 'delete'],
14
+ retriever: ['retrieve', 'add', 'delete'],
15
+ store: ['put', 'get', 'delete', 'search', 'listNamespaces'],
16
+ };
17
+ function build(kind, definition, contract) {
18
+ for (const field of ['name', 'version', 'nexus']) {
19
+ if (typeof definition[field] !== 'string' || !definition[field])
20
+ throw new TypeError(`An adapter needs a ${field}`);
21
+ }
22
+ satisfiesRange(NEXUS_VERSION, definition.nexus);
23
+ const create = async (config, options = {}) => instrument(kind, definition, await definition.create(config), options);
24
+ return {
25
+ kind,
26
+ name: definition.name,
27
+ version: definition.version,
28
+ nexus: definition.nexus,
29
+ capabilities: definition.capabilities,
30
+ ...(definition.normalizeError ? { normalizeError: definition.normalizeError } : {}),
31
+ ...(definition.budgets ? { budgets: definition.budgets } : {}),
32
+ create,
33
+ compatible: (nexusVersion = NEXUS_VERSION) => satisfiesRange(nexusVersion, definition.nexus),
34
+ async verify(config, options) {
35
+ const durations = new Map();
36
+ const instance = await create(config, {
37
+ onCall: (event) => {
38
+ if (event.ok)
39
+ durations.set(event.operation, [...(durations.get(event.operation) ?? []), event.durationMs]);
40
+ },
41
+ });
42
+ const compatible = satisfiesRange(NEXUS_VERSION, definition.nexus);
43
+ const checks = [
44
+ {
45
+ name: `declares support for nexus-ai-pro ${NEXUS_VERSION}`,
46
+ ok: compatible,
47
+ ...(compatible ? {} : { detail: `the declared range is ${definition.nexus}` }),
48
+ },
49
+ ...(await contract(instance, options, definition.capabilities)),
50
+ ];
51
+ const benchmark = {};
52
+ for (const [operation, values] of durations) {
53
+ const sorted = [...values].sort((a, b) => a - b);
54
+ const at = (q) => round(sorted[Math.min(sorted.length - 1, Math.ceil(q * sorted.length) - 1)] ?? 0);
55
+ benchmark[operation] = { calls: sorted.length, p50Ms: at(0.5), p95Ms: at(0.95) };
56
+ }
57
+ for (const [operation, budget] of Object.entries(definition.budgets ?? {})) {
58
+ const measured = benchmark[operation]?.p95Ms;
59
+ checks.push(measured === undefined
60
+ ? {
61
+ name: `${operation} stays within ${budget} ms at p95`,
62
+ ok: true,
63
+ skipped: true,
64
+ detail: 'not called by the contract',
65
+ }
66
+ : {
67
+ name: `${operation} stays within ${budget} ms at p95`,
68
+ ok: measured <= budget,
69
+ ...(measured <= budget ? {} : { detail: `measured ${measured} ms` }),
70
+ });
71
+ }
72
+ return {
73
+ adapter: definition.name,
74
+ version: definition.version,
75
+ kind,
76
+ nexusVersion: NEXUS_VERSION,
77
+ compatible,
78
+ passed: checks.every((check) => check.ok),
79
+ checks,
80
+ benchmark,
81
+ };
82
+ },
83
+ };
84
+ }
85
+ function instrument(kind, definition, instance, options) {
86
+ const operations = new Set(OPERATIONS[kind]);
87
+ return new Proxy(instance, {
88
+ get(target, property, receiver) {
89
+ const value = Reflect.get(target, property, receiver);
90
+ if (typeof property !== 'string' || !operations.has(property) || typeof value !== 'function') {
91
+ return typeof value === 'function' ? value.bind(target) : value;
92
+ }
93
+ return async (...args) => {
94
+ const started = performance.now();
95
+ try {
96
+ const result = await value.apply(target, args);
97
+ options.onCall?.({
98
+ adapter: definition.name,
99
+ kind,
100
+ operation: property,
101
+ durationMs: performance.now() - started,
102
+ ok: true,
103
+ });
104
+ return result;
105
+ }
106
+ catch (error) {
107
+ const failure = error instanceof AdapterError
108
+ ? {
109
+ code: error.code,
110
+ retryable: error.retryable,
111
+ ...(error.status === undefined ? {} : { status: error.status }),
112
+ }
113
+ : (definition.normalizeError?.(error, property) ?? classifyAdapterError(error));
114
+ options.onCall?.({
115
+ adapter: definition.name,
116
+ kind,
117
+ operation: property,
118
+ durationMs: performance.now() - started,
119
+ ok: false,
120
+ error: failure,
121
+ });
122
+ throw error instanceof AdapterError ? error : new AdapterError(definition.name, property, failure, error);
123
+ }
124
+ };
125
+ },
126
+ });
127
+ }
128
+ export function defineProviderAdapter(definition) {
129
+ return build('provider', definition, async (provider, options, capabilities) => {
130
+ const results = await runProviderConformance(definition.name, provider, {
131
+ ...options,
132
+ testStream: capabilities.streaming,
133
+ testJson: capabilities.json,
134
+ testTools: capabilities.tools,
135
+ testHealth: capabilities.health,
136
+ });
137
+ return results.flatMap((result) => [
138
+ {
139
+ name: `completes the ${result.caseName} case`,
140
+ ok: result.completeOk,
141
+ ...(result.completeOk ? {} : { detail: result.error ?? 'the response was not accepted' }),
142
+ },
143
+ ...(result.streamOk === undefined ? [] : [{ name: `streams the ${result.caseName} case`, ok: result.streamOk }]),
144
+ ...(result.healthOk === undefined ? [] : [{ name: 'answers its health check', ok: result.healthOk }]),
145
+ ]);
146
+ });
147
+ }
148
+ export function defineEmbeddingsAdapter(definition) {
149
+ return build('embeddings', definition, async (provider, options, capabilities) => {
150
+ const results = await runEmbeddingProviderConformance(definition.name, provider, {
151
+ ...options,
152
+ testAbort: capabilities.abort,
153
+ testDeterminism: capabilities.deterministic,
154
+ });
155
+ return results.flatMap((result) => [
156
+ {
157
+ name: `embeds the ${result.caseName} case`,
158
+ ok: result.ok,
159
+ ...(result.ok ? {} : { detail: result.error ?? 'not accepted' }),
160
+ },
161
+ ...(result.abortOk === undefined
162
+ ? []
163
+ : [{ name: `stops the ${result.caseName} case when aborted`, ok: result.abortOk }]),
164
+ ]);
165
+ });
166
+ }
167
+ export function defineVectorStoreAdapter(definition) {
168
+ return build('vector-store', definition, (store, options, capabilities) => runVectorStoreContract(store, { ...options, capabilities }));
169
+ }
170
+ export function defineRetrieverAdapter(definition) {
171
+ return build('retriever', definition, (retriever, options, capabilities) => runRetrieverContract(retriever, { ...options, capabilities }));
172
+ }
173
+ export function defineStoreAdapter(definition) {
174
+ return build('store', definition, (store, _options, capabilities) => runStoreContract(store, { capabilities }));
175
+ }
176
+ function round(value) {
177
+ return Math.round(value * 100) / 100;
178
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Version ranges, as an adapter declares the releases of `nexus-ai-pro` it works with. A small,
3
+ * dependency-free subset of npm's ranges: comparators joined by spaces must all hold, alternatives
4
+ * joined by `||` need one to hold, and `>=`, `>`, `<=`, `<`, `=`, `^`, `~`, `x`, and `*` mean what
5
+ * they mean in npm.
6
+ */
7
+ type Version = [number, number, number];
8
+ /** A version as three numbers. A prerelease or build tag is ignored. `undefined` for anything else. */
9
+ export declare function parseVersion(version: string): Version | undefined;
10
+ /** Whether `version` satisfies `range`, such as `>=2.4.0 <3` or `^2.4.0 || ^3.0.0`. */
11
+ export declare function satisfiesRange(version: string, range: string): boolean;
12
+ export {};
@@ -0,0 +1,55 @@
1
+ export function parseVersion(version) {
2
+ const match = /^\s*v?(\d+)\.(\d+)\.(\d+)/.exec(version);
3
+ return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : undefined;
4
+ }
5
+ export function satisfiesRange(version, range) {
6
+ const parsed = parseVersion(version);
7
+ if (!parsed)
8
+ return false;
9
+ return range.split('||').some((alternative) => {
10
+ const comparators = alternative.trim().split(/\s+/).filter(Boolean);
11
+ return comparators.length === 0 || comparators.every((comparator) => holds(parsed, comparator));
12
+ });
13
+ }
14
+ function holds(version, comparator) {
15
+ const match = /^(>=|<=|>|<|=|\^|~)?v?(\d+|x|X|\*)(?:\.(\d+|x|X|\*))?(?:\.(\d+|x|X|\*))?/.exec(comparator);
16
+ if (!match)
17
+ throw new RangeError(`"${comparator}" is not a version range`);
18
+ const operator = match[1] ?? '';
19
+ const parts = [match[2], match[3], match[4]];
20
+ const fixed = parts.findIndex((part) => part === undefined || /^[xX*]$/.test(part));
21
+ const known = fixed === -1 ? 3 : fixed;
22
+ const base = parts.map((part, index) => (index < known ? Number(part) : 0));
23
+ if (known === 0)
24
+ return operator === '' || operator === '=' || operator === '>=' || operator === '<=';
25
+ switch (operator) {
26
+ case '>=':
27
+ return compare(version, base) >= 0;
28
+ case '>':
29
+ return known === 3 ? compare(version, base) > 0 : compare(version, bump(base, known - 1)) >= 0;
30
+ case '<=':
31
+ return known === 3 ? compare(version, base) <= 0 : compare(version, bump(base, known - 1)) < 0;
32
+ case '<':
33
+ return compare(version, base) < 0;
34
+ case '^': {
35
+ const pinned = base[0] > 0 || known === 1 ? 0 : base[1] > 0 || known === 2 ? 1 : 2;
36
+ return compare(version, base) >= 0 && compare(version, bump(base, pinned)) < 0;
37
+ }
38
+ case '~':
39
+ return compare(version, base) >= 0 && compare(version, bump(base, known >= 2 ? 1 : 0)) < 0;
40
+ default:
41
+ return known === 3
42
+ ? compare(version, base) === 0
43
+ : compare(version, base) >= 0 && compare(version, bump(base, known - 1)) < 0;
44
+ }
45
+ }
46
+ function bump(version, part) {
47
+ return version.map((value, index) => (index < part ? value : index === part ? value + 1 : 0));
48
+ }
49
+ function compare(left, right) {
50
+ for (let index = 0; index < 3; index += 1) {
51
+ if (left[index] !== right[index])
52
+ return left[index] - right[index];
53
+ }
54
+ return 0;
55
+ }
@@ -0,0 +1,39 @@
1
+ import type { ToolDefinition } from '../types/messages.js';
2
+ /**
3
+ * Capabilities: what a tool does to the world, written as strings a policy can decide on.
4
+ *
5
+ * | Capability | Means |
6
+ * | --- | --- |
7
+ * | `filesystem:read`, `filesystem:read:<path>` | Reads files, or one path |
8
+ * | `filesystem:write`, `filesystem:write:<path>` | Writes, creates, or deletes files |
9
+ * | `network`, `network:<host or URL>` | Opens a network connection, to a host when given |
10
+ * | `shell`, `shell:<command line>` | Runs a shell command |
11
+ * | `code` | Runs code it was given, as an interpreter does |
12
+ * | `<name>`, `<name>:<detail>` | Anything the application names, such as `payments:refund` |
13
+ *
14
+ * A tool that declares `capabilities: []` does nothing to the world; one that declares none at all
15
+ * is undeclared, and a policy decides on it as such.
16
+ */
17
+ /** One capability, split into its parts. */
18
+ export interface ParsedCapability {
19
+ /** `filesystem`, `network`, `shell`, `code`, or the application's own name. */
20
+ kind: string;
21
+ /** `read` or `write`, for the filesystem. */
22
+ access?: 'read' | 'write';
23
+ /** The path, host, command, or detail, when the capability names one. */
24
+ target?: string;
25
+ }
26
+ /** Splits a capability string into its kind, access, and target. */
27
+ export declare function parseCapability(capability: string): ParsedCapability;
28
+ /**
29
+ * The capabilities one call of a tool declares: its static list, or what its function computes from
30
+ * the call's arguments. `undefined` means undeclared — no list, or a function that threw — which is
31
+ * not the same as `[]`, a tool that declares it does nothing to the world.
32
+ */
33
+ export declare function capabilitiesOf(tool: Pick<ToolDefinition, 'capabilities'> | undefined, args: Record<string, unknown>): string[] | undefined;
34
+ /**
35
+ * Whether a capability is sensitive: anything but reading files. A pure tool declares
36
+ * `capabilities: []`; whatever it does declare, a write, a command, code, the network, or an
37
+ * effect of the application's own such as `payments`, changes the world or leaves the process.
38
+ */
39
+ export declare function isSensitiveCapability(capability: string): boolean;
@@ -0,0 +1,36 @@
1
+ export function parseCapability(capability) {
2
+ const text = capability.trim();
3
+ const colon = text.indexOf(':');
4
+ const kind = (colon < 0 ? text : text.slice(0, colon)).toLowerCase();
5
+ const rest = colon < 0 ? undefined : text.slice(colon + 1);
6
+ if (kind === 'filesystem') {
7
+ if (!rest)
8
+ return { kind };
9
+ const [access, ...path] = rest.split(':');
10
+ const parsed = { kind };
11
+ if (access === 'read' || access === 'write')
12
+ parsed.access = access;
13
+ const target = parsed.access ? path.join(':') : rest;
14
+ if (target)
15
+ parsed.target = target;
16
+ return parsed;
17
+ }
18
+ return rest === undefined || rest === '' ? { kind } : { kind, target: rest };
19
+ }
20
+ export function capabilitiesOf(tool, args) {
21
+ const declared = tool?.capabilities;
22
+ if (!declared)
23
+ return undefined;
24
+ if (typeof declared !== 'function')
25
+ return [...declared];
26
+ try {
27
+ return [...declared(args)];
28
+ }
29
+ catch {
30
+ return undefined;
31
+ }
32
+ }
33
+ export function isSensitiveCapability(capability) {
34
+ const parsed = parseCapability(capability);
35
+ return !(parsed.kind === 'filesystem' && parsed.access === 'read');
36
+ }
@@ -1,9 +1,11 @@
1
1
  import type { OperationLifecycleLike } from '../types/lifecycle.js';
2
2
  import { type CompiledGraph } from '../graph/graph.js';
3
- import type { GraphCheckpointer, NodeContext } from '../types/graph.js';
3
+ import type { GraphCheckpointer, InterruptRequest, NodeContext } from '../types/graph.js';
4
4
  import type { CompletionRequest, Message, ToolDefinition } from '../types/messages.js';
5
5
  import type { NexusResponse, StreamChunk } from '../types/response.js';
6
+ import type { Principal } from '../types/principal.js';
6
7
  import type { Store } from '../types/store.js';
8
+ import type { PermissionPolicyLike } from './permissions.js';
7
9
  /**
8
10
  * An agent as a graph.
9
11
  *
@@ -28,6 +30,10 @@ export interface AgentToolCall {
28
30
  name: string;
29
31
  /** Arguments, parsed from the model's JSON. */
30
32
  args: Record<string, unknown>;
33
+ /** What the call declares it does, when the tool declares capabilities. */
34
+ capabilities?: readonly string[];
35
+ /** Why the permission policy asked for approval, when it did. */
36
+ permission?: string;
31
37
  }
32
38
  /** What an approver may answer: allow, refuse with a reason, or allow with corrected arguments. */
33
39
  export type AgentApproval = boolean | {
@@ -42,24 +48,58 @@ export interface AgentApprovalPolicy {
42
48
  /** The question an operator sees. Defaults to naming the tool and its arguments. */
43
49
  reason?: (call: AgentToolCall) => string;
44
50
  }
51
+ /** What every middleware hook can read about the step it runs in. */
52
+ export interface AgentMiddlewareContext {
53
+ /** The agent's state at this step: the whole transcript, tool calls and results included. */
54
+ state: AgentState;
55
+ /** Long-term memory, when the agent has a store. */
56
+ store?: Store;
57
+ /** The thread the run belongs to. */
58
+ threadId: string;
59
+ /** The tenant the run is for, when it has one. */
60
+ tenantId?: string;
61
+ /** Who the run is for, when it has a principal: the caller the server authenticated. */
62
+ principal?: Readonly<Principal>;
63
+ /** Aborted when the run is cancelled or the step times out. A hook that waits should stop with it. */
64
+ signal: AbortSignal;
65
+ /**
66
+ * Suspends the run until a person answers, as `interruptOn` does. When the run resumes, the step
67
+ * runs again and this returns the answer instead of suspending.
68
+ */
69
+ interrupt<T = unknown>(request: InterruptRequest): T;
70
+ }
71
+ /** What `wrapModelCall` can read, and how it ends the run without calling the model. */
72
+ export interface AgentModelCallContext extends AgentMiddlewareContext {
73
+ /**
74
+ * Ends the run with this answer and `stopReason: 'stopped'`, without another model call. Return
75
+ * what it returns: `return context.stop('The model call limit was reached.')`.
76
+ */
77
+ stop(answer: string): NexusResponse;
78
+ }
45
79
  /** Hooks around the agent's model calls and tool calls. Each hook is optional. */
46
80
  export interface AgentMiddleware {
47
81
  /** Names the middleware in traces and errors. */
48
82
  name?: string;
49
83
  /** Adjusts the request before it is sent: trim history, add context, swap the model. */
50
- beforeModel?(context: {
84
+ beforeModel?(context: AgentMiddlewareContext & {
51
85
  request: CompletionRequest;
52
- state: AgentState;
53
- store?: Store;
54
86
  }): CompletionRequest | void | Promise<CompletionRequest | void>;
55
87
  /** Inspects or replaces the response: redact, validate, count. */
56
- afterModel?(context: {
88
+ afterModel?(context: AgentMiddlewareContext & {
57
89
  response: NexusResponse;
58
- state: AgentState;
59
- store?: Store;
60
90
  }): NexusResponse | void | Promise<NexusResponse | void>;
61
- /** Wraps a tool call, so a policy can log it, time it, or refuse it. */
62
- wrapToolCall?(call: AgentToolCall, next: () => Promise<AgentToolResult>): Promise<AgentToolResult> | AgentToolResult;
91
+ /**
92
+ * Wraps the model call itself, after every `beforeModel` and before every `afterModel`. `next`
93
+ * sends a request and may be called again, with the same request or a changed one, to retry or to
94
+ * fall back to another model. The first middleware is the outermost.
95
+ */
96
+ wrapModelCall?(request: CompletionRequest, next: (request: CompletionRequest) => Promise<NexusResponse>, context: AgentModelCallContext): Promise<NexusResponse> | NexusResponse;
97
+ /**
98
+ * Wraps a tool call, so a policy can log it, time it, retry it, or refuse it. `next` runs the
99
+ * rest of the chain and may be called again; given a call, it runs that call's arguments instead,
100
+ * and the permission policy decides them again first. The first middleware is the outermost.
101
+ */
102
+ wrapToolCall?(call: AgentToolCall, next: (call?: AgentToolCall) => Promise<AgentToolResult>, context: AgentMiddlewareContext): Promise<AgentToolResult> | AgentToolResult;
63
103
  }
64
104
  /** What a tool call produced. */
65
105
  export interface AgentToolResult {
@@ -88,6 +128,13 @@ export interface CreateAgentOptions {
88
128
  interruptOn?: Record<string, AgentApprovalPolicy | true>;
89
129
  /** Hooks around model and tool calls, applied in order. */
90
130
  middleware?: AgentMiddleware[];
131
+ /**
132
+ * Decides every tool call from the capabilities it declares, before it runs: allow it, deny it,
133
+ * or interrupt for a person's approval, as `interruptOn` does. A denied call reaches the model as a
134
+ * failed tool result naming the reason, and never runs. See `permissionPolicy()` in
135
+ * `nexus-ai-pro/agent/permissions`.
136
+ */
137
+ permissions?: PermissionPolicyLike;
91
138
  /** Long-term memory, available to tools and middleware as `store`. */
92
139
  store?: Store;
93
140
  /**
@@ -136,8 +183,11 @@ export type AgentState = {
136
183
  /** Why the agent stopped. */
137
184
  stopReason?: AgentStopReason;
138
185
  };
139
- /** `completed` when the model answered, `max_iterations` when it ran out of model calls. */
140
- export type AgentStopReason = 'completed' | 'max_iterations';
186
+ /**
187
+ * `completed` when the model answered, `max_iterations` when it ran out of model calls, `stopped`
188
+ * when a middleware ended the run through `context.stop()`.
189
+ */
190
+ export type AgentStopReason = 'completed' | 'max_iterations' | 'stopped';
141
191
  /** An agent: a compiled graph over the agent's channels. */
142
192
  export type AgentGraph = CompiledGraph<AgentChannels>;
143
193
  /** Wraps a question into the state an agent starts from. */