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,238 @@
1
+ import { AgentError } from "../errors.js";
2
+ import { executeTool, toolJsonSchema } from "../sdk/tools.js";
3
+ import { NativeRpc } from "./rpc.js";
4
+ import { codexEnvironment, codexConfiguration, validateCodexModel } from "./codex-config.js";
5
+ export async function openCodex(options) {
6
+ const env = codexEnvironment(options);
7
+ const rpc = new NativeRpc("codex", ["app-server", "--stdio"], options.cwd, env);
8
+ rpc.onMessage = message => {
9
+ if (message.id !== undefined)
10
+ rpc.abort(new AgentError("INPUT_REQUIRED", "Codex startup requested interactive input. Complete its native setup before running an agent."));
11
+ };
12
+ try {
13
+ await rpc.request("initialize", { clientInfo: { name: "subharness", version: "0.1.0" }, capabilities: { experimentalApi: true } });
14
+ rpc.send({ method: "initialized", params: {} });
15
+ const configuration = await codexConfiguration(rpc, options);
16
+ const result = await rpc.request("thread/start", {
17
+ ...(options.harness.model ? { model: options.harness.model } : {}), ...configuration, allowProviderModelFallback: false,
18
+ config: { ...configuration.config, ...(options.harness.effort ? { model_reasoning_effort: options.harness.effort } : {}), "features.fast_mode": options.harness.fast },
19
+ dynamicTools: Object.keys(options.agent.tools ?? {}).length ? [{
20
+ type: "namespace", name: "subharness", description: "Tools declared by this agent.",
21
+ tools: Object.entries(options.agent.tools ?? {}).map(([name, definition]) => ({ type: "function", name, description: definition.description, inputSchema: toolJsonSchema(definition) })),
22
+ }] : [],
23
+ cwd: options.cwd, serviceTier: options.harness.fast ? "fast" : null,
24
+ });
25
+ if (typeof result.thread?.id !== "string")
26
+ throw new AgentError("PROTOCOL_ERROR", "Codex did not return a native thread identifier.");
27
+ if (typeof result.model !== "string" || result.model.length === 0) {
28
+ throw new AgentError("INVALID_CONFIG", "Codex could not select a native default for this connection. Supply --model <model>.");
29
+ }
30
+ if ((options.harness.model && result.model !== options.harness.model) || result.modelProvider !== configuration.modelProvider) {
31
+ throw new AgentError("INVALID_CONFIG", options.harness.model
32
+ ? "Codex changed the explicitly selected model or provider."
33
+ : "Codex could not select a verifiable native default for this connection. Supply --model <model>.");
34
+ }
35
+ if (options.harness.effort && result.reasoningEffort !== options.harness.effort) {
36
+ throw new AgentError("INVALID_CONFIG", "Codex did not apply the explicitly selected effort.");
37
+ }
38
+ await validateCodexModel(rpc, options, result.model);
39
+ const requestedTier = options.harness.fast ? "fast" : "default";
40
+ if ((options.harness.fast && result.serviceTier !== "fast") || (result.serviceTier != null && result.serviceTier !== requestedTier))
41
+ throw new AgentError("INVALID_CONFIG", "Codex did not accept the requested speed setting.");
42
+ return new CodexSession(rpc, result.thread.id, result.model, options);
43
+ }
44
+ catch (error) {
45
+ await rpc.close();
46
+ throw error;
47
+ }
48
+ }
49
+ class CodexSession {
50
+ rpc;
51
+ threadId;
52
+ model;
53
+ options;
54
+ active;
55
+ constructor(rpc, threadId, model, options) {
56
+ this.rpc = rpc;
57
+ this.threadId = threadId;
58
+ this.model = model;
59
+ this.options = options;
60
+ rpc.onFailure = error => {
61
+ const active = this.active;
62
+ if (active)
63
+ void this.finish(active, undefined, error);
64
+ };
65
+ rpc.onMessage = message => {
66
+ const p = message.params;
67
+ const current = this.active;
68
+ if (p?.threadId !== this.threadId || !current)
69
+ return;
70
+ void Promise.resolve(current.started).then(() => {
71
+ if (this.active !== current || current.terminal)
72
+ return;
73
+ const turnId = p.turnId ?? p.turn?.id;
74
+ if (turnId && turnId !== current.id)
75
+ return;
76
+ if (message.method === "item/tool/call" && message.id !== undefined) {
77
+ if (!current.acceptingTools) {
78
+ this.rpc.send({ id: message.id, result: { success: false, contentItems: [{ type: "inputText", text: "The task is not accepting tool calls." }] } });
79
+ return;
80
+ }
81
+ const call = this.toolCall(message.id, p);
82
+ current.tools.add(call);
83
+ void call.finally(() => current.tools.delete(call));
84
+ return;
85
+ }
86
+ if (message.id !== undefined) {
87
+ this.stopForInput();
88
+ return;
89
+ }
90
+ if (message.method === "item/completed" && p.item?.type === "agentMessage") {
91
+ if (typeof p.item.id !== "string" || typeof p.item.text !== "string") {
92
+ current.failure = new AgentError("PROTOCOL_ERROR", "Codex sent an invalid turn event.");
93
+ void this.finish(current, undefined, current.failure);
94
+ return;
95
+ }
96
+ current.messages.set(p.item.id, { text: p.item.text, final: p.item.phase === "final_answer" });
97
+ }
98
+ if (message.method === "turn/completed")
99
+ void this.finish(current, p.turn);
100
+ }).catch(() => {
101
+ void this.finish(current, undefined, new AgentError("PROTOCOL_ERROR", "Codex sent an invalid turn event."));
102
+ });
103
+ };
104
+ }
105
+ async finish(active, turn, failure) {
106
+ if (active.terminal)
107
+ return;
108
+ active.terminal = true;
109
+ active.acceptingTools = false;
110
+ await Promise.allSettled([...active.tools]);
111
+ if (this.active === active)
112
+ this.active = undefined;
113
+ if (failure)
114
+ return active.reject(failure);
115
+ if (active.failure)
116
+ return active.reject(active.failure);
117
+ if (typeof turn !== "object" || turn === null || !Array.isArray(turn.items)) {
118
+ return active.reject(new AgentError("PROTOCOL_ERROR", "Codex sent an invalid turn event."));
119
+ }
120
+ for (const item of turn.items) {
121
+ if (item?.type !== "agentMessage")
122
+ continue;
123
+ if (typeof item.id !== "string" || typeof item.text !== "string") {
124
+ return active.reject(new AgentError("PROTOCOL_ERROR", "Codex sent an invalid turn event."));
125
+ }
126
+ active.messages.set(item.id, { text: item.text, final: item.phase === "final_answer" });
127
+ }
128
+ const messages = [...active.messages.values()].reverse();
129
+ const text = messages.find(m => m.final)?.text ?? messages[0]?.text ?? "";
130
+ if (Buffer.byteLength(text, "utf8") > 1024 * 1024)
131
+ active.reject(new AgentError("RESPONSE_TOO_LARGE", "Codex response exceeds 1 MiB."));
132
+ else if (turn?.status === "completed")
133
+ active.resolve(text);
134
+ else
135
+ active.reject(new AgentError(turn?.status === "interrupted" ? "INTERRUPTED" : "HARNESS_FAILED", "Codex did not complete the turn successfully."));
136
+ }
137
+ stopForInput() {
138
+ const active = this.active;
139
+ if (!active || active.failure)
140
+ return;
141
+ active.acceptingTools = false;
142
+ active.failure = new AgentError("INPUT_REQUIRED", "Codex requested interactive input or approval. Configure its native permissions before running this task; no approval was granted.");
143
+ void (async () => {
144
+ try {
145
+ await active.started;
146
+ if (this.active === active)
147
+ await this.rpc.request("turn/interrupt", { threadId: this.threadId, turnId: active.id });
148
+ }
149
+ catch {
150
+ const stopping = this.finish(active, undefined, new AgentError("CANCELLATION_FAILED", "Codex could not confirm interruption after requesting input."));
151
+ await this.rpc.close();
152
+ await stopping;
153
+ }
154
+ })();
155
+ }
156
+ async toolCall(id, params) {
157
+ let result, success = false;
158
+ try {
159
+ const tools = this.options.agent.tools ?? {};
160
+ if (params.namespace !== "subharness" || !Object.hasOwn(tools, params.tool))
161
+ throw new AgentError("TOOL_UNKNOWN", "Unknown tool.");
162
+ result = await executeTool(tools[params.tool], params.arguments);
163
+ success = true;
164
+ }
165
+ catch (error) {
166
+ result = error instanceof AgentError ? `Tool failed (${error.code}).` : "Tool execution failed.";
167
+ }
168
+ try {
169
+ this.rpc.send({ id, result: { contentItems: codexContent(result), success } });
170
+ }
171
+ catch { /* A cancelled native turn no longer accepts its tool result. */ }
172
+ }
173
+ async turn(prompt) {
174
+ if (this.active)
175
+ throw new AgentError("SESSION_BUSY", "Codex already has an active turn.");
176
+ let resolve, reject;
177
+ const completion = new Promise((a, b) => { resolve = a; reject = b; });
178
+ const active = { messages: new Map(), tools: new Set(), acceptingTools: true, resolve, reject, completion };
179
+ this.active = active;
180
+ void completion.catch(() => { });
181
+ try {
182
+ active.started = this.rpc.request("turn/start", {
183
+ threadId: this.threadId, input: [{ type: "text", text: prompt }], effort: this.options.harness.effort,
184
+ model: this.model,
185
+ serviceTierForTurn: this.options.harness.fast ? "fast" : "default",
186
+ }).then(result => { active.id = result.turn.id; });
187
+ await active.started;
188
+ return await completion;
189
+ }
190
+ catch (error) {
191
+ if (this.active === active)
192
+ this.active = undefined;
193
+ throw error;
194
+ }
195
+ }
196
+ async steer(prompt) {
197
+ const active = this.active;
198
+ await active?.started;
199
+ if (!active?.id || this.active !== active)
200
+ throw new AgentError("UNSUPPORTED_DELIVERY", "Codex has no active turn to steer.");
201
+ await this.rpc.request("turn/steer", { threadId: this.threadId, expectedTurnId: active.id, input: [{ type: "text", text: prompt }] });
202
+ }
203
+ async interrupt() {
204
+ const active = this.active;
205
+ if (!active)
206
+ return;
207
+ active.acceptingTools = false;
208
+ await active.started;
209
+ if (this.active !== active)
210
+ return;
211
+ if (!active.terminal)
212
+ await this.rpc.request("turn/interrupt", { threadId: this.threadId, turnId: active.id });
213
+ try {
214
+ await active.completion;
215
+ }
216
+ catch (error) {
217
+ if (!(error instanceof AgentError) || error.code !== "INTERRUPTED")
218
+ throw error;
219
+ }
220
+ }
221
+ async resume() { throw new AgentError("RECOVERY_UNSUPPORTED", "Codex does not expose retry of a failed turn without replay."); }
222
+ async close() {
223
+ const active = this.active;
224
+ if (active)
225
+ active.acceptingTools = false;
226
+ await this.rpc.close();
227
+ if (active)
228
+ await Promise.allSettled([...active.tools]);
229
+ }
230
+ }
231
+ function codexContent(result) {
232
+ if (typeof result === "string")
233
+ return [{ type: "inputText", text: result }];
234
+ return result.content.map(block => block.type === "text"
235
+ ? { type: "inputText", text: block.text }
236
+ : { type: "inputImage", imageUrl: `data:${block.mimeType};base64,${block.data}` });
237
+ }
238
+ //# sourceMappingURL=codex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/adapters/codex.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAE9D,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAgB7F,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAuB;IACrD,MAAM,GAAG,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACtC,MAAM,GAAG,GAAG,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC,YAAY,EAAE,SAAS,CAAC,EAAE,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAChF,GAAG,CAAC,SAAS,GAAG,OAAO,CAAC,EAAE;QACxB,IAAI,OAAO,CAAC,EAAE,KAAK,SAAS;YAAE,GAAG,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,gBAAgB,EAAE,+FAA+F,CAAC,CAAC,CAAC;IAC7K,CAAC,CAAC;IACF,IAAI,CAAC;QACH,MAAM,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,YAAY,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;QACnI,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;QAChD,MAAM,aAAa,GAAG,MAAM,kBAAkB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAC7D,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE;YAC/C,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,aAAa,EAAE,0BAA0B,EAAE,KAAK;YACvH,MAAM,EAAE,EAAE,GAAG,aAAa,CAAC,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,sBAAsB,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,oBAAoB,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE;YACtK,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;oBAC7D,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,+BAA+B;oBACnF,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,CAAC,WAAW,EAAE,WAAW,EAAE,cAAc,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;iBACzL,CAAC,CAAC,CAAC,CAAC,EAAE;YACP,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;SACpE,CAAC,CAAC;QACH,IAAI,OAAO,MAAM,CAAC,MAAM,EAAE,EAAE,KAAK,QAAQ;YAAE,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAE,kDAAkD,CAAC,CAAC;QACtI,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClE,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAE,sFAAsF,CAAC,CAAC;QACjI,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,KAAK,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,aAAa,KAAK,aAAa,CAAC,aAAa,EAAE,CAAC;YAC9H,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK;gBAC1D,CAAC,CAAC,0DAA0D;gBAC5D,CAAC,CAAC,iGAAiG,CAAC,CAAC;QACzG,CAAC;QACD,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,IAAI,MAAM,CAAC,eAAe,KAAK,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YAChF,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAE,qDAAqD,CAAC,CAAC;QAChG,CAAC;QACD,MAAM,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;QACrD,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;QAChE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,IAAI,MAAM,CAAC,WAAW,KAAK,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,IAAI,IAAI,MAAM,CAAC,WAAW,KAAK,aAAa,CAAC;YAAE,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAE,mDAAmD,CAAC,CAAC;QACjO,OAAO,IAAI,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACxE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAAC,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;QAAC,MAAM,KAAK,CAAC;IAAC,CAAC;AACrD,CAAC;AAED,MAAM,YAAY;IAGI,GAAG;IAAqB,QAAQ;IAAkB,KAAK;IAAkB,OAAO;IAF5F,MAAM,CAAc;IAE5B,YAAoB,GAAc,EAAU,QAAgB,EAAU,KAAa,EAAU,OAAuB;mBAAhG,GAAG;wBAAqB,QAAQ;qBAAkB,KAAK;uBAAkB,OAAO;QAClG,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC,EAAE;YACtB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;YAC3B,IAAI,MAAM;gBAAE,KAAK,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;QACzD,CAAC,CAAC;QACF,GAAG,CAAC,SAAS,GAAG,OAAO,CAAC,EAAE;YACxB,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;YACzB,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC;YAC5B,IAAI,CAAC,EAAE,QAAQ,KAAK,IAAI,CAAC,QAAQ,IAAI,CAAC,OAAO;gBAAE,OAAO;YACtD,KAAK,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;gBAC9C,IAAI,IAAI,CAAC,MAAM,KAAK,OAAO,IAAI,OAAO,CAAC,QAAQ;oBAAE,OAAO;gBACxD,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;gBACtC,IAAI,MAAM,IAAI,MAAM,KAAK,OAAO,CAAC,EAAE;oBAAE,OAAO;gBAC5C,IAAI,OAAO,CAAC,MAAM,KAAK,gBAAgB,IAAI,OAAO,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;oBACpE,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC;wBAC5B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,uCAAuC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;wBACpJ,OAAO;oBACT,CAAC;oBACD,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;oBAC1C,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;oBACxB,KAAK,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;oBACpD,OAAO;gBACT,CAAC;gBACD,IAAI,OAAO,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;oBAC7B,IAAI,CAAC,YAAY,EAAE,CAAC;oBACpB,OAAO;gBACT,CAAC;gBACD,IAAI,OAAO,CAAC,MAAM,KAAK,gBAAgB,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,KAAK,cAAc,EAAE,CAAC;oBAC3E,IAAI,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;wBACrE,OAAO,CAAC,OAAO,GAAG,IAAI,UAAU,CAAC,gBAAgB,EAAE,mCAAmC,CAAC,CAAC;wBACxF,KAAK,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;wBACtD,OAAO;oBACT,CAAC;oBACD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,KAAK,cAAc,EAAE,CAAC,CAAC;gBACjG,CAAC;gBACD,IAAI,OAAO,CAAC,MAAM,KAAK,gBAAgB;oBAAE,KAAK,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;YAC7E,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;gBACZ,KAAK,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,UAAU,CAAC,gBAAgB,EAAE,mCAAmC,CAAC,CAAC,CAAC;YAC9G,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,MAAM,CAAC,MAAkB,EAAE,IAAU,EAAE,OAAoB;QACvE,IAAI,MAAM,CAAC,QAAQ;YAAE,OAAO;QAC5B,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC;QACvB,MAAM,CAAC,cAAc,GAAG,KAAK,CAAC;QAC9B,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC5C,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM;YAAE,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;QACpD,IAAI,OAAO;YAAE,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC3C,IAAI,MAAM,CAAC,OAAO;YAAE,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACzD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5E,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,gBAAgB,EAAE,mCAAmC,CAAC,CAAC,CAAC;QAC9F,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,IAAI,IAAI,EAAE,IAAI,KAAK,cAAc;gBAAE,SAAS;YAC5C,IAAI,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACjE,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,gBAAgB,EAAE,mCAAmC,CAAC,CAAC,CAAC;YAC9F,CAAC;YACD,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,KAAK,cAAc,EAAE,CAAC,CAAC;QAC1F,CAAC;QACD,MAAM,QAAQ,GAAG,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;QACzD,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,IAAI,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;QAC1E,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,IAAI,GAAG,IAAI;YAAE,MAAM,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,oBAAoB,EAAE,+BAA+B,CAAC,CAAC,CAAC;aACnI,IAAI,IAAI,EAAE,MAAM,KAAK,WAAW;YAAE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;;YACvD,MAAM,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,IAAI,EAAE,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,gBAAgB,EAAE,+CAA+C,CAAC,CAAC,CAAC;IACzJ,CAAC;IAEO,YAAY;QAClB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC3B,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,OAAO;YAAE,OAAO;QACtC,MAAM,CAAC,cAAc,GAAG,KAAK,CAAC;QAC9B,MAAM,CAAC,OAAO,GAAG,IAAI,UAAU,CAAC,gBAAgB,EAAE,oIAAoI,CAAC,CAAC;QACxL,KAAK,CAAC,KAAK,IAAI,EAAE;YACf,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,OAAO,CAAC;gBACrB,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM;oBAAE,MAAM,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;YACvH,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,UAAU,CAAC,qBAAqB,EAAE,8DAA8D,CAAC,CAAC,CAAC;gBACvJ,MAAM,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;gBACvB,MAAM,QAAQ,CAAC;YACjB,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;IACP,CAAC;IAEO,KAAK,CAAC,QAAQ,CAAC,EAAmB,EAAE,MAAW;QACrD,IAAI,MAA0B,EAAE,OAAO,GAAG,KAAK,CAAC;QAChD,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;YAC7C,IAAI,MAAM,CAAC,SAAS,KAAK,YAAY,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC;gBAAE,MAAM,IAAI,UAAU,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;YACnI,MAAM,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAE,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;YAClE,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,GAAG,KAAK,YAAY,UAAU,CAAC,CAAC,CAAC,gBAAgB,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,wBAAwB,CAAC;QACnG,CAAC;QACD,IAAI,CAAC;YAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,gEAAgE,CAAC,CAAC;IACpK,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,MAAc;QACvB,IAAI,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,UAAU,CAAC,cAAc,EAAE,mCAAmC,CAAC,CAAC;QAC3F,IAAI,OAAgC,EAAE,MAA+B,CAAC;QACtE,MAAM,UAAU,GAAG,IAAI,OAAO,CAAS,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/E,MAAM,MAAM,GAAe,EAAE,QAAQ,EAAE,IAAI,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;QACxH,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,KAAK,UAAU,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAChC,IAAI,CAAC;YACH,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE;gBAC9C,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM;gBACrG,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,kBAAkB,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;aACnE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YACnD,MAAM,MAAM,CAAC,OAAO,CAAC;YACrB,OAAO,MAAM,UAAU,CAAC;QAC1B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAAC,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM;gBAAE,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;YAAC,MAAM,KAAK,CAAC;QAAC,CAAC;IACvF,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,MAAc;QACxB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC3B,MAAM,MAAM,EAAE,OAAO,CAAC;QACtB,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM;YAAE,MAAM,IAAI,UAAU,CAAC,sBAAsB,EAAE,oCAAoC,CAAC,CAAC;QAC9H,MAAM,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;IACxI,CAAC;IAED,KAAK,CAAC,SAAS;QACb,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC3B,IAAI,CAAC,MAAM;YAAE,OAAO;QACpB,MAAM,CAAC,cAAc,GAAG,KAAK,CAAC;QAC9B,MAAM,MAAM,CAAC,OAAO,CAAC;QACrB,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM;YAAE,OAAO;QACnC,IAAI,CAAC,MAAM,CAAC,QAAQ;YAAE,MAAM,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;QAC/G,IAAI,CAAC;YAAC,MAAM,MAAM,CAAC,UAAU,CAAC;QAAC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAC9C,IAAI,CAAC,CAAC,KAAK,YAAY,UAAU,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa;gBAAE,MAAM,KAAK,CAAC;QAClF,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM,KAAsB,MAAM,IAAI,UAAU,CAAC,sBAAsB,EAAE,8DAA8D,CAAC,CAAC,CAAC,CAAC;IACjJ,KAAK,CAAC,KAAK;QACT,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC3B,IAAI,MAAM;YAAE,MAAM,CAAC,cAAc,GAAG,KAAK,CAAC;QAC1C,MAAM,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;QACvB,IAAI,MAAM;YAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1D,CAAC;CACF;AAED,SAAS,YAAY,CAAC,MAA0B;IAC9C,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,CAAC,EAAE,IAAI,EAAE,WAAoB,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IACtF,OAAO,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM;QACtD,CAAC,CAAC,EAAE,IAAI,EAAE,WAAoB,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE;QAClD,CAAC,CAAC,EAAE,IAAI,EAAE,YAAqB,EAAE,QAAQ,EAAE,QAAQ,KAAK,CAAC,QAAQ,WAAW,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AAChG,CAAC","sourcesContent":["import { AgentError } from \"../errors.js\";\nimport { executeTool, toolJsonSchema } from \"../sdk/tools.js\";\nimport type { ExecutedToolResult } from \"../sdk/tool-result.js\";\nimport { NativeRpc } from \"./rpc.js\";\nimport { codexEnvironment, codexConfiguration, validateCodexModel } from \"./codex-config.js\";\nimport type { AdapterOptions, NativeSession } from \"./types.js\";\n\ntype ActiveTurn = {\n id?: string;\n messages: Map<string, { text: string; final: boolean }>;\n resolve(text: string): void;\n reject(error: Error): void;\n completion: Promise<string>;\n started?: Promise<void>;\n failure?: AgentError;\n tools: Set<Promise<void>>;\n terminal?: boolean;\n acceptingTools: boolean;\n};\n\nexport async function openCodex(options: AdapterOptions): Promise<NativeSession> {\n const env = codexEnvironment(options);\n const rpc = new NativeRpc(\"codex\", [\"app-server\", \"--stdio\"], options.cwd, env);\n rpc.onMessage = message => {\n if (message.id !== undefined) rpc.abort(new AgentError(\"INPUT_REQUIRED\", \"Codex startup requested interactive input. Complete its native setup before running an agent.\"));\n };\n try {\n await rpc.request(\"initialize\", { clientInfo: { name: \"subharness\", version: \"0.1.0\" }, capabilities: { experimentalApi: true } });\n rpc.send({ method: \"initialized\", params: {} });\n const configuration = await codexConfiguration(rpc, options);\n const result = await rpc.request(\"thread/start\", {\n ...(options.harness.model ? { model: options.harness.model } : {}), ...configuration, allowProviderModelFallback: false,\n config: { ...configuration.config, ...(options.harness.effort ? { model_reasoning_effort: options.harness.effort } : {}), \"features.fast_mode\": options.harness.fast },\n dynamicTools: Object.keys(options.agent.tools ?? {}).length ? [{\n type: \"namespace\", name: \"subharness\", description: \"Tools declared by this agent.\",\n tools: Object.entries(options.agent.tools ?? {}).map(([name, definition]) => ({ type: \"function\", name, description: definition.description, inputSchema: toolJsonSchema(definition) })),\n }] : [],\n cwd: options.cwd, serviceTier: options.harness.fast ? \"fast\" : null,\n });\n if (typeof result.thread?.id !== \"string\") throw new AgentError(\"PROTOCOL_ERROR\", \"Codex did not return a native thread identifier.\");\n if (typeof result.model !== \"string\" || result.model.length === 0) {\n throw new AgentError(\"INVALID_CONFIG\", \"Codex could not select a native default for this connection. Supply --model <model>.\");\n }\n if ((options.harness.model && result.model !== options.harness.model) || result.modelProvider !== configuration.modelProvider) {\n throw new AgentError(\"INVALID_CONFIG\", options.harness.model\n ? \"Codex changed the explicitly selected model or provider.\"\n : \"Codex could not select a verifiable native default for this connection. Supply --model <model>.\");\n }\n if (options.harness.effort && result.reasoningEffort !== options.harness.effort) {\n throw new AgentError(\"INVALID_CONFIG\", \"Codex did not apply the explicitly selected effort.\");\n }\n await validateCodexModel(rpc, options, result.model);\n const requestedTier = options.harness.fast ? \"fast\" : \"default\";\n if ((options.harness.fast && result.serviceTier !== \"fast\") || (result.serviceTier != null && result.serviceTier !== requestedTier)) throw new AgentError(\"INVALID_CONFIG\", \"Codex did not accept the requested speed setting.\");\n return new CodexSession(rpc, result.thread.id, result.model, options);\n } catch (error) { await rpc.close(); throw error; }\n}\n\nclass CodexSession implements NativeSession {\n private active?: ActiveTurn;\n\n constructor(private rpc: NativeRpc, private threadId: string, private model: string, private options: AdapterOptions) {\n rpc.onFailure = error => {\n const active = this.active;\n if (active) void this.finish(active, undefined, error);\n };\n rpc.onMessage = message => {\n const p = message.params;\n const current = this.active;\n if (p?.threadId !== this.threadId || !current) return;\n void Promise.resolve(current.started).then(() => {\n if (this.active !== current || current.terminal) return;\n const turnId = p.turnId ?? p.turn?.id;\n if (turnId && turnId !== current.id) return;\n if (message.method === \"item/tool/call\" && message.id !== undefined) {\n if (!current.acceptingTools) {\n this.rpc.send({ id: message.id, result: { success: false, contentItems: [{ type: \"inputText\", text: \"The task is not accepting tool calls.\" }] } });\n return;\n }\n const call = this.toolCall(message.id, p);\n current.tools.add(call);\n void call.finally(() => current.tools.delete(call));\n return;\n }\n if (message.id !== undefined) {\n this.stopForInput();\n return;\n }\n if (message.method === \"item/completed\" && p.item?.type === \"agentMessage\") {\n if (typeof p.item.id !== \"string\" || typeof p.item.text !== \"string\") {\n current.failure = new AgentError(\"PROTOCOL_ERROR\", \"Codex sent an invalid turn event.\");\n void this.finish(current, undefined, current.failure);\n return;\n }\n current.messages.set(p.item.id, { text: p.item.text, final: p.item.phase === \"final_answer\" });\n }\n if (message.method === \"turn/completed\") void this.finish(current, p.turn);\n }).catch(() => {\n void this.finish(current, undefined, new AgentError(\"PROTOCOL_ERROR\", \"Codex sent an invalid turn event.\"));\n });\n };\n }\n\n private async finish(active: ActiveTurn, turn?: any, failure?: AgentError): Promise<void> {\n if (active.terminal) return;\n active.terminal = true;\n active.acceptingTools = false;\n await Promise.allSettled([...active.tools]);\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 (typeof turn !== \"object\" || turn === null || !Array.isArray(turn.items)) {\n return active.reject(new AgentError(\"PROTOCOL_ERROR\", \"Codex sent an invalid turn event.\"));\n }\n for (const item of turn.items) {\n if (item?.type !== \"agentMessage\") continue;\n if (typeof item.id !== \"string\" || typeof item.text !== \"string\") {\n return active.reject(new AgentError(\"PROTOCOL_ERROR\", \"Codex sent an invalid turn event.\"));\n }\n active.messages.set(item.id, { text: item.text, final: item.phase === \"final_answer\" });\n }\n const messages = [...active.messages.values()].reverse();\n const text = messages.find(m => m.final)?.text ?? messages[0]?.text ?? \"\";\n if (Buffer.byteLength(text, \"utf8\") > 1024 * 1024) active.reject(new AgentError(\"RESPONSE_TOO_LARGE\", \"Codex response exceeds 1 MiB.\"));\n else if (turn?.status === \"completed\") active.resolve(text);\n else active.reject(new AgentError(turn?.status === \"interrupted\" ? \"INTERRUPTED\" : \"HARNESS_FAILED\", \"Codex did not complete the turn successfully.\"));\n }\n\n private stopForInput(): void {\n const active = this.active;\n if (!active || active.failure) return;\n active.acceptingTools = false;\n active.failure = new AgentError(\"INPUT_REQUIRED\", \"Codex requested interactive input or approval. Configure its native permissions before running this task; no approval was granted.\");\n void (async () => {\n try {\n await active.started;\n if (this.active === active) await this.rpc.request(\"turn/interrupt\", { threadId: this.threadId, turnId: active.id });\n } catch {\n const stopping = this.finish(active, undefined, new AgentError(\"CANCELLATION_FAILED\", \"Codex could not confirm interruption after requesting input.\"));\n await this.rpc.close();\n await stopping;\n }\n })();\n }\n\n private async toolCall(id: string | number, params: any): Promise<void> {\n let result: ExecutedToolResult, success = false;\n try {\n const tools = this.options.agent.tools ?? {};\n if (params.namespace !== \"subharness\" || !Object.hasOwn(tools, params.tool)) throw new AgentError(\"TOOL_UNKNOWN\", \"Unknown tool.\");\n result = await executeTool(tools[params.tool]!, params.arguments);\n success = true;\n } catch (error) {\n result = error instanceof AgentError ? `Tool failed (${error.code}).` : \"Tool execution failed.\";\n }\n try { this.rpc.send({ id, result: { contentItems: codexContent(result), success } }); } catch { /* A cancelled native turn no longer accepts its tool result. */ }\n }\n\n async turn(prompt: string): Promise<string> {\n if (this.active) throw new AgentError(\"SESSION_BUSY\", \"Codex already has an active turn.\");\n let resolve!: (text: string) => void, reject!: (error: Error) => void;\n const completion = new Promise<string>((a, b) => { resolve = a; reject = b; });\n const active: ActiveTurn = { messages: new Map(), tools: new Set(), acceptingTools: true, resolve, reject, completion };\n this.active = active;\n void completion.catch(() => {});\n try {\n active.started = this.rpc.request(\"turn/start\", {\n threadId: this.threadId, input: [{ type: \"text\", text: prompt }], effort: this.options.harness.effort,\n model: this.model,\n serviceTierForTurn: this.options.harness.fast ? \"fast\" : \"default\",\n }).then(result => { active.id = result.turn.id; });\n await active.started;\n return await completion;\n } catch (error) { if (this.active === active) this.active = undefined; throw error; }\n }\n\n async steer(prompt: string): Promise<void> {\n const active = this.active;\n await active?.started;\n if (!active?.id || this.active !== active) throw new AgentError(\"UNSUPPORTED_DELIVERY\", \"Codex has no active turn to steer.\");\n await this.rpc.request(\"turn/steer\", { threadId: this.threadId, expectedTurnId: active.id, input: [{ type: \"text\", text: prompt }] });\n }\n\n async interrupt(): Promise<void> {\n const active = this.active;\n if (!active) return;\n active.acceptingTools = false;\n await active.started;\n if (this.active !== active) return;\n if (!active.terminal) await this.rpc.request(\"turn/interrupt\", { threadId: this.threadId, turnId: active.id });\n try { await active.completion; } catch (error) {\n if (!(error instanceof AgentError) || error.code !== \"INTERRUPTED\") throw error;\n }\n }\n\n async resume(): Promise<string> { throw new AgentError(\"RECOVERY_UNSUPPORTED\", \"Codex does not expose retry of a failed turn without replay.\"); }\n async close(): Promise<void> {\n const active = this.active;\n if (active) active.acceptingTools = false;\n await this.rpc.close();\n if (active) await Promise.allSettled([...active.tools]);\n }\n}\n\nfunction codexContent(result: ExecutedToolResult) {\n if (typeof result === \"string\") return [{ type: \"inputText\" as const, text: result }];\n return result.content.map(block => block.type === \"text\"\n ? { type: \"inputText\" as const, text: block.text }\n : { type: \"inputImage\" as const, imageUrl: `data:${block.mimeType};base64,${block.data}` });\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import type { AdapterOptions } from "./types.js";
2
+ export declare function fxEnvironment(options: AdapterOptions): NodeJS.ProcessEnv;
3
+ export declare function verifyFxAccess(cwd: string, env: NodeJS.ProcessEnv, accessType: string): Promise<void>;
4
+ export declare function fxSettingsFingerprint(env: NodeJS.ProcessEnv): Promise<string>;
@@ -0,0 +1,116 @@
1
+ import { spawn } from "node:child_process";
2
+ import { createHash } from "node:crypto";
3
+ import { readFile } from "node:fs/promises";
4
+ import { homedir } from "node:os";
5
+ import { join } from "node:path";
6
+ import { AgentError } from "../errors.js";
7
+ const unsafeEnvironment = [
8
+ "FX_AUTH_MODE", "FX_GATEWAY_CHAT_URL", "FX_GATEWAY_BASE_URL", "FX_E2E_GATEWAY_CHAT_URL",
9
+ "FX_E2E_GATEWAY_CREDITS_URL", "FX_E2E_GATEWAY_MODELS_URL", "FX_DEBUG_RECORD",
10
+ "FX_DEBUG_RECORD_SILENT_BANNER", "FX_RECORD", "FX_RECORD_INPUT", "FX_TRACE", "FX_TRACE_LOG",
11
+ "FX_TRACE_SCOPES", "FX_TRACE_STDERR", "FX_UI_OBSERVE_DIR",
12
+ ];
13
+ export function fxEnvironment(options) {
14
+ if (options.access.type !== "vercel-api-key" && options.access.type !== "vercel-oidc") {
15
+ throw new AgentError("UNSUPPORTED_OPTION", "fx supports only explicit Vercel AI Gateway API key or OIDC access.");
16
+ }
17
+ if (!options.access.token)
18
+ throw new AgentError("ACCESS_UNAVAILABLE", "The selected fx connection has no credential.");
19
+ const env = { ...options.env };
20
+ delete env.AI_GATEWAY_API_KEY;
21
+ delete env.VERCEL_OIDC_TOKEN;
22
+ for (const name of unsafeEnvironment)
23
+ delete env[name];
24
+ env.FX_PROVIDER = "gateway";
25
+ if (options.harness.model)
26
+ env.FX_MODEL = options.harness.model;
27
+ env[options.access.type === "vercel-api-key" ? "AI_GATEWAY_API_KEY" : "VERCEL_OIDC_TOKEN"] = options.access.token;
28
+ return env;
29
+ }
30
+ export async function verifyFxAccess(cwd, env, accessType) {
31
+ const expected = accessType === "vercel-api-key" ? "AI_GATEWAY_API_KEY" : "VERCEL_OIDC_TOKEN";
32
+ const stdout = await captureStatus(cwd, env);
33
+ let status;
34
+ try {
35
+ status = JSON.parse(stdout);
36
+ }
37
+ catch {
38
+ throw new AgentError("PROTOCOL_ERROR", "fx returned malformed credential-source status.");
39
+ }
40
+ if (!status || typeof status !== "object" || Array.isArray(status) || status.kind !== "status" || typeof status.auth !== "string") {
41
+ throw new AgentError("PROTOCOL_ERROR", "fx returned malformed credential-source status.");
42
+ }
43
+ const actual = status.auth;
44
+ if (actual !== expected && !knownAuthSource(actual)) {
45
+ throw new AgentError("PROTOCOL_ERROR", "fx returned an unrecognized credential source.");
46
+ }
47
+ if (actual !== expected) {
48
+ throw new AgentError("ACCESS_UNAVAILABLE", `fx is not using ${expected}. Select the matching environment source in fx before starting this session.`);
49
+ }
50
+ }
51
+ function knownAuthSource(value) {
52
+ return value === "missing" || value === "AI_GATEWAY_API_KEY" || value === "VERCEL_OIDC_TOKEN"
53
+ || value === "fx login" || value === "Codex subscription" || value === "Grok subscription"
54
+ || value === "host managed" || /^stored API key \([^)]+\)$/u.test(value);
55
+ }
56
+ async function captureStatus(cwd, env) {
57
+ return await new Promise((resolve, reject) => {
58
+ const child = (() => {
59
+ try {
60
+ return spawn("fx", ["status", "--json"], { cwd, env, stdio: ["ignore", "pipe", "pipe"] });
61
+ }
62
+ catch {
63
+ reject(new AgentError("INVALID_CONFIG", "fx credential-source verification could not start with the selected process configuration."));
64
+ return undefined;
65
+ }
66
+ })();
67
+ if (!child)
68
+ return;
69
+ let output = "";
70
+ let settled = false;
71
+ const finish = (error) => {
72
+ if (settled)
73
+ return;
74
+ settled = true;
75
+ clearTimeout(timer);
76
+ if (error)
77
+ reject(error);
78
+ else
79
+ resolve(output);
80
+ };
81
+ const timer = setTimeout(() => {
82
+ child.kill("SIGKILL");
83
+ finish(new AgentError("HARNESS_UNAVAILABLE", "fx credential-source verification did not finish."));
84
+ }, 2_000);
85
+ timer.unref();
86
+ child.stdout.setEncoding("utf8");
87
+ child.stdout.on("data", chunk => {
88
+ output += chunk;
89
+ if (output.length > 1024 * 1024)
90
+ child.kill("SIGKILL");
91
+ });
92
+ child.stderr.resume();
93
+ child.on("error", () => finish(new AgentError("HARNESS_UNAVAILABLE", "Cannot start fx. Install fx 0.0.9 or a compatible release and make it available on PATH.")));
94
+ child.on("close", code => {
95
+ if (output.length > 1024 * 1024)
96
+ finish(new AgentError("PROTOCOL_ERROR", "fx returned oversized credential-source status."));
97
+ else if (code !== 0)
98
+ finish(new AgentError("ACCESS_UNAVAILABLE", "fx could not verify the selected Gateway credential source."));
99
+ else
100
+ finish();
101
+ });
102
+ });
103
+ }
104
+ export async function fxSettingsFingerprint(env) {
105
+ const path = join(env.HOME || homedir(), ".fx", "settings.json");
106
+ try {
107
+ const data = await readFile(path);
108
+ return createHash("sha256").update(data).digest("hex");
109
+ }
110
+ catch (error) {
111
+ if (error.code === "ENOENT")
112
+ return "missing";
113
+ throw new AgentError("INVALID_CONFIG", "fx native settings could not be verified.");
114
+ }
115
+ }
116
+ //# sourceMappingURL=fx-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fx-auth.js","sourceRoot":"","sources":["../../src/adapters/fx-auth.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { readFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { AgentError } from \"../errors.js\";\nimport type { AdapterOptions } from \"./types.js\";\n\nconst unsafeEnvironment = [\n \"FX_AUTH_MODE\", \"FX_GATEWAY_CHAT_URL\", \"FX_GATEWAY_BASE_URL\", \"FX_E2E_GATEWAY_CHAT_URL\",\n \"FX_E2E_GATEWAY_CREDITS_URL\", \"FX_E2E_GATEWAY_MODELS_URL\", \"FX_DEBUG_RECORD\",\n \"FX_DEBUG_RECORD_SILENT_BANNER\", \"FX_RECORD\", \"FX_RECORD_INPUT\", \"FX_TRACE\", \"FX_TRACE_LOG\",\n \"FX_TRACE_SCOPES\", \"FX_TRACE_STDERR\", \"FX_UI_OBSERVE_DIR\",\n] as const;\n\nexport function fxEnvironment(options: AdapterOptions): NodeJS.ProcessEnv {\n if (options.access.type !== \"vercel-api-key\" && options.access.type !== \"vercel-oidc\") {\n throw new AgentError(\"UNSUPPORTED_OPTION\", \"fx supports only explicit Vercel AI Gateway API key or OIDC access.\");\n }\n if (!options.access.token) throw new AgentError(\"ACCESS_UNAVAILABLE\", \"The selected fx connection has no credential.\");\n const env = { ...options.env };\n delete env.AI_GATEWAY_API_KEY;\n delete env.VERCEL_OIDC_TOKEN;\n for (const name of unsafeEnvironment) delete env[name];\n env.FX_PROVIDER = \"gateway\";\n if (options.harness.model) env.FX_MODEL = options.harness.model;\n env[options.access.type === \"vercel-api-key\" ? \"AI_GATEWAY_API_KEY\" : \"VERCEL_OIDC_TOKEN\"] = options.access.token;\n return env;\n}\n\nexport async function verifyFxAccess(cwd: string, env: NodeJS.ProcessEnv, accessType: string): Promise<void> {\n const expected = accessType === \"vercel-api-key\" ? \"AI_GATEWAY_API_KEY\" : \"VERCEL_OIDC_TOKEN\";\n const stdout = await captureStatus(cwd, env);\n let status: unknown;\n try { status = JSON.parse(stdout); } catch { throw new AgentError(\"PROTOCOL_ERROR\", \"fx returned malformed credential-source status.\"); }\n if (!status || typeof status !== \"object\" || Array.isArray(status) || (status as any).kind !== \"status\" || typeof (status as any).auth !== \"string\") {\n throw new AgentError(\"PROTOCOL_ERROR\", \"fx returned malformed credential-source status.\");\n }\n const actual = (status as any).auth;\n if (actual !== expected && !knownAuthSource(actual)) {\n throw new AgentError(\"PROTOCOL_ERROR\", \"fx returned an unrecognized credential source.\");\n }\n if (actual !== expected) {\n throw new AgentError(\"ACCESS_UNAVAILABLE\", `fx is not using ${expected}. Select the matching environment source in fx before starting this session.`);\n }\n}\n\nfunction knownAuthSource(value: string): boolean {\n return value === \"missing\" || value === \"AI_GATEWAY_API_KEY\" || value === \"VERCEL_OIDC_TOKEN\"\n || value === \"fx login\" || value === \"Codex subscription\" || value === \"Grok subscription\"\n || value === \"host managed\" || /^stored API key \\([^)]+\\)$/u.test(value);\n}\n\nasync function captureStatus(cwd: string, env: NodeJS.ProcessEnv): Promise<string> {\n return await new Promise((resolve, reject) => {\n const child = (() => {\n try { return spawn(\"fx\", [\"status\", \"--json\"], { cwd, env, stdio: [\"ignore\", \"pipe\", \"pipe\"] }); }\n catch {\n reject(new AgentError(\"INVALID_CONFIG\", \"fx credential-source verification could not start with the selected process configuration.\"));\n return undefined;\n }\n })();\n if (!child) return;\n let output = \"\";\n let settled = false;\n const finish = (error?: AgentError) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n if (error) reject(error); else resolve(output);\n };\n const timer = setTimeout(() => {\n child.kill(\"SIGKILL\");\n finish(new AgentError(\"HARNESS_UNAVAILABLE\", \"fx credential-source verification did not finish.\"));\n }, 2_000);\n timer.unref();\n child.stdout.setEncoding(\"utf8\");\n child.stdout.on(\"data\", chunk => {\n output += chunk;\n if (output.length > 1024 * 1024) child.kill(\"SIGKILL\");\n });\n child.stderr.resume();\n child.on(\"error\", () => finish(new AgentError(\"HARNESS_UNAVAILABLE\", \"Cannot start fx. Install fx 0.0.9 or a compatible release and make it available on PATH.\")));\n child.on(\"close\", code => {\n if (output.length > 1024 * 1024) finish(new AgentError(\"PROTOCOL_ERROR\", \"fx returned oversized credential-source status.\"));\n else if (code !== 0) finish(new AgentError(\"ACCESS_UNAVAILABLE\", \"fx could not verify the selected Gateway credential source.\"));\n else finish();\n });\n });\n}\n\nexport async function fxSettingsFingerprint(env: NodeJS.ProcessEnv): Promise<string> {\n const path = join(env.HOME || homedir(), \".fx\", \"settings.json\");\n try {\n const data = await readFile(path);\n return createHash(\"sha256\").update(data).digest(\"hex\");\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return \"missing\";\n throw new AgentError(\"INVALID_CONFIG\", \"fx native settings could not be verified.\");\n }\n}\n"]}
@@ -0,0 +1,29 @@
1
+ import { AgentError } from "../errors.js";
2
+ export type AcpEnvelope = {
3
+ jsonrpc?: string;
4
+ id?: string | number;
5
+ method?: string;
6
+ params?: any;
7
+ result?: any;
8
+ error?: unknown;
9
+ };
10
+ /** A JSON-RPC 2.0 newline transport for fx's native ACP process. */
11
+ export declare class FxRpc {
12
+ private readonly child;
13
+ private readonly pending;
14
+ private sequence;
15
+ private buffer;
16
+ private failure?;
17
+ private readonly exited;
18
+ private failureHandler;
19
+ onMessage: (message: AcpEnvelope) => void;
20
+ constructor(cwd: string, env: NodeJS.ProcessEnv, model?: string);
21
+ request(method: string, params: unknown): Promise<any>;
22
+ send(message: AcpEnvelope): void;
23
+ abort(error: AgentError): void;
24
+ setFailureHandler(handler: (error: AgentError) => void): void;
25
+ close(): Promise<void>;
26
+ private read;
27
+ private invalid;
28
+ private fail;
29
+ }
@@ -0,0 +1,124 @@
1
+ import { spawn } from "node:child_process";
2
+ import { AgentError } from "../errors.js";
3
+ /** A JSON-RPC 2.0 newline transport for fx's native ACP process. */
4
+ export class FxRpc {
5
+ child;
6
+ pending = new Map();
7
+ sequence = 0;
8
+ buffer = "";
9
+ failure;
10
+ exited;
11
+ failureHandler = () => { };
12
+ onMessage = () => { };
13
+ constructor(cwd, env, model) {
14
+ this.child = spawn("fx", model ? ["acp", "--model", model] : ["acp"], { cwd, env, stdio: ["pipe", "pipe", "pipe"] });
15
+ this.child.stdout.setEncoding("utf8");
16
+ this.child.stdout.on("data", chunk => this.read(chunk));
17
+ this.child.stderr.resume();
18
+ this.child.stdin.on("error", () => this.fail(new AgentError("HARNESS_FAILED", "The fx ACP input connection closed.")));
19
+ this.child.on("error", () => this.fail(new AgentError("HARNESS_UNAVAILABLE", "Cannot start fx. Install fx 0.0.9 or a compatible release and make it available on PATH.")));
20
+ this.exited = new Promise(resolve => this.child.once("close", () => {
21
+ this.fail(new AgentError("HARNESS_FAILED", "fx exited before the native operation completed."));
22
+ resolve();
23
+ }));
24
+ }
25
+ request(method, params) {
26
+ if (this.failure)
27
+ return Promise.reject(this.failure);
28
+ const id = ++this.sequence;
29
+ return new Promise((resolve, reject) => {
30
+ this.pending.set(id, { method, resolve, reject });
31
+ this.send({ id, method, params });
32
+ });
33
+ }
34
+ send(message) {
35
+ if (this.failure)
36
+ throw this.failure;
37
+ this.child.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", ...message })}\n`);
38
+ }
39
+ abort(error) {
40
+ this.fail(error);
41
+ void this.close();
42
+ }
43
+ setFailureHandler(handler) {
44
+ this.failureHandler = handler;
45
+ if (this.failure)
46
+ handler(this.failure);
47
+ }
48
+ async close() {
49
+ if (this.child.exitCode !== null || this.child.signalCode !== null)
50
+ return this.exited;
51
+ this.child.kill("SIGTERM");
52
+ const timer = setTimeout(() => this.child.kill("SIGKILL"), 2_000);
53
+ timer.unref();
54
+ await this.exited;
55
+ clearTimeout(timer);
56
+ }
57
+ read(chunk) {
58
+ this.buffer += chunk;
59
+ if (this.buffer.length > 16 * 1024 * 1024)
60
+ return this.invalid();
61
+ let newline;
62
+ while ((newline = this.buffer.indexOf("\n")) >= 0) {
63
+ const line = this.buffer.slice(0, newline);
64
+ this.buffer = this.buffer.slice(newline + 1);
65
+ if (!line.trim())
66
+ continue;
67
+ let message;
68
+ try {
69
+ message = JSON.parse(line);
70
+ }
71
+ catch {
72
+ return this.invalid();
73
+ }
74
+ if (!message || typeof message !== "object" || Array.isArray(message) || message.jsonrpc !== "2.0")
75
+ return this.invalid();
76
+ if (typeof message.method === "string") {
77
+ if (Object.hasOwn(message, "result") || Object.hasOwn(message, "error"))
78
+ return this.invalid();
79
+ this.onMessage(message);
80
+ continue;
81
+ }
82
+ if (typeof message.id !== "number")
83
+ return this.invalid();
84
+ const hasResult = Object.hasOwn(message, "result");
85
+ const hasError = Object.hasOwn(message, "error");
86
+ if (hasResult === hasError)
87
+ return this.invalid();
88
+ if (hasError) {
89
+ const error = message.error;
90
+ if (!error || typeof error !== "object" || Array.isArray(error)
91
+ || !Number.isInteger(error.code)
92
+ || typeof error.message !== "string")
93
+ return this.invalid();
94
+ }
95
+ const pending = this.pending.get(message.id);
96
+ if (!pending)
97
+ continue;
98
+ this.pending.delete(message.id);
99
+ if (hasError) {
100
+ const nativeCode = message.error?.code;
101
+ const unsupported = pending.method === "session/set_config_option" && (nativeCode === -32601 || nativeCode === -32602);
102
+ const code = unsupported ? "UNSUPPORTED_OPTION" : "NATIVE_ERROR";
103
+ pending.reject(new AgentError(code, code === "UNSUPPORTED_OPTION" ? "fx rejected the requested session option." : `fx rejected ${pending.method}. Check the native harness configuration.`));
104
+ }
105
+ else {
106
+ pending.resolve(message.result);
107
+ }
108
+ }
109
+ }
110
+ invalid() {
111
+ this.fail(new AgentError("PROTOCOL_ERROR", "fx returned invalid ACP protocol data."));
112
+ void this.close();
113
+ }
114
+ fail(error) {
115
+ if (this.failure)
116
+ return;
117
+ this.failure = error;
118
+ for (const pending of this.pending.values())
119
+ pending.reject(error);
120
+ this.pending.clear();
121
+ this.failureHandler(error);
122
+ }
123
+ }
124
+ //# sourceMappingURL=fx-rpc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fx-rpc.js","sourceRoot":"","sources":["../../src/adapters/fx-rpc.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn, type ChildProcessWithoutNullStreams } from \"node:child_process\";\nimport { AgentError } from \"../errors.js\";\n\nexport type AcpEnvelope = {\n jsonrpc?: string;\n id?: string | number;\n method?: string;\n params?: any;\n result?: any;\n error?: unknown;\n};\n\ntype Pending = { method: string; resolve(value: any): void; reject(error: Error): void };\n\n/** A JSON-RPC 2.0 newline transport for fx's native ACP process. */\nexport class FxRpc {\n private readonly child: ChildProcessWithoutNullStreams;\n private readonly pending = new Map<number, Pending>();\n private sequence = 0;\n private buffer = \"\";\n private failure?: AgentError;\n private readonly exited: Promise<void>;\n private failureHandler: (error: AgentError) => void = () => {};\n onMessage: (message: AcpEnvelope) => void = () => {};\n\n constructor(cwd: string, env: NodeJS.ProcessEnv, model?: string) {\n this.child = spawn(\"fx\", model ? [\"acp\", \"--model\", model] : [\"acp\"], { cwd, env, stdio: [\"pipe\", \"pipe\", \"pipe\"] });\n this.child.stdout.setEncoding(\"utf8\");\n this.child.stdout.on(\"data\", chunk => this.read(chunk));\n this.child.stderr.resume();\n this.child.stdin.on(\"error\", () => this.fail(new AgentError(\"HARNESS_FAILED\", \"The fx ACP input connection closed.\")));\n this.child.on(\"error\", () => this.fail(new AgentError(\"HARNESS_UNAVAILABLE\", \"Cannot start fx. Install fx 0.0.9 or a compatible release and make it available on PATH.\")));\n this.exited = new Promise(resolve => this.child.once(\"close\", () => {\n this.fail(new AgentError(\"HARNESS_FAILED\", \"fx exited before the native operation completed.\"));\n resolve();\n }));\n }\n\n request(method: string, params: unknown): Promise<any> {\n if (this.failure) return Promise.reject(this.failure);\n const id = ++this.sequence;\n return new Promise((resolve, reject) => {\n this.pending.set(id, { method, resolve, reject });\n this.send({ id, method, params });\n });\n }\n\n send(message: AcpEnvelope): void {\n if (this.failure) throw this.failure;\n this.child.stdin.write(`${JSON.stringify({ jsonrpc: \"2.0\", ...message })}\\n`);\n }\n\n abort(error: AgentError): void {\n this.fail(error);\n void this.close();\n }\n\n setFailureHandler(handler: (error: AgentError) => void): void {\n this.failureHandler = handler;\n if (this.failure) handler(this.failure);\n }\n\n async close(): Promise<void> {\n if (this.child.exitCode !== null || this.child.signalCode !== null) return this.exited;\n this.child.kill(\"SIGTERM\");\n const timer = setTimeout(() => this.child.kill(\"SIGKILL\"), 2_000);\n timer.unref();\n await this.exited;\n clearTimeout(timer);\n }\n\n private read(chunk: string): void {\n this.buffer += chunk;\n if (this.buffer.length > 16 * 1024 * 1024) return this.invalid();\n let newline: number;\n while ((newline = this.buffer.indexOf(\"\\n\")) >= 0) {\n const line = this.buffer.slice(0, newline);\n this.buffer = this.buffer.slice(newline + 1);\n if (!line.trim()) continue;\n let message: AcpEnvelope;\n try { message = JSON.parse(line); } catch { return this.invalid(); }\n if (!message || typeof message !== \"object\" || Array.isArray(message) || message.jsonrpc !== \"2.0\") return this.invalid();\n if (typeof message.method === \"string\") {\n if (Object.hasOwn(message, \"result\") || Object.hasOwn(message, \"error\")) return this.invalid();\n this.onMessage(message);\n continue;\n }\n if (typeof message.id !== \"number\") return this.invalid();\n const hasResult = Object.hasOwn(message, \"result\");\n const hasError = Object.hasOwn(message, \"error\");\n if (hasResult === hasError) return this.invalid();\n if (hasError) {\n const error = message.error;\n if (!error || typeof error !== \"object\" || Array.isArray(error)\n || !Number.isInteger((error as { code?: unknown }).code)\n || typeof (error as { message?: unknown }).message !== \"string\") return this.invalid();\n }\n const pending = this.pending.get(message.id);\n if (!pending) continue;\n this.pending.delete(message.id);\n if (hasError) {\n const nativeCode = (message.error as { code?: unknown } | null)?.code;\n const unsupported = pending.method === \"session/set_config_option\" && (nativeCode === -32601 || nativeCode === -32602);\n const code = unsupported ? \"UNSUPPORTED_OPTION\" : \"NATIVE_ERROR\";\n pending.reject(new AgentError(code, code === \"UNSUPPORTED_OPTION\" ? \"fx rejected the requested session option.\" : `fx rejected ${pending.method}. Check the native harness configuration.`));\n } else {\n pending.resolve(message.result);\n }\n }\n }\n\n private invalid(): void {\n this.fail(new AgentError(\"PROTOCOL_ERROR\", \"fx returned invalid ACP protocol data.\"));\n void this.close();\n }\n\n private fail(error: AgentError): void {\n if (this.failure) return;\n this.failure = error;\n for (const pending of this.pending.values()) pending.reject(error);\n this.pending.clear();\n this.failureHandler(error);\n }\n}\n"]}
@@ -0,0 +1,19 @@
1
+ import { AgentError } from "../errors.js";
2
+ import type { ExecutionDefinition } from "./types.js";
3
+ export type FxToolEndpoint = {
4
+ descriptor?: {
5
+ type: "http";
6
+ name: string;
7
+ url: string;
8
+ headers: {
9
+ name: string;
10
+ value: string;
11
+ }[];
12
+ };
13
+ onFailure(handler: (error: AgentError) => void): void;
14
+ beginTurn(): void;
15
+ stopAdmission(): void;
16
+ drain(): Promise<void>;
17
+ close(): Promise<void>;
18
+ };
19
+ export declare function startFxTools(agent: Pick<ExecutionDefinition, "tools">): Promise<FxToolEndpoint>;