@posthog/agent 2.3.168 → 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 +569 -386
- package/dist/agent.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/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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
248
|
+
version: "2.3.169",
|
|
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(
|
|
730
|
-
this.items.push({ type: "diff", path:
|
|
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,6 +4102,224 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
4138
4102
|
}
|
|
4139
4103
|
};
|
|
4140
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
|
+
|
|
4141
4323
|
// src/adapters/codex/spawn.ts
|
|
4142
4324
|
import { spawn as spawn2 } from "child_process";
|
|
4143
4325
|
import { existsSync as existsSync3 } from "fs";
|
|
@@ -4234,64 +4416,216 @@ function spawnCodexProcess(options) {
|
|
|
4234
4416
|
};
|
|
4235
4417
|
}
|
|
4236
4418
|
|
|
4237
|
-
// src/adapters/
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
const
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
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
|
|
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
|
|
4274
4444
|
};
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
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
|
+
);
|
|
4278
4465
|
}
|
|
4279
|
-
|
|
4466
|
+
async initialize(request) {
|
|
4467
|
+
await this.session.settingsManager.initialize();
|
|
4468
|
+
const response = await this.codexConnection.initialize(request);
|
|
4280
4469
|
return {
|
|
4281
|
-
...
|
|
4282
|
-
|
|
4283
|
-
...
|
|
4284
|
-
|
|
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
|
|
4285
4488
|
}
|
|
4286
4489
|
};
|
|
4287
4490
|
}
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
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
|
|
4295
4629
|
function createAcpConnection(config = {}) {
|
|
4296
4630
|
const adapterType = config.adapter ?? "claude";
|
|
4297
4631
|
if (adapterType === "codex") {
|
|
@@ -4332,7 +4666,7 @@ function createClaudeConnection(config) {
|
|
|
4332
4666
|
hasLogWriter: !!logWriter
|
|
4333
4667
|
});
|
|
4334
4668
|
}
|
|
4335
|
-
const agentStream =
|
|
4669
|
+
const agentStream = ndJsonStream2(agentWritable, streams.agent.readable);
|
|
4336
4670
|
let agent = null;
|
|
4337
4671
|
const agentConnection = new AgentSideConnection((client) => {
|
|
4338
4672
|
agent = new ClaudeAcpAgent(client, config.processCallbacks);
|
|
@@ -4364,214 +4698,63 @@ function createClaudeConnection(config) {
|
|
|
4364
4698
|
function createCodexConnection(config) {
|
|
4365
4699
|
const logger = config.logger?.child("CodexConnection") ?? new Logger({ debug: true, prefix: "[CodexConnection]" });
|
|
4366
4700
|
const { logWriter } = config;
|
|
4367
|
-
const
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
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
|
|
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
|
|
4527
4710
|
});
|
|
4528
4711
|
}
|
|
4529
|
-
|
|
4712
|
+
const taskRunId = config.taskRunId;
|
|
4713
|
+
agentWritable = createTappedWritableStream(streams.agent.writable, {
|
|
4530
4714
|
onMessage: (line) => {
|
|
4531
|
-
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);
|
|
4532
4722
|
},
|
|
4533
4723
|
logger
|
|
4534
4724
|
});
|
|
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
4725
|
} else {
|
|
4559
4726
|
logger.info("Tapped streams NOT enabled for Codex", {
|
|
4560
4727
|
hasTaskRunId: !!config.taskRunId,
|
|
4561
4728
|
hasLogWriter: !!logWriter
|
|
4562
4729
|
});
|
|
4563
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);
|
|
4564
4741
|
return {
|
|
4565
|
-
agentConnection
|
|
4742
|
+
agentConnection,
|
|
4566
4743
|
clientStreams: {
|
|
4567
|
-
readable:
|
|
4744
|
+
readable: streams.client.readable,
|
|
4568
4745
|
writable: clientWritable
|
|
4569
4746
|
},
|
|
4570
4747
|
cleanup: async () => {
|
|
4571
4748
|
logger.info("Cleaning up Codex connection");
|
|
4572
|
-
|
|
4749
|
+
if (agent) {
|
|
4750
|
+
await agent.closeSession();
|
|
4751
|
+
}
|
|
4573
4752
|
try {
|
|
4574
|
-
await
|
|
4753
|
+
await streams.client.writable.close();
|
|
4754
|
+
} catch {
|
|
4755
|
+
}
|
|
4756
|
+
try {
|
|
4757
|
+
await streams.agent.writable.close();
|
|
4575
4758
|
} catch {
|
|
4576
4759
|
}
|
|
4577
4760
|
}
|
|
@@ -4779,9 +4962,9 @@ var PostHogAPIClient = class {
|
|
|
4779
4962
|
};
|
|
4780
4963
|
|
|
4781
4964
|
// src/session-log-writer.ts
|
|
4782
|
-
import
|
|
4965
|
+
import fs6 from "fs";
|
|
4783
4966
|
import fsp from "fs/promises";
|
|
4784
|
-
import
|
|
4967
|
+
import path8 from "path";
|
|
4785
4968
|
var SessionLogWriter = class _SessionLogWriter {
|
|
4786
4969
|
static FLUSH_DEBOUNCE_MS = 500;
|
|
4787
4970
|
static FLUSH_MAX_INTERVAL_MS = 5e3;
|
|
@@ -4821,13 +5004,13 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
4821
5004
|
this.sessions.set(sessionId, { context, currentTurnMessages: [] });
|
|
4822
5005
|
this.lastFlushAttemptTime.set(sessionId, Date.now());
|
|
4823
5006
|
if (this.localCachePath) {
|
|
4824
|
-
const sessionDir =
|
|
5007
|
+
const sessionDir = path8.join(
|
|
4825
5008
|
this.localCachePath,
|
|
4826
5009
|
"sessions",
|
|
4827
5010
|
context.runId
|
|
4828
5011
|
);
|
|
4829
5012
|
try {
|
|
4830
|
-
|
|
5013
|
+
fs6.mkdirSync(sessionDir, { recursive: true });
|
|
4831
5014
|
} catch (error) {
|
|
4832
5015
|
this.logger.warn("Failed to create local cache directory", {
|
|
4833
5016
|
sessionDir,
|
|
@@ -5079,14 +5262,14 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
5079
5262
|
if (!this.localCachePath) return;
|
|
5080
5263
|
const session = this.sessions.get(sessionId);
|
|
5081
5264
|
if (!session) return;
|
|
5082
|
-
const logPath =
|
|
5265
|
+
const logPath = path8.join(
|
|
5083
5266
|
this.localCachePath,
|
|
5084
5267
|
"sessions",
|
|
5085
5268
|
session.context.runId,
|
|
5086
5269
|
"logs.ndjson"
|
|
5087
5270
|
);
|
|
5088
5271
|
try {
|
|
5089
|
-
|
|
5272
|
+
fs6.appendFileSync(logPath, `${JSON.stringify(entry)}
|
|
5090
5273
|
`);
|
|
5091
5274
|
} catch (error) {
|
|
5092
5275
|
this.logger.warn("Failed to write to local cache", {
|
|
@@ -5098,13 +5281,13 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
5098
5281
|
}
|
|
5099
5282
|
}
|
|
5100
5283
|
static async cleanupOldSessions(localCachePath) {
|
|
5101
|
-
const sessionsDir =
|
|
5284
|
+
const sessionsDir = path8.join(localCachePath, "sessions");
|
|
5102
5285
|
let deleted = 0;
|
|
5103
5286
|
try {
|
|
5104
5287
|
const entries = await fsp.readdir(sessionsDir);
|
|
5105
5288
|
const now = Date.now();
|
|
5106
5289
|
for (const entry of entries) {
|
|
5107
|
-
const entryPath =
|
|
5290
|
+
const entryPath = path8.join(sessionsDir, entry);
|
|
5108
5291
|
try {
|
|
5109
5292
|
const stats = await fsp.stat(entryPath);
|
|
5110
5293
|
if (stats.isDirectory() && now - stats.birthtimeMs > _SessionLogWriter.SESSIONS_MAX_AGE_MS) {
|