@finalai/agent-provider 0.1.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.

Potentially problematic release.


This version of @finalai/agent-provider might be problematic. Click here for more details.

Files changed (176) hide show
  1. package/README.md +12 -0
  2. package/dist/modules/channel-context.d.mts +102 -0
  3. package/dist/modules/channel-context.mjs +52 -0
  4. package/dist/modules/channel-context.mjs.map +7 -0
  5. package/dist/modules/channel-socket.d.mts +65 -0
  6. package/dist/modules/channel-socket.mjs +188 -0
  7. package/dist/modules/channel-socket.mjs.map +7 -0
  8. package/dist/modules/channel.d.mts +382 -0
  9. package/dist/modules/channel.mjs +146 -0
  10. package/dist/modules/channel.mjs.map +7 -0
  11. package/dist/modules/conformance/agent.d.mts +20 -0
  12. package/dist/modules/conformance/agent.mjs +623 -0
  13. package/dist/modules/conformance/agent.mjs.map +7 -0
  14. package/dist/modules/conformance/fixtures.d.mts +41 -0
  15. package/dist/modules/conformance/fixtures.mjs +190 -0
  16. package/dist/modules/conformance/fixtures.mjs.map +7 -0
  17. package/dist/modules/conformance/harness-kit.d.mts +82 -0
  18. package/dist/modules/conformance/harness-kit.mjs +1303 -0
  19. package/dist/modules/conformance/harness-kit.mjs.map +7 -0
  20. package/dist/modules/conformance/image.d.mts +2 -0
  21. package/dist/modules/conformance/image.mjs +79 -0
  22. package/dist/modules/conformance/image.mjs.map +7 -0
  23. package/dist/modules/conformance/index.d.mts +8 -0
  24. package/dist/modules/conformance/index.mjs +12 -0
  25. package/dist/modules/conformance/index.mjs.map +7 -0
  26. package/dist/modules/conformance/local-harness.d.mts +25 -0
  27. package/dist/modules/conformance/local-harness.mjs +108 -0
  28. package/dist/modules/conformance/local-harness.mjs.map +7 -0
  29. package/dist/modules/conformance/protocol.d.mts +30 -0
  30. package/dist/modules/conformance/protocol.mjs +56 -0
  31. package/dist/modules/conformance/protocol.mjs.map +7 -0
  32. package/dist/modules/conformance/sandbox-kit.d.mts +19 -0
  33. package/dist/modules/conformance/sandbox-kit.mjs +320 -0
  34. package/dist/modules/conformance/sandbox-kit.mjs.map +7 -0
  35. package/dist/modules/conformance/scripted-model/chat-completions.d.mts +30 -0
  36. package/dist/modules/conformance/scripted-model/chat-completions.mjs +125 -0
  37. package/dist/modules/conformance/scripted-model/chat-completions.mjs.map +7 -0
  38. package/dist/modules/conformance/scripted-model/directives.d.mts +84 -0
  39. package/dist/modules/conformance/scripted-model/directives.mjs +304 -0
  40. package/dist/modules/conformance/scripted-model/directives.mjs.map +7 -0
  41. package/dist/modules/conformance/scripted-model/handler.d.mts +14 -0
  42. package/dist/modules/conformance/scripted-model/handler.mjs +133 -0
  43. package/dist/modules/conformance/scripted-model/handler.mjs.map +7 -0
  44. package/dist/modules/conformance/scripted-model/index.d.mts +6 -0
  45. package/dist/modules/conformance/scripted-model/index.mjs +7 -0
  46. package/dist/modules/conformance/scripted-model/index.mjs.map +7 -0
  47. package/dist/modules/conformance/scripted-model/messages.d.mts +39 -0
  48. package/dist/modules/conformance/scripted-model/messages.mjs +139 -0
  49. package/dist/modules/conformance/scripted-model/messages.mjs.map +7 -0
  50. package/dist/modules/conformance/scripted-model/responses.d.mts +62 -0
  51. package/dist/modules/conformance/scripted-model/responses.mjs +273 -0
  52. package/dist/modules/conformance/scripted-model/responses.mjs.map +7 -0
  53. package/dist/modules/conformance/scripted-model/sse.d.mts +15 -0
  54. package/dist/modules/conformance/scripted-model/sse.mjs +75 -0
  55. package/dist/modules/conformance/scripted-model/sse.mjs.map +7 -0
  56. package/dist/modules/conformance/v1-agent.d.mts +24 -0
  57. package/dist/modules/conformance/v1-agent.mjs +40 -0
  58. package/dist/modules/conformance/v1-agent.mjs.map +7 -0
  59. package/dist/modules/credential-routes.d.mts +24 -0
  60. package/dist/modules/credential-routes.mjs +25 -0
  61. package/dist/modules/credential-routes.mjs.map +7 -0
  62. package/dist/modules/credentials.d.mts +206 -0
  63. package/dist/modules/credentials.mjs +207 -0
  64. package/dist/modules/credentials.mjs.map +7 -0
  65. package/dist/modules/dynamic.d.mts +32 -0
  66. package/dist/modules/dynamic.mjs +77 -0
  67. package/dist/modules/dynamic.mjs.map +7 -0
  68. package/dist/modules/harness.d.mts +397 -0
  69. package/dist/modules/harness.mjs +213 -0
  70. package/dist/modules/harness.mjs.map +7 -0
  71. package/dist/modules/index.d.mts +15 -0
  72. package/dist/modules/index.mjs +40 -0
  73. package/dist/modules/index.mjs.map +7 -0
  74. package/dist/modules/json.d.mts +12 -0
  75. package/dist/modules/json.mjs +19 -0
  76. package/dist/modules/json.mjs.map +7 -0
  77. package/dist/modules/local-channel-socket.d.mts +23 -0
  78. package/dist/modules/local-channel-socket.mjs +141 -0
  79. package/dist/modules/local-channel-socket.mjs.map +7 -0
  80. package/dist/modules/manifest.d.mts +558 -0
  81. package/dist/modules/manifest.mjs +266 -0
  82. package/dist/modules/manifest.mjs.map +7 -0
  83. package/dist/modules/mcp-content.d.mts +21 -0
  84. package/dist/modules/mcp-content.mjs +86 -0
  85. package/dist/modules/mcp-content.mjs.map +7 -0
  86. package/dist/modules/provider-ref.d.mts +29 -0
  87. package/dist/modules/provider-ref.mjs +55 -0
  88. package/dist/modules/provider-ref.mjs.map +7 -0
  89. package/dist/modules/sandbox/bytes.d.mts +9 -0
  90. package/dist/modules/sandbox/bytes.mjs +154 -0
  91. package/dist/modules/sandbox/bytes.mjs.map +7 -0
  92. package/dist/modules/sandbox/client.d.mts +51 -0
  93. package/dist/modules/sandbox/client.mjs +500 -0
  94. package/dist/modules/sandbox/client.mjs.map +7 -0
  95. package/dist/modules/sandbox/confined-files.d.mts +22 -0
  96. package/dist/modules/sandbox/confined-files.mjs +142 -0
  97. package/dist/modules/sandbox/confined-files.mjs.map +7 -0
  98. package/dist/modules/sandbox/convenience.d.mts +10 -0
  99. package/dist/modules/sandbox/convenience.mjs +116 -0
  100. package/dist/modules/sandbox/convenience.mjs.map +7 -0
  101. package/dist/modules/sandbox/editor.d.mts +49 -0
  102. package/dist/modules/sandbox/editor.mjs +43 -0
  103. package/dist/modules/sandbox/editor.mjs.map +7 -0
  104. package/dist/modules/sandbox/frame-channel.d.mts +47 -0
  105. package/dist/modules/sandbox/frame-channel.mjs +153 -0
  106. package/dist/modules/sandbox/frame-channel.mjs.map +7 -0
  107. package/dist/modules/sandbox/index.d.mts +18 -0
  108. package/dist/modules/sandbox/index.mjs +70 -0
  109. package/dist/modules/sandbox/index.mjs.map +7 -0
  110. package/dist/modules/sandbox/mcp-channel.d.mts +9 -0
  111. package/dist/modules/sandbox/mcp-channel.mjs +77 -0
  112. package/dist/modules/sandbox/mcp-channel.mjs.map +7 -0
  113. package/dist/modules/sandbox/mcp-hosted.d.mts +46 -0
  114. package/dist/modules/sandbox/mcp-hosted.mjs +221 -0
  115. package/dist/modules/sandbox/mcp-hosted.mjs.map +7 -0
  116. package/dist/modules/sandbox/mcp-search.d.mts +51 -0
  117. package/dist/modules/sandbox/mcp-search.mjs +129 -0
  118. package/dist/modules/sandbox/mcp-search.mjs.map +7 -0
  119. package/dist/modules/sandbox/mcp-shell.d.mts +21 -0
  120. package/dist/modules/sandbox/mcp-shell.mjs +205 -0
  121. package/dist/modules/sandbox/mcp-shell.mjs.map +7 -0
  122. package/dist/modules/sandbox/mcp-testing.d.mts +11 -0
  123. package/dist/modules/sandbox/mcp-testing.mjs +33 -0
  124. package/dist/modules/sandbox/mcp-testing.mjs.map +7 -0
  125. package/dist/modules/sandbox/mcp.d.mts +83 -0
  126. package/dist/modules/sandbox/mcp.mjs +971 -0
  127. package/dist/modules/sandbox/mcp.mjs.map +7 -0
  128. package/dist/modules/sandbox/memory-sandbox.d.mts +32 -0
  129. package/dist/modules/sandbox/memory-sandbox.mjs +416 -0
  130. package/dist/modules/sandbox/memory-sandbox.mjs.map +7 -0
  131. package/dist/modules/sandbox/memory-shell.d.mts +29 -0
  132. package/dist/modules/sandbox/memory-shell.mjs +278 -0
  133. package/dist/modules/sandbox/memory-shell.mjs.map +7 -0
  134. package/dist/modules/sandbox/open-scope-node.d.mts +4 -0
  135. package/dist/modules/sandbox/open-scope-node.mjs +19 -0
  136. package/dist/modules/sandbox/open-scope-node.mjs.map +7 -0
  137. package/dist/modules/sandbox/open-scope.d.mts +16 -0
  138. package/dist/modules/sandbox/open-scope.mjs +66 -0
  139. package/dist/modules/sandbox/open-scope.mjs.map +7 -0
  140. package/dist/modules/sandbox/paths.d.mts +7 -0
  141. package/dist/modules/sandbox/paths.mjs +50 -0
  142. package/dist/modules/sandbox/paths.mjs.map +7 -0
  143. package/dist/modules/sandbox/rpc-peer.d.mts +35 -0
  144. package/dist/modules/sandbox/rpc-peer.mjs +224 -0
  145. package/dist/modules/sandbox/rpc-peer.mjs.map +7 -0
  146. package/dist/modules/sandbox/seeds.d.mts +26 -0
  147. package/dist/modules/sandbox/seeds.mjs +228 -0
  148. package/dist/modules/sandbox/seeds.mjs.map +7 -0
  149. package/dist/modules/sandbox/server.d.mts +66 -0
  150. package/dist/modules/sandbox/server.mjs +567 -0
  151. package/dist/modules/sandbox/server.mjs.map +7 -0
  152. package/dist/modules/sandbox/snapshots.d.mts +49 -0
  153. package/dist/modules/sandbox/snapshots.mjs +55 -0
  154. package/dist/modules/sandbox/snapshots.mjs.map +7 -0
  155. package/dist/modules/sandbox/stream-mux.d.mts +18 -0
  156. package/dist/modules/sandbox/stream-mux.mjs +285 -0
  157. package/dist/modules/sandbox/stream-mux.mjs.map +7 -0
  158. package/dist/modules/sandbox/testing.d.mts +25 -0
  159. package/dist/modules/sandbox/testing.mjs +64 -0
  160. package/dist/modules/sandbox/testing.mjs.map +7 -0
  161. package/dist/modules/sandbox/types.d.mts +352 -0
  162. package/dist/modules/sandbox/types.mjs +86 -0
  163. package/dist/modules/sandbox/types.mjs.map +7 -0
  164. package/dist/modules/sandbox/wire.d.mts +671 -0
  165. package/dist/modules/sandbox/wire.mjs +537 -0
  166. package/dist/modules/sandbox/wire.mjs.map +7 -0
  167. package/dist/modules/sandbox/workspace-root.d.mts +8 -0
  168. package/dist/modules/sandbox/workspace-root.mjs +79 -0
  169. package/dist/modules/sandbox/workspace-root.mjs.map +7 -0
  170. package/dist/modules/schemas.d.mts +121 -0
  171. package/dist/modules/schemas.mjs +146 -0
  172. package/dist/modules/schemas.mjs.map +7 -0
  173. package/dist/modules/semantic-events.d.mts +31 -0
  174. package/dist/modules/semantic-events.mjs +23 -0
  175. package/dist/modules/semantic-events.mjs.map +7 -0
  176. package/package.json +199 -0
@@ -0,0 +1,623 @@
1
+ import {
2
+ agent,
3
+ methods,
4
+ PROTOCOL_VERSION,
5
+ RequestError
6
+ } from "@agentclientprotocol/sdk/experimental/v2";
7
+ import {
8
+ RESOURCE_LINK_DESCRIPTION_BYTES,
9
+ utf8Prefix
10
+ } from "@finalai/acp-session";
11
+ import {
12
+ Client,
13
+ StreamableHTTPClientTransport
14
+ } from "@modelcontextprotocol/client";
15
+ import * as z from "zod";
16
+ import { PromptWhileRunning } from "../harness.mjs";
17
+ import { jsonValueSchema } from "../json.mjs";
18
+ import { conformanceImageBase64 } from "./image.mjs";
19
+ import {
20
+ AFTER_SEQ_REPLAY_TYPE,
21
+ ConformanceDirective,
22
+ FINAL_META_KEY,
23
+ OBSERVE_METHOD,
24
+ parseDirective
25
+ } from "./protocol.mjs";
26
+ const observeParamsSchema = z.object({
27
+ sessionId: z.string(),
28
+ content: z.array(z.object({ type: z.string(), text: z.string().optional() }).passthrough())
29
+ });
30
+ const textOf = (content) => content.map((block) => textBlockSchema.safeParse(block).data?.text ?? "").join("");
31
+ const authorMetaSchema = z.object({
32
+ _meta: z.object({
33
+ [FINAL_META_KEY]: z.object({ author: z.object({ displayName: z.string().min(1) }) })
34
+ })
35
+ });
36
+ const directiveTextOf = (content, text) => {
37
+ const author = content.map((block) => authorMetaSchema.safeParse(block).data?._meta[FINAL_META_KEY].author).find((entry) => entry != null);
38
+ const trimmed = text.trimStart();
39
+ if (author != null && trimmed.startsWith(`${author.displayName}: `))
40
+ return trimmed.slice(author.displayName.length + 2);
41
+ const prefixed = /^[^\n]+?: (conformance:[\s\S]*)$/u.exec(trimmed);
42
+ return prefixed?.[1] ?? text;
43
+ };
44
+ const randomId = () => crypto.randomUUID();
45
+ const delay = (ms, signal) => new Promise((resolve) => {
46
+ if (signal.aborted) {
47
+ resolve();
48
+ return;
49
+ }
50
+ const timer = setTimeout(resolve, ms);
51
+ signal.addEventListener(
52
+ "abort",
53
+ () => {
54
+ clearTimeout(timer);
55
+ resolve();
56
+ },
57
+ { once: true }
58
+ );
59
+ });
60
+ const toolResultSchema = z.object({
61
+ content: z.array(z.object({ type: z.string(), text: z.string().optional() }))
62
+ });
63
+ const mcpResultText = (parsed) => parsed.success ? parsed.data.content.map((block) => block.text ?? "").join("") : "unreadable tool result";
64
+ const textBlockSchema = z.object({ type: z.literal("text"), text: z.string() });
65
+ const acpServerSchema = z.object({
66
+ type: z.literal("acp"),
67
+ name: z.string(),
68
+ serverId: z.string()
69
+ });
70
+ const httpServerSchema = z.object({
71
+ type: z.literal("http"),
72
+ name: z.string(),
73
+ url: z.string(),
74
+ headers: z.array(z.object({ name: z.string(), value: z.string() })).optional()
75
+ });
76
+ const namedServerSchema = z.object({ name: z.string() });
77
+ const afterSeqSchema = z.object({ seq: z.number().int().nonnegative() });
78
+ const permissionResultSchema = z.object({
79
+ outcome: z.union([
80
+ z.object({ outcome: z.literal("selected"), optionId: z.string() }),
81
+ z.object({ outcome: z.literal("cancelled") })
82
+ ])
83
+ });
84
+ const elicitationResultSchema = z.object({
85
+ action: z.string(),
86
+ content: z.record(z.string(), z.unknown()).optional()
87
+ });
88
+ const rawRequestSchema = z.object({ id: z.union([z.string(), z.number()]), method: z.string() });
89
+ const rawResponseSchema = z.object({
90
+ id: z.union([z.string(), z.number()]),
91
+ result: jsonValueSchema
92
+ });
93
+ const rawErrorSchema = z.object({ id: z.union([z.string(), z.number()]), error: z.unknown() });
94
+ const isBatch = (wire) => Array.isArray(wire);
95
+ const isCall = (message) => "method" in message;
96
+ const isResponse = (message) => !("method" in message);
97
+ const messagesOf = (wire) => isBatch(wire) ? wire : [wire];
98
+ const memoryAttachments = () => {
99
+ let counter = 0;
100
+ return {
101
+ put: async () => {
102
+ counter += 1;
103
+ return { uri: `memory://conformance-attachments/${counter}` };
104
+ }
105
+ };
106
+ };
107
+ const cancelledAnswer = (method) => method === methods.client.session.requestPermission ? { outcome: { outcome: "cancelled" } } : { action: "cancel" };
108
+ const LINK_SEPARATOR = "|";
109
+ const createConformanceAgent = (options = {}) => {
110
+ const extensions = options.extensions ?? true;
111
+ const slowTurnMs = options.slowTurnMs ?? 3e4;
112
+ const inject = options.promptWhileRunning === PromptWhileRunning.Inject;
113
+ const survives = options.survivesDisconnect ?? false;
114
+ const attachments = options.attachments ?? memoryAttachments();
115
+ const sessions = /* @__PURE__ */ new Map();
116
+ const links = /* @__PURE__ */ new Map();
117
+ const linkOf = (requestId) => {
118
+ const parsed = z.string().safeParse(requestId);
119
+ if (!parsed.success) return null;
120
+ const separator = parsed.data.indexOf(LINK_SEPARATOR);
121
+ return separator < 0 ? null : links.get(parsed.data.slice(0, separator)) ?? null;
122
+ };
123
+ const getSession = (sessionId) => {
124
+ const session = sessions.get(sessionId);
125
+ if (session == null) throw RequestError.resourceNotFound(sessionId);
126
+ return session;
127
+ };
128
+ const attach = (session, client, requestId) => {
129
+ session.client = client;
130
+ session.link = linkOf(requestId) ?? session.link;
131
+ };
132
+ const emit = async (session, update, record = true) => {
133
+ if (record) session.history.push(update);
134
+ const sending = session.client.notify(methods.client.session.update, {
135
+ sessionId: session.id,
136
+ update
137
+ });
138
+ if (survives) await sending.catch(() => void 0);
139
+ else await sending;
140
+ };
141
+ const say = async (session, messageId, text) => {
142
+ const middle = Math.ceil(text.length / 2);
143
+ const parts = text.length > 1 ? [text.slice(0, middle), text.slice(middle)] : [text];
144
+ for (const part of parts) {
145
+ await emit(session, {
146
+ sessionUpdate: "agent_message_chunk",
147
+ messageId,
148
+ content: { type: "text", text: part }
149
+ });
150
+ }
151
+ };
152
+ const ask = async (session, method, params, viaSdk) => {
153
+ const current = session.link;
154
+ if (!survives || current == null) {
155
+ return current == null ? viaSdk().then((result) => jsonValueSchema.parse(result)) : Promise.race([
156
+ viaSdk().then((result) => jsonValueSchema.parse(result)),
157
+ current.gone.then(() => cancelledAnswer(method))
158
+ ]);
159
+ }
160
+ const id = `conformance-request-${randomId()}`;
161
+ const message = { jsonrpc: "2.0", id, method, params };
162
+ const answered = new Promise((resolve) => {
163
+ session.open.set(id, { method, message, resolve });
164
+ });
165
+ if (!current.closed) await current.write(message).catch(() => void 0);
166
+ try {
167
+ return await answered;
168
+ } finally {
169
+ session.open.delete(id);
170
+ }
171
+ };
172
+ const callMcp = async (session, rest) => {
173
+ const [serverName = "", toolName = "", ...argParts] = rest.split(" ");
174
+ const toolArgs = argParts.length === 0 ? {} : z.record(z.string(), z.json()).parse(JSON.parse(argParts.join(" ")));
175
+ const server = session.mcpServers.find(
176
+ (entry) => namedServerSchema.safeParse(entry).data?.name === serverName
177
+ );
178
+ if (server == null) throw new Error(`no MCP server named ${serverName}`);
179
+ const acp = acpServerSchema.safeParse(server);
180
+ const http = httpServerSchema.safeParse(server);
181
+ if (acp.success) {
182
+ const response = await session.client.request(methods.client.mcp.message, {
183
+ serverId: acp.data.serverId,
184
+ requestId: randomId(),
185
+ method: "tools/call",
186
+ params: { name: toolName, arguments: toolArgs }
187
+ });
188
+ if ("error" in response) throw new Error(response.error.message);
189
+ return mcpResultText(toolResultSchema.safeParse(response.result));
190
+ }
191
+ if (http.success) {
192
+ const headers = {};
193
+ for (const header of http.data.headers ?? []) headers[header.name] = header.value;
194
+ const client = new Client({ name: "final-conformance-agent", version: "1" });
195
+ await client.connect(
196
+ new StreamableHTTPClientTransport(new URL(http.data.url), {
197
+ fetch: options.fetch,
198
+ requestInit: { headers }
199
+ })
200
+ );
201
+ try {
202
+ return mcpResultText(
203
+ toolResultSchema.safeParse(
204
+ await client.callTool({ name: toolName, arguments: toolArgs })
205
+ )
206
+ );
207
+ } finally {
208
+ await client.close();
209
+ }
210
+ }
211
+ throw new Error(`unsupported MCP server type ${server.type}`);
212
+ };
213
+ const linked = async (args) => {
214
+ const { uri } = await attachments.put(args);
215
+ const link = {
216
+ type: "resource_link",
217
+ uri,
218
+ name: args.name,
219
+ mimeType: args.mimeType,
220
+ size: args.bytes.length
221
+ };
222
+ if (args.text != null)
223
+ link.description = utf8Prefix(args.text, RESOURCE_LINK_DESCRIPTION_BYTES);
224
+ return link;
225
+ };
226
+ const runTurn = async (session, text, signal) => {
227
+ const messageId = randomId();
228
+ const parsed = parseDirective(text);
229
+ const endTurn = {
230
+ sessionUpdate: "state_update",
231
+ state: "idle",
232
+ stopReason: "end_turn"
233
+ };
234
+ const cancelled = {
235
+ sessionUpdate: "state_update",
236
+ state: "idle",
237
+ stopReason: "cancelled"
238
+ };
239
+ if (parsed == null) {
240
+ await say(session, messageId, `unknown directive: ${text}`);
241
+ return endTurn;
242
+ }
243
+ switch (parsed.name) {
244
+ case ConformanceDirective.Echo:
245
+ await say(session, messageId, parsed.rest);
246
+ return endTurn;
247
+ case ConformanceDirective.Permission: {
248
+ const params = {
249
+ sessionId: session.id,
250
+ title: "Conformance permission",
251
+ options: [
252
+ { optionId: "allow", name: "Allow once", kind: "allow_once" },
253
+ { optionId: "reject", name: "Reject", kind: "reject_once" }
254
+ ]
255
+ };
256
+ const response = permissionResultSchema.safeParse(
257
+ await ask(
258
+ session,
259
+ methods.client.session.requestPermission,
260
+ params,
261
+ () => session.client.request(methods.client.session.requestPermission, params)
262
+ )
263
+ );
264
+ const outcome = response.success ? response.data.outcome : { outcome: "cancelled" };
265
+ const kind = outcome.outcome === "selected" && "optionId" in outcome ? outcome.optionId === "allow" ? "allow_once" : "reject_once" : "cancelled";
266
+ await say(session, messageId, `permission:${kind}`);
267
+ return endTurn;
268
+ }
269
+ case ConformanceDirective.Elicit: {
270
+ const params = {
271
+ mode: "form",
272
+ sessionId: session.id,
273
+ message: "Conformance question",
274
+ requestedSchema: {
275
+ type: "object",
276
+ properties: { answer: { type: "string", title: "Answer" } },
277
+ required: ["answer"]
278
+ }
279
+ };
280
+ const response = elicitationResultSchema.safeParse(
281
+ await ask(
282
+ session,
283
+ methods.client.elicitation.create,
284
+ params,
285
+ () => session.client.request(methods.client.elicitation.create, params)
286
+ )
287
+ );
288
+ const action = response.success ? response.data.action : "cancel";
289
+ const answer = z.object({ answer: z.union([z.string(), z.number(), z.boolean()]) }).safeParse(response.data?.content);
290
+ await say(
291
+ session,
292
+ messageId,
293
+ `elicitation:${action}:${action === "accept" && answer.success ? String(answer.data.answer) : ""}`
294
+ );
295
+ return endTurn;
296
+ }
297
+ case ConformanceDirective.Slow:
298
+ await say(session, messageId, "slow:started");
299
+ await delay(slowTurnMs, signal);
300
+ return signal.aborted ? cancelled : endTurn;
301
+ case ConformanceDirective.Wait: {
302
+ await say(session, messageId, "wait:started");
303
+ await delay(Number.parseInt(parsed.rest, 10) || 500, signal);
304
+ if (signal.aborted) return cancelled;
305
+ await say(session, messageId, "wait:done");
306
+ return endTurn;
307
+ }
308
+ case ConformanceDirective.Clear:
309
+ session.nativeId = randomId();
310
+ session.transcript = [];
311
+ await say(session, messageId, "cleared");
312
+ return endTurn;
313
+ case ConformanceDirective.Big: {
314
+ const bytes = Number.parseInt(parsed.rest, 10) || 3 * 1024 * 1024;
315
+ const toolCallId = randomId();
316
+ const text2 = "x".repeat(bytes);
317
+ const image = conformanceImageBase64();
318
+ const encoder = new TextEncoder();
319
+ const blocks = extensions ? [
320
+ await linked({
321
+ bytes: encoder.encode(text2),
322
+ mimeType: "text/plain",
323
+ name: "output.txt",
324
+ text: text2
325
+ }),
326
+ await linked({
327
+ bytes: Uint8Array.from(atob(image), (char) => char.charCodeAt(0)),
328
+ mimeType: "image/png",
329
+ name: "image.png",
330
+ text: null
331
+ })
332
+ ] : [
333
+ { type: "text", text: text2 },
334
+ { type: "image", mimeType: "image/png", data: image }
335
+ ];
336
+ await emit(session, {
337
+ sessionUpdate: "tool_call_update",
338
+ toolCallId,
339
+ title: "Produce a large result",
340
+ kind: "read",
341
+ status: "in_progress"
342
+ });
343
+ await emit(session, {
344
+ sessionUpdate: "tool_call_update",
345
+ toolCallId,
346
+ status: "completed",
347
+ content: blocks.map((content) => ({ type: "content", content }))
348
+ });
349
+ await say(session, messageId, "big:done");
350
+ return endTurn;
351
+ }
352
+ case ConformanceDirective.Error: {
353
+ const error = { code: -32603, message: "conformance error" };
354
+ if (!extensions)
355
+ return { sessionUpdate: "state_update", state: "idle", stopReason: "error", error };
356
+ const providerError = {
357
+ code: "conformance_error",
358
+ message: "conformance error",
359
+ retryable: false
360
+ };
361
+ return {
362
+ sessionUpdate: "state_update",
363
+ state: "idle",
364
+ stopReason: "error",
365
+ error,
366
+ _meta: { [FINAL_META_KEY]: { providerError } }
367
+ };
368
+ }
369
+ case ConformanceDirective.Mcp: {
370
+ let reply;
371
+ try {
372
+ reply = `mcp:${await callMcp(session, parsed.rest)}`;
373
+ } catch (error) {
374
+ reply = `mcp-error:${error instanceof Error ? error.message : String(error)}`;
375
+ }
376
+ await say(session, messageId, reply);
377
+ return endTurn;
378
+ }
379
+ case ConformanceDirective.History:
380
+ await say(session, messageId, session.transcript.join("\n"));
381
+ return endTurn;
382
+ }
383
+ };
384
+ const echo = (session, prompt, userMessageId) => emit(session, {
385
+ sessionUpdate: "user_message",
386
+ messageId: userMessageId,
387
+ content: [...prompt]
388
+ });
389
+ const injectIntoTurn = (session, turn, prompt, userMessageId) => {
390
+ const text = textOf(prompt);
391
+ session.transcript.push(text);
392
+ const work = (async () => {
393
+ await echo(session, prompt, userMessageId);
394
+ await runTurn(session, directiveTextOf(prompt, text), turn.signal);
395
+ })().catch(() => void 0);
396
+ session.injected.push(work);
397
+ };
398
+ const startTurn = (session, prompt, userMessageId) => {
399
+ const text = textOf(prompt);
400
+ const cancels = session.cancels;
401
+ session.queue = session.queue.then(async () => {
402
+ if (session.cancels !== cancels) return;
403
+ session.transcript.push(text);
404
+ const controller = new AbortController();
405
+ session.turn = controller;
406
+ try {
407
+ await echo(session, prompt, userMessageId);
408
+ await emit(session, { sessionUpdate: "state_update", state: "running" });
409
+ const end = await runTurn(session, directiveTextOf(prompt, text), controller.signal).catch(
410
+ (cause) => ({
411
+ sessionUpdate: "state_update",
412
+ state: "idle",
413
+ stopReason: "error",
414
+ error: {
415
+ code: -32603,
416
+ message: cause instanceof Error ? cause.message : String(cause)
417
+ }
418
+ })
419
+ );
420
+ while (session.injected.length > 0) await Promise.all(session.injected.splice(0));
421
+ await emit(
422
+ session,
423
+ controller.signal.aborted && end.sessionUpdate === "state_update" ? { sessionUpdate: "state_update", state: "idle", stopReason: "cancelled" } : end
424
+ );
425
+ } catch {
426
+ } finally {
427
+ session.turn = null;
428
+ }
429
+ });
430
+ };
431
+ const cancelOpen = (session) => {
432
+ for (const request of session.open.values()) request.resolve(cancelledAnswer(request.method));
433
+ };
434
+ const app = agent({ name: "final-conformance-agent" }).onRequest(methods.agent.initialize, () => ({
435
+ protocolVersion: PROTOCOL_VERSION,
436
+ info: { name: "final-conformance-agent", version: "1" },
437
+ capabilities: extensions ? {
438
+ session: { mcp: { acp: {}, http: {} } },
439
+ _meta: {
440
+ [FINAL_META_KEY]: {
441
+ supports: { observe: true, authorMeta: false, afterSeqReplay: true },
442
+ privateMethods: options.privateMethods ?? []
443
+ }
444
+ }
445
+ } : { session: { mcp: { acp: {}, http: {} } } }
446
+ })).onRequest(methods.agent.session.new, ({ params, client, requestId }) => {
447
+ const id = randomId();
448
+ sessions.set(id, {
449
+ id,
450
+ nativeId: randomId(),
451
+ cwd: params.cwd,
452
+ mcpServers: params.mcpServers ?? [],
453
+ history: [],
454
+ transcript: [],
455
+ client,
456
+ link: linkOf(requestId),
457
+ turn: null,
458
+ queue: Promise.resolve(),
459
+ injected: [],
460
+ cancels: 0,
461
+ open: /* @__PURE__ */ new Map()
462
+ });
463
+ return { sessionId: id };
464
+ }).onRequest(methods.agent.session.resume, async ({ params, client, requestId }) => {
465
+ const session = getSession(params.sessionId);
466
+ attach(session, client, requestId);
467
+ session.cwd = params.cwd;
468
+ if (params.mcpServers != null) session.mcpServers = params.mcpServers;
469
+ const replayFrom = params.replayFrom;
470
+ let replay = [];
471
+ if (replayFrom?.type === "start") replay = [...session.history];
472
+ else if (extensions && replayFrom?.type === AFTER_SEQ_REPLAY_TYPE) {
473
+ const seq = afterSeqSchema.safeParse(replayFrom).data?.seq ?? 0;
474
+ replay = session.history.slice(Math.max(0, seq));
475
+ }
476
+ for (const update of replay) await emit(session, update, false);
477
+ const link = session.link;
478
+ if (link != null) {
479
+ for (const request of session.open.values()) {
480
+ await link.write(request.message).catch(() => void 0);
481
+ }
482
+ }
483
+ return {};
484
+ }).onRequest(methods.agent.session.prompt, ({ params, client, requestId }) => {
485
+ const session = getSession(params.sessionId);
486
+ attach(session, client, requestId);
487
+ const messageId = randomId();
488
+ setTimeout(() => {
489
+ const running = session.turn;
490
+ if (inject && running != null) injectIntoTurn(session, running, params.prompt, messageId);
491
+ else startTurn(session, params.prompt, messageId);
492
+ }, 0);
493
+ return { messageId };
494
+ }).onRequest(methods.agent.session.close, async ({ params }) => {
495
+ const session = sessions.get(params.sessionId);
496
+ if (session != null) {
497
+ session.cancels += 1;
498
+ session.turn?.abort();
499
+ cancelOpen(session);
500
+ await session.queue;
501
+ }
502
+ sessions.delete(params.sessionId);
503
+ return {};
504
+ }).onNotification(methods.agent.session.cancel, ({ params }) => {
505
+ const session = sessions.get(params.sessionId);
506
+ if (session == null) return;
507
+ session.cancels += 1;
508
+ session.turn?.abort();
509
+ cancelOpen(session);
510
+ });
511
+ for (const method of extensions ? options.privateMethods ?? [] : []) {
512
+ app.onNotification(method, z.unknown(), () => void 0);
513
+ }
514
+ if (extensions) {
515
+ app.onNotification(OBSERVE_METHOD, observeParamsSchema, ({ params }) => {
516
+ const session = sessions.get(params.sessionId);
517
+ if (session == null) return;
518
+ session.transcript.push(params.content.map((block) => block.text ?? "").join(""));
519
+ });
520
+ }
521
+ const openRequestOf = (id) => {
522
+ for (const session of sessions.values()) {
523
+ const request = session.open.get(String(id));
524
+ if (request != null) return request;
525
+ }
526
+ return null;
527
+ };
528
+ const connect = (stream) => {
529
+ const linkId = randomId();
530
+ const originals = /* @__PURE__ */ new Map();
531
+ const writer = stream.writable.getWriter();
532
+ let writing = Promise.resolve();
533
+ const write = (message) => {
534
+ writing = writing.then(() => writer.write(message));
535
+ return writing;
536
+ };
537
+ const gone = Promise.withResolvers();
538
+ const link = { id: linkId, write, closed: false, gone: gone.promise };
539
+ links.set(linkId, link);
540
+ const writable = new WritableStream({
541
+ write: async (wire) => {
542
+ const restored = messagesOf(wire).map((message) => {
543
+ if ("method" in message) return message;
544
+ const id = z.string().safeParse(message.id);
545
+ if (!id.success) return message;
546
+ const original = originals.get(id.data);
547
+ if (original === void 0) return message;
548
+ originals.delete(id.data);
549
+ return { ...message, id: original };
550
+ });
551
+ const [first, ...rest] = restored;
552
+ await write(
553
+ isBatch(wire) && first != null ? mergeBatch(first, rest, wire) : first ?? wire
554
+ );
555
+ },
556
+ close: () => writing.then(() => writer.close()),
557
+ abort: (reason) => writer.abort(reason)
558
+ });
559
+ const readable = stream.readable.pipeThrough(
560
+ new TransformStream({
561
+ transform: (wire, controller) => {
562
+ const passed = [];
563
+ for (const message of messagesOf(wire)) {
564
+ const answered = rawResponseSchema.safeParse(message);
565
+ const failed = rawErrorSchema.safeParse(message);
566
+ const id = answered.success ? answered.data.id : failed.success ? failed.data.id : null;
567
+ const open = id == null || "method" in message ? null : openRequestOf(id);
568
+ if (open != null) {
569
+ open.resolve(answered.success ? answered.data.result : null);
570
+ continue;
571
+ }
572
+ const request = rawRequestSchema.safeParse(message);
573
+ if (request.success && "method" in message && "id" in message) {
574
+ const scoped = `${linkId}${LINK_SEPARATOR}${JSON.stringify(request.data.id)}`;
575
+ originals.set(scoped, request.data.id);
576
+ passed.push({ ...message, id: scoped });
577
+ continue;
578
+ }
579
+ passed.push(message);
580
+ }
581
+ const [first, ...rest] = passed;
582
+ if (first == null) return;
583
+ controller.enqueue(isBatch(wire) ? mergeBatch(first, rest, wire) : first);
584
+ },
585
+ // The client hung up: the SDK connection may outlive it while its own
586
+ // requests are open.
587
+ flush: () => {
588
+ link.closed = true;
589
+ gone.resolve();
590
+ }
591
+ })
592
+ );
593
+ const connection = app.connect({ readable, writable });
594
+ void connection.closed.then(() => {
595
+ link.closed = true;
596
+ links.delete(linkId);
597
+ gone.resolve();
598
+ });
599
+ return connection;
600
+ };
601
+ return {
602
+ app,
603
+ connect,
604
+ sessions: () => [...sessions.keys()],
605
+ nativeId: (sessionId) => sessions.get(sessionId)?.nativeId ?? null
606
+ };
607
+ };
608
+ const mergeBatch = (first, rest, original) => {
609
+ const all = [first, ...rest];
610
+ const calls = all.filter(isCall);
611
+ const [firstCall, ...restCalls] = calls;
612
+ if (firstCall != null && calls.length === all.length) return [firstCall, ...restCalls];
613
+ const responses = all.filter(isResponse);
614
+ const [firstResponse, ...restResponses] = responses;
615
+ if (firstResponse != null && responses.length === all.length) {
616
+ return [firstResponse, ...restResponses];
617
+ }
618
+ return original;
619
+ };
620
+ export {
621
+ createConformanceAgent
622
+ };
623
+ //# sourceMappingURL=agent.mjs.map