@posthog/agent 2.3.168 → 2.3.171

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.
package/dist/agent.js CHANGED
@@ -1,132 +1,5 @@
1
1
  // src/adapters/acp-connection.ts
2
- import { AgentSideConnection, ndJsonStream } from "@agentclientprotocol/sdk";
3
-
4
- // src/acp-extensions.ts
5
- var POSTHOG_NOTIFICATIONS = {
6
- /** Git branch was created for a task */
7
- BRANCH_CREATED: "_posthog/branch_created",
8
- /** Task run has started execution */
9
- RUN_STARTED: "_posthog/run_started",
10
- /** Task has completed (success or failure) */
11
- TASK_COMPLETE: "_posthog/task_complete",
12
- /** Agent finished processing a turn (prompt returned, waiting for next input) */
13
- TURN_COMPLETE: "_posthog/turn_complete",
14
- /** Error occurred during task execution */
15
- ERROR: "_posthog/error",
16
- /** Console/log output from the agent */
17
- CONSOLE: "_posthog/console",
18
- /** Maps taskRunId to agent's sessionId and adapter type (for resumption) */
19
- SDK_SESSION: "_posthog/sdk_session",
20
- /** Tree state snapshot captured (git tree hash + file archive) */
21
- TREE_SNAPSHOT: "_posthog/tree_snapshot",
22
- /** Agent mode changed (interactive/background) */
23
- MODE_CHANGE: "_posthog/mode_change",
24
- /** Request to resume a session from previous state */
25
- SESSION_RESUME: "_posthog/session/resume",
26
- /** User message sent from client to agent */
27
- USER_MESSAGE: "_posthog/user_message",
28
- /** Request to cancel current operation */
29
- CANCEL: "_posthog/cancel",
30
- /** Request to close the session */
31
- CLOSE: "_posthog/close",
32
- /** Agent status update (thinking, working, etc.) */
33
- STATUS: "_posthog/status",
34
- /** Task-level notification (progress, milestones) */
35
- TASK_NOTIFICATION: "_posthog/task_notification",
36
- /** Marks a boundary for log compaction */
37
- COMPACT_BOUNDARY: "_posthog/compact_boundary"
38
- };
39
-
40
- // src/gateway-models.ts
41
- var DEFAULT_GATEWAY_MODEL = "claude-opus-4-6";
42
- var DEFAULT_CODEX_MODEL = "gpt-5.4";
43
- var BLOCKED_MODELS = /* @__PURE__ */ new Set(["gpt-5-mini", "openai/gpt-5-mini"]);
44
- var CACHE_TTL = 10 * 60 * 1e3;
45
- var gatewayModelsCache = null;
46
- async function fetchGatewayModels(options) {
47
- const gatewayUrl = options?.gatewayUrl ?? process.env.ANTHROPIC_BASE_URL;
48
- if (!gatewayUrl) {
49
- return [];
50
- }
51
- if (gatewayModelsCache && gatewayModelsCache.url === gatewayUrl && Date.now() < gatewayModelsCache.expiry) {
52
- return gatewayModelsCache.models;
53
- }
54
- const modelsUrl = `${gatewayUrl}/v1/models`;
55
- try {
56
- const response = await fetch(modelsUrl);
57
- if (!response.ok) {
58
- return [];
59
- }
60
- const data = await response.json();
61
- const models = (data.data ?? []).filter((m) => !BLOCKED_MODELS.has(m.id));
62
- gatewayModelsCache = {
63
- models,
64
- expiry: Date.now() + CACHE_TTL,
65
- url: gatewayUrl
66
- };
67
- return models;
68
- } catch {
69
- return [];
70
- }
71
- }
72
- function isAnthropicModel(model) {
73
- if (model.owned_by) {
74
- return model.owned_by === "anthropic";
75
- }
76
- return model.id.startsWith("claude-") || model.id.startsWith("anthropic/");
77
- }
78
- var modelsListCache = null;
79
- async function fetchModelsList(options) {
80
- const gatewayUrl = options?.gatewayUrl ?? process.env.ANTHROPIC_BASE_URL;
81
- if (!gatewayUrl) {
82
- return [];
83
- }
84
- if (modelsListCache && modelsListCache.url === gatewayUrl && Date.now() < modelsListCache.expiry) {
85
- return modelsListCache.models;
86
- }
87
- try {
88
- const modelsUrl = `${gatewayUrl}/v1/models`;
89
- const response = await fetch(modelsUrl);
90
- if (!response.ok) {
91
- return [];
92
- }
93
- const data = await response.json();
94
- const models = Array.isArray(data) ? data : data.data ?? data.models ?? [];
95
- const results = [];
96
- for (const model of models) {
97
- const id = model?.id ? String(model.id) : "";
98
- if (!id) continue;
99
- results.push({ id, owned_by: model?.owned_by });
100
- }
101
- modelsListCache = {
102
- models: results,
103
- expiry: Date.now() + CACHE_TTL,
104
- url: gatewayUrl
105
- };
106
- return results;
107
- } catch {
108
- return [];
109
- }
110
- }
111
- var PROVIDER_PREFIXES = ["anthropic/", "openai/", "google-vertex/"];
112
- function formatGatewayModelName(model) {
113
- return formatModelId(model.id);
114
- }
115
- function formatModelId(modelId) {
116
- let cleanId = modelId;
117
- for (const prefix of PROVIDER_PREFIXES) {
118
- if (cleanId.startsWith(prefix)) {
119
- cleanId = cleanId.slice(prefix.length);
120
- break;
121
- }
122
- }
123
- cleanId = cleanId.replace(/(\d)-(\d)/g, "$1.$2");
124
- const words = cleanId.split(/[-_]/).map((word) => {
125
- if (word.match(/^[0-9.]+$/)) return word;
126
- return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
127
- });
128
- return words.join(" ");
129
- }
2
+ import { AgentSideConnection, ndJsonStream as ndJsonStream2 } from "@agentclientprotocol/sdk";
130
3
 
131
4
  // src/utils/logger.ts
132
5
  var Logger = class _Logger {
@@ -182,7 +55,7 @@ var Logger = class _Logger {
182
55
  };
183
56
 
184
57
  // src/utils/streams.ts
185
- import { ReadableStream, WritableStream as WritableStream2 } from "stream/web";
58
+ import { ReadableStream, WritableStream } from "stream/web";
186
59
  var Pushable = class {
187
60
  queue = [];
188
61
  resolvers = [];
@@ -240,7 +113,7 @@ function createBidirectionalStreams() {
240
113
  const agentToClientPushable = new Pushable();
241
114
  const clientToAgentReadable = pushableToReadableStream(clientToAgentPushable);
242
115
  const agentToClientReadable = pushableToReadableStream(agentToClientPushable);
243
- const clientToAgentWritable = new WritableStream2({
116
+ const clientToAgentWritable = new WritableStream({
244
117
  write(chunk) {
245
118
  clientToAgentPushable.push(chunk);
246
119
  },
@@ -248,7 +121,7 @@ function createBidirectionalStreams() {
248
121
  clientToAgentPushable.end();
249
122
  }
250
123
  });
251
- const agentToClientWritable = new WritableStream2({
124
+ const agentToClientWritable = new WritableStream({
252
125
  write(chunk) {
253
126
  agentToClientPushable.push(chunk);
254
127
  },
@@ -272,7 +145,7 @@ function createTappedWritableStream(underlying, options) {
272
145
  const decoder = new TextDecoder();
273
146
  let buffer = "";
274
147
  let _messageCount = 0;
275
- return new WritableStream2({
148
+ return new WritableStream({
276
149
  async write(chunk) {
277
150
  buffer += decoder.decode(chunk, { stream: true });
278
151
  const lines = buffer.split("\n");
@@ -328,7 +201,7 @@ function nodeReadableToWebReadable(nodeStream) {
328
201
  });
329
202
  }
330
203
  function nodeWritableToWebWritable(nodeStream) {
331
- return new WritableStream2({
204
+ return new WritableStream({
332
205
  write(chunk) {
333
206
  return new Promise((resolve3, reject) => {
334
207
  const ok = nodeStream.write(Buffer.from(chunk), (err) => {
@@ -372,7 +245,7 @@ import { v7 as uuidv7 } from "uuid";
372
245
  // package.json
373
246
  var package_default = {
374
247
  name: "@posthog/agent",
375
- version: "2.3.168",
248
+ version: "2.3.171",
376
249
  repository: "https://github.com/PostHog/code",
377
250
  description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
378
251
  exports: {
@@ -519,6 +392,97 @@ function unreachable(value, logger) {
519
392
  logger.error(`Unexpected case: ${valueAsString}`);
520
393
  }
521
394
 
395
+ // src/gateway-models.ts
396
+ var DEFAULT_GATEWAY_MODEL = "claude-opus-4-6";
397
+ var DEFAULT_CODEX_MODEL = "gpt-5.4";
398
+ var BLOCKED_MODELS = /* @__PURE__ */ new Set(["gpt-5-mini", "openai/gpt-5-mini"]);
399
+ var CACHE_TTL = 10 * 60 * 1e3;
400
+ var gatewayModelsCache = null;
401
+ async function fetchGatewayModels(options) {
402
+ const gatewayUrl = options?.gatewayUrl ?? process.env.ANTHROPIC_BASE_URL;
403
+ if (!gatewayUrl) {
404
+ return [];
405
+ }
406
+ if (gatewayModelsCache && gatewayModelsCache.url === gatewayUrl && Date.now() < gatewayModelsCache.expiry) {
407
+ return gatewayModelsCache.models;
408
+ }
409
+ const modelsUrl = `${gatewayUrl}/v1/models`;
410
+ try {
411
+ const response = await fetch(modelsUrl);
412
+ if (!response.ok) {
413
+ return [];
414
+ }
415
+ const data = await response.json();
416
+ const models = (data.data ?? []).filter((m) => !BLOCKED_MODELS.has(m.id));
417
+ gatewayModelsCache = {
418
+ models,
419
+ expiry: Date.now() + CACHE_TTL,
420
+ url: gatewayUrl
421
+ };
422
+ return models;
423
+ } catch {
424
+ return [];
425
+ }
426
+ }
427
+ function isAnthropicModel(model) {
428
+ if (model.owned_by) {
429
+ return model.owned_by === "anthropic";
430
+ }
431
+ return model.id.startsWith("claude-") || model.id.startsWith("anthropic/");
432
+ }
433
+ var modelsListCache = null;
434
+ async function fetchModelsList(options) {
435
+ const gatewayUrl = options?.gatewayUrl ?? process.env.ANTHROPIC_BASE_URL;
436
+ if (!gatewayUrl) {
437
+ return [];
438
+ }
439
+ if (modelsListCache && modelsListCache.url === gatewayUrl && Date.now() < modelsListCache.expiry) {
440
+ return modelsListCache.models;
441
+ }
442
+ try {
443
+ const modelsUrl = `${gatewayUrl}/v1/models`;
444
+ const response = await fetch(modelsUrl);
445
+ if (!response.ok) {
446
+ return [];
447
+ }
448
+ const data = await response.json();
449
+ const models = Array.isArray(data) ? data : data.data ?? data.models ?? [];
450
+ const results = [];
451
+ for (const model of models) {
452
+ const id = model?.id ? String(model.id) : "";
453
+ if (!id) continue;
454
+ results.push({ id, owned_by: model?.owned_by });
455
+ }
456
+ modelsListCache = {
457
+ models: results,
458
+ expiry: Date.now() + CACHE_TTL,
459
+ url: gatewayUrl
460
+ };
461
+ return results;
462
+ } catch {
463
+ return [];
464
+ }
465
+ }
466
+ var PROVIDER_PREFIXES = ["anthropic/", "openai/", "google-vertex/"];
467
+ function formatGatewayModelName(model) {
468
+ return formatModelId(model.id);
469
+ }
470
+ function formatModelId(modelId) {
471
+ let cleanId = modelId;
472
+ for (const prefix of PROVIDER_PREFIXES) {
473
+ if (cleanId.startsWith(prefix)) {
474
+ cleanId = cleanId.slice(prefix.length);
475
+ break;
476
+ }
477
+ }
478
+ cleanId = cleanId.replace(/(\d)-(\d)/g, "$1.$2");
479
+ const words = cleanId.split(/[-_]/).map((word) => {
480
+ if (word.match(/^[0-9.]+$/)) return word;
481
+ return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
482
+ });
483
+ return words.join(" ");
484
+ }
485
+
522
486
  // src/adapters/base-acp-agent.ts
523
487
  var DEFAULT_CONTEXT_WINDOW = 2e5;
524
488
  var BaseAcpAgent = class {
@@ -726,8 +690,8 @@ var ToolContentBuilder = class {
726
690
  this.items.push({ type: "content", content: image(data, mimeType, uri) });
727
691
  return this;
728
692
  }
729
- diff(path8, oldText, newText) {
730
- this.items.push({ type: "diff", path: path8, oldText, newText });
693
+ diff(path9, oldText, newText) {
694
+ this.items.push({ type: "diff", path: path9, oldText, newText });
731
695
  return this;
732
696
  }
733
697
  build() {
@@ -4138,44 +4102,282 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
4138
4102
  }
4139
4103
  };
4140
4104
 
4141
- // src/adapters/codex/spawn.ts
4142
- import { spawn as spawn2 } from "child_process";
4143
- import { existsSync as existsSync3 } from "fs";
4144
- import { delimiter, dirname } from "path";
4145
- function buildConfigArgs(options) {
4146
- const args = [];
4147
- args.push("-c", `features.remote_models=false`);
4148
- if (options.apiBaseUrl) {
4149
- args.push("-c", `model_provider="posthog"`);
4150
- args.push("-c", `model_providers.posthog.name="PostHog Gateway"`);
4151
- args.push("-c", `model_providers.posthog.base_url="${options.apiBaseUrl}"`);
4152
- args.push("-c", `model_providers.posthog.wire_api="responses"`);
4153
- args.push(
4154
- "-c",
4155
- `model_providers.posthog.env_key="POSTHOG_GATEWAY_API_KEY"`
4156
- );
4157
- }
4158
- if (options.model) {
4159
- args.push("-c", `model="${options.model}"`);
4160
- }
4161
- return args;
4162
- }
4163
- function findCodexBinary(options) {
4164
- const configArgs = buildConfigArgs(options);
4165
- if (options.binaryPath && existsSync3(options.binaryPath)) {
4166
- return { command: options.binaryPath, args: configArgs };
4167
- }
4168
- if (options.binaryPath) {
4169
- throw new Error(
4170
- `codex-acp binary not found at ${options.binaryPath}. Run "node apps/code/scripts/download-binaries.mjs" to download it.`
4171
- );
4172
- }
4173
- return { command: "npx", args: ["@zed-industries/codex-acp", ...configArgs] };
4174
- }
4175
- function spawnCodexProcess(options) {
4176
- const logger = options.logger ?? new Logger({ debug: true, prefix: "[CodexSpawn]" });
4177
- const env = { ...process.env };
4178
- delete env.ELECTRON_RUN_AS_NODE;
4105
+ // src/adapters/codex/codex-agent.ts
4106
+ import {
4107
+ ClientSideConnection,
4108
+ ndJsonStream
4109
+ } from "@agentclientprotocol/sdk";
4110
+
4111
+ // src/acp-extensions.ts
4112
+ var POSTHOG_NOTIFICATIONS = {
4113
+ /** Git branch was created for a task */
4114
+ BRANCH_CREATED: "_posthog/branch_created",
4115
+ /** Task run has started execution */
4116
+ RUN_STARTED: "_posthog/run_started",
4117
+ /** Task has completed (success or failure) */
4118
+ TASK_COMPLETE: "_posthog/task_complete",
4119
+ /** Agent finished processing a turn (prompt returned, waiting for next input) */
4120
+ TURN_COMPLETE: "_posthog/turn_complete",
4121
+ /** Error occurred during task execution */
4122
+ ERROR: "_posthog/error",
4123
+ /** Console/log output from the agent */
4124
+ CONSOLE: "_posthog/console",
4125
+ /** Maps taskRunId to agent's sessionId and adapter type (for resumption) */
4126
+ SDK_SESSION: "_posthog/sdk_session",
4127
+ /** Tree state snapshot captured (git tree hash + file archive) */
4128
+ TREE_SNAPSHOT: "_posthog/tree_snapshot",
4129
+ /** Agent mode changed (interactive/background) */
4130
+ MODE_CHANGE: "_posthog/mode_change",
4131
+ /** Request to resume a session from previous state */
4132
+ SESSION_RESUME: "_posthog/session/resume",
4133
+ /** User message sent from client to agent */
4134
+ USER_MESSAGE: "_posthog/user_message",
4135
+ /** Request to cancel current operation */
4136
+ CANCEL: "_posthog/cancel",
4137
+ /** Request to close the session */
4138
+ CLOSE: "_posthog/close",
4139
+ /** Agent status update (thinking, working, etc.) */
4140
+ STATUS: "_posthog/status",
4141
+ /** Task-level notification (progress, milestones) */
4142
+ TASK_NOTIFICATION: "_posthog/task_notification",
4143
+ /** Marks a boundary for log compaction */
4144
+ COMPACT_BOUNDARY: "_posthog/compact_boundary"
4145
+ };
4146
+
4147
+ // src/adapters/codex/codex-client.ts
4148
+ function createCodexClient(upstreamClient, logger, sessionState, callbacks) {
4149
+ const terminalHandles = /* @__PURE__ */ new Map();
4150
+ return {
4151
+ async requestPermission(params) {
4152
+ logger.debug("Relaying permission request to upstream", {
4153
+ sessionId: params.sessionId
4154
+ });
4155
+ return upstreamClient.requestPermission(params);
4156
+ },
4157
+ async sessionUpdate(params) {
4158
+ const update = params.update;
4159
+ if (update?.sessionUpdate === "usage_update") {
4160
+ const used = update.used;
4161
+ const size = update.size;
4162
+ if (used !== void 0) sessionState.contextUsed = used;
4163
+ if (size !== void 0) sessionState.contextSize = size;
4164
+ const inputTokens = update.inputTokens;
4165
+ const outputTokens = update.outputTokens;
4166
+ if (inputTokens !== void 0) {
4167
+ sessionState.accumulatedUsage.inputTokens += inputTokens;
4168
+ }
4169
+ if (outputTokens !== void 0) {
4170
+ sessionState.accumulatedUsage.outputTokens += outputTokens;
4171
+ }
4172
+ const cachedRead = update.cachedReadTokens;
4173
+ const cachedWrite = update.cachedWriteTokens;
4174
+ if (cachedRead !== void 0) {
4175
+ sessionState.accumulatedUsage.cachedReadTokens += cachedRead;
4176
+ }
4177
+ if (cachedWrite !== void 0) {
4178
+ sessionState.accumulatedUsage.cachedWriteTokens += cachedWrite;
4179
+ }
4180
+ callbacks?.onUsageUpdate?.(update);
4181
+ }
4182
+ await upstreamClient.sessionUpdate(params);
4183
+ },
4184
+ async readTextFile(params) {
4185
+ return upstreamClient.readTextFile(params);
4186
+ },
4187
+ async writeTextFile(params) {
4188
+ return upstreamClient.writeTextFile(params);
4189
+ },
4190
+ async createTerminal(params) {
4191
+ const handle = await upstreamClient.createTerminal(params);
4192
+ terminalHandles.set(handle.id, handle);
4193
+ return { terminalId: handle.id };
4194
+ },
4195
+ async terminalOutput(params) {
4196
+ const handle = terminalHandles.get(params.terminalId);
4197
+ if (!handle) {
4198
+ return { output: "", truncated: false };
4199
+ }
4200
+ return handle.currentOutput();
4201
+ },
4202
+ async releaseTerminal(params) {
4203
+ const handle = terminalHandles.get(params.terminalId);
4204
+ if (handle) {
4205
+ terminalHandles.delete(params.terminalId);
4206
+ const result = await handle.release();
4207
+ return result ?? void 0;
4208
+ }
4209
+ },
4210
+ async waitForTerminalExit(params) {
4211
+ const handle = terminalHandles.get(params.terminalId);
4212
+ if (!handle) {
4213
+ return { exitCode: 1 };
4214
+ }
4215
+ return handle.waitForExit();
4216
+ },
4217
+ async killTerminal(params) {
4218
+ const handle = terminalHandles.get(params.terminalId);
4219
+ if (handle) {
4220
+ return handle.kill();
4221
+ }
4222
+ },
4223
+ async extMethod(method, params) {
4224
+ return upstreamClient.extMethod(method, params);
4225
+ },
4226
+ async extNotification(method, params) {
4227
+ return upstreamClient.extNotification(method, params);
4228
+ }
4229
+ };
4230
+ }
4231
+
4232
+ // src/adapters/codex/session-state.ts
4233
+ function createSessionState(sessionId, cwd, opts) {
4234
+ return {
4235
+ sessionId,
4236
+ cwd,
4237
+ modeId: opts?.modeId ?? "default",
4238
+ modelId: opts?.modelId,
4239
+ configOptions: [],
4240
+ accumulatedUsage: {
4241
+ inputTokens: 0,
4242
+ outputTokens: 0,
4243
+ cachedReadTokens: 0,
4244
+ cachedWriteTokens: 0
4245
+ },
4246
+ cancelled: false,
4247
+ taskRunId: opts?.taskRunId,
4248
+ taskId: opts?.taskId
4249
+ };
4250
+ }
4251
+ function resetUsage(state) {
4252
+ state.accumulatedUsage = {
4253
+ inputTokens: 0,
4254
+ outputTokens: 0,
4255
+ cachedReadTokens: 0,
4256
+ cachedWriteTokens: 0
4257
+ };
4258
+ }
4259
+
4260
+ // src/adapters/codex/settings.ts
4261
+ import * as fs5 from "fs";
4262
+ import * as os5 from "os";
4263
+ import * as path7 from "path";
4264
+ var CodexSettingsManager = class {
4265
+ cwd;
4266
+ settings = {};
4267
+ initialized = false;
4268
+ constructor(cwd) {
4269
+ this.cwd = cwd;
4270
+ }
4271
+ async initialize() {
4272
+ if (this.initialized) {
4273
+ return;
4274
+ }
4275
+ await this.loadSettings();
4276
+ this.initialized = true;
4277
+ }
4278
+ getConfigPath() {
4279
+ return path7.join(os5.homedir(), ".codex", "config.toml");
4280
+ }
4281
+ async loadSettings() {
4282
+ const configPath = this.getConfigPath();
4283
+ try {
4284
+ const content = await fs5.promises.readFile(configPath, "utf-8");
4285
+ this.settings = parseCodexToml(content, this.cwd);
4286
+ } catch {
4287
+ this.settings = {};
4288
+ }
4289
+ }
4290
+ getSettings() {
4291
+ return this.settings;
4292
+ }
4293
+ getCwd() {
4294
+ return this.cwd;
4295
+ }
4296
+ async setCwd(cwd) {
4297
+ if (this.cwd === cwd) {
4298
+ return;
4299
+ }
4300
+ this.dispose();
4301
+ this.cwd = cwd;
4302
+ this.initialized = false;
4303
+ await this.initialize();
4304
+ }
4305
+ dispose() {
4306
+ this.initialized = false;
4307
+ }
4308
+ };
4309
+ function parseCodexToml(content, cwd) {
4310
+ const settings = {};
4311
+ let currentSection = "";
4312
+ for (const line of content.split("\n")) {
4313
+ const trimmed = line.trim();
4314
+ if (!trimmed || trimmed.startsWith("#")) continue;
4315
+ const sectionMatch = trimmed.match(/^\[(.+)\]$/);
4316
+ if (sectionMatch) {
4317
+ currentSection = sectionMatch[1] ?? "";
4318
+ continue;
4319
+ }
4320
+ const kvMatch = trimmed.match(/^(\w+)\s*=\s*(.+)$/);
4321
+ if (!kvMatch) continue;
4322
+ const key = kvMatch[1];
4323
+ let value = kvMatch[2]?.trim() ?? "";
4324
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
4325
+ value = value.slice(1, -1);
4326
+ }
4327
+ if (!currentSection) {
4328
+ if (key === "model") settings.model = value;
4329
+ if (key === "personality") settings.personality = value;
4330
+ if (key === "model_reasoning_effort")
4331
+ settings.modelReasoningEffort = value;
4332
+ } else if (currentSection === `projects."${cwd}"`) {
4333
+ if (key === "trust_level") settings.trustLevel = value;
4334
+ }
4335
+ }
4336
+ return settings;
4337
+ }
4338
+
4339
+ // src/adapters/codex/spawn.ts
4340
+ import { spawn as spawn2 } from "child_process";
4341
+ import { existsSync as existsSync3 } from "fs";
4342
+ import { delimiter, dirname } from "path";
4343
+ function buildConfigArgs(options) {
4344
+ const args = [];
4345
+ args.push("-c", `features.remote_models=false`);
4346
+ if (options.apiBaseUrl) {
4347
+ args.push("-c", `model_provider="posthog"`);
4348
+ args.push("-c", `model_providers.posthog.name="PostHog Gateway"`);
4349
+ args.push("-c", `model_providers.posthog.base_url="${options.apiBaseUrl}"`);
4350
+ args.push("-c", `model_providers.posthog.wire_api="responses"`);
4351
+ args.push(
4352
+ "-c",
4353
+ `model_providers.posthog.env_key="POSTHOG_GATEWAY_API_KEY"`
4354
+ );
4355
+ }
4356
+ if (options.model) {
4357
+ args.push("-c", `model="${options.model}"`);
4358
+ }
4359
+ if (options.instructions) {
4360
+ const escaped = options.instructions.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
4361
+ args.push("-c", `instructions="${escaped}"`);
4362
+ }
4363
+ return args;
4364
+ }
4365
+ function findCodexBinary(options) {
4366
+ const configArgs = buildConfigArgs(options);
4367
+ if (options.binaryPath && existsSync3(options.binaryPath)) {
4368
+ return { command: options.binaryPath, args: configArgs };
4369
+ }
4370
+ if (options.binaryPath) {
4371
+ throw new Error(
4372
+ `codex-acp binary not found at ${options.binaryPath}. Run "node apps/code/scripts/download-binaries.mjs" to download it.`
4373
+ );
4374
+ }
4375
+ return { command: "npx", args: ["@zed-industries/codex-acp", ...configArgs] };
4376
+ }
4377
+ function spawnCodexProcess(options) {
4378
+ const logger = options.logger ?? new Logger({ debug: true, prefix: "[CodexSpawn]" });
4379
+ const env = { ...process.env };
4380
+ delete env.ELECTRON_RUN_AS_NODE;
4179
4381
  delete env.ELECTRON_NO_ASAR;
4180
4382
  if (options.apiKey) {
4181
4383
  env.POSTHOG_GATEWAY_API_KEY = options.apiKey;
@@ -4234,64 +4436,236 @@ function spawnCodexProcess(options) {
4234
4436
  };
4235
4437
  }
4236
4438
 
4237
- // src/adapters/acp-connection.ts
4238
- function isGroupedOptions(options) {
4239
- return options.length > 0 && "group" in options[0];
4240
- }
4241
- function formatOption(o) {
4242
- if (!o.value) return o;
4243
- return { ...o, name: formatModelId(o.value) };
4244
- }
4245
- function filterModelConfigOptions(msg, allowedModelIds) {
4246
- const payload = msg;
4247
- const configOptions = payload.result?.configOptions ?? payload.params?.update?.configOptions;
4248
- if (!configOptions) return null;
4249
- const filtered = configOptions.map((opt) => {
4250
- if (opt.category !== "model" || !opt.options) return opt;
4251
- const options = opt.options;
4252
- if (isGroupedOptions(options)) {
4253
- const filteredOptions2 = options.map((group) => ({
4254
- ...group,
4255
- options: (group.options ?? []).filter((o) => o?.value && allowedModelIds.has(o.value)).map(formatOption)
4256
- }));
4257
- const flat = filteredOptions2.flatMap((g) => g.options ?? []);
4258
- const currentAllowed2 = opt.currentValue && allowedModelIds.has(opt.currentValue);
4259
- const nextCurrent2 = currentAllowed2 || flat.length === 0 ? opt.currentValue : flat[0]?.value;
4260
- return {
4261
- ...opt,
4262
- currentValue: nextCurrent2,
4263
- options: filteredOptions2
4264
- };
4265
- }
4266
- const valueOptions = options;
4267
- const filteredOptions = valueOptions.filter((o) => o?.value && allowedModelIds.has(o.value)).map(formatOption);
4268
- const currentAllowed = opt.currentValue && allowedModelIds.has(opt.currentValue);
4269
- const nextCurrent = currentAllowed || filteredOptions.length === 0 ? opt.currentValue : filteredOptions[0]?.value;
4270
- return {
4271
- ...opt,
4272
- currentValue: nextCurrent,
4273
- options: filteredOptions
4439
+ // src/adapters/codex/codex-agent.ts
4440
+ var CodexAcpAgent = class extends BaseAcpAgent {
4441
+ adapterName = "codex";
4442
+ codexProcess;
4443
+ codexConnection;
4444
+ sessionState;
4445
+ constructor(client, options) {
4446
+ super(client);
4447
+ this.logger = new Logger({ debug: true, prefix: "[CodexAcpAgent]" });
4448
+ this.codexProcess = spawnCodexProcess({
4449
+ ...options.codexProcessOptions,
4450
+ logger: this.logger,
4451
+ processCallbacks: options.processCallbacks
4452
+ });
4453
+ const codexReadable = nodeReadableToWebReadable(this.codexProcess.stdout);
4454
+ const codexWritable = nodeWritableToWebWritable(this.codexProcess.stdin);
4455
+ const codexStream = ndJsonStream(codexWritable, codexReadable);
4456
+ const cwd = options.codexProcessOptions.cwd ?? process.cwd();
4457
+ const settingsManager = new CodexSettingsManager(cwd);
4458
+ const abortController = new AbortController();
4459
+ this.session = {
4460
+ abortController,
4461
+ settingsManager,
4462
+ notificationHistory: [],
4463
+ cancelled: false
4274
4464
  };
4275
- });
4276
- if (payload.result?.configOptions) {
4277
- return { ...msg, result: { ...payload.result, configOptions: filtered } };
4465
+ this.codexConnection = new ClientSideConnection(
4466
+ (_agent) => createCodexClient(
4467
+ this.client,
4468
+ this.logger,
4469
+ this.sessionState ?? {
4470
+ sessionId: "",
4471
+ cwd: "",
4472
+ modeId: "default",
4473
+ configOptions: [],
4474
+ accumulatedUsage: {
4475
+ inputTokens: 0,
4476
+ outputTokens: 0,
4477
+ cachedReadTokens: 0,
4478
+ cachedWriteTokens: 0
4479
+ },
4480
+ cancelled: false
4481
+ }
4482
+ ),
4483
+ codexStream
4484
+ );
4278
4485
  }
4279
- if (payload.params?.update?.configOptions) {
4486
+ async initialize(request) {
4487
+ await this.session.settingsManager.initialize();
4488
+ const response = await this.codexConnection.initialize(request);
4280
4489
  return {
4281
- ...msg,
4282
- params: {
4283
- ...payload.params,
4284
- update: { ...payload.params.update, configOptions: filtered }
4490
+ ...response,
4491
+ agentCapabilities: {
4492
+ ...response.agentCapabilities,
4493
+ sessionCapabilities: {
4494
+ ...response.agentCapabilities?.sessionCapabilities,
4495
+ resume: {},
4496
+ fork: {}
4497
+ },
4498
+ _meta: {
4499
+ posthog: {
4500
+ resumeSession: true
4501
+ }
4502
+ }
4503
+ },
4504
+ agentInfo: {
4505
+ name: package_default.name,
4506
+ title: "Codex Agent",
4507
+ version: package_default.version
4285
4508
  }
4286
4509
  };
4287
4510
  }
4288
- return null;
4289
- }
4290
- function extractReasoningEffort(configOptions) {
4291
- if (!configOptions) return void 0;
4292
- const option = configOptions.find((opt) => opt.id === "reasoning_effort");
4293
- return option?.currentValue ?? void 0;
4294
- }
4511
+ async newSession(params) {
4512
+ const meta = params._meta;
4513
+ const response = await this.codexConnection.newSession(params);
4514
+ this.sessionState = createSessionState(response.sessionId, params.cwd, {
4515
+ taskRunId: meta?.taskRunId,
4516
+ taskId: meta?.taskId ?? meta?.persistence?.taskId,
4517
+ modeId: response.modes?.currentModeId ?? "default",
4518
+ modelId: response.models?.currentModelId
4519
+ });
4520
+ this.sessionId = response.sessionId;
4521
+ this.sessionState.configOptions = response.configOptions ?? [];
4522
+ if (meta?.taskRunId) {
4523
+ await this.client.extNotification(POSTHOG_NOTIFICATIONS.SDK_SESSION, {
4524
+ taskRunId: meta.taskRunId,
4525
+ sessionId: response.sessionId,
4526
+ adapter: "codex"
4527
+ });
4528
+ }
4529
+ this.logger.info("Codex session created", {
4530
+ sessionId: response.sessionId,
4531
+ taskRunId: meta?.taskRunId
4532
+ });
4533
+ return response;
4534
+ }
4535
+ async loadSession(params) {
4536
+ const response = await this.codexConnection.loadSession(params);
4537
+ this.sessionState = createSessionState(params.sessionId, params.cwd);
4538
+ this.sessionId = params.sessionId;
4539
+ this.sessionState.configOptions = response.configOptions ?? [];
4540
+ return response;
4541
+ }
4542
+ async unstable_resumeSession(params) {
4543
+ const loadResponse = await this.codexConnection.loadSession({
4544
+ sessionId: params.sessionId,
4545
+ cwd: params.cwd,
4546
+ mcpServers: params.mcpServers ?? []
4547
+ });
4548
+ this.sessionState = createSessionState(params.sessionId, params.cwd);
4549
+ this.sessionId = params.sessionId;
4550
+ this.sessionState.configOptions = loadResponse.configOptions ?? [];
4551
+ const meta = params._meta;
4552
+ if (meta?.taskRunId) {
4553
+ await this.client.extNotification(POSTHOG_NOTIFICATIONS.SDK_SESSION, {
4554
+ taskRunId: meta.taskRunId,
4555
+ sessionId: params.sessionId,
4556
+ adapter: "codex"
4557
+ });
4558
+ }
4559
+ return {
4560
+ modes: loadResponse.modes,
4561
+ models: loadResponse.models,
4562
+ configOptions: loadResponse.configOptions
4563
+ };
4564
+ }
4565
+ async unstable_forkSession(params) {
4566
+ const newResponse = await this.codexConnection.newSession({
4567
+ cwd: params.cwd,
4568
+ mcpServers: params.mcpServers ?? [],
4569
+ _meta: params._meta
4570
+ });
4571
+ this.sessionState = createSessionState(newResponse.sessionId, params.cwd);
4572
+ this.sessionId = newResponse.sessionId;
4573
+ this.sessionState.configOptions = newResponse.configOptions ?? [];
4574
+ return newResponse;
4575
+ }
4576
+ async listSessions(params) {
4577
+ return this.codexConnection.listSessions(params);
4578
+ }
4579
+ async unstable_listSessions(params) {
4580
+ return this.codexConnection.listSessions(params);
4581
+ }
4582
+ async prompt(params) {
4583
+ if (this.sessionState) {
4584
+ this.sessionState.cancelled = false;
4585
+ this.sessionState.interruptReason = void 0;
4586
+ resetUsage(this.sessionState);
4587
+ }
4588
+ const response = await this.codexConnection.prompt(params);
4589
+ if (this.sessionState && response.usage) {
4590
+ this.sessionState.accumulatedUsage.inputTokens += response.usage.inputTokens ?? 0;
4591
+ this.sessionState.accumulatedUsage.outputTokens += response.usage.outputTokens ?? 0;
4592
+ this.sessionState.accumulatedUsage.cachedReadTokens += response.usage.cachedReadTokens ?? 0;
4593
+ this.sessionState.accumulatedUsage.cachedWriteTokens += response.usage.cachedWriteTokens ?? 0;
4594
+ }
4595
+ if (this.sessionState?.taskRunId) {
4596
+ const { accumulatedUsage } = this.sessionState;
4597
+ await this.client.extNotification(POSTHOG_NOTIFICATIONS.TURN_COMPLETE, {
4598
+ sessionId: params.sessionId,
4599
+ stopReason: response.stopReason ?? "end_turn",
4600
+ usage: {
4601
+ inputTokens: accumulatedUsage.inputTokens,
4602
+ outputTokens: accumulatedUsage.outputTokens,
4603
+ cachedReadTokens: accumulatedUsage.cachedReadTokens,
4604
+ cachedWriteTokens: accumulatedUsage.cachedWriteTokens,
4605
+ totalTokens: accumulatedUsage.inputTokens + accumulatedUsage.outputTokens + accumulatedUsage.cachedReadTokens + accumulatedUsage.cachedWriteTokens
4606
+ }
4607
+ });
4608
+ if (response.usage) {
4609
+ await this.client.extNotification("_posthog/usage_update", {
4610
+ sessionId: params.sessionId,
4611
+ used: {
4612
+ inputTokens: response.usage.inputTokens ?? 0,
4613
+ outputTokens: response.usage.outputTokens ?? 0,
4614
+ cachedReadTokens: response.usage.cachedReadTokens ?? 0,
4615
+ cachedWriteTokens: response.usage.cachedWriteTokens ?? 0
4616
+ },
4617
+ cost: null
4618
+ });
4619
+ }
4620
+ }
4621
+ return response;
4622
+ }
4623
+ async interrupt() {
4624
+ if (this.sessionState) {
4625
+ this.sessionState.cancelled = true;
4626
+ }
4627
+ await this.codexConnection.cancel({
4628
+ sessionId: this.sessionId
4629
+ });
4630
+ }
4631
+ async cancel(params) {
4632
+ if (this.sessionState) {
4633
+ this.sessionState.cancelled = true;
4634
+ const meta = params._meta;
4635
+ if (meta?.interruptReason) {
4636
+ this.sessionState.interruptReason = meta.interruptReason;
4637
+ }
4638
+ }
4639
+ await this.codexConnection.cancel(params);
4640
+ }
4641
+ async setSessionMode(params) {
4642
+ const response = await this.codexConnection.setSessionMode(params);
4643
+ if (this.sessionState) {
4644
+ this.sessionState.modeId = params.modeId;
4645
+ }
4646
+ return response ?? {};
4647
+ }
4648
+ async setSessionConfigOption(params) {
4649
+ const response = await this.codexConnection.setSessionConfigOption(params);
4650
+ if (this.sessionState && response.configOptions) {
4651
+ this.sessionState.configOptions = response.configOptions;
4652
+ }
4653
+ return response;
4654
+ }
4655
+ async authenticate(_params) {
4656
+ }
4657
+ async closeSession() {
4658
+ this.logger.info("Closing Codex session", { sessionId: this.sessionId });
4659
+ this.session.settingsManager.dispose();
4660
+ try {
4661
+ this.codexProcess.kill();
4662
+ } catch (err) {
4663
+ this.logger.warn("Failed to kill codex-acp process", { error: err });
4664
+ }
4665
+ }
4666
+ };
4667
+
4668
+ // src/adapters/acp-connection.ts
4295
4669
  function createAcpConnection(config = {}) {
4296
4670
  const adapterType = config.adapter ?? "claude";
4297
4671
  if (adapterType === "codex") {
@@ -4332,7 +4706,7 @@ function createClaudeConnection(config) {
4332
4706
  hasLogWriter: !!logWriter
4333
4707
  });
4334
4708
  }
4335
- const agentStream = ndJsonStream(agentWritable, streams.agent.readable);
4709
+ const agentStream = ndJsonStream2(agentWritable, streams.agent.readable);
4336
4710
  let agent = null;
4337
4711
  const agentConnection = new AgentSideConnection((client) => {
4338
4712
  agent = new ClaudeAcpAgent(client, config.processCallbacks);
@@ -4364,214 +4738,63 @@ function createClaudeConnection(config) {
4364
4738
  function createCodexConnection(config) {
4365
4739
  const logger = config.logger?.child("CodexConnection") ?? new Logger({ debug: true, prefix: "[CodexConnection]" });
4366
4740
  const { logWriter } = config;
4367
- const allowedModelIds = config.allowedModelIds;
4368
- const codexProcess = spawnCodexProcess({
4369
- ...config.codexOptions,
4370
- logger,
4371
- processCallbacks: config.processCallbacks
4372
- });
4373
- let clientReadable = nodeReadableToWebReadable(codexProcess.stdout);
4374
- let clientWritable = nodeWritableToWebWritable(codexProcess.stdin);
4375
- let isLoadingSession = false;
4376
- let loadRequestId = null;
4377
- let newSessionRequestId = null;
4378
- let sdkSessionEmitted = false;
4379
- const reasoningEffortBySessionId = /* @__PURE__ */ new Map();
4380
- let injectedConfigId = 0;
4381
- const decoder = new TextDecoder();
4382
- const encoder = new TextEncoder();
4383
- let readBuffer = "";
4384
- const taskRunId = config.taskRunId;
4385
- const filteringReadable = clientReadable.pipeThrough(
4386
- new TransformStream({
4387
- transform(chunk, controller) {
4388
- readBuffer += decoder.decode(chunk, { stream: true });
4389
- const lines = readBuffer.split("\n");
4390
- readBuffer = lines.pop() ?? "";
4391
- const outputLines = [];
4392
- for (const line of lines) {
4393
- const trimmed = line.trim();
4394
- if (!trimmed) {
4395
- outputLines.push(line);
4396
- continue;
4397
- }
4398
- let shouldFilter = false;
4399
- try {
4400
- const msg = JSON.parse(trimmed);
4401
- const sessionId = msg?.params?.sessionId ?? msg?.result?.sessionId ?? null;
4402
- const configOptions = msg?.result?.configOptions ?? msg?.params?.update?.configOptions;
4403
- if (sessionId && configOptions) {
4404
- const effort = extractReasoningEffort(configOptions);
4405
- if (effort) {
4406
- reasoningEffortBySessionId.set(sessionId, effort);
4407
- }
4408
- }
4409
- if (!sdkSessionEmitted && newSessionRequestId !== null && msg.id === newSessionRequestId && "result" in msg) {
4410
- const sessionId2 = msg.result?.sessionId;
4411
- if (sessionId2 && taskRunId) {
4412
- const sdkSessionNotification = {
4413
- jsonrpc: "2.0",
4414
- method: POSTHOG_NOTIFICATIONS.SDK_SESSION,
4415
- params: {
4416
- taskRunId,
4417
- sessionId: sessionId2,
4418
- adapter: "codex"
4419
- }
4420
- };
4421
- outputLines.push(JSON.stringify(sdkSessionNotification));
4422
- sdkSessionEmitted = true;
4423
- }
4424
- newSessionRequestId = null;
4425
- }
4426
- if (isLoadingSession) {
4427
- if (msg.id === loadRequestId && "result" in msg) {
4428
- logger.debug("session/load complete, resuming stream");
4429
- isLoadingSession = false;
4430
- loadRequestId = null;
4431
- } else if (msg.method === "session/update") {
4432
- shouldFilter = true;
4433
- }
4434
- }
4435
- if (!shouldFilter && allowedModelIds && allowedModelIds.size > 0) {
4436
- const updated = filterModelConfigOptions(msg, allowedModelIds);
4437
- if (updated) {
4438
- outputLines.push(JSON.stringify(updated));
4439
- continue;
4440
- }
4441
- }
4442
- } catch {
4443
- }
4444
- if (!shouldFilter) {
4445
- outputLines.push(line);
4446
- const isChunkNoise = trimmed.includes('"sessionUpdate":"agent_message_chunk"') || trimmed.includes('"sessionUpdate":"agent_thought_chunk"');
4447
- if (!isChunkNoise) {
4448
- logger.debug("codex-acp stdout:", trimmed);
4449
- }
4450
- }
4451
- }
4452
- if (outputLines.length > 0) {
4453
- const output = `${outputLines.join("\n")}
4454
- `;
4455
- controller.enqueue(encoder.encode(output));
4456
- }
4457
- },
4458
- flush(controller) {
4459
- if (readBuffer.trim()) {
4460
- controller.enqueue(encoder.encode(readBuffer));
4461
- }
4462
- }
4463
- })
4464
- );
4465
- clientReadable = filteringReadable;
4466
- const originalWritable = clientWritable;
4467
- clientWritable = new WritableStream({
4468
- write(chunk) {
4469
- const text2 = decoder.decode(chunk, { stream: true });
4470
- const trimmed = text2.trim();
4471
- logger.debug("codex-acp stdin:", trimmed);
4472
- try {
4473
- const msg = JSON.parse(trimmed);
4474
- if (msg.method === "session/set_config_option" && msg.params?.configId === "reasoning_effort" && msg.params?.sessionId && msg.params?.value) {
4475
- reasoningEffortBySessionId.set(
4476
- msg.params.sessionId,
4477
- msg.params.value
4478
- );
4479
- }
4480
- if (msg.method === "session/prompt" && msg.params?.sessionId) {
4481
- const effort = reasoningEffortBySessionId.get(msg.params.sessionId);
4482
- if (effort) {
4483
- const injection = {
4484
- jsonrpc: "2.0",
4485
- id: `reasoning_effort_${Date.now()}_${injectedConfigId++}`,
4486
- method: "session/set_config_option",
4487
- params: {
4488
- sessionId: msg.params.sessionId,
4489
- configId: "reasoning_effort",
4490
- value: effort
4491
- }
4492
- };
4493
- const injectionLine = `${JSON.stringify(injection)}
4494
- `;
4495
- const writer2 = originalWritable.getWriter();
4496
- return writer2.write(encoder.encode(injectionLine)).then(() => writer2.releaseLock()).then(() => {
4497
- const nextWriter = originalWritable.getWriter();
4498
- return nextWriter.write(chunk).finally(() => nextWriter.releaseLock());
4499
- });
4500
- }
4501
- }
4502
- if (msg.method === "session/new" && msg.id) {
4503
- logger.debug("session/new detected, tracking request ID");
4504
- newSessionRequestId = msg.id;
4505
- } else if (msg.method === "session/load" && msg.id) {
4506
- logger.debug("session/load detected, pausing stream updates");
4507
- isLoadingSession = true;
4508
- loadRequestId = msg.id;
4509
- }
4510
- } catch {
4511
- }
4512
- const writer = originalWritable.getWriter();
4513
- return writer.write(chunk).finally(() => writer.releaseLock());
4514
- },
4515
- close() {
4516
- const writer = originalWritable.getWriter();
4517
- return writer.close().finally(() => writer.releaseLock());
4518
- }
4519
- });
4520
- const shouldTapLogs = config.taskRunId && logWriter;
4521
- if (shouldTapLogs && config.taskRunId) {
4522
- const taskRunId2 = config.taskRunId;
4523
- if (!logWriter.isRegistered(taskRunId2)) {
4524
- logWriter.register(taskRunId2, {
4525
- taskId: config.taskId ?? taskRunId2,
4526
- runId: taskRunId2
4741
+ const streams = createBidirectionalStreams();
4742
+ let agentWritable = streams.agent.writable;
4743
+ let clientWritable = streams.client.writable;
4744
+ if (config.taskRunId && logWriter) {
4745
+ if (!logWriter.isRegistered(config.taskRunId)) {
4746
+ logWriter.register(config.taskRunId, {
4747
+ taskId: config.taskId ?? config.taskRunId,
4748
+ runId: config.taskRunId,
4749
+ deviceType: config.deviceType
4527
4750
  });
4528
4751
  }
4529
- clientWritable = createTappedWritableStream(clientWritable, {
4752
+ const taskRunId = config.taskRunId;
4753
+ agentWritable = createTappedWritableStream(streams.agent.writable, {
4530
4754
  onMessage: (line) => {
4531
- logWriter.appendRawLine(taskRunId2, line);
4755
+ logWriter.appendRawLine(taskRunId, line);
4756
+ },
4757
+ logger
4758
+ });
4759
+ clientWritable = createTappedWritableStream(streams.client.writable, {
4760
+ onMessage: (line) => {
4761
+ logWriter.appendRawLine(taskRunId, line);
4532
4762
  },
4533
4763
  logger
4534
4764
  });
4535
- const originalReadable = clientReadable;
4536
- const logDecoder = new TextDecoder();
4537
- let logBuffer = "";
4538
- clientReadable = originalReadable.pipeThrough(
4539
- new TransformStream({
4540
- transform(chunk, controller) {
4541
- logBuffer += logDecoder.decode(chunk, { stream: true });
4542
- const lines = logBuffer.split("\n");
4543
- logBuffer = lines.pop() ?? "";
4544
- for (const line of lines) {
4545
- if (line.trim()) {
4546
- logWriter.appendRawLine(taskRunId2, line);
4547
- }
4548
- }
4549
- controller.enqueue(chunk);
4550
- },
4551
- flush() {
4552
- if (logBuffer.trim()) {
4553
- logWriter.appendRawLine(taskRunId2, logBuffer);
4554
- }
4555
- }
4556
- })
4557
- );
4558
4765
  } else {
4559
4766
  logger.info("Tapped streams NOT enabled for Codex", {
4560
4767
  hasTaskRunId: !!config.taskRunId,
4561
4768
  hasLogWriter: !!logWriter
4562
4769
  });
4563
4770
  }
4771
+ const agentStream = ndJsonStream2(agentWritable, streams.agent.readable);
4772
+ let agent = null;
4773
+ const agentConnection = new AgentSideConnection((client) => {
4774
+ agent = new CodexAcpAgent(client, {
4775
+ codexProcessOptions: config.codexOptions ?? {},
4776
+ processCallbacks: config.processCallbacks
4777
+ });
4778
+ logger.info(`Created ${agent.adapterName} agent`);
4779
+ return agent;
4780
+ }, agentStream);
4564
4781
  return {
4565
- agentConnection: void 0,
4782
+ agentConnection,
4566
4783
  clientStreams: {
4567
- readable: clientReadable,
4784
+ readable: streams.client.readable,
4568
4785
  writable: clientWritable
4569
4786
  },
4570
4787
  cleanup: async () => {
4571
4788
  logger.info("Cleaning up Codex connection");
4572
- codexProcess.kill();
4789
+ if (agent) {
4790
+ await agent.closeSession();
4791
+ }
4573
4792
  try {
4574
- await clientWritable.close();
4793
+ await streams.client.writable.close();
4794
+ } catch {
4795
+ }
4796
+ try {
4797
+ await streams.agent.writable.close();
4575
4798
  } catch {
4576
4799
  }
4577
4800
  }
@@ -4779,9 +5002,9 @@ var PostHogAPIClient = class {
4779
5002
  };
4780
5003
 
4781
5004
  // src/session-log-writer.ts
4782
- import fs5 from "fs";
5005
+ import fs6 from "fs";
4783
5006
  import fsp from "fs/promises";
4784
- import path7 from "path";
5007
+ import path8 from "path";
4785
5008
  var SessionLogWriter = class _SessionLogWriter {
4786
5009
  static FLUSH_DEBOUNCE_MS = 500;
4787
5010
  static FLUSH_MAX_INTERVAL_MS = 5e3;
@@ -4821,13 +5044,13 @@ var SessionLogWriter = class _SessionLogWriter {
4821
5044
  this.sessions.set(sessionId, { context, currentTurnMessages: [] });
4822
5045
  this.lastFlushAttemptTime.set(sessionId, Date.now());
4823
5046
  if (this.localCachePath) {
4824
- const sessionDir = path7.join(
5047
+ const sessionDir = path8.join(
4825
5048
  this.localCachePath,
4826
5049
  "sessions",
4827
5050
  context.runId
4828
5051
  );
4829
5052
  try {
4830
- fs5.mkdirSync(sessionDir, { recursive: true });
5053
+ fs6.mkdirSync(sessionDir, { recursive: true });
4831
5054
  } catch (error) {
4832
5055
  this.logger.warn("Failed to create local cache directory", {
4833
5056
  sessionDir,
@@ -5079,14 +5302,14 @@ var SessionLogWriter = class _SessionLogWriter {
5079
5302
  if (!this.localCachePath) return;
5080
5303
  const session = this.sessions.get(sessionId);
5081
5304
  if (!session) return;
5082
- const logPath = path7.join(
5305
+ const logPath = path8.join(
5083
5306
  this.localCachePath,
5084
5307
  "sessions",
5085
5308
  session.context.runId,
5086
5309
  "logs.ndjson"
5087
5310
  );
5088
5311
  try {
5089
- fs5.appendFileSync(logPath, `${JSON.stringify(entry)}
5312
+ fs6.appendFileSync(logPath, `${JSON.stringify(entry)}
5090
5313
  `);
5091
5314
  } catch (error) {
5092
5315
  this.logger.warn("Failed to write to local cache", {
@@ -5098,13 +5321,13 @@ var SessionLogWriter = class _SessionLogWriter {
5098
5321
  }
5099
5322
  }
5100
5323
  static async cleanupOldSessions(localCachePath) {
5101
- const sessionsDir = path7.join(localCachePath, "sessions");
5324
+ const sessionsDir = path8.join(localCachePath, "sessions");
5102
5325
  let deleted = 0;
5103
5326
  try {
5104
5327
  const entries = await fsp.readdir(sessionsDir);
5105
5328
  const now = Date.now();
5106
5329
  for (const entry of entries) {
5107
- const entryPath = path7.join(sessionsDir, entry);
5330
+ const entryPath = path8.join(sessionsDir, entry);
5108
5331
  try {
5109
5332
  const stats = await fsp.stat(entryPath);
5110
5333
  if (stats.isDirectory() && now - stats.birthtimeMs > _SessionLogWriter.SESSIONS_MAX_AGE_MS) {
@@ -5210,7 +5433,8 @@ var Agent = class {
5210
5433
  apiBaseUrl: `${gatewayConfig.gatewayUrl}/v1`,
5211
5434
  apiKey: gatewayConfig.apiKey,
5212
5435
  binaryPath: options.codexBinaryPath,
5213
- model: sanitizedModel
5436
+ model: sanitizedModel,
5437
+ instructions: options.instructions
5214
5438
  } : void 0
5215
5439
  });
5216
5440
  return this.acpConnection;