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,87 @@
1
+ import type { Message } from '../types/messages.js';
2
+ import type { Principal } from '../types/principal.js';
3
+ import { type ProtocolGraph, type ProtocolInterrupt } from './shared.js';
4
+ export type { ProtocolGraph, ProtocolInterrupt, ProtocolResult, ProtocolRunOptions } from './shared.js';
5
+ /** The protocol version this module speaks. */
6
+ export declare const ACP_PROTOCOL_VERSION = 1;
7
+ /** What a tool call does, so the editor can show it: ACP's tool kinds. */
8
+ export type AcpToolKind = 'read' | 'edit' | 'delete' | 'move' | 'search' | 'execute' | 'think' | 'fetch' | 'other';
9
+ /** Why a prompt's turn ended. */
10
+ export type AcpStopReason = 'end_turn' | 'max_tokens' | 'max_turn_requests' | 'refusal' | 'cancelled';
11
+ /** One block of a prompt: text, a file the editor embedded, or a link to one. */
12
+ export interface AcpContentBlock {
13
+ /** `text`, `resource`, `resource_link`, or a kind this agent does not read, such as `image`. */
14
+ type: string;
15
+ /** A text block's text. */
16
+ text?: string;
17
+ /** A link's URI. */
18
+ uri?: string;
19
+ /** A link's name. */
20
+ name?: string;
21
+ /** An embedded file. */
22
+ resource?: {
23
+ uri: string;
24
+ text?: string;
25
+ mimeType?: string;
26
+ };
27
+ }
28
+ /** What the agent tells the editor during a turn: ACP's `session/update`. */
29
+ export type AcpSessionUpdate = {
30
+ sessionUpdate: string;
31
+ } & Record<string, unknown>;
32
+ /** An editor session, as `input` sees it. */
33
+ export interface AcpSessionInfo {
34
+ /** Its id, which is also the graph's thread. */
35
+ id: string;
36
+ /** The directory the editor opened the session in. */
37
+ cwd: string;
38
+ /** The MCP servers the editor offered. */
39
+ mcpServers: unknown[];
40
+ }
41
+ /** Where the agent reads and writes: `process.stdin` and `process.stdout`, or any pair like them. */
42
+ export interface AcpStreams {
43
+ /** What the editor writes. */
44
+ input: AsyncIterable<Uint8Array | string>;
45
+ /** Where the agent writes. */
46
+ output: {
47
+ write(chunk: string): unknown;
48
+ };
49
+ }
50
+ /** Options for `serveAcp()`. */
51
+ export interface AcpOptions {
52
+ /** The agent's name and version, as the editor shows them. */
53
+ agentInfo?: {
54
+ name: string;
55
+ version: string;
56
+ title?: string;
57
+ };
58
+ /**
59
+ * The graph input for a prompt. Defaults to `{ messages }`: the session's conversation and the
60
+ * prompt, which is what an agent from `createAgent()` takes.
61
+ */
62
+ input?: (prompt: string, session: AcpSessionInfo, history: Message[]) => unknown;
63
+ /**
64
+ * The answer the next prompt gives a question that is not a tool approval. Such a question is
65
+ * asked as the agent's message, and the turn ends. Defaults to the prompt's text.
66
+ */
67
+ answer?: (prompt: string, interrupt: ProtocolInterrupt) => unknown;
68
+ /** What a tool does, for the editor. Defaults to a guess from its name. */
69
+ kind?: (name: string, args: unknown) => AcpToolKind;
70
+ /** Who the agent acts for: the person at the editor. */
71
+ principal?: Principal;
72
+ }
73
+ /** A running ACP connection. */
74
+ export interface AcpServer {
75
+ /** Resolves when the editor closes its end. */
76
+ closed: Promise<void>;
77
+ /** Stops every running prompt. */
78
+ close(): void;
79
+ }
80
+ /**
81
+ * Serves a graph to an editor over ACP. Run it as the agent's process:
82
+ *
83
+ * ```ts
84
+ * serveAcp(agent, { input: process.stdin, output: process.stdout }, { agentInfo: { name: 'reviewer', version: '1.0.0' } });
85
+ * ```
86
+ */
87
+ export declare function serveAcp(graph: ProtocolGraph, streams: AcpStreams, options?: AcpOptions): AcpServer;
@@ -0,0 +1,322 @@
1
+ import { answerOf, asText, messageOf, protocolId, toolCallOf, transcriptOf, } from './shared.js';
2
+ export const ACP_PROTOCOL_VERSION = 1;
3
+ export function serveAcp(graph, streams, options = {}) {
4
+ const sessions = new Map();
5
+ const waiting = new Map();
6
+ let requests = 0;
7
+ const write = (message) => streams.output.write(`${JSON.stringify(message)}\n`);
8
+ const notify = (sessionId, update) => write({ jsonrpc: '2.0', method: 'session/update', params: { sessionId, update } });
9
+ const request = (method, params, signal) => new Promise((resolve) => {
10
+ const id = `agent-${++requests}`;
11
+ const cancel = () => {
12
+ waiting.delete(id);
13
+ resolve({ result: { outcome: { outcome: 'cancelled' } } });
14
+ };
15
+ if (signal.aborted)
16
+ return cancel();
17
+ signal.addEventListener('abort', cancel, { once: true });
18
+ waiting.set(id, (message) => {
19
+ signal.removeEventListener('abort', cancel);
20
+ resolve(message);
21
+ });
22
+ write({ jsonrpc: '2.0', id, method, params });
23
+ });
24
+ const kind = options.kind ?? guessKind;
25
+ const answerText = options.answer ?? ((prompt) => prompt);
26
+ const permit = async (session, interrupt, signal) => {
27
+ const call = toolCallOf(interrupt);
28
+ const standing = session.always.get(call.name);
29
+ if (standing !== undefined)
30
+ return standing;
31
+ const response = await request('session/request_permission', {
32
+ sessionId: session.info.id,
33
+ toolCall: {
34
+ toolCallId: call.id,
35
+ title: interrupt.reason ?? titleOf(call.name, call.args),
36
+ kind: kind(call.name, call.args),
37
+ status: 'pending',
38
+ rawInput: call.args,
39
+ },
40
+ options: [
41
+ { optionId: 'allow_once', name: 'Allow', kind: 'allow_once' },
42
+ { optionId: 'allow_always', name: `Always allow ${call.name}`, kind: 'allow_always' },
43
+ { optionId: 'reject_once', name: 'Reject', kind: 'reject_once' },
44
+ { optionId: 'reject_always', name: `Always reject ${call.name}`, kind: 'reject_always' },
45
+ ],
46
+ }, signal);
47
+ const outcome = response.result?.outcome;
48
+ if (outcome?.outcome !== 'selected')
49
+ return 'cancelled';
50
+ const allowed = outcome.optionId?.startsWith('allow') ?? false;
51
+ if (outcome.optionId?.endsWith('always'))
52
+ session.always.set(call.name, allowed);
53
+ return allowed;
54
+ };
55
+ const prompt = async (session, blocks) => {
56
+ session.controller?.abort();
57
+ const controller = new AbortController();
58
+ session.controller = controller;
59
+ const id = session.info.id;
60
+ const text = promptText(blocks);
61
+ let spoke = false;
62
+ const calls = new Map();
63
+ const runOptions = {
64
+ threadId: id,
65
+ signal: controller.signal,
66
+ ...(options.principal ? { principal: options.principal } : {}),
67
+ onEvent: (event) => {
68
+ if (event.namespace)
69
+ return;
70
+ if (event.type === 'message' && event.chunk.content) {
71
+ spoke = true;
72
+ notify(id, {
73
+ sessionUpdate: event.chunk.kind === 'reasoning' ? 'agent_thought_chunk' : 'agent_message_chunk',
74
+ content: { type: 'text', text: event.chunk.content },
75
+ });
76
+ }
77
+ else if (event.type === 'tool') {
78
+ spoke = false;
79
+ for (const update of toolUpdates(event.tool, kind, calls))
80
+ notify(id, update);
81
+ }
82
+ },
83
+ };
84
+ try {
85
+ return await turn(session, text, runOptions, controller.signal, () => spoke);
86
+ }
87
+ catch (error) {
88
+ if (controller.signal.aborted)
89
+ return 'cancelled';
90
+ throw error;
91
+ }
92
+ };
93
+ const turn = async (session, text, runOptions, signal, spoke) => {
94
+ const id = session.info.id;
95
+ const user = messageOf('user', text);
96
+ let result;
97
+ if (session.pending?.length) {
98
+ const answers = {
99
+ ...session.answered,
100
+ ...Object.fromEntries(session.pending.map((item) => [item.id, answerText(text, item)])),
101
+ };
102
+ session.pending = undefined;
103
+ session.answered = undefined;
104
+ session.history.push(user);
105
+ result = await graph.resumeInterruptsWith(id, answers, runOptions);
106
+ }
107
+ else {
108
+ const history = session.history;
109
+ result = await graph.invoke(options.input ? options.input(text, session.info, history) : { messages: [...history, user] }, runOptions);
110
+ session.history = [...history, user];
111
+ }
112
+ while (result.status === 'awaiting_input' && result.interrupts?.length) {
113
+ if (signal.aborted)
114
+ return 'cancelled';
115
+ const approvals = result.interrupts.filter((item) => toolCallOf(item));
116
+ const questions = result.interrupts.filter((item) => !toolCallOf(item));
117
+ const answers = {};
118
+ for (const interrupt of approvals) {
119
+ const decision = await permit(session, interrupt, signal);
120
+ if (decision === 'cancelled')
121
+ return 'cancelled';
122
+ answers[interrupt.id] = decision;
123
+ }
124
+ if (questions.length) {
125
+ notify(id, {
126
+ sessionUpdate: 'agent_message_chunk',
127
+ content: { type: 'text', text: questions.map(questionOf).join('\n') },
128
+ });
129
+ session.pending = questions;
130
+ session.answered = answers;
131
+ return 'end_turn';
132
+ }
133
+ result = await graph.resumeInterruptsWith(id, answers, runOptions);
134
+ }
135
+ if (signal.aborted || result.status === 'interrupted')
136
+ return 'cancelled';
137
+ const answer = answerOf(result.state);
138
+ if (!spoke() && answer)
139
+ notify(id, { sessionUpdate: 'agent_message_chunk', content: { type: 'text', text: answer } });
140
+ session.history = transcriptOf(result.state, [...session.history, messageOf('assistant', answer)]);
141
+ return result.state?.stopReason === 'max_iterations'
142
+ ? 'max_turn_requests'
143
+ : 'end_turn';
144
+ };
145
+ const handle = async (message) => {
146
+ const params = message.params ?? {};
147
+ switch (message.method) {
148
+ case 'initialize':
149
+ return {
150
+ protocolVersion: ACP_PROTOCOL_VERSION,
151
+ agentCapabilities: {
152
+ loadSession: false,
153
+ promptCapabilities: { image: false, audio: false, embeddedContext: true },
154
+ },
155
+ authMethods: [],
156
+ ...(options.agentInfo ? { agentInfo: options.agentInfo } : {}),
157
+ };
158
+ case 'authenticate':
159
+ return {};
160
+ case 'session/new': {
161
+ const info = {
162
+ id: protocolId('session'),
163
+ cwd: typeof params.cwd === 'string' ? params.cwd : '',
164
+ mcpServers: Array.isArray(params.mcpServers) ? params.mcpServers : [],
165
+ };
166
+ sessions.set(info.id, { info, history: [], always: new Map() });
167
+ return { sessionId: info.id };
168
+ }
169
+ case 'session/prompt': {
170
+ const session = sessions.get(String(params.sessionId));
171
+ if (!session)
172
+ throw Object.assign(new Error(`Session ${String(params.sessionId)} was not found`), { code: -32602 });
173
+ return {
174
+ stopReason: await prompt(session, Array.isArray(params.prompt) ? params.prompt : []),
175
+ };
176
+ }
177
+ default:
178
+ throw Object.assign(new Error(`Method ${String(message.method)} is not supported`), { code: -32601 });
179
+ }
180
+ };
181
+ const receive = (message) => {
182
+ if (message.method === undefined) {
183
+ if (message.id !== undefined && message.id !== null)
184
+ waiting.get(message.id)?.(message);
185
+ waiting.delete(message.id);
186
+ return;
187
+ }
188
+ if (message.id === undefined || message.id === null) {
189
+ if (message.method === 'session/cancel')
190
+ sessions.get(String(message.params?.sessionId))?.controller?.abort();
191
+ return;
192
+ }
193
+ handle(message).then((result) => write({ jsonrpc: '2.0', id: message.id, result }), (error) => write({
194
+ jsonrpc: '2.0',
195
+ id: message.id,
196
+ error: { code: typeof error.code === 'number' ? error.code : -32603, message: error.message },
197
+ }));
198
+ };
199
+ const closed = (async () => {
200
+ const decoder = new TextDecoder();
201
+ let buffer = '';
202
+ for await (const chunk of streams.input) {
203
+ buffer += typeof chunk === 'string' ? chunk : decoder.decode(chunk, { stream: true });
204
+ let newline = buffer.indexOf('\n');
205
+ while (newline !== -1) {
206
+ const line = buffer.slice(0, newline).trim();
207
+ buffer = buffer.slice(newline + 1);
208
+ if (line) {
209
+ try {
210
+ receive(JSON.parse(line));
211
+ }
212
+ catch {
213
+ write({ jsonrpc: '2.0', id: null, error: { code: -32700, message: 'A line is not JSON' } });
214
+ }
215
+ }
216
+ newline = buffer.indexOf('\n');
217
+ }
218
+ }
219
+ })();
220
+ return {
221
+ closed,
222
+ close() {
223
+ for (const session of sessions.values())
224
+ session.controller?.abort();
225
+ },
226
+ };
227
+ }
228
+ function toolUpdates(tool, kind, calls) {
229
+ const args = (tool.args ?? calls.get(tool.id) ?? {});
230
+ if (tool.phase === 'start') {
231
+ calls.set(tool.id, args);
232
+ const updates = [
233
+ {
234
+ sessionUpdate: 'tool_call',
235
+ toolCallId: tool.id,
236
+ title: titleOf(tool.name, args),
237
+ kind: kind(tool.name, args),
238
+ status: 'in_progress',
239
+ rawInput: args,
240
+ ...(typeof args.path === 'string' ? { locations: [{ path: args.path }] } : {}),
241
+ },
242
+ ];
243
+ if (tool.name === 'write_todos' && Array.isArray(args.todos)) {
244
+ updates.push({
245
+ sessionUpdate: 'plan',
246
+ entries: args.todos.map((todo) => ({
247
+ content: String(todo.content ?? ''),
248
+ priority: 'medium',
249
+ status: todo.status === 'in_progress' || todo.status === 'completed' ? todo.status : 'pending',
250
+ })),
251
+ });
252
+ }
253
+ return updates;
254
+ }
255
+ if (tool.phase !== 'result' && tool.phase !== 'error')
256
+ return [];
257
+ const content = [];
258
+ if (tool.phase === 'result' && typeof args.path === 'string') {
259
+ const oldText = args.old_text ?? args.oldText;
260
+ const newText = args.new_text ?? args.newText ?? (tool.name === 'write_file' ? args.content : undefined);
261
+ if (typeof newText === 'string') {
262
+ content.push({ type: 'diff', path: args.path, oldText: typeof oldText === 'string' ? oldText : null, newText });
263
+ }
264
+ }
265
+ content.push({
266
+ type: 'content',
267
+ content: { type: 'text', text: tool.phase === 'result' ? asText(tool.result) : (tool.error ?? 'The tool failed') },
268
+ });
269
+ return [
270
+ {
271
+ sessionUpdate: 'tool_call_update',
272
+ toolCallId: tool.id,
273
+ status: tool.phase === 'result' ? 'completed' : 'failed',
274
+ content,
275
+ ...(tool.phase === 'result' ? { rawOutput: tool.result } : {}),
276
+ },
277
+ ];
278
+ }
279
+ function guessKind(name) {
280
+ const lower = name.toLowerCase();
281
+ if (lower === 'write_todos' || /think|plan/.test(lower))
282
+ return 'think';
283
+ if (/delete|remove|^rm$/.test(lower))
284
+ return 'delete';
285
+ if (/move|rename|^mv$/.test(lower))
286
+ return 'move';
287
+ if (/edit|write|patch|replace|create/.test(lower))
288
+ return 'edit';
289
+ if (/grep|glob|search|find|query/.test(lower))
290
+ return 'search';
291
+ if (/read|^ls$|list|cat|open|view/.test(lower))
292
+ return 'read';
293
+ if (/exec|shell|bash|run|command|terminal/.test(lower))
294
+ return 'execute';
295
+ if (/fetch|http|url|web|download|browse/.test(lower))
296
+ return 'fetch';
297
+ return 'other';
298
+ }
299
+ function titleOf(name, args) {
300
+ const values = (args ?? {});
301
+ const subject = [values.path, values.command, values.query, values.url, values.pattern].find((value) => typeof value === 'string');
302
+ return subject ? `${name} ${subject}` : name;
303
+ }
304
+ function questionOf(interrupt) {
305
+ return (interrupt.reason ??
306
+ (interrupt.payload === undefined ? 'The agent needs an answer to continue.' : asText(interrupt.payload)));
307
+ }
308
+ function promptText(blocks) {
309
+ return blocks
310
+ .map((block) => {
311
+ if (block.type === 'text')
312
+ return block.text ?? '';
313
+ if (block.type === 'resource' && typeof block.resource?.text === 'string') {
314
+ return `${block.resource.uri}\n\`\`\`\n${block.resource.text}\n\`\`\``;
315
+ }
316
+ if (block.type === 'resource_link' && block.uri)
317
+ return `@${block.uri}`;
318
+ return '';
319
+ })
320
+ .filter(Boolean)
321
+ .join('\n\n');
322
+ }
@@ -0,0 +1,120 @@
1
+ import type { Message } from '../types/messages.js';
2
+ import type { Principal } from '../types/principal.js';
3
+ import { type ProtocolGraph } from './shared.js';
4
+ export type { ProtocolGraph, ProtocolInterrupt, ProtocolResult, ProtocolRunOptions } from './shared.js';
5
+ /** A message in AG-UI's shape. */
6
+ export interface AgUiMessage {
7
+ /** Its id. */
8
+ id: string;
9
+ /** `user`, `assistant`, `system`, `developer`, or `tool`; other roles are passed over. */
10
+ role: string;
11
+ /** Its text, or a list of parts with text. */
12
+ content?: unknown;
13
+ /** The tool calls an assistant message made. */
14
+ toolCalls?: Array<{
15
+ id: string;
16
+ type: 'function';
17
+ function: {
18
+ name: string;
19
+ arguments: string;
20
+ };
21
+ }>;
22
+ /** The call a tool message answers. */
23
+ toolCallId?: string;
24
+ }
25
+ /** One answer to an interrupt, in a resumed run. */
26
+ export interface AgUiResumeEntry {
27
+ /** The interrupt it answers. */
28
+ interruptId: string;
29
+ /** `resolved` with a payload, or `cancelled`. */
30
+ status: 'resolved' | 'cancelled';
31
+ /** The answer. */
32
+ payload?: unknown;
33
+ }
34
+ /** What a frontend sends to start or resume a run: AG-UI's `RunAgentInput`. */
35
+ export interface AgUiRunInput {
36
+ /** The conversation. */
37
+ threadId: string;
38
+ /** This run. */
39
+ runId: string;
40
+ /** The run this one continues, when it does. */
41
+ parentRunId?: string;
42
+ /** The whole conversation so far. */
43
+ messages: AgUiMessage[];
44
+ /** Tools the frontend offers. Passed to `input` for an application that uses them. */
45
+ tools?: Array<{
46
+ name: string;
47
+ description: string;
48
+ parameters: unknown;
49
+ }>;
50
+ /** Extra context the frontend supplies. */
51
+ context?: Array<{
52
+ description: string;
53
+ value: string;
54
+ }>;
55
+ /** Shared state, when the frontend keeps any. */
56
+ state?: unknown;
57
+ /** Anything else the frontend forwards. */
58
+ forwardedProps?: unknown;
59
+ /** Answers to the questions a paused run asked. */
60
+ resume?: AgUiResumeEntry[];
61
+ }
62
+ /** A question a paused run asks, in AG-UI's shape. */
63
+ export interface AgUiInterrupt {
64
+ /** Its id, which a resume entry names. */
65
+ id: string;
66
+ /** `tool_call` for an approval, `input_required` for anything else. */
67
+ reason: string;
68
+ /** The question, for a person. */
69
+ message?: string;
70
+ /** The tool call awaiting approval, when it is one. */
71
+ toolCallId?: string;
72
+ /** What the run asked about, whole. */
73
+ metadata?: Record<string, unknown>;
74
+ }
75
+ /** An AG-UI event, as the stream carries it. */
76
+ export type AgUiEvent = {
77
+ type: string;
78
+ timestamp?: number;
79
+ } & Record<string, unknown>;
80
+ /** Options for `agUiEvents()` and `agUiHandler()`. */
81
+ export interface AgUiOptions {
82
+ /**
83
+ * The graph input for a run. Defaults to `{ messages }`, the conversation as Nexus messages,
84
+ * which is what an agent from `createAgent()` takes.
85
+ */
86
+ input?: (run: AgUiRunInput, messages: Message[]) => unknown;
87
+ /** The answer a resume entry gives a question. Defaults to its payload, `true` when it has none, and `false` when cancelled. */
88
+ answer?: (entry: AgUiResumeEntry) => unknown;
89
+ /** Who the run is for, from the request: the place to authenticate a frontend's caller. */
90
+ principal?: (request: Request) => Principal | undefined | Promise<Principal | undefined>;
91
+ /** Adds a `STATE_SNAPSHOT` with the final state before the run finishes. Defaults to true. */
92
+ stateSnapshot?: boolean;
93
+ }
94
+ /** Options for `agUiEvents()`: everything `agUiHandler()` takes, with the caller already known. */
95
+ export interface AgUiEventsOptions extends Omit<AgUiOptions, 'principal'> {
96
+ /** Stops the run. */
97
+ signal?: AbortSignal;
98
+ /** Who the run is for. */
99
+ principal?: Principal;
100
+ }
101
+ /** The conversation from a `RunAgentInput`, as Nexus messages. */
102
+ export declare function agUiMessages(messages: readonly AgUiMessage[]): Message[];
103
+ /**
104
+ * A run as AG-UI events, for any transport: Server-Sent Events, a WebSocket, a test. Events are
105
+ * produced as the graph emits them; the last is `RUN_FINISHED` or `RUN_ERROR`.
106
+ */
107
+ export declare function agUiEvents(graph: ProtocolGraph, run: AgUiRunInput, options?: AgUiEventsOptions): AsyncGenerator<AgUiEvent>;
108
+ /**
109
+ * An HTTP handler that serves a graph to AG-UI frontends: POST a `RunAgentInput`, read the run as
110
+ * Server-Sent Events. Mount it on any route, under any framework that speaks `Request` and
111
+ * `Response`.
112
+ *
113
+ * ```ts
114
+ * const handler = agUiHandler(agent);
115
+ * app.post('/agent', (request) => handler(request));
116
+ * ```
117
+ */
118
+ export declare function agUiHandler(graph: ProtocolGraph, options?: AgUiOptions): (request: Request) => Promise<Response>;
119
+ /** One event as a Server-Sent Event: `data: <json>` and a blank line. */
120
+ export declare function encodeAgUiEvent(event: AgUiEvent): string;