subharness 0.0.1

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 (168) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +158 -0
  3. package/dist/adapters/claude-auth.d.ts +7 -0
  4. package/dist/adapters/claude-auth.js +87 -0
  5. package/dist/adapters/claude-auth.js.map +1 -0
  6. package/dist/adapters/claude-config.d.ts +6 -0
  7. package/dist/adapters/claude-config.js +37 -0
  8. package/dist/adapters/claude-config.js.map +1 -0
  9. package/dist/adapters/claude-input.d.ts +9 -0
  10. package/dist/adapters/claude-input.js +32 -0
  11. package/dist/adapters/claude-input.js.map +1 -0
  12. package/dist/adapters/claude-permissions.d.ts +3 -0
  13. package/dist/adapters/claude-permissions.js +24 -0
  14. package/dist/adapters/claude-permissions.js.map +1 -0
  15. package/dist/adapters/claude-settings.d.ts +14 -0
  16. package/dist/adapters/claude-settings.js +43 -0
  17. package/dist/adapters/claude-settings.js.map +1 -0
  18. package/dist/adapters/claude-tools.d.ts +9 -0
  19. package/dist/adapters/claude-tools.js +47 -0
  20. package/dist/adapters/claude-tools.js.map +1 -0
  21. package/dist/adapters/claude.d.ts +22 -0
  22. package/dist/adapters/claude.js +295 -0
  23. package/dist/adapters/claude.js.map +1 -0
  24. package/dist/adapters/codex-config.d.ts +25 -0
  25. package/dist/adapters/codex-config.js +66 -0
  26. package/dist/adapters/codex-config.js.map +1 -0
  27. package/dist/adapters/codex.d.ts +2 -0
  28. package/dist/adapters/codex.js +238 -0
  29. package/dist/adapters/codex.js.map +1 -0
  30. package/dist/adapters/fx-auth.d.ts +4 -0
  31. package/dist/adapters/fx-auth.js +116 -0
  32. package/dist/adapters/fx-auth.js.map +1 -0
  33. package/dist/adapters/fx-rpc.d.ts +29 -0
  34. package/dist/adapters/fx-rpc.js +124 -0
  35. package/dist/adapters/fx-rpc.js.map +1 -0
  36. package/dist/adapters/fx-tools.d.ts +19 -0
  37. package/dist/adapters/fx-tools.js +119 -0
  38. package/dist/adapters/fx-tools.js.map +1 -0
  39. package/dist/adapters/fx.d.ts +3 -0
  40. package/dist/adapters/fx.js +302 -0
  41. package/dist/adapters/fx.js.map +1 -0
  42. package/dist/adapters/mcp-tool-content.d.ts +12 -0
  43. package/dist/adapters/mcp-tool-content.js +8 -0
  44. package/dist/adapters/mcp-tool-content.js.map +1 -0
  45. package/dist/adapters/rpc.d.ts +28 -0
  46. package/dist/adapters/rpc.js +101 -0
  47. package/dist/adapters/rpc.js.map +1 -0
  48. package/dist/adapters/types.d.ts +28 -0
  49. package/dist/adapters/types.js +2 -0
  50. package/dist/adapters/types.js.map +1 -0
  51. package/dist/cli/args.d.ts +18 -0
  52. package/dist/cli/args.js +118 -0
  53. package/dist/cli/args.js.map +1 -0
  54. package/dist/cli/catalog-worker.d.ts +1 -0
  55. package/dist/cli/catalog-worker.js +22 -0
  56. package/dist/cli/catalog-worker.js.map +1 -0
  57. package/dist/cli/catalog.d.ts +26 -0
  58. package/dist/cli/catalog.js +41 -0
  59. package/dist/cli/catalog.js.map +1 -0
  60. package/dist/cli/help.d.ts +3 -0
  61. package/dist/cli/help.js +68 -0
  62. package/dist/cli/help.js.map +1 -0
  63. package/dist/cli/input.d.ts +5 -0
  64. package/dist/cli/input.js +69 -0
  65. package/dist/cli/input.js.map +1 -0
  66. package/dist/cli/main.d.ts +2 -0
  67. package/dist/cli/main.js +105 -0
  68. package/dist/cli/main.js.map +1 -0
  69. package/dist/cli/output.d.ts +7 -0
  70. package/dist/cli/output.js +43 -0
  71. package/dist/cli/output.js.map +1 -0
  72. package/dist/config/access.d.ts +21 -0
  73. package/dist/config/access.js +97 -0
  74. package/dist/config/access.js.map +1 -0
  75. package/dist/config/loader.d.ts +13 -0
  76. package/dist/config/loader.js +80 -0
  77. package/dist/config/loader.js.map +1 -0
  78. package/dist/config/oidc.d.ts +1 -0
  79. package/dist/config/oidc.js +53 -0
  80. package/dist/config/oidc.js.map +1 -0
  81. package/dist/config/project.d.ts +5 -0
  82. package/dist/config/project.js +56 -0
  83. package/dist/config/project.js.map +1 -0
  84. package/dist/config/resolve-access.d.ts +4 -0
  85. package/dist/config/resolve-access.js +42 -0
  86. package/dist/config/resolve-access.js.map +1 -0
  87. package/dist/errors.d.ts +9 -0
  88. package/dist/errors.js +14 -0
  89. package/dist/errors.js.map +1 -0
  90. package/dist/index.d.ts +4 -0
  91. package/dist/index.js +3 -0
  92. package/dist/index.js.map +1 -0
  93. package/dist/runtime/client.d.ts +9 -0
  94. package/dist/runtime/client.js +91 -0
  95. package/dist/runtime/client.js.map +1 -0
  96. package/dist/runtime/coordinator.d.ts +61 -0
  97. package/dist/runtime/coordinator.js +296 -0
  98. package/dist/runtime/coordinator.js.map +1 -0
  99. package/dist/runtime/daemon.d.ts +1 -0
  100. package/dist/runtime/daemon.js +28 -0
  101. package/dist/runtime/daemon.js.map +1 -0
  102. package/dist/runtime/definition.d.ts +6 -0
  103. package/dist/runtime/definition.js +19 -0
  104. package/dist/runtime/definition.js.map +1 -0
  105. package/dist/runtime/native-owner.d.ts +8 -0
  106. package/dist/runtime/native-owner.js +25 -0
  107. package/dist/runtime/native-owner.js.map +1 -0
  108. package/dist/runtime/observation.d.ts +1 -0
  109. package/dist/runtime/observation.js +15 -0
  110. package/dist/runtime/observation.js.map +1 -0
  111. package/dist/runtime/select-native.d.ts +3 -0
  112. package/dist/runtime/select-native.js +34 -0
  113. package/dist/runtime/select-native.js.map +1 -0
  114. package/dist/runtime/service.d.ts +5 -0
  115. package/dist/runtime/service.js +90 -0
  116. package/dist/runtime/service.js.map +1 -0
  117. package/dist/runtime/session-launcher.d.ts +6 -0
  118. package/dist/runtime/session-launcher.js +29 -0
  119. package/dist/runtime/session-launcher.js.map +1 -0
  120. package/dist/runtime/state.d.ts +14 -0
  121. package/dist/runtime/state.js +69 -0
  122. package/dist/runtime/state.js.map +1 -0
  123. package/dist/runtime/types.d.ts +81 -0
  124. package/dist/runtime/types.js +2 -0
  125. package/dist/runtime/types.js.map +1 -0
  126. package/dist/runtime/worker-client.d.ts +3 -0
  127. package/dist/runtime/worker-client.js +81 -0
  128. package/dist/runtime/worker-client.js.map +1 -0
  129. package/dist/runtime/worker.d.ts +1 -0
  130. package/dist/runtime/worker.js +67 -0
  131. package/dist/runtime/worker.js.map +1 -0
  132. package/dist/sdk/definitions.d.ts +6 -0
  133. package/dist/sdk/definitions.js +72 -0
  134. package/dist/sdk/definitions.js.map +1 -0
  135. package/dist/sdk/tool-result.d.ts +23 -0
  136. package/dist/sdk/tool-result.js +95 -0
  137. package/dist/sdk/tool-result.js.map +1 -0
  138. package/dist/sdk/tools.d.ts +9 -0
  139. package/dist/sdk/tools.js +73 -0
  140. package/dist/sdk/tools.js.map +1 -0
  141. package/dist/sdk/types.d.ts +49 -0
  142. package/dist/sdk/types.js +2 -0
  143. package/dist/sdk/types.js.map +1 -0
  144. package/dist/sdk/validation.d.ts +5 -0
  145. package/dist/sdk/validation.js +20 -0
  146. package/dist/sdk/validation.js.map +1 -0
  147. package/dist/shell.d.ts +2 -0
  148. package/dist/shell.js +5 -0
  149. package/dist/shell.js.map +1 -0
  150. package/package.json +61 -0
  151. package/sdk/access-config.md +52 -0
  152. package/sdk/adapter-contract.md +33 -0
  153. package/sdk/agent.md +52 -0
  154. package/sdk/authentication.md +11 -0
  155. package/sdk/cli/index.md +67 -0
  156. package/sdk/cli/output.md +28 -0
  157. package/sdk/completion-notifications.md +29 -0
  158. package/sdk/config.md +41 -0
  159. package/sdk/distribution.md +31 -0
  160. package/sdk/fx.md +71 -0
  161. package/sdk/harnesses.md +32 -0
  162. package/sdk/index.md +22 -0
  163. package/sdk/message-delivery.md +39 -0
  164. package/sdk/plugins/sub-agents.md +57 -0
  165. package/sdk/project-team.md +57 -0
  166. package/sdk/sessions.md +31 -0
  167. package/sdk/tools.md +73 -0
  168. package/sdk/v1-runtime.md +63 -0
@@ -0,0 +1,119 @@
1
+ import { randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
2
+ import { createServer } from "node:http";
3
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
5
+ import { AgentError } from "../errors.js";
6
+ import { executeTool, toolJsonSchema } from "../sdk/tools.js";
7
+ import { mcpToolContent } from "./mcp-tool-content.js";
8
+ export async function startFxTools(agent) {
9
+ const definitions = Object.entries(agent.tools ?? {});
10
+ if (definitions.length === 0)
11
+ return emptyEndpoint();
12
+ for (const [, definition] of definitions)
13
+ toolJsonSchema(definition);
14
+ const token = randomBytes(32).toString("base64url");
15
+ const namespace = `subharness_${randomUUID().replaceAll("-", "")}`;
16
+ const pending = new Set();
17
+ let accepting = false;
18
+ let endpointFailure;
19
+ let failureHandler;
20
+ const mcp = new McpServer({ name: namespace, version: "1.0.0" });
21
+ for (const [name, definition] of definitions) {
22
+ mcp.registerTool(name, { description: definition.description, inputSchema: definition.inputSchema }, async (input) => {
23
+ if (!accepting)
24
+ return toolError("The task is not accepting tool calls.");
25
+ const execution = executeTool(definition, input);
26
+ pending.add(execution);
27
+ try {
28
+ return { content: mcpToolContent(await execution) };
29
+ }
30
+ catch (error) {
31
+ return toolError(error instanceof AgentError ? `Tool failed (${error.code}).` : "The custom tool failed.");
32
+ }
33
+ finally {
34
+ pending.delete(execution);
35
+ }
36
+ });
37
+ }
38
+ const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: randomUUID, enableJsonResponse: true });
39
+ await mcp.connect(transport);
40
+ let http;
41
+ let closing;
42
+ const closeEndpoint = () => closing ??= (async () => {
43
+ accepting = false;
44
+ await Promise.allSettled([...pending]);
45
+ await mcp.close().catch(() => { });
46
+ if (http)
47
+ await closeHttp(http);
48
+ })();
49
+ const failEndpoint = () => {
50
+ if (endpointFailure)
51
+ return;
52
+ endpointFailure = new AgentError("HARNESS_FAILED", "The private fx tool endpoint failed.");
53
+ accepting = false;
54
+ failureHandler?.(endpointFailure);
55
+ void closeEndpoint();
56
+ };
57
+ try {
58
+ http = createServer((request, response) => {
59
+ if (request.url !== "/mcp" || !authorized(request.headers.authorization, token)) {
60
+ response.writeHead(401, { "content-type": "application/json" });
61
+ response.end(JSON.stringify({ error: "unauthorized" }));
62
+ return;
63
+ }
64
+ void transport.handleRequest(request, response).catch(() => {
65
+ if (!response.headersSent)
66
+ response.writeHead(500);
67
+ response.end();
68
+ });
69
+ });
70
+ await new Promise((resolve, reject) => {
71
+ http.once("error", reject);
72
+ http.listen(0, "127.0.0.1", () => {
73
+ http.off("error", reject);
74
+ http.on("error", failEndpoint);
75
+ resolve();
76
+ });
77
+ });
78
+ }
79
+ catch (error) {
80
+ await closeEndpoint();
81
+ throw new AgentError("HARNESS_FAILED", "The private fx tool endpoint could not start.");
82
+ }
83
+ const address = http.address();
84
+ if (!address || typeof address === "string") {
85
+ await closeEndpoint();
86
+ throw new AgentError("HARNESS_FAILED", "The private fx tool endpoint did not bind to loopback.");
87
+ }
88
+ return {
89
+ descriptor: { type: "http", name: namespace, url: `http://127.0.0.1:${address.port}/mcp`, headers: [{ name: "Authorization", value: `Bearer ${token}` }] },
90
+ onFailure(handler) { failureHandler = handler; if (endpointFailure)
91
+ handler(endpointFailure); },
92
+ beginTurn() { accepting = true; },
93
+ stopAdmission() { accepting = false; },
94
+ async drain() { accepting = false; await Promise.allSettled([...pending]); },
95
+ close: closeEndpoint,
96
+ };
97
+ }
98
+ function authorized(header, token) {
99
+ if (typeof header !== "string")
100
+ return false;
101
+ const expected = Buffer.from(`Bearer ${token}`);
102
+ const actual = Buffer.from(header);
103
+ return actual.length === expected.length && timingSafeEqual(actual, expected);
104
+ }
105
+ function toolError(text) {
106
+ return { isError: true, content: [{ type: "text", text }] };
107
+ }
108
+ function emptyEndpoint() {
109
+ return { onFailure() { }, beginTurn() { }, stopAdmission() { }, async drain() { }, async close() { } };
110
+ }
111
+ async function closeHttp(server) {
112
+ if (!server.listening)
113
+ return;
114
+ await new Promise(resolve => {
115
+ server.close(() => resolve());
116
+ server.closeAllConnections();
117
+ });
118
+ }
119
+ //# sourceMappingURL=fx-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fx-tools.js","sourceRoot":"","sources":["../../src/adapters/fx-tools.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomBytes, randomUUID, timingSafeEqual } from \"node:crypto\";\nimport { createServer, type Server as HttpServer } from \"node:http\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport { AgentError } from \"../errors.js\";\nimport { executeTool, toolJsonSchema } from \"../sdk/tools.js\";\nimport type { ExecutionDefinition } from \"./types.js\";\nimport { mcpToolContent } from \"./mcp-tool-content.js\";\n\nexport type FxToolEndpoint = {\n descriptor?: { type: \"http\"; name: string; url: string; headers: { name: string; value: string }[] };\n onFailure(handler: (error: AgentError) => void): void;\n beginTurn(): void;\n stopAdmission(): void;\n drain(): Promise<void>;\n close(): Promise<void>;\n};\n\nexport async function startFxTools(agent: Pick<ExecutionDefinition, \"tools\">): Promise<FxToolEndpoint> {\n const definitions = Object.entries(agent.tools ?? {});\n if (definitions.length === 0) return emptyEndpoint();\n for (const [, definition] of definitions) toolJsonSchema(definition);\n\n const token = randomBytes(32).toString(\"base64url\");\n const namespace = `subharness_${randomUUID().replaceAll(\"-\", \"\")}`;\n const pending = new Set<Promise<unknown>>();\n let accepting = false;\n let endpointFailure: AgentError | undefined;\n let failureHandler: ((error: AgentError) => void) | undefined;\n const mcp = new McpServer({ name: namespace, version: \"1.0.0\" });\n for (const [name, definition] of definitions) {\n mcp.registerTool(name, { description: definition.description, inputSchema: definition.inputSchema }, async (input: unknown) => {\n if (!accepting) return toolError(\"The task is not accepting tool calls.\");\n const execution = executeTool(definition, input);\n pending.add(execution);\n try {\n return { content: mcpToolContent(await execution) };\n } catch (error) {\n return toolError(error instanceof AgentError ? `Tool failed (${error.code}).` : \"The custom tool failed.\");\n } finally {\n pending.delete(execution);\n }\n });\n }\n\n const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: randomUUID, enableJsonResponse: true });\n await mcp.connect(transport);\n let http: HttpServer | undefined;\n let closing: Promise<void> | undefined;\n const closeEndpoint = (): Promise<void> => closing ??= (async () => {\n accepting = false;\n await Promise.allSettled([...pending]);\n await mcp.close().catch(() => {});\n if (http) await closeHttp(http);\n })();\n const failEndpoint = () => {\n if (endpointFailure) return;\n endpointFailure = new AgentError(\"HARNESS_FAILED\", \"The private fx tool endpoint failed.\");\n accepting = false;\n failureHandler?.(endpointFailure);\n void closeEndpoint();\n };\n try {\n http = createServer((request, response) => {\n if (request.url !== \"/mcp\" || !authorized(request.headers.authorization, token)) {\n response.writeHead(401, { \"content-type\": \"application/json\" });\n response.end(JSON.stringify({ error: \"unauthorized\" }));\n return;\n }\n void transport.handleRequest(request, response).catch(() => {\n if (!response.headersSent) response.writeHead(500);\n response.end();\n });\n });\n await new Promise<void>((resolve, reject) => {\n http!.once(\"error\", reject);\n http!.listen(0, \"127.0.0.1\", () => {\n http!.off(\"error\", reject);\n http!.on(\"error\", failEndpoint);\n resolve();\n });\n });\n } catch (error) {\n await closeEndpoint();\n throw new AgentError(\"HARNESS_FAILED\", \"The private fx tool endpoint could not start.\");\n }\n const address = http.address();\n if (!address || typeof address === \"string\") {\n await closeEndpoint();\n throw new AgentError(\"HARNESS_FAILED\", \"The private fx tool endpoint did not bind to loopback.\");\n }\n\n return {\n descriptor: { type: \"http\", name: namespace, url: `http://127.0.0.1:${address.port}/mcp`, headers: [{ name: \"Authorization\", value: `Bearer ${token}` }] },\n onFailure(handler) { failureHandler = handler; if (endpointFailure) handler(endpointFailure); },\n beginTurn() { accepting = true; },\n stopAdmission() { accepting = false; },\n async drain() { accepting = false; await Promise.allSettled([...pending]); },\n close: closeEndpoint,\n };\n}\n\nfunction authorized(header: string | undefined, token: string): boolean {\n if (typeof header !== \"string\") return false;\n const expected = Buffer.from(`Bearer ${token}`);\n const actual = Buffer.from(header);\n return actual.length === expected.length && timingSafeEqual(actual, expected);\n}\n\nfunction toolError(text: string) {\n return { isError: true, content: [{ type: \"text\" as const, text }] };\n}\n\nfunction emptyEndpoint(): FxToolEndpoint {\n return { onFailure() {}, beginTurn() {}, stopAdmission() {}, async drain() {}, async close() {} };\n}\n\nasync function closeHttp(server: HttpServer): Promise<void> {\n if (!server.listening) return;\n await new Promise<void>(resolve => {\n server.close(() => resolve());\n server.closeAllConnections();\n });\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import { FxRpc } from "./fx-rpc.js";
2
+ import type { AdapterOptions, NativeSession } from "./types.js";
3
+ export declare function openFx(options: AdapterOptions, createRpc?: (cwd: string, env: NodeJS.ProcessEnv, model?: string) => FxRpc): Promise<NativeSession>;
@@ -0,0 +1,302 @@
1
+ import { AgentError } from "../errors.js";
2
+ import { fxEnvironment, fxSettingsFingerprint, verifyFxAccess } from "./fx-auth.js";
3
+ import { FxRpc } from "./fx-rpc.js";
4
+ import { startFxTools } from "./fx-tools.js";
5
+ export async function openFx(options, createRpc = (cwd, env, model) => new FxRpc(cwd, env, model)) {
6
+ const env = fxEnvironment(options);
7
+ const baseline = await fxSettingsFingerprint(env);
8
+ await verifyFxAccess(options.cwd, env, options.access.type);
9
+ const tools = await startFxTools(options.agent);
10
+ let rpc;
11
+ try {
12
+ const startedRpc = createRpc(options.cwd, env, options.harness.model);
13
+ rpc = startedRpc;
14
+ let startupFailure;
15
+ startedRpc.setFailureHandler(error => { startupFailure ??= error; });
16
+ tools.onFailure(error => startedRpc.abort(error));
17
+ startedRpc.onMessage = message => startupRequest(startedRpc, message);
18
+ const initialized = await startedRpc.request("initialize", { protocolVersion: 1, clientInfo: { name: "subharness", version: "0.1.0" }, clientCapabilities: {} });
19
+ if (!initialized || typeof initialized !== "object" || Array.isArray(initialized) || typeof initialized.protocolVersion !== "number") {
20
+ throw new AgentError("PROTOCOL_ERROR", "fx returned an invalid ACP initialization response.");
21
+ }
22
+ if (initialized.protocolVersion !== 1)
23
+ throw new AgentError("HARNESS_UNAVAILABLE", "The installed fx ACP protocol is not compatible with version 1.");
24
+ const created = await startedRpc.request("session/new", {
25
+ cwd: options.cwd,
26
+ mcpServers: tools.descriptor ? [tools.descriptor] : [],
27
+ });
28
+ if (typeof created?.sessionId !== "string" || created.sessionId.length === 0)
29
+ throw new AgentError("PROTOCOL_ERROR", "fx did not return a native session identifier.");
30
+ const selectedModel = verifySelection(created.configOptions, options.harness.model);
31
+ if (options.harness.effort !== undefined) {
32
+ verifyEffortAvailable(created.configOptions, options.harness.effort);
33
+ const configured = await startedRpc.request("session/set_config_option", { sessionId: created.sessionId, configId: "effort", value: options.harness.effort });
34
+ verifySelection(configured?.configOptions, selectedModel, options.harness.effort);
35
+ }
36
+ if (await fxSettingsFingerprint(env) !== baseline)
37
+ throw new AgentError("INVALID_CONFIG", "fx native settings changed during session startup. Start a new session.");
38
+ if (startupFailure)
39
+ throw startupFailure;
40
+ return new FxSession(startedRpc, created.sessionId, options, env, baseline, tools);
41
+ }
42
+ catch (error) {
43
+ await rpc?.close();
44
+ await tools.close();
45
+ if (error instanceof AgentError)
46
+ throw error;
47
+ throw new AgentError("HARNESS_UNAVAILABLE", "Cannot start fx. Check the native executable and session configuration.");
48
+ }
49
+ }
50
+ function startupRequest(rpc, message) {
51
+ if (message.id === undefined)
52
+ return;
53
+ try {
54
+ rpc.send({ id: message.id, result: { outcome: { outcome: "cancelled" } } });
55
+ }
56
+ catch { /* process may already be closing */ }
57
+ rpc.abort(new AgentError("INPUT_REQUIRED", "fx requested interactive input during startup. Complete its native setup before running an agent."));
58
+ }
59
+ function option(options, id) {
60
+ if (!Array.isArray(options))
61
+ throw new AgentError("PROTOCOL_ERROR", "fx returned invalid native session options.");
62
+ return options.find(value => value && typeof value === "object" && value.id === id);
63
+ }
64
+ function verifySelection(configOptions, requestedModel, effort) {
65
+ const provider = option(configOptions, "provider");
66
+ const selectedModel = option(configOptions, "model");
67
+ if (!provider || !selectedModel) {
68
+ throw new AgentError("PROTOCOL_ERROR", "fx did not expose compatible native provider and model selectors.");
69
+ }
70
+ if (provider.currentValue !== "gateway") {
71
+ throw new AgentError("INVALID_CONFIG", "fx selected a provider outside the authorized Gateway route.");
72
+ }
73
+ const model = selectedModel.currentValue;
74
+ if (typeof model !== "string" || model.length === 0) {
75
+ throw new AgentError("INVALID_CONFIG", "fx could not select a verifiable native default for this connection. Supply --model <model>.");
76
+ }
77
+ if (requestedModel && model !== requestedModel) {
78
+ throw new AgentError("INVALID_CONFIG", "fx changed the explicitly selected Gateway model.");
79
+ }
80
+ if (effort !== undefined && option(configOptions, "effort")?.currentValue !== effort) {
81
+ throw new AgentError("INVALID_CONFIG", "fx did not apply the explicitly selected effort.");
82
+ }
83
+ return model;
84
+ }
85
+ function verifyEffortAvailable(configOptions, effort) {
86
+ const configured = option(configOptions, "effort");
87
+ if (!configured || !Array.isArray(configured.options) || !configured.options.some((value) => value?.value === effort)) {
88
+ throw new AgentError("UNSUPPORTED_OPTION", "The requested fx effort is not supported by the selected model.");
89
+ }
90
+ }
91
+ class FxSession {
92
+ rpc;
93
+ sessionId;
94
+ options;
95
+ env;
96
+ settingsFingerprint;
97
+ tools;
98
+ active;
99
+ failure;
100
+ retirement;
101
+ first = true;
102
+ closed = false;
103
+ constructor(rpc, sessionId, options, env, settingsFingerprint, tools) {
104
+ this.rpc = rpc;
105
+ this.sessionId = sessionId;
106
+ this.options = options;
107
+ this.env = env;
108
+ this.settingsFingerprint = settingsFingerprint;
109
+ this.tools = tools;
110
+ rpc.setFailureHandler(error => {
111
+ this.failure ??= error;
112
+ const active = this.active;
113
+ this.retirement ??= this.rpc.close();
114
+ if (active)
115
+ void this.retirement.then(() => this.finish(active, undefined, error));
116
+ });
117
+ rpc.onMessage = message => this.message(message);
118
+ }
119
+ message(message) {
120
+ const active = this.active;
121
+ const params = message.params;
122
+ if (message.id !== undefined) {
123
+ try {
124
+ this.rpc.send({ id: message.id, result: { outcome: { outcome: "cancelled" } } });
125
+ }
126
+ catch { /* cancellation will surface the transport failure */ }
127
+ if (!active) {
128
+ this.rpc.abort(new AgentError("INPUT_REQUIRED", "fx requested interactive input outside an active task."));
129
+ }
130
+ else if (!active.failure) {
131
+ active.failure = new AgentError("INPUT_REQUIRED", "fx requested interactive input or approval. Configure native permissions before retrying; no approval was granted.");
132
+ this.tools.stopAdmission();
133
+ try {
134
+ this.rpc.send({ method: "session/cancel", params: { sessionId: this.sessionId } });
135
+ }
136
+ catch { /* onFailure settles the turn */ }
137
+ active.cancellationTimer = setTimeout(() => {
138
+ if (this.active === active && !active.terminal)
139
+ this.rpc.abort(new AgentError("CANCELLATION_FAILED", "fx did not stop after requesting interactive input."));
140
+ }, 2_000);
141
+ active.cancellationTimer.unref();
142
+ }
143
+ return;
144
+ }
145
+ if (params?.sessionId !== this.sessionId)
146
+ return;
147
+ if (!active || message.method !== "session/update")
148
+ return;
149
+ const update = params.update;
150
+ if (!update || typeof update !== "object" || typeof update.sessionUpdate !== "string") {
151
+ this.rpc.abort(new AgentError("PROTOCOL_ERROR", "fx returned an invalid ACP session update."));
152
+ return;
153
+ }
154
+ if (update.sessionUpdate !== "agent_message_chunk")
155
+ return;
156
+ if (typeof update.messageId !== "string" || update.content?.type !== "text" || typeof update.content.text !== "string") {
157
+ this.rpc.abort(new AgentError("PROTOCOL_ERROR", "fx returned an invalid agent message chunk."));
158
+ return;
159
+ }
160
+ if (active.lastMessageId !== update.messageId) {
161
+ active.lastMessageId = update.messageId;
162
+ active.text = "";
163
+ active.responseBytes = 0;
164
+ active.responseTooLarge = false;
165
+ }
166
+ active.responseBytes += Buffer.byteLength(update.content.text, "utf8");
167
+ if (active.responseBytes > 1024 * 1024)
168
+ active.responseTooLarge = true;
169
+ else
170
+ active.text += update.content.text;
171
+ }
172
+ async finish(active, result, failure) {
173
+ if (active.terminal)
174
+ return;
175
+ active.terminal = true;
176
+ active.resolveNativeStopped();
177
+ if (active.cancellationTimer)
178
+ clearTimeout(active.cancellationTimer);
179
+ this.tools.stopAdmission();
180
+ await this.tools.drain();
181
+ if (this.active === active)
182
+ this.active = undefined;
183
+ if (failure)
184
+ return active.reject(failure);
185
+ if (active.failure)
186
+ return active.reject(active.failure);
187
+ if (active.responseTooLarge)
188
+ return active.reject(new AgentError("RESPONSE_TOO_LARGE", "fx response exceeds 1 MiB."));
189
+ if (result?.stopReason === "end_turn")
190
+ active.resolve(active.text);
191
+ else
192
+ active.reject(new AgentError(result?.stopReason === "cancelled" ? "INTERRUPTED" : "HARNESS_FAILED", "fx did not complete the turn successfully."));
193
+ }
194
+ async turn(prompt) {
195
+ if (this.closed)
196
+ throw new AgentError("HARNESS_FAILED", "The fx session is closed.");
197
+ if (this.failure)
198
+ throw this.failure;
199
+ if (this.active)
200
+ throw new AgentError("SESSION_BUSY", "fx already has an active turn.");
201
+ let resolve, reject;
202
+ let releaseAdmission;
203
+ let resolveNativeStopped;
204
+ const completion = new Promise((a, b) => { resolve = a; reject = b; });
205
+ const admission = new Promise(resolveAdmission => { releaseAdmission = resolveAdmission; });
206
+ const nativeStopped = new Promise(resolveStopped => { resolveNativeStopped = resolveStopped; });
207
+ const active = { text: "", responseBytes: 0, responseTooLarge: false, completion, resolve, reject, terminal: false, submitted: false, cancelRequested: false, admission, releaseAdmission, nativeStopped, resolveNativeStopped };
208
+ this.active = active;
209
+ void completion.catch(() => { });
210
+ try {
211
+ if (await fxSettingsFingerprint(this.env) !== this.settingsFingerprint) {
212
+ throw new AgentError("INVALID_CONFIG", "fx native settings changed while the session was active. Start a new session.");
213
+ }
214
+ if (this.failure)
215
+ throw this.failure;
216
+ if (active.terminal || this.active !== active)
217
+ throw new AgentError("HARNESS_FAILED", "fx stopped while preparing the native prompt.");
218
+ if (active.cancelRequested || this.closed)
219
+ throw new AgentError("INTERRUPTED", "The fx turn was interrupted before submission.");
220
+ this.tools.beginTurn();
221
+ const includeInstructions = this.first;
222
+ const text = includeInstructions && this.options.agent.instructions ? firstPrompt(this.options.agent.instructions, prompt) : prompt;
223
+ active.submitted = true;
224
+ active.releaseAdmission();
225
+ const result = await this.rpc.request("session/prompt", { sessionId: this.sessionId, prompt: [{ type: "text", text }] });
226
+ if (includeInstructions)
227
+ this.first = false;
228
+ await this.finish(active, result);
229
+ return await completion;
230
+ }
231
+ catch (error) {
232
+ active.releaseAdmission();
233
+ if (this.failure && this.retirement)
234
+ await this.retirement;
235
+ await this.finish(active, undefined, error instanceof AgentError ? error : new AgentError("HARNESS_FAILED", "fx could not complete the native prompt."));
236
+ return await completion;
237
+ }
238
+ }
239
+ async steer(_prompt) {
240
+ throw new AgentError("UNSUPPORTED_DELIVERY", "fx does not expose verified active steering.");
241
+ }
242
+ async interrupt() {
243
+ const active = this.active;
244
+ if (!active)
245
+ return;
246
+ active.cancelRequested = true;
247
+ this.tools.stopAdmission();
248
+ await bounded(active.admission, 2_000);
249
+ const admittedTools = this.tools.drain();
250
+ let cancellationFailure;
251
+ try {
252
+ if (active.submitted && !active.terminal)
253
+ this.rpc.send({ method: "session/cancel", params: { sessionId: this.sessionId } });
254
+ }
255
+ catch (error) {
256
+ cancellationFailure = error;
257
+ }
258
+ await admittedTools;
259
+ if (cancellationFailure && !this.failure)
260
+ throw cancellationFailure;
261
+ await bounded(active.nativeStopped, 3_000);
262
+ await active.completion.catch(() => { });
263
+ }
264
+ async resume() {
265
+ throw new AgentError("RECOVERY_UNSUPPORTED", "fx recovery without a new prompt is unavailable.");
266
+ }
267
+ async close() {
268
+ if (this.closed)
269
+ return;
270
+ this.closed = true;
271
+ this.tools.stopAdmission();
272
+ try {
273
+ if (this.active) {
274
+ this.active.cancelRequested = true;
275
+ await bounded(this.active.admission, 2_000);
276
+ if (this.active.submitted && !this.active.terminal)
277
+ this.rpc.send({ method: "session/cancel", params: { sessionId: this.sessionId } });
278
+ }
279
+ await bounded(this.rpc.request("session/close", { sessionId: this.sessionId }), 2_000);
280
+ }
281
+ catch { /* process termination below still retires the session */ }
282
+ await this.rpc.close();
283
+ await this.tools.close();
284
+ }
285
+ }
286
+ function firstPrompt(instructions, prompt) {
287
+ return `<subharness-instructions>\n${instructions}\n</subharness-instructions>\n\n${prompt}`;
288
+ }
289
+ async function bounded(promise, milliseconds) {
290
+ let timer;
291
+ const timeout = new Promise((_resolve, reject) => {
292
+ timer = setTimeout(() => reject(new AgentError("CANCELLATION_FAILED", "fx did not confirm that native execution stopped.")), milliseconds);
293
+ timer.unref();
294
+ });
295
+ try {
296
+ return await Promise.race([promise, timeout]);
297
+ }
298
+ finally {
299
+ clearTimeout(timer);
300
+ }
301
+ }
302
+ //# sourceMappingURL=fx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fx.js","sourceRoot":"","sources":["../../src/adapters/fx.ts"],"names":[],"mappings":"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","sourcesContent":["import { AgentError } from \"../errors.js\";\nimport { fxEnvironment, fxSettingsFingerprint, verifyFxAccess } from \"./fx-auth.js\";\nimport { FxRpc, type AcpEnvelope } from \"./fx-rpc.js\";\nimport { startFxTools, type FxToolEndpoint } from \"./fx-tools.js\";\nimport type { AdapterOptions, NativeSession } from \"./types.js\";\n\ntype ActiveTurn = {\n lastMessageId?: string;\n text: string;\n responseBytes: number;\n responseTooLarge: boolean;\n completion: Promise<string>;\n resolve(text: string): void;\n reject(error: Error): void;\n terminal: boolean;\n submitted: boolean;\n cancelRequested: boolean;\n admission: Promise<void>;\n releaseAdmission(): void;\n nativeStopped: Promise<void>;\n resolveNativeStopped(): void;\n cancellationTimer?: NodeJS.Timeout;\n failure?: AgentError;\n};\n\nexport async function openFx(\n options: AdapterOptions,\n createRpc: (cwd: string, env: NodeJS.ProcessEnv, model?: string) => FxRpc = (cwd, env, model) => new FxRpc(cwd, env, model),\n): Promise<NativeSession> {\n const env = fxEnvironment(options);\n const baseline = await fxSettingsFingerprint(env);\n await verifyFxAccess(options.cwd, env, options.access.type);\n const tools = await startFxTools(options.agent);\n let rpc: FxRpc | undefined;\n try {\n const startedRpc = createRpc(options.cwd, env, options.harness.model);\n rpc = startedRpc;\n let startupFailure: AgentError | undefined;\n startedRpc.setFailureHandler(error => { startupFailure ??= error; });\n tools.onFailure(error => startedRpc.abort(error));\n startedRpc.onMessage = message => startupRequest(startedRpc, message);\n const initialized = await startedRpc.request(\"initialize\", { protocolVersion: 1, clientInfo: { name: \"subharness\", version: \"0.1.0\" }, clientCapabilities: {} });\n if (!initialized || typeof initialized !== \"object\" || Array.isArray(initialized) || typeof initialized.protocolVersion !== \"number\") {\n throw new AgentError(\"PROTOCOL_ERROR\", \"fx returned an invalid ACP initialization response.\");\n }\n if (initialized.protocolVersion !== 1) throw new AgentError(\"HARNESS_UNAVAILABLE\", \"The installed fx ACP protocol is not compatible with version 1.\");\n const created = await startedRpc.request(\"session/new\", {\n cwd: options.cwd,\n mcpServers: tools.descriptor ? [tools.descriptor] : [],\n });\n if (typeof created?.sessionId !== \"string\" || created.sessionId.length === 0) throw new AgentError(\"PROTOCOL_ERROR\", \"fx did not return a native session identifier.\");\n const selectedModel = verifySelection(created.configOptions, options.harness.model);\n if (options.harness.effort !== undefined) {\n verifyEffortAvailable(created.configOptions, options.harness.effort);\n const configured = await startedRpc.request(\"session/set_config_option\", { sessionId: created.sessionId, configId: \"effort\", value: options.harness.effort });\n verifySelection(configured?.configOptions, selectedModel, options.harness.effort);\n }\n if (await fxSettingsFingerprint(env) !== baseline) throw new AgentError(\"INVALID_CONFIG\", \"fx native settings changed during session startup. Start a new session.\");\n if (startupFailure) throw startupFailure;\n return new FxSession(startedRpc, created.sessionId, options, env, baseline, tools);\n } catch (error) {\n await rpc?.close();\n await tools.close();\n if (error instanceof AgentError) throw error;\n throw new AgentError(\"HARNESS_UNAVAILABLE\", \"Cannot start fx. Check the native executable and session configuration.\");\n }\n}\n\nfunction startupRequest(rpc: FxRpc, message: AcpEnvelope): void {\n if (message.id === undefined) return;\n try { rpc.send({ id: message.id, result: { outcome: { outcome: \"cancelled\" } } }); } catch { /* process may already be closing */ }\n rpc.abort(new AgentError(\"INPUT_REQUIRED\", \"fx requested interactive input during startup. Complete its native setup before running an agent.\"));\n}\n\nfunction option(options: unknown, id: string): any {\n if (!Array.isArray(options)) throw new AgentError(\"PROTOCOL_ERROR\", \"fx returned invalid native session options.\");\n return options.find(value => value && typeof value === \"object\" && (value as any).id === id);\n}\n\nfunction verifySelection(configOptions: unknown, requestedModel?: string, effort?: string): string {\n const provider = option(configOptions, \"provider\");\n const selectedModel = option(configOptions, \"model\");\n if (!provider || !selectedModel) {\n throw new AgentError(\"PROTOCOL_ERROR\", \"fx did not expose compatible native provider and model selectors.\");\n }\n if (provider.currentValue !== \"gateway\") {\n throw new AgentError(\"INVALID_CONFIG\", \"fx selected a provider outside the authorized Gateway route.\");\n }\n const model = selectedModel.currentValue;\n if (typeof model !== \"string\" || model.length === 0) {\n throw new AgentError(\"INVALID_CONFIG\", \"fx could not select a verifiable native default for this connection. Supply --model <model>.\");\n }\n if (requestedModel && model !== requestedModel) {\n throw new AgentError(\"INVALID_CONFIG\", \"fx changed the explicitly selected Gateway model.\");\n }\n if (effort !== undefined && option(configOptions, \"effort\")?.currentValue !== effort) {\n throw new AgentError(\"INVALID_CONFIG\", \"fx did not apply the explicitly selected effort.\");\n }\n return model;\n}\n\nfunction verifyEffortAvailable(configOptions: unknown, effort: string): void {\n const configured = option(configOptions, \"effort\");\n if (!configured || !Array.isArray(configured.options) || !configured.options.some((value: any) => value?.value === effort)) {\n throw new AgentError(\"UNSUPPORTED_OPTION\", \"The requested fx effort is not supported by the selected model.\");\n }\n}\n\nclass FxSession implements NativeSession {\n private active?: ActiveTurn;\n private failure?: AgentError;\n private retirement?: Promise<void>;\n private first = true;\n private closed = false;\n\n constructor(\n private readonly rpc: FxRpc,\n private readonly sessionId: string,\n private readonly options: AdapterOptions,\n private readonly env: NodeJS.ProcessEnv,\n private readonly settingsFingerprint: string,\n private readonly tools: FxToolEndpoint,\n ) {\n rpc.setFailureHandler(error => {\n this.failure ??= error;\n const active = this.active;\n this.retirement ??= this.rpc.close();\n if (active) void this.retirement.then(() => this.finish(active, undefined, error));\n });\n rpc.onMessage = message => this.message(message);\n }\n\n private message(message: AcpEnvelope): void {\n const active = this.active;\n const params = message.params;\n if (message.id !== undefined) {\n try { this.rpc.send({ id: message.id, result: { outcome: { outcome: \"cancelled\" } } }); } catch { /* cancellation will surface the transport failure */ }\n if (!active) {\n this.rpc.abort(new AgentError(\"INPUT_REQUIRED\", \"fx requested interactive input outside an active task.\"));\n } else if (!active.failure) {\n active.failure = new AgentError(\"INPUT_REQUIRED\", \"fx requested interactive input or approval. Configure native permissions before retrying; no approval was granted.\");\n this.tools.stopAdmission();\n try { this.rpc.send({ method: \"session/cancel\", params: { sessionId: this.sessionId } }); } catch { /* onFailure settles the turn */ }\n active.cancellationTimer = setTimeout(() => {\n if (this.active === active && !active.terminal) this.rpc.abort(new AgentError(\"CANCELLATION_FAILED\", \"fx did not stop after requesting interactive input.\"));\n }, 2_000);\n active.cancellationTimer.unref();\n }\n return;\n }\n if (params?.sessionId !== this.sessionId) return;\n if (!active || message.method !== \"session/update\") return;\n const update = params.update;\n if (!update || typeof update !== \"object\" || typeof update.sessionUpdate !== \"string\") {\n this.rpc.abort(new AgentError(\"PROTOCOL_ERROR\", \"fx returned an invalid ACP session update.\"));\n return;\n }\n if (update.sessionUpdate !== \"agent_message_chunk\") return;\n if (typeof update.messageId !== \"string\" || update.content?.type !== \"text\" || typeof update.content.text !== \"string\") {\n this.rpc.abort(new AgentError(\"PROTOCOL_ERROR\", \"fx returned an invalid agent message chunk.\"));\n return;\n }\n if (active.lastMessageId !== update.messageId) {\n active.lastMessageId = update.messageId;\n active.text = \"\";\n active.responseBytes = 0;\n active.responseTooLarge = false;\n }\n active.responseBytes += Buffer.byteLength(update.content.text, \"utf8\");\n if (active.responseBytes > 1024 * 1024) active.responseTooLarge = true;\n else active.text += update.content.text;\n }\n\n private async finish(active: ActiveTurn, result?: any, failure?: AgentError): Promise<void> {\n if (active.terminal) return;\n active.terminal = true;\n active.resolveNativeStopped();\n if (active.cancellationTimer) clearTimeout(active.cancellationTimer);\n this.tools.stopAdmission();\n await this.tools.drain();\n if (this.active === active) this.active = undefined;\n if (failure) return active.reject(failure);\n if (active.failure) return active.reject(active.failure);\n if (active.responseTooLarge) return active.reject(new AgentError(\"RESPONSE_TOO_LARGE\", \"fx response exceeds 1 MiB.\"));\n if (result?.stopReason === \"end_turn\") active.resolve(active.text);\n else active.reject(new AgentError(result?.stopReason === \"cancelled\" ? \"INTERRUPTED\" : \"HARNESS_FAILED\", \"fx did not complete the turn successfully.\"));\n }\n\n async turn(prompt: string): Promise<string> {\n if (this.closed) throw new AgentError(\"HARNESS_FAILED\", \"The fx session is closed.\");\n if (this.failure) throw this.failure;\n if (this.active) throw new AgentError(\"SESSION_BUSY\", \"fx already has an active turn.\");\n let resolve!: (text: string) => void, reject!: (error: Error) => void;\n let releaseAdmission!: () => void;\n let resolveNativeStopped!: () => void;\n const completion = new Promise<string>((a, b) => { resolve = a; reject = b; });\n const admission = new Promise<void>(resolveAdmission => { releaseAdmission = resolveAdmission; });\n const nativeStopped = new Promise<void>(resolveStopped => { resolveNativeStopped = resolveStopped; });\n const active: ActiveTurn = { text: \"\", responseBytes: 0, responseTooLarge: false, completion, resolve, reject, terminal: false, submitted: false, cancelRequested: false, admission, releaseAdmission, nativeStopped, resolveNativeStopped };\n this.active = active;\n void completion.catch(() => {});\n try {\n if (await fxSettingsFingerprint(this.env) !== this.settingsFingerprint) {\n throw new AgentError(\"INVALID_CONFIG\", \"fx native settings changed while the session was active. Start a new session.\");\n }\n if (this.failure) throw this.failure;\n if (active.terminal || this.active !== active) throw new AgentError(\"HARNESS_FAILED\", \"fx stopped while preparing the native prompt.\");\n if (active.cancelRequested || this.closed) throw new AgentError(\"INTERRUPTED\", \"The fx turn was interrupted before submission.\");\n this.tools.beginTurn();\n const includeInstructions = this.first;\n const text = includeInstructions && this.options.agent.instructions ? firstPrompt(this.options.agent.instructions, prompt) : prompt;\n active.submitted = true;\n active.releaseAdmission();\n const result = await this.rpc.request(\"session/prompt\", { sessionId: this.sessionId, prompt: [{ type: \"text\", text }] });\n if (includeInstructions) this.first = false;\n await this.finish(active, result);\n return await completion;\n } catch (error) {\n active.releaseAdmission();\n if (this.failure && this.retirement) await this.retirement;\n await this.finish(active, undefined, error instanceof AgentError ? error : new AgentError(\"HARNESS_FAILED\", \"fx could not complete the native prompt.\"));\n return await completion;\n }\n }\n\n async steer(_prompt: string): Promise<void> {\n throw new AgentError(\"UNSUPPORTED_DELIVERY\", \"fx does not expose verified active steering.\");\n }\n\n async interrupt(): Promise<void> {\n const active = this.active;\n if (!active) return;\n active.cancelRequested = true;\n this.tools.stopAdmission();\n await bounded(active.admission, 2_000);\n const admittedTools = this.tools.drain();\n let cancellationFailure: unknown;\n try {\n if (active.submitted && !active.terminal) this.rpc.send({ method: \"session/cancel\", params: { sessionId: this.sessionId } });\n } catch (error) {\n cancellationFailure = error;\n }\n await admittedTools;\n if (cancellationFailure && !this.failure) throw cancellationFailure;\n await bounded(active.nativeStopped, 3_000);\n await active.completion.catch(() => {});\n }\n\n async resume(): Promise<string> {\n throw new AgentError(\"RECOVERY_UNSUPPORTED\", \"fx recovery without a new prompt is unavailable.\");\n }\n\n async close(): Promise<void> {\n if (this.closed) return;\n this.closed = true;\n this.tools.stopAdmission();\n try {\n if (this.active) {\n this.active.cancelRequested = true;\n await bounded(this.active.admission, 2_000);\n if (this.active.submitted && !this.active.terminal) this.rpc.send({ method: \"session/cancel\", params: { sessionId: this.sessionId } });\n }\n await bounded(this.rpc.request(\"session/close\", { sessionId: this.sessionId }), 2_000);\n } catch { /* process termination below still retires the session */ }\n await this.rpc.close();\n await this.tools.close();\n }\n}\n\nfunction firstPrompt(instructions: string, prompt: string): string {\n return `<subharness-instructions>\\n${instructions}\\n</subharness-instructions>\\n\\n${prompt}`;\n}\n\nasync function bounded<T>(promise: Promise<T>, milliseconds: number): Promise<T> {\n let timer!: NodeJS.Timeout;\n const timeout = new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => reject(new AgentError(\"CANCELLATION_FAILED\", \"fx did not confirm that native execution stopped.\")), milliseconds);\n timer.unref();\n });\n try { return await Promise.race([promise, timeout]); }\n finally { clearTimeout(timer); }\n}\n"]}
@@ -0,0 +1,12 @@
1
+ import type { ExecutedToolResult } from "../sdk/tool-result.js";
2
+ export declare function mcpToolContent(result: ExecutedToolResult): ({
3
+ type: "text";
4
+ text: string;
5
+ data?: undefined;
6
+ mimeType?: undefined;
7
+ } | {
8
+ text?: undefined;
9
+ type: "image";
10
+ data: string;
11
+ mimeType: "image/gif" | "image/jpeg" | "image/png" | "image/webp";
12
+ })[];
@@ -0,0 +1,8 @@
1
+ export function mcpToolContent(result) {
2
+ if (typeof result === "string")
3
+ return [{ type: "text", text: result }];
4
+ return result.content.map(block => block.type === "text"
5
+ ? { type: "text", text: block.text }
6
+ : { type: "image", data: block.data, mimeType: block.mimeType });
7
+ }
8
+ //# sourceMappingURL=mcp-tool-content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-tool-content.js","sourceRoot":"","sources":["../../src/adapters/mcp-tool-content.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,cAAc,CAAC,MAA0B;IACvD,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IACjF,OAAO,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM;QACtD,CAAC,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE;QAC7C,CAAC,CAAC,EAAE,IAAI,EAAE,OAAgB,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC9E,CAAC","sourcesContent":["import type { ExecutedToolResult } from \"../sdk/tool-result.js\";\n\nexport function mcpToolContent(result: ExecutedToolResult) {\n if (typeof result === \"string\") return [{ type: \"text\" as const, text: result }];\n return result.content.map(block => block.type === \"text\"\n ? { type: \"text\" as const, text: block.text }\n : { type: \"image\" as const, data: block.data, mimeType: block.mimeType });\n}\n"]}
@@ -0,0 +1,28 @@
1
+ import { AgentError } from "../errors.js";
2
+ type Envelope = {
3
+ id?: string | number;
4
+ method?: string;
5
+ params?: any;
6
+ result?: any;
7
+ error?: unknown;
8
+ };
9
+ /** A bidirectional JSON-lines connection to an external native process. */
10
+ export declare class NativeRpc {
11
+ private readonly process;
12
+ private readonly pending;
13
+ private sequence;
14
+ private buffer;
15
+ private failure?;
16
+ private readonly exited;
17
+ onMessage: (message: Envelope) => void;
18
+ onFailure: (error: AgentError) => void;
19
+ constructor(command: string, args: string[], cwd: string, env: NodeJS.ProcessEnv);
20
+ request(method: string, params: unknown): Promise<any>;
21
+ send(message: Envelope): void;
22
+ abort(error: AgentError): void;
23
+ close(): Promise<void>;
24
+ private read;
25
+ private invalid;
26
+ private fail;
27
+ }
28
+ export {};