@posthog/agent 2.3.167 → 2.3.169
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 +570 -386
- package/dist/agent.js.map +1 -1
- package/dist/gateway-models.d.ts +2 -1
- package/dist/gateway-models.js +2 -0
- package/dist/gateway-models.js.map +1 -1
- package/dist/posthog-api.js +1 -1
- package/dist/posthog-api.js.map +1 -1
- package/dist/server/agent-server.js +580 -397
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +557 -377
- package/dist/server/bin.cjs.map +1 -1
- package/package.json +1 -1
- package/src/adapters/acp-connection.ts +53 -334
- package/src/adapters/base-acp-agent.ts +13 -2
- package/src/adapters/codex/codex-agent.ts +355 -0
- package/src/adapters/codex/codex-client.ts +151 -0
- package/src/adapters/codex/session-state.ts +65 -0
- package/src/adapters/codex/settings.ts +127 -0
- package/src/agent.ts +4 -1
- package/src/gateway-models.ts +2 -0
package/dist/agent.js
CHANGED
|
@@ -1,131 +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 BLOCKED_MODELS = /* @__PURE__ */ new Set(["gpt-5-mini", "openai/gpt-5-mini"]);
|
|
43
|
-
var CACHE_TTL = 10 * 60 * 1e3;
|
|
44
|
-
var gatewayModelsCache = null;
|
|
45
|
-
async function fetchGatewayModels(options) {
|
|
46
|
-
const gatewayUrl = options?.gatewayUrl ?? process.env.ANTHROPIC_BASE_URL;
|
|
47
|
-
if (!gatewayUrl) {
|
|
48
|
-
return [];
|
|
49
|
-
}
|
|
50
|
-
if (gatewayModelsCache && gatewayModelsCache.url === gatewayUrl && Date.now() < gatewayModelsCache.expiry) {
|
|
51
|
-
return gatewayModelsCache.models;
|
|
52
|
-
}
|
|
53
|
-
const modelsUrl = `${gatewayUrl}/v1/models`;
|
|
54
|
-
try {
|
|
55
|
-
const response = await fetch(modelsUrl);
|
|
56
|
-
if (!response.ok) {
|
|
57
|
-
return [];
|
|
58
|
-
}
|
|
59
|
-
const data = await response.json();
|
|
60
|
-
const models = (data.data ?? []).filter((m) => !BLOCKED_MODELS.has(m.id));
|
|
61
|
-
gatewayModelsCache = {
|
|
62
|
-
models,
|
|
63
|
-
expiry: Date.now() + CACHE_TTL,
|
|
64
|
-
url: gatewayUrl
|
|
65
|
-
};
|
|
66
|
-
return models;
|
|
67
|
-
} catch {
|
|
68
|
-
return [];
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
function isAnthropicModel(model) {
|
|
72
|
-
if (model.owned_by) {
|
|
73
|
-
return model.owned_by === "anthropic";
|
|
74
|
-
}
|
|
75
|
-
return model.id.startsWith("claude-") || model.id.startsWith("anthropic/");
|
|
76
|
-
}
|
|
77
|
-
var modelsListCache = null;
|
|
78
|
-
async function fetchModelsList(options) {
|
|
79
|
-
const gatewayUrl = options?.gatewayUrl ?? process.env.ANTHROPIC_BASE_URL;
|
|
80
|
-
if (!gatewayUrl) {
|
|
81
|
-
return [];
|
|
82
|
-
}
|
|
83
|
-
if (modelsListCache && modelsListCache.url === gatewayUrl && Date.now() < modelsListCache.expiry) {
|
|
84
|
-
return modelsListCache.models;
|
|
85
|
-
}
|
|
86
|
-
try {
|
|
87
|
-
const modelsUrl = `${gatewayUrl}/v1/models`;
|
|
88
|
-
const response = await fetch(modelsUrl);
|
|
89
|
-
if (!response.ok) {
|
|
90
|
-
return [];
|
|
91
|
-
}
|
|
92
|
-
const data = await response.json();
|
|
93
|
-
const models = Array.isArray(data) ? data : data.data ?? data.models ?? [];
|
|
94
|
-
const results = [];
|
|
95
|
-
for (const model of models) {
|
|
96
|
-
const id = model?.id ? String(model.id) : "";
|
|
97
|
-
if (!id) continue;
|
|
98
|
-
results.push({ id, owned_by: model?.owned_by });
|
|
99
|
-
}
|
|
100
|
-
modelsListCache = {
|
|
101
|
-
models: results,
|
|
102
|
-
expiry: Date.now() + CACHE_TTL,
|
|
103
|
-
url: gatewayUrl
|
|
104
|
-
};
|
|
105
|
-
return results;
|
|
106
|
-
} catch {
|
|
107
|
-
return [];
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
var PROVIDER_PREFIXES = ["anthropic/", "openai/", "google-vertex/"];
|
|
111
|
-
function formatGatewayModelName(model) {
|
|
112
|
-
return formatModelId(model.id);
|
|
113
|
-
}
|
|
114
|
-
function formatModelId(modelId) {
|
|
115
|
-
let cleanId = modelId;
|
|
116
|
-
for (const prefix of PROVIDER_PREFIXES) {
|
|
117
|
-
if (cleanId.startsWith(prefix)) {
|
|
118
|
-
cleanId = cleanId.slice(prefix.length);
|
|
119
|
-
break;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
cleanId = cleanId.replace(/(\d)-(\d)/g, "$1.$2");
|
|
123
|
-
const words = cleanId.split(/[-_]/).map((word) => {
|
|
124
|
-
if (word.match(/^[0-9.]+$/)) return word;
|
|
125
|
-
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
126
|
-
});
|
|
127
|
-
return words.join(" ");
|
|
128
|
-
}
|
|
2
|
+
import { AgentSideConnection, ndJsonStream as ndJsonStream2 } from "@agentclientprotocol/sdk";
|
|
129
3
|
|
|
130
4
|
// src/utils/logger.ts
|
|
131
5
|
var Logger = class _Logger {
|
|
@@ -181,7 +55,7 @@ var Logger = class _Logger {
|
|
|
181
55
|
};
|
|
182
56
|
|
|
183
57
|
// src/utils/streams.ts
|
|
184
|
-
import { ReadableStream, WritableStream
|
|
58
|
+
import { ReadableStream, WritableStream } from "stream/web";
|
|
185
59
|
var Pushable = class {
|
|
186
60
|
queue = [];
|
|
187
61
|
resolvers = [];
|
|
@@ -239,7 +113,7 @@ function createBidirectionalStreams() {
|
|
|
239
113
|
const agentToClientPushable = new Pushable();
|
|
240
114
|
const clientToAgentReadable = pushableToReadableStream(clientToAgentPushable);
|
|
241
115
|
const agentToClientReadable = pushableToReadableStream(agentToClientPushable);
|
|
242
|
-
const clientToAgentWritable = new
|
|
116
|
+
const clientToAgentWritable = new WritableStream({
|
|
243
117
|
write(chunk) {
|
|
244
118
|
clientToAgentPushable.push(chunk);
|
|
245
119
|
},
|
|
@@ -247,7 +121,7 @@ function createBidirectionalStreams() {
|
|
|
247
121
|
clientToAgentPushable.end();
|
|
248
122
|
}
|
|
249
123
|
});
|
|
250
|
-
const agentToClientWritable = new
|
|
124
|
+
const agentToClientWritable = new WritableStream({
|
|
251
125
|
write(chunk) {
|
|
252
126
|
agentToClientPushable.push(chunk);
|
|
253
127
|
},
|
|
@@ -271,7 +145,7 @@ function createTappedWritableStream(underlying, options) {
|
|
|
271
145
|
const decoder = new TextDecoder();
|
|
272
146
|
let buffer = "";
|
|
273
147
|
let _messageCount = 0;
|
|
274
|
-
return new
|
|
148
|
+
return new WritableStream({
|
|
275
149
|
async write(chunk) {
|
|
276
150
|
buffer += decoder.decode(chunk, { stream: true });
|
|
277
151
|
const lines = buffer.split("\n");
|
|
@@ -327,7 +201,7 @@ function nodeReadableToWebReadable(nodeStream) {
|
|
|
327
201
|
});
|
|
328
202
|
}
|
|
329
203
|
function nodeWritableToWebWritable(nodeStream) {
|
|
330
|
-
return new
|
|
204
|
+
return new WritableStream({
|
|
331
205
|
write(chunk) {
|
|
332
206
|
return new Promise((resolve3, reject) => {
|
|
333
207
|
const ok = nodeStream.write(Buffer.from(chunk), (err) => {
|
|
@@ -371,7 +245,7 @@ import { v7 as uuidv7 } from "uuid";
|
|
|
371
245
|
// package.json
|
|
372
246
|
var package_default = {
|
|
373
247
|
name: "@posthog/agent",
|
|
374
|
-
version: "2.3.
|
|
248
|
+
version: "2.3.169",
|
|
375
249
|
repository: "https://github.com/PostHog/code",
|
|
376
250
|
description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
377
251
|
exports: {
|
|
@@ -518,6 +392,97 @@ function unreachable(value, logger) {
|
|
|
518
392
|
logger.error(`Unexpected case: ${valueAsString}`);
|
|
519
393
|
}
|
|
520
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
|
+
|
|
521
486
|
// src/adapters/base-acp-agent.ts
|
|
522
487
|
var DEFAULT_CONTEXT_WINDOW = 2e5;
|
|
523
488
|
var BaseAcpAgent = class {
|
|
@@ -725,8 +690,8 @@ var ToolContentBuilder = class {
|
|
|
725
690
|
this.items.push({ type: "content", content: image(data, mimeType, uri) });
|
|
726
691
|
return this;
|
|
727
692
|
}
|
|
728
|
-
diff(
|
|
729
|
-
this.items.push({ type: "diff", path:
|
|
693
|
+
diff(path9, oldText, newText) {
|
|
694
|
+
this.items.push({ type: "diff", path: path9, oldText, newText });
|
|
730
695
|
return this;
|
|
731
696
|
}
|
|
732
697
|
build() {
|
|
@@ -4137,6 +4102,224 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
4137
4102
|
}
|
|
4138
4103
|
};
|
|
4139
4104
|
|
|
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
|
+
callbacks?.onUsageUpdate?.(update);
|
|
4165
|
+
}
|
|
4166
|
+
await upstreamClient.sessionUpdate(params);
|
|
4167
|
+
},
|
|
4168
|
+
async readTextFile(params) {
|
|
4169
|
+
return upstreamClient.readTextFile(params);
|
|
4170
|
+
},
|
|
4171
|
+
async writeTextFile(params) {
|
|
4172
|
+
return upstreamClient.writeTextFile(params);
|
|
4173
|
+
},
|
|
4174
|
+
async createTerminal(params) {
|
|
4175
|
+
const handle = await upstreamClient.createTerminal(params);
|
|
4176
|
+
terminalHandles.set(handle.id, handle);
|
|
4177
|
+
return { terminalId: handle.id };
|
|
4178
|
+
},
|
|
4179
|
+
async terminalOutput(params) {
|
|
4180
|
+
const handle = terminalHandles.get(params.terminalId);
|
|
4181
|
+
if (!handle) {
|
|
4182
|
+
return { output: "", truncated: false };
|
|
4183
|
+
}
|
|
4184
|
+
return handle.currentOutput();
|
|
4185
|
+
},
|
|
4186
|
+
async releaseTerminal(params) {
|
|
4187
|
+
const handle = terminalHandles.get(params.terminalId);
|
|
4188
|
+
if (handle) {
|
|
4189
|
+
terminalHandles.delete(params.terminalId);
|
|
4190
|
+
const result = await handle.release();
|
|
4191
|
+
return result ?? void 0;
|
|
4192
|
+
}
|
|
4193
|
+
},
|
|
4194
|
+
async waitForTerminalExit(params) {
|
|
4195
|
+
const handle = terminalHandles.get(params.terminalId);
|
|
4196
|
+
if (!handle) {
|
|
4197
|
+
return { exitCode: 1 };
|
|
4198
|
+
}
|
|
4199
|
+
return handle.waitForExit();
|
|
4200
|
+
},
|
|
4201
|
+
async killTerminal(params) {
|
|
4202
|
+
const handle = terminalHandles.get(params.terminalId);
|
|
4203
|
+
if (handle) {
|
|
4204
|
+
return handle.kill();
|
|
4205
|
+
}
|
|
4206
|
+
},
|
|
4207
|
+
async extMethod(method, params) {
|
|
4208
|
+
return upstreamClient.extMethod(method, params);
|
|
4209
|
+
},
|
|
4210
|
+
async extNotification(method, params) {
|
|
4211
|
+
return upstreamClient.extNotification(method, params);
|
|
4212
|
+
}
|
|
4213
|
+
};
|
|
4214
|
+
}
|
|
4215
|
+
|
|
4216
|
+
// src/adapters/codex/session-state.ts
|
|
4217
|
+
function createSessionState(sessionId, cwd, opts) {
|
|
4218
|
+
return {
|
|
4219
|
+
sessionId,
|
|
4220
|
+
cwd,
|
|
4221
|
+
modeId: opts?.modeId ?? "default",
|
|
4222
|
+
modelId: opts?.modelId,
|
|
4223
|
+
configOptions: [],
|
|
4224
|
+
accumulatedUsage: {
|
|
4225
|
+
inputTokens: 0,
|
|
4226
|
+
outputTokens: 0,
|
|
4227
|
+
cachedReadTokens: 0,
|
|
4228
|
+
cachedWriteTokens: 0
|
|
4229
|
+
},
|
|
4230
|
+
cancelled: false,
|
|
4231
|
+
taskRunId: opts?.taskRunId,
|
|
4232
|
+
taskId: opts?.taskId
|
|
4233
|
+
};
|
|
4234
|
+
}
|
|
4235
|
+
function resetUsage(state) {
|
|
4236
|
+
state.accumulatedUsage = {
|
|
4237
|
+
inputTokens: 0,
|
|
4238
|
+
outputTokens: 0,
|
|
4239
|
+
cachedReadTokens: 0,
|
|
4240
|
+
cachedWriteTokens: 0
|
|
4241
|
+
};
|
|
4242
|
+
}
|
|
4243
|
+
|
|
4244
|
+
// src/adapters/codex/settings.ts
|
|
4245
|
+
import * as fs5 from "fs";
|
|
4246
|
+
import * as os5 from "os";
|
|
4247
|
+
import * as path7 from "path";
|
|
4248
|
+
var CodexSettingsManager = class {
|
|
4249
|
+
cwd;
|
|
4250
|
+
settings = {};
|
|
4251
|
+
initialized = false;
|
|
4252
|
+
constructor(cwd) {
|
|
4253
|
+
this.cwd = cwd;
|
|
4254
|
+
}
|
|
4255
|
+
async initialize() {
|
|
4256
|
+
if (this.initialized) {
|
|
4257
|
+
return;
|
|
4258
|
+
}
|
|
4259
|
+
await this.loadSettings();
|
|
4260
|
+
this.initialized = true;
|
|
4261
|
+
}
|
|
4262
|
+
getConfigPath() {
|
|
4263
|
+
return path7.join(os5.homedir(), ".codex", "config.toml");
|
|
4264
|
+
}
|
|
4265
|
+
async loadSettings() {
|
|
4266
|
+
const configPath = this.getConfigPath();
|
|
4267
|
+
try {
|
|
4268
|
+
const content = await fs5.promises.readFile(configPath, "utf-8");
|
|
4269
|
+
this.settings = parseCodexToml(content, this.cwd);
|
|
4270
|
+
} catch {
|
|
4271
|
+
this.settings = {};
|
|
4272
|
+
}
|
|
4273
|
+
}
|
|
4274
|
+
getSettings() {
|
|
4275
|
+
return this.settings;
|
|
4276
|
+
}
|
|
4277
|
+
getCwd() {
|
|
4278
|
+
return this.cwd;
|
|
4279
|
+
}
|
|
4280
|
+
async setCwd(cwd) {
|
|
4281
|
+
if (this.cwd === cwd) {
|
|
4282
|
+
return;
|
|
4283
|
+
}
|
|
4284
|
+
this.dispose();
|
|
4285
|
+
this.cwd = cwd;
|
|
4286
|
+
this.initialized = false;
|
|
4287
|
+
await this.initialize();
|
|
4288
|
+
}
|
|
4289
|
+
dispose() {
|
|
4290
|
+
this.initialized = false;
|
|
4291
|
+
}
|
|
4292
|
+
};
|
|
4293
|
+
function parseCodexToml(content, cwd) {
|
|
4294
|
+
const settings = {};
|
|
4295
|
+
let currentSection = "";
|
|
4296
|
+
for (const line of content.split("\n")) {
|
|
4297
|
+
const trimmed = line.trim();
|
|
4298
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
4299
|
+
const sectionMatch = trimmed.match(/^\[(.+)\]$/);
|
|
4300
|
+
if (sectionMatch) {
|
|
4301
|
+
currentSection = sectionMatch[1] ?? "";
|
|
4302
|
+
continue;
|
|
4303
|
+
}
|
|
4304
|
+
const kvMatch = trimmed.match(/^(\w+)\s*=\s*(.+)$/);
|
|
4305
|
+
if (!kvMatch) continue;
|
|
4306
|
+
const key = kvMatch[1];
|
|
4307
|
+
let value = kvMatch[2]?.trim() ?? "";
|
|
4308
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
4309
|
+
value = value.slice(1, -1);
|
|
4310
|
+
}
|
|
4311
|
+
if (!currentSection) {
|
|
4312
|
+
if (key === "model") settings.model = value;
|
|
4313
|
+
if (key === "personality") settings.personality = value;
|
|
4314
|
+
if (key === "model_reasoning_effort")
|
|
4315
|
+
settings.modelReasoningEffort = value;
|
|
4316
|
+
} else if (currentSection === `projects."${cwd}"`) {
|
|
4317
|
+
if (key === "trust_level") settings.trustLevel = value;
|
|
4318
|
+
}
|
|
4319
|
+
}
|
|
4320
|
+
return settings;
|
|
4321
|
+
}
|
|
4322
|
+
|
|
4140
4323
|
// src/adapters/codex/spawn.ts
|
|
4141
4324
|
import { spawn as spawn2 } from "child_process";
|
|
4142
4325
|
import { existsSync as existsSync3 } from "fs";
|
|
@@ -4233,64 +4416,216 @@ function spawnCodexProcess(options) {
|
|
|
4233
4416
|
};
|
|
4234
4417
|
}
|
|
4235
4418
|
|
|
4236
|
-
// src/adapters/
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
const
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
currentValue: nextCurrent2,
|
|
4262
|
-
options: filteredOptions2
|
|
4263
|
-
};
|
|
4264
|
-
}
|
|
4265
|
-
const valueOptions = options;
|
|
4266
|
-
const filteredOptions = valueOptions.filter((o) => o?.value && allowedModelIds.has(o.value)).map(formatOption);
|
|
4267
|
-
const currentAllowed = opt.currentValue && allowedModelIds.has(opt.currentValue);
|
|
4268
|
-
const nextCurrent = currentAllowed || filteredOptions.length === 0 ? opt.currentValue : filteredOptions[0]?.value;
|
|
4269
|
-
return {
|
|
4270
|
-
...opt,
|
|
4271
|
-
currentValue: nextCurrent,
|
|
4272
|
-
options: filteredOptions
|
|
4419
|
+
// src/adapters/codex/codex-agent.ts
|
|
4420
|
+
var CodexAcpAgent = class extends BaseAcpAgent {
|
|
4421
|
+
adapterName = "codex";
|
|
4422
|
+
codexProcess;
|
|
4423
|
+
codexConnection;
|
|
4424
|
+
sessionState;
|
|
4425
|
+
constructor(client, options) {
|
|
4426
|
+
super(client);
|
|
4427
|
+
this.logger = new Logger({ debug: true, prefix: "[CodexAcpAgent]" });
|
|
4428
|
+
this.codexProcess = spawnCodexProcess({
|
|
4429
|
+
...options.codexProcessOptions,
|
|
4430
|
+
logger: this.logger,
|
|
4431
|
+
processCallbacks: options.processCallbacks
|
|
4432
|
+
});
|
|
4433
|
+
const codexReadable = nodeReadableToWebReadable(this.codexProcess.stdout);
|
|
4434
|
+
const codexWritable = nodeWritableToWebWritable(this.codexProcess.stdin);
|
|
4435
|
+
const codexStream = ndJsonStream(codexWritable, codexReadable);
|
|
4436
|
+
const cwd = options.codexProcessOptions.cwd ?? process.cwd();
|
|
4437
|
+
const settingsManager = new CodexSettingsManager(cwd);
|
|
4438
|
+
const abortController = new AbortController();
|
|
4439
|
+
this.session = {
|
|
4440
|
+
abortController,
|
|
4441
|
+
settingsManager,
|
|
4442
|
+
notificationHistory: [],
|
|
4443
|
+
cancelled: false
|
|
4273
4444
|
};
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4445
|
+
this.codexConnection = new ClientSideConnection(
|
|
4446
|
+
(_agent) => createCodexClient(
|
|
4447
|
+
this.client,
|
|
4448
|
+
this.logger,
|
|
4449
|
+
this.sessionState ?? {
|
|
4450
|
+
sessionId: "",
|
|
4451
|
+
cwd: "",
|
|
4452
|
+
modeId: "default",
|
|
4453
|
+
configOptions: [],
|
|
4454
|
+
accumulatedUsage: {
|
|
4455
|
+
inputTokens: 0,
|
|
4456
|
+
outputTokens: 0,
|
|
4457
|
+
cachedReadTokens: 0,
|
|
4458
|
+
cachedWriteTokens: 0
|
|
4459
|
+
},
|
|
4460
|
+
cancelled: false
|
|
4461
|
+
}
|
|
4462
|
+
),
|
|
4463
|
+
codexStream
|
|
4464
|
+
);
|
|
4277
4465
|
}
|
|
4278
|
-
|
|
4466
|
+
async initialize(request) {
|
|
4467
|
+
await this.session.settingsManager.initialize();
|
|
4468
|
+
const response = await this.codexConnection.initialize(request);
|
|
4279
4469
|
return {
|
|
4280
|
-
...
|
|
4281
|
-
|
|
4282
|
-
...
|
|
4283
|
-
|
|
4470
|
+
...response,
|
|
4471
|
+
agentCapabilities: {
|
|
4472
|
+
...response.agentCapabilities,
|
|
4473
|
+
sessionCapabilities: {
|
|
4474
|
+
...response.agentCapabilities?.sessionCapabilities,
|
|
4475
|
+
resume: {},
|
|
4476
|
+
fork: {}
|
|
4477
|
+
},
|
|
4478
|
+
_meta: {
|
|
4479
|
+
posthog: {
|
|
4480
|
+
resumeSession: true
|
|
4481
|
+
}
|
|
4482
|
+
}
|
|
4483
|
+
},
|
|
4484
|
+
agentInfo: {
|
|
4485
|
+
name: package_default.name,
|
|
4486
|
+
title: "Codex Agent",
|
|
4487
|
+
version: package_default.version
|
|
4284
4488
|
}
|
|
4285
4489
|
};
|
|
4286
4490
|
}
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4491
|
+
async newSession(params) {
|
|
4492
|
+
const meta = params._meta;
|
|
4493
|
+
const response = await this.codexConnection.newSession(params);
|
|
4494
|
+
this.sessionState = createSessionState(response.sessionId, params.cwd, {
|
|
4495
|
+
taskRunId: meta?.taskRunId,
|
|
4496
|
+
taskId: meta?.taskId ?? meta?.persistence?.taskId,
|
|
4497
|
+
modeId: response.modes?.currentModeId ?? "default",
|
|
4498
|
+
modelId: response.models?.currentModelId
|
|
4499
|
+
});
|
|
4500
|
+
this.sessionId = response.sessionId;
|
|
4501
|
+
this.sessionState.configOptions = response.configOptions ?? [];
|
|
4502
|
+
if (meta?.taskRunId) {
|
|
4503
|
+
await this.client.extNotification(POSTHOG_NOTIFICATIONS.SDK_SESSION, {
|
|
4504
|
+
taskRunId: meta.taskRunId,
|
|
4505
|
+
sessionId: response.sessionId,
|
|
4506
|
+
adapter: "codex"
|
|
4507
|
+
});
|
|
4508
|
+
}
|
|
4509
|
+
this.logger.info("Codex session created", {
|
|
4510
|
+
sessionId: response.sessionId,
|
|
4511
|
+
taskRunId: meta?.taskRunId
|
|
4512
|
+
});
|
|
4513
|
+
return response;
|
|
4514
|
+
}
|
|
4515
|
+
async loadSession(params) {
|
|
4516
|
+
const response = await this.codexConnection.loadSession(params);
|
|
4517
|
+
this.sessionState = createSessionState(params.sessionId, params.cwd);
|
|
4518
|
+
this.sessionId = params.sessionId;
|
|
4519
|
+
this.sessionState.configOptions = response.configOptions ?? [];
|
|
4520
|
+
return response;
|
|
4521
|
+
}
|
|
4522
|
+
async unstable_resumeSession(params) {
|
|
4523
|
+
const loadResponse = await this.codexConnection.loadSession({
|
|
4524
|
+
sessionId: params.sessionId,
|
|
4525
|
+
cwd: params.cwd,
|
|
4526
|
+
mcpServers: params.mcpServers ?? []
|
|
4527
|
+
});
|
|
4528
|
+
this.sessionState = createSessionState(params.sessionId, params.cwd);
|
|
4529
|
+
this.sessionId = params.sessionId;
|
|
4530
|
+
this.sessionState.configOptions = loadResponse.configOptions ?? [];
|
|
4531
|
+
const meta = params._meta;
|
|
4532
|
+
if (meta?.taskRunId) {
|
|
4533
|
+
await this.client.extNotification(POSTHOG_NOTIFICATIONS.SDK_SESSION, {
|
|
4534
|
+
taskRunId: meta.taskRunId,
|
|
4535
|
+
sessionId: params.sessionId,
|
|
4536
|
+
adapter: "codex"
|
|
4537
|
+
});
|
|
4538
|
+
}
|
|
4539
|
+
return {
|
|
4540
|
+
modes: loadResponse.modes,
|
|
4541
|
+
models: loadResponse.models,
|
|
4542
|
+
configOptions: loadResponse.configOptions
|
|
4543
|
+
};
|
|
4544
|
+
}
|
|
4545
|
+
async unstable_forkSession(params) {
|
|
4546
|
+
const newResponse = await this.codexConnection.newSession({
|
|
4547
|
+
cwd: params.cwd,
|
|
4548
|
+
mcpServers: params.mcpServers ?? [],
|
|
4549
|
+
_meta: params._meta
|
|
4550
|
+
});
|
|
4551
|
+
this.sessionState = createSessionState(newResponse.sessionId, params.cwd);
|
|
4552
|
+
this.sessionId = newResponse.sessionId;
|
|
4553
|
+
this.sessionState.configOptions = newResponse.configOptions ?? [];
|
|
4554
|
+
return newResponse;
|
|
4555
|
+
}
|
|
4556
|
+
async listSessions(params) {
|
|
4557
|
+
return this.codexConnection.listSessions(params);
|
|
4558
|
+
}
|
|
4559
|
+
async unstable_listSessions(params) {
|
|
4560
|
+
return this.codexConnection.listSessions(params);
|
|
4561
|
+
}
|
|
4562
|
+
async prompt(params) {
|
|
4563
|
+
if (this.sessionState) {
|
|
4564
|
+
this.sessionState.cancelled = false;
|
|
4565
|
+
this.sessionState.interruptReason = void 0;
|
|
4566
|
+
resetUsage(this.sessionState);
|
|
4567
|
+
}
|
|
4568
|
+
const response = await this.codexConnection.prompt(params);
|
|
4569
|
+
if (this.sessionState?.taskRunId && response.usage) {
|
|
4570
|
+
await this.client.extNotification("_posthog/usage_update", {
|
|
4571
|
+
sessionId: params.sessionId,
|
|
4572
|
+
used: {
|
|
4573
|
+
inputTokens: response.usage.inputTokens ?? 0,
|
|
4574
|
+
outputTokens: response.usage.outputTokens ?? 0,
|
|
4575
|
+
cachedReadTokens: response.usage.cachedReadTokens ?? 0,
|
|
4576
|
+
cachedWriteTokens: response.usage.cachedWriteTokens ?? 0
|
|
4577
|
+
},
|
|
4578
|
+
cost: null
|
|
4579
|
+
});
|
|
4580
|
+
}
|
|
4581
|
+
return response;
|
|
4582
|
+
}
|
|
4583
|
+
async interrupt() {
|
|
4584
|
+
if (this.sessionState) {
|
|
4585
|
+
this.sessionState.cancelled = true;
|
|
4586
|
+
}
|
|
4587
|
+
await this.codexConnection.cancel({
|
|
4588
|
+
sessionId: this.sessionId
|
|
4589
|
+
});
|
|
4590
|
+
}
|
|
4591
|
+
async cancel(params) {
|
|
4592
|
+
if (this.sessionState) {
|
|
4593
|
+
this.sessionState.cancelled = true;
|
|
4594
|
+
const meta = params._meta;
|
|
4595
|
+
if (meta?.interruptReason) {
|
|
4596
|
+
this.sessionState.interruptReason = meta.interruptReason;
|
|
4597
|
+
}
|
|
4598
|
+
}
|
|
4599
|
+
await this.codexConnection.cancel(params);
|
|
4600
|
+
}
|
|
4601
|
+
async setSessionMode(params) {
|
|
4602
|
+
const response = await this.codexConnection.setSessionMode(params);
|
|
4603
|
+
if (this.sessionState) {
|
|
4604
|
+
this.sessionState.modeId = params.modeId;
|
|
4605
|
+
}
|
|
4606
|
+
return response ?? {};
|
|
4607
|
+
}
|
|
4608
|
+
async setSessionConfigOption(params) {
|
|
4609
|
+
const response = await this.codexConnection.setSessionConfigOption(params);
|
|
4610
|
+
if (this.sessionState && response.configOptions) {
|
|
4611
|
+
this.sessionState.configOptions = response.configOptions;
|
|
4612
|
+
}
|
|
4613
|
+
return response;
|
|
4614
|
+
}
|
|
4615
|
+
async authenticate(_params) {
|
|
4616
|
+
}
|
|
4617
|
+
async closeSession() {
|
|
4618
|
+
this.logger.info("Closing Codex session", { sessionId: this.sessionId });
|
|
4619
|
+
this.session.settingsManager.dispose();
|
|
4620
|
+
try {
|
|
4621
|
+
this.codexProcess.kill();
|
|
4622
|
+
} catch (err) {
|
|
4623
|
+
this.logger.warn("Failed to kill codex-acp process", { error: err });
|
|
4624
|
+
}
|
|
4625
|
+
}
|
|
4626
|
+
};
|
|
4627
|
+
|
|
4628
|
+
// src/adapters/acp-connection.ts
|
|
4294
4629
|
function createAcpConnection(config = {}) {
|
|
4295
4630
|
const adapterType = config.adapter ?? "claude";
|
|
4296
4631
|
if (adapterType === "codex") {
|
|
@@ -4331,7 +4666,7 @@ function createClaudeConnection(config) {
|
|
|
4331
4666
|
hasLogWriter: !!logWriter
|
|
4332
4667
|
});
|
|
4333
4668
|
}
|
|
4334
|
-
const agentStream =
|
|
4669
|
+
const agentStream = ndJsonStream2(agentWritable, streams.agent.readable);
|
|
4335
4670
|
let agent = null;
|
|
4336
4671
|
const agentConnection = new AgentSideConnection((client) => {
|
|
4337
4672
|
agent = new ClaudeAcpAgent(client, config.processCallbacks);
|
|
@@ -4363,214 +4698,63 @@ function createClaudeConnection(config) {
|
|
|
4363
4698
|
function createCodexConnection(config) {
|
|
4364
4699
|
const logger = config.logger?.child("CodexConnection") ?? new Logger({ debug: true, prefix: "[CodexConnection]" });
|
|
4365
4700
|
const { logWriter } = config;
|
|
4366
|
-
const
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
let loadRequestId = null;
|
|
4376
|
-
let newSessionRequestId = null;
|
|
4377
|
-
let sdkSessionEmitted = false;
|
|
4378
|
-
const reasoningEffortBySessionId = /* @__PURE__ */ new Map();
|
|
4379
|
-
let injectedConfigId = 0;
|
|
4380
|
-
const decoder = new TextDecoder();
|
|
4381
|
-
const encoder = new TextEncoder();
|
|
4382
|
-
let readBuffer = "";
|
|
4383
|
-
const taskRunId = config.taskRunId;
|
|
4384
|
-
const filteringReadable = clientReadable.pipeThrough(
|
|
4385
|
-
new TransformStream({
|
|
4386
|
-
transform(chunk, controller) {
|
|
4387
|
-
readBuffer += decoder.decode(chunk, { stream: true });
|
|
4388
|
-
const lines = readBuffer.split("\n");
|
|
4389
|
-
readBuffer = lines.pop() ?? "";
|
|
4390
|
-
const outputLines = [];
|
|
4391
|
-
for (const line of lines) {
|
|
4392
|
-
const trimmed = line.trim();
|
|
4393
|
-
if (!trimmed) {
|
|
4394
|
-
outputLines.push(line);
|
|
4395
|
-
continue;
|
|
4396
|
-
}
|
|
4397
|
-
let shouldFilter = false;
|
|
4398
|
-
try {
|
|
4399
|
-
const msg = JSON.parse(trimmed);
|
|
4400
|
-
const sessionId = msg?.params?.sessionId ?? msg?.result?.sessionId ?? null;
|
|
4401
|
-
const configOptions = msg?.result?.configOptions ?? msg?.params?.update?.configOptions;
|
|
4402
|
-
if (sessionId && configOptions) {
|
|
4403
|
-
const effort = extractReasoningEffort(configOptions);
|
|
4404
|
-
if (effort) {
|
|
4405
|
-
reasoningEffortBySessionId.set(sessionId, effort);
|
|
4406
|
-
}
|
|
4407
|
-
}
|
|
4408
|
-
if (!sdkSessionEmitted && newSessionRequestId !== null && msg.id === newSessionRequestId && "result" in msg) {
|
|
4409
|
-
const sessionId2 = msg.result?.sessionId;
|
|
4410
|
-
if (sessionId2 && taskRunId) {
|
|
4411
|
-
const sdkSessionNotification = {
|
|
4412
|
-
jsonrpc: "2.0",
|
|
4413
|
-
method: POSTHOG_NOTIFICATIONS.SDK_SESSION,
|
|
4414
|
-
params: {
|
|
4415
|
-
taskRunId,
|
|
4416
|
-
sessionId: sessionId2,
|
|
4417
|
-
adapter: "codex"
|
|
4418
|
-
}
|
|
4419
|
-
};
|
|
4420
|
-
outputLines.push(JSON.stringify(sdkSessionNotification));
|
|
4421
|
-
sdkSessionEmitted = true;
|
|
4422
|
-
}
|
|
4423
|
-
newSessionRequestId = null;
|
|
4424
|
-
}
|
|
4425
|
-
if (isLoadingSession) {
|
|
4426
|
-
if (msg.id === loadRequestId && "result" in msg) {
|
|
4427
|
-
logger.debug("session/load complete, resuming stream");
|
|
4428
|
-
isLoadingSession = false;
|
|
4429
|
-
loadRequestId = null;
|
|
4430
|
-
} else if (msg.method === "session/update") {
|
|
4431
|
-
shouldFilter = true;
|
|
4432
|
-
}
|
|
4433
|
-
}
|
|
4434
|
-
if (!shouldFilter && allowedModelIds && allowedModelIds.size > 0) {
|
|
4435
|
-
const updated = filterModelConfigOptions(msg, allowedModelIds);
|
|
4436
|
-
if (updated) {
|
|
4437
|
-
outputLines.push(JSON.stringify(updated));
|
|
4438
|
-
continue;
|
|
4439
|
-
}
|
|
4440
|
-
}
|
|
4441
|
-
} catch {
|
|
4442
|
-
}
|
|
4443
|
-
if (!shouldFilter) {
|
|
4444
|
-
outputLines.push(line);
|
|
4445
|
-
const isChunkNoise = trimmed.includes('"sessionUpdate":"agent_message_chunk"') || trimmed.includes('"sessionUpdate":"agent_thought_chunk"');
|
|
4446
|
-
if (!isChunkNoise) {
|
|
4447
|
-
logger.debug("codex-acp stdout:", trimmed);
|
|
4448
|
-
}
|
|
4449
|
-
}
|
|
4450
|
-
}
|
|
4451
|
-
if (outputLines.length > 0) {
|
|
4452
|
-
const output = `${outputLines.join("\n")}
|
|
4453
|
-
`;
|
|
4454
|
-
controller.enqueue(encoder.encode(output));
|
|
4455
|
-
}
|
|
4456
|
-
},
|
|
4457
|
-
flush(controller) {
|
|
4458
|
-
if (readBuffer.trim()) {
|
|
4459
|
-
controller.enqueue(encoder.encode(readBuffer));
|
|
4460
|
-
}
|
|
4461
|
-
}
|
|
4462
|
-
})
|
|
4463
|
-
);
|
|
4464
|
-
clientReadable = filteringReadable;
|
|
4465
|
-
const originalWritable = clientWritable;
|
|
4466
|
-
clientWritable = new WritableStream({
|
|
4467
|
-
write(chunk) {
|
|
4468
|
-
const text2 = decoder.decode(chunk, { stream: true });
|
|
4469
|
-
const trimmed = text2.trim();
|
|
4470
|
-
logger.debug("codex-acp stdin:", trimmed);
|
|
4471
|
-
try {
|
|
4472
|
-
const msg = JSON.parse(trimmed);
|
|
4473
|
-
if (msg.method === "session/set_config_option" && msg.params?.configId === "reasoning_effort" && msg.params?.sessionId && msg.params?.value) {
|
|
4474
|
-
reasoningEffortBySessionId.set(
|
|
4475
|
-
msg.params.sessionId,
|
|
4476
|
-
msg.params.value
|
|
4477
|
-
);
|
|
4478
|
-
}
|
|
4479
|
-
if (msg.method === "session/prompt" && msg.params?.sessionId) {
|
|
4480
|
-
const effort = reasoningEffortBySessionId.get(msg.params.sessionId);
|
|
4481
|
-
if (effort) {
|
|
4482
|
-
const injection = {
|
|
4483
|
-
jsonrpc: "2.0",
|
|
4484
|
-
id: `reasoning_effort_${Date.now()}_${injectedConfigId++}`,
|
|
4485
|
-
method: "session/set_config_option",
|
|
4486
|
-
params: {
|
|
4487
|
-
sessionId: msg.params.sessionId,
|
|
4488
|
-
configId: "reasoning_effort",
|
|
4489
|
-
value: effort
|
|
4490
|
-
}
|
|
4491
|
-
};
|
|
4492
|
-
const injectionLine = `${JSON.stringify(injection)}
|
|
4493
|
-
`;
|
|
4494
|
-
const writer2 = originalWritable.getWriter();
|
|
4495
|
-
return writer2.write(encoder.encode(injectionLine)).then(() => writer2.releaseLock()).then(() => {
|
|
4496
|
-
const nextWriter = originalWritable.getWriter();
|
|
4497
|
-
return nextWriter.write(chunk).finally(() => nextWriter.releaseLock());
|
|
4498
|
-
});
|
|
4499
|
-
}
|
|
4500
|
-
}
|
|
4501
|
-
if (msg.method === "session/new" && msg.id) {
|
|
4502
|
-
logger.debug("session/new detected, tracking request ID");
|
|
4503
|
-
newSessionRequestId = msg.id;
|
|
4504
|
-
} else if (msg.method === "session/load" && msg.id) {
|
|
4505
|
-
logger.debug("session/load detected, pausing stream updates");
|
|
4506
|
-
isLoadingSession = true;
|
|
4507
|
-
loadRequestId = msg.id;
|
|
4508
|
-
}
|
|
4509
|
-
} catch {
|
|
4510
|
-
}
|
|
4511
|
-
const writer = originalWritable.getWriter();
|
|
4512
|
-
return writer.write(chunk).finally(() => writer.releaseLock());
|
|
4513
|
-
},
|
|
4514
|
-
close() {
|
|
4515
|
-
const writer = originalWritable.getWriter();
|
|
4516
|
-
return writer.close().finally(() => writer.releaseLock());
|
|
4517
|
-
}
|
|
4518
|
-
});
|
|
4519
|
-
const shouldTapLogs = config.taskRunId && logWriter;
|
|
4520
|
-
if (shouldTapLogs && config.taskRunId) {
|
|
4521
|
-
const taskRunId2 = config.taskRunId;
|
|
4522
|
-
if (!logWriter.isRegistered(taskRunId2)) {
|
|
4523
|
-
logWriter.register(taskRunId2, {
|
|
4524
|
-
taskId: config.taskId ?? taskRunId2,
|
|
4525
|
-
runId: taskRunId2
|
|
4701
|
+
const streams = createBidirectionalStreams();
|
|
4702
|
+
let agentWritable = streams.agent.writable;
|
|
4703
|
+
let clientWritable = streams.client.writable;
|
|
4704
|
+
if (config.taskRunId && logWriter) {
|
|
4705
|
+
if (!logWriter.isRegistered(config.taskRunId)) {
|
|
4706
|
+
logWriter.register(config.taskRunId, {
|
|
4707
|
+
taskId: config.taskId ?? config.taskRunId,
|
|
4708
|
+
runId: config.taskRunId,
|
|
4709
|
+
deviceType: config.deviceType
|
|
4526
4710
|
});
|
|
4527
4711
|
}
|
|
4528
|
-
|
|
4712
|
+
const taskRunId = config.taskRunId;
|
|
4713
|
+
agentWritable = createTappedWritableStream(streams.agent.writable, {
|
|
4529
4714
|
onMessage: (line) => {
|
|
4530
|
-
logWriter.appendRawLine(
|
|
4715
|
+
logWriter.appendRawLine(taskRunId, line);
|
|
4716
|
+
},
|
|
4717
|
+
logger
|
|
4718
|
+
});
|
|
4719
|
+
clientWritable = createTappedWritableStream(streams.client.writable, {
|
|
4720
|
+
onMessage: (line) => {
|
|
4721
|
+
logWriter.appendRawLine(taskRunId, line);
|
|
4531
4722
|
},
|
|
4532
4723
|
logger
|
|
4533
4724
|
});
|
|
4534
|
-
const originalReadable = clientReadable;
|
|
4535
|
-
const logDecoder = new TextDecoder();
|
|
4536
|
-
let logBuffer = "";
|
|
4537
|
-
clientReadable = originalReadable.pipeThrough(
|
|
4538
|
-
new TransformStream({
|
|
4539
|
-
transform(chunk, controller) {
|
|
4540
|
-
logBuffer += logDecoder.decode(chunk, { stream: true });
|
|
4541
|
-
const lines = logBuffer.split("\n");
|
|
4542
|
-
logBuffer = lines.pop() ?? "";
|
|
4543
|
-
for (const line of lines) {
|
|
4544
|
-
if (line.trim()) {
|
|
4545
|
-
logWriter.appendRawLine(taskRunId2, line);
|
|
4546
|
-
}
|
|
4547
|
-
}
|
|
4548
|
-
controller.enqueue(chunk);
|
|
4549
|
-
},
|
|
4550
|
-
flush() {
|
|
4551
|
-
if (logBuffer.trim()) {
|
|
4552
|
-
logWriter.appendRawLine(taskRunId2, logBuffer);
|
|
4553
|
-
}
|
|
4554
|
-
}
|
|
4555
|
-
})
|
|
4556
|
-
);
|
|
4557
4725
|
} else {
|
|
4558
4726
|
logger.info("Tapped streams NOT enabled for Codex", {
|
|
4559
4727
|
hasTaskRunId: !!config.taskRunId,
|
|
4560
4728
|
hasLogWriter: !!logWriter
|
|
4561
4729
|
});
|
|
4562
4730
|
}
|
|
4731
|
+
const agentStream = ndJsonStream2(agentWritable, streams.agent.readable);
|
|
4732
|
+
let agent = null;
|
|
4733
|
+
const agentConnection = new AgentSideConnection((client) => {
|
|
4734
|
+
agent = new CodexAcpAgent(client, {
|
|
4735
|
+
codexProcessOptions: config.codexOptions ?? {},
|
|
4736
|
+
processCallbacks: config.processCallbacks
|
|
4737
|
+
});
|
|
4738
|
+
logger.info(`Created ${agent.adapterName} agent`);
|
|
4739
|
+
return agent;
|
|
4740
|
+
}, agentStream);
|
|
4563
4741
|
return {
|
|
4564
|
-
agentConnection
|
|
4742
|
+
agentConnection,
|
|
4565
4743
|
clientStreams: {
|
|
4566
|
-
readable:
|
|
4744
|
+
readable: streams.client.readable,
|
|
4567
4745
|
writable: clientWritable
|
|
4568
4746
|
},
|
|
4569
4747
|
cleanup: async () => {
|
|
4570
4748
|
logger.info("Cleaning up Codex connection");
|
|
4571
|
-
|
|
4749
|
+
if (agent) {
|
|
4750
|
+
await agent.closeSession();
|
|
4751
|
+
}
|
|
4572
4752
|
try {
|
|
4573
|
-
await
|
|
4753
|
+
await streams.client.writable.close();
|
|
4754
|
+
} catch {
|
|
4755
|
+
}
|
|
4756
|
+
try {
|
|
4757
|
+
await streams.agent.writable.close();
|
|
4574
4758
|
} catch {
|
|
4575
4759
|
}
|
|
4576
4760
|
}
|
|
@@ -4778,9 +4962,9 @@ var PostHogAPIClient = class {
|
|
|
4778
4962
|
};
|
|
4779
4963
|
|
|
4780
4964
|
// src/session-log-writer.ts
|
|
4781
|
-
import
|
|
4965
|
+
import fs6 from "fs";
|
|
4782
4966
|
import fsp from "fs/promises";
|
|
4783
|
-
import
|
|
4967
|
+
import path8 from "path";
|
|
4784
4968
|
var SessionLogWriter = class _SessionLogWriter {
|
|
4785
4969
|
static FLUSH_DEBOUNCE_MS = 500;
|
|
4786
4970
|
static FLUSH_MAX_INTERVAL_MS = 5e3;
|
|
@@ -4820,13 +5004,13 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
4820
5004
|
this.sessions.set(sessionId, { context, currentTurnMessages: [] });
|
|
4821
5005
|
this.lastFlushAttemptTime.set(sessionId, Date.now());
|
|
4822
5006
|
if (this.localCachePath) {
|
|
4823
|
-
const sessionDir =
|
|
5007
|
+
const sessionDir = path8.join(
|
|
4824
5008
|
this.localCachePath,
|
|
4825
5009
|
"sessions",
|
|
4826
5010
|
context.runId
|
|
4827
5011
|
);
|
|
4828
5012
|
try {
|
|
4829
|
-
|
|
5013
|
+
fs6.mkdirSync(sessionDir, { recursive: true });
|
|
4830
5014
|
} catch (error) {
|
|
4831
5015
|
this.logger.warn("Failed to create local cache directory", {
|
|
4832
5016
|
sessionDir,
|
|
@@ -5078,14 +5262,14 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
5078
5262
|
if (!this.localCachePath) return;
|
|
5079
5263
|
const session = this.sessions.get(sessionId);
|
|
5080
5264
|
if (!session) return;
|
|
5081
|
-
const logPath =
|
|
5265
|
+
const logPath = path8.join(
|
|
5082
5266
|
this.localCachePath,
|
|
5083
5267
|
"sessions",
|
|
5084
5268
|
session.context.runId,
|
|
5085
5269
|
"logs.ndjson"
|
|
5086
5270
|
);
|
|
5087
5271
|
try {
|
|
5088
|
-
|
|
5272
|
+
fs6.appendFileSync(logPath, `${JSON.stringify(entry)}
|
|
5089
5273
|
`);
|
|
5090
5274
|
} catch (error) {
|
|
5091
5275
|
this.logger.warn("Failed to write to local cache", {
|
|
@@ -5097,13 +5281,13 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
5097
5281
|
}
|
|
5098
5282
|
}
|
|
5099
5283
|
static async cleanupOldSessions(localCachePath) {
|
|
5100
|
-
const sessionsDir =
|
|
5284
|
+
const sessionsDir = path8.join(localCachePath, "sessions");
|
|
5101
5285
|
let deleted = 0;
|
|
5102
5286
|
try {
|
|
5103
5287
|
const entries = await fsp.readdir(sessionsDir);
|
|
5104
5288
|
const now = Date.now();
|
|
5105
5289
|
for (const entry of entries) {
|
|
5106
|
-
const entryPath =
|
|
5290
|
+
const entryPath = path8.join(sessionsDir, entry);
|
|
5107
5291
|
try {
|
|
5108
5292
|
const stats = await fsp.stat(entryPath);
|
|
5109
5293
|
if (stats.isDirectory() && now - stats.birthtimeMs > _SessionLogWriter.SESSIONS_MAX_AGE_MS) {
|
|
@@ -5189,7 +5373,7 @@ var Agent = class {
|
|
|
5189
5373
|
allowedModelIds = new Set(codexModelIds);
|
|
5190
5374
|
}
|
|
5191
5375
|
if (!sanitizedModel || !allowedModelIds?.has(sanitizedModel)) {
|
|
5192
|
-
sanitizedModel = codexModelIds[0];
|
|
5376
|
+
sanitizedModel = codexModelIds.includes(DEFAULT_CODEX_MODEL) ? DEFAULT_CODEX_MODEL : codexModelIds[0];
|
|
5193
5377
|
}
|
|
5194
5378
|
}
|
|
5195
5379
|
if (!sanitizedModel && options.adapter !== "codex") {
|