doer-agent 0.8.5 → 0.8.7
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-codex-cli.js +36 -8
- package/dist/agent-settings.js +74 -4
- package/dist/agent-skill-rpc.js +8 -1
- package/dist/codex-app-server-manager.js +74 -4
- package/dist/codex-chat-bridge.js +898 -0
- package/dist/codex-chat-bridge.test.js +520 -0
- package/dist/codex-cli.js +21 -1
- package/dist/litellm-responses-proxy.js +685 -0
- package/package.json +6 -4
package/dist/agent-codex-cli.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { spawn, spawnSync } from "node:child_process";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
3
4
|
import path from "node:path";
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
4
6
|
const ANSI_RE = /\u001b\[[0-9;]*m/g;
|
|
5
7
|
function shellSingleQuote(value) {
|
|
6
8
|
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
@@ -32,6 +34,20 @@ function hasDirectCodexBinary() {
|
|
|
32
34
|
});
|
|
33
35
|
return result.status === 0;
|
|
34
36
|
}
|
|
37
|
+
function resolveBundledCodexCliBinPath() {
|
|
38
|
+
try {
|
|
39
|
+
const packageJsonPath = require.resolve("@openai/codex/package.json");
|
|
40
|
+
const packageJson = require(packageJsonPath);
|
|
41
|
+
const codexBin = packageJson.bin?.codex;
|
|
42
|
+
if (!codexBin) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
return path.resolve(path.dirname(packageJsonPath), codexBin);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
35
51
|
export function stripAnsi(value) {
|
|
36
52
|
return value.replace(ANSI_RE, "");
|
|
37
53
|
}
|
|
@@ -144,6 +160,10 @@ function buildWorkspaceMcpConfigArgs(args) {
|
|
|
144
160
|
}
|
|
145
161
|
export function buildLocalCodexCliCommand(args) {
|
|
146
162
|
const quotedArgs = args.map(shellSingleQuote).join(" ");
|
|
163
|
+
const bundledCodex = resolveBundledCodexCliBinPath();
|
|
164
|
+
if (bundledCodex) {
|
|
165
|
+
return `exec ${shellSingleQuote(process.execPath)} ${shellSingleQuote(bundledCodex)} ${quotedArgs}`;
|
|
166
|
+
}
|
|
147
167
|
const direct = `exec codex ${quotedArgs}`;
|
|
148
168
|
const fallback = `exec npm exec --yes --package doer-agent -- codex ${quotedArgs}`;
|
|
149
169
|
const script = [
|
|
@@ -159,19 +179,27 @@ export function spawnManagedCodexCommand(args) {
|
|
|
159
179
|
...args.env,
|
|
160
180
|
DOER_AGENT_TOKEN: args.agentToken,
|
|
161
181
|
};
|
|
162
|
-
const
|
|
163
|
-
|
|
182
|
+
const bundledCodex = resolveBundledCodexCliBinPath();
|
|
183
|
+
const child = bundledCodex
|
|
184
|
+
? spawn(process.execPath, [bundledCodex, ...args.codexArgs], {
|
|
164
185
|
cwd: args.taskWorkspace,
|
|
165
186
|
detached: process.platform !== "win32",
|
|
166
187
|
env,
|
|
167
188
|
stdio: ["ignore", "pipe", "pipe"],
|
|
168
189
|
})
|
|
169
|
-
:
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
190
|
+
: hasDirectCodexBinary()
|
|
191
|
+
? spawn("codex", args.codexArgs, {
|
|
192
|
+
cwd: args.taskWorkspace,
|
|
193
|
+
detached: process.platform !== "win32",
|
|
194
|
+
env,
|
|
195
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
196
|
+
})
|
|
197
|
+
: spawn("npm", ["exec", "--yes", "--package", "doer-agent", "--", "codex", ...args.codexArgs], {
|
|
198
|
+
cwd: args.taskWorkspace,
|
|
199
|
+
detached: process.platform !== "win32",
|
|
200
|
+
env,
|
|
201
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
202
|
+
});
|
|
175
203
|
child.stdout?.setEncoding("utf8");
|
|
176
204
|
child.stderr?.setEncoding("utf8");
|
|
177
205
|
return child;
|
package/dist/agent-settings.js
CHANGED
|
@@ -15,7 +15,9 @@ export function createDefaultAgentSettingsConfig() {
|
|
|
15
15
|
personality: "pragmatic",
|
|
16
16
|
},
|
|
17
17
|
codex: {
|
|
18
|
-
|
|
18
|
+
providerModels: { openai: "gpt-5.5" },
|
|
19
|
+
modelProvider: null,
|
|
20
|
+
customProvider: null,
|
|
19
21
|
reasoningEffort: "medium",
|
|
20
22
|
serviceTier: null,
|
|
21
23
|
authMode: "api_key",
|
|
@@ -63,6 +65,50 @@ function normalizeServiceTier(value) {
|
|
|
63
65
|
}
|
|
64
66
|
return normalized;
|
|
65
67
|
}
|
|
68
|
+
function normalizeCodexCustomProvider(value, fallback = null) {
|
|
69
|
+
if (value === null) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
73
|
+
return fallback;
|
|
74
|
+
}
|
|
75
|
+
const raw = value;
|
|
76
|
+
const id = typeof raw.id === "string" ? raw.id.trim() : "";
|
|
77
|
+
const baseUrl = typeof raw.baseUrl === "string" ? raw.baseUrl.trim() : "";
|
|
78
|
+
if (!id || !baseUrl) {
|
|
79
|
+
return fallback;
|
|
80
|
+
}
|
|
81
|
+
const name = typeof raw.name === "string" && raw.name.trim() ? raw.name.trim() : id;
|
|
82
|
+
const envKey = typeof raw.envKey === "string" && raw.envKey.trim() ? raw.envKey.trim() : `${id.toUpperCase()}_API_KEY`;
|
|
83
|
+
const apiKey = raw.apiKey === null
|
|
84
|
+
? null
|
|
85
|
+
: typeof raw.apiKey === "string" && raw.apiKey.trim()
|
|
86
|
+
? raw.apiKey.trim()
|
|
87
|
+
: fallback?.id === id
|
|
88
|
+
? fallback.apiKey
|
|
89
|
+
: null;
|
|
90
|
+
return {
|
|
91
|
+
id,
|
|
92
|
+
name,
|
|
93
|
+
baseUrl,
|
|
94
|
+
envKey,
|
|
95
|
+
apiKey,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function normalizeCodexProviderModels(value, fallback) {
|
|
99
|
+
const models = { ...fallback };
|
|
100
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
101
|
+
return models;
|
|
102
|
+
}
|
|
103
|
+
for (const [rawKey, rawModel] of Object.entries(value)) {
|
|
104
|
+
const key = rawKey.trim();
|
|
105
|
+
const model = typeof rawModel === "string" ? rawModel.trim() : "";
|
|
106
|
+
if (key && model) {
|
|
107
|
+
models[key] = model;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return models;
|
|
111
|
+
}
|
|
66
112
|
function normalizeCodexPersonality(value, fallback) {
|
|
67
113
|
return value === "friendly" || value === "pragmatic" ? value : fallback;
|
|
68
114
|
}
|
|
@@ -200,7 +246,13 @@ export function normalizeAgentSettingsConfig(value, fallback) {
|
|
|
200
246
|
personality: normalizeCodexPersonality(general.personality, base.general.personality),
|
|
201
247
|
},
|
|
202
248
|
codex: {
|
|
203
|
-
|
|
249
|
+
providerModels: normalizeCodexProviderModels(codex.providerModels, base.codex.providerModels),
|
|
250
|
+
modelProvider: codex.modelProvider === null
|
|
251
|
+
? null
|
|
252
|
+
: typeof codex.modelProvider === "string" && codex.modelProvider.trim()
|
|
253
|
+
? codex.modelProvider.trim()
|
|
254
|
+
: base.codex.modelProvider,
|
|
255
|
+
customProvider: normalizeCodexCustomProvider(codex.customProvider, base.codex.customProvider),
|
|
204
256
|
reasoningEffort: normalizeReasoningEffort(codex.reasoningEffort, base.codex.reasoningEffort),
|
|
205
257
|
serviceTier: codex.serviceTier === null ? null : normalizeServiceTier(codex.serviceTier) ?? base.codex.serviceTier,
|
|
206
258
|
authMode: codex.authMode === "chatgpt" ? "chatgpt" : codex.authMode === "api_key" ? "api_key" : base.codex.authMode,
|
|
@@ -275,6 +327,7 @@ function toMaskedSecret(value) {
|
|
|
275
327
|
export async function toAgentSettingsPublic(args) {
|
|
276
328
|
const realtimeKey = toMaskedSecret(args.config.realtime.apiKey);
|
|
277
329
|
const gitOauth = toMaskedSecret(args.config.git.oauthToken);
|
|
330
|
+
const codexProviderKey = toMaskedSecret(args.config.codex.customProvider?.apiKey ?? null);
|
|
278
331
|
const customInstructions = await readAgentModelInstructions(args.workspaceRoot);
|
|
279
332
|
return {
|
|
280
333
|
general: {
|
|
@@ -282,7 +335,19 @@ export async function toAgentSettingsPublic(args) {
|
|
|
282
335
|
customInstructions,
|
|
283
336
|
},
|
|
284
337
|
codex: {
|
|
285
|
-
|
|
338
|
+
providerModels: { ...args.config.codex.providerModels },
|
|
339
|
+
modelProvider: args.config.codex.modelProvider,
|
|
340
|
+
customProvider: args.config.codex.customProvider
|
|
341
|
+
? {
|
|
342
|
+
id: args.config.codex.customProvider.id,
|
|
343
|
+
name: args.config.codex.customProvider.name,
|
|
344
|
+
baseUrl: args.config.codex.customProvider.baseUrl,
|
|
345
|
+
envKey: args.config.codex.customProvider.envKey,
|
|
346
|
+
hasApiKey: codexProviderKey.has,
|
|
347
|
+
apiKeyMasked: codexProviderKey.masked,
|
|
348
|
+
apiKeyLength: codexProviderKey.length,
|
|
349
|
+
}
|
|
350
|
+
: null,
|
|
286
351
|
reasoningEffort: args.config.codex.reasoningEffort,
|
|
287
352
|
serviceTier: args.config.codex.serviceTier,
|
|
288
353
|
authMode: args.config.codex.authMode,
|
|
@@ -353,7 +418,9 @@ export function normalizeAgentSettingsPatch(value) {
|
|
|
353
418
|
delete patch[flatKey];
|
|
354
419
|
};
|
|
355
420
|
move("personality", "general", "personality");
|
|
356
|
-
move("
|
|
421
|
+
move("codexProviderModels", "codex", "providerModels");
|
|
422
|
+
move("codexModelProvider", "codex", "modelProvider");
|
|
423
|
+
move("codexCustomProvider", "codex", "customProvider");
|
|
357
424
|
move("codexReasoningEffort", "codex", "reasoningEffort");
|
|
358
425
|
move("codexServiceTier", "codex", "serviceTier");
|
|
359
426
|
move("codexAuthMode", "codex", "authMode");
|
|
@@ -377,6 +444,9 @@ export function normalizeAgentSettingsPatch(value) {
|
|
|
377
444
|
}
|
|
378
445
|
export function buildAgentSettingsEnvPatch(config) {
|
|
379
446
|
const envPatch = {};
|
|
447
|
+
if (config.codex.customProvider?.apiKey && config.codex.customProvider.envKey) {
|
|
448
|
+
envPatch[config.codex.customProvider.envKey] = config.codex.customProvider.apiKey;
|
|
449
|
+
}
|
|
380
450
|
if (config.git.enabled) {
|
|
381
451
|
if (config.git.name)
|
|
382
452
|
envPatch.GIT_AUTHOR_NAME = config.git.name;
|
package/dist/agent-skill-rpc.js
CHANGED
|
@@ -70,11 +70,18 @@ function normalizeGeneratedSkill(value) {
|
|
|
70
70
|
function buildSkillGeneratorCodexArgs(prompt, model) {
|
|
71
71
|
return ["--dangerously-bypass-approvals-and-sandbox", "--model", model, "exec", "--", prompt];
|
|
72
72
|
}
|
|
73
|
+
function resolveCodexModel(settings) {
|
|
74
|
+
const providerKey = settings.codex.modelProvider || "openai";
|
|
75
|
+
if (providerKey === "zai") {
|
|
76
|
+
return settings.codex.providerModels.zai || "glm-5.2";
|
|
77
|
+
}
|
|
78
|
+
return settings.codex.providerModels[providerKey] || settings.codex.providerModels.openai || "gpt-5.5";
|
|
79
|
+
}
|
|
73
80
|
async function generateSkillViaCodex(args) {
|
|
74
81
|
const localAgentSettings = await args.readAgentSettingsConfig({ workspaceRoot: args.workspaceRoot });
|
|
75
82
|
const envPatch = args.buildAgentSettingsEnvPatch(localAgentSettings);
|
|
76
83
|
const prompt = buildSkillGeneratorPrompt(args.userPrompt);
|
|
77
|
-
const result = await args.runLocalCodexCli(buildSkillGeneratorCodexArgs(prompt, localAgentSettings
|
|
84
|
+
const result = await args.runLocalCodexCli(buildSkillGeneratorCodexArgs(prompt, resolveCodexModel(localAgentSettings)), 120_000, envPatch);
|
|
78
85
|
if (result.timedOut) {
|
|
79
86
|
throw new Error("Codex timed out while generating the skill");
|
|
80
87
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { buildAgentSettingsEnvPatch, readAgentModelInstructions, resolveAgentModelInstructionsFilePath, } from "./agent-settings.js";
|
|
2
2
|
import { buildCustomMcpConfigArgs, buildDaemonMcpConfigArgs, buildMobileMcpConfigArgs, buildThreadsMcpConfigArgs } from "./agent-codex-cli.js";
|
|
3
3
|
import { CodexAppServerClient } from "./codex-app-server-client.js";
|
|
4
|
+
import { startCodexChatBridge } from "./codex-chat-bridge.js";
|
|
4
5
|
function toTomlStringLiteral(value) {
|
|
5
6
|
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
6
7
|
}
|
|
@@ -10,9 +11,37 @@ function buildConfigArg(key, tomlValue) {
|
|
|
10
11
|
function buildFeatureArg(enabled, name) {
|
|
11
12
|
return [enabled ? "--enable" : "--disable", name];
|
|
12
13
|
}
|
|
14
|
+
function resolveCodexModel(settings) {
|
|
15
|
+
const providerKey = settings.codex.modelProvider || "openai";
|
|
16
|
+
if (providerKey === "zai") {
|
|
17
|
+
return settings.codex.providerModels.zai || "glm-5.2";
|
|
18
|
+
}
|
|
19
|
+
return settings.codex.providerModels[providerKey] || settings.codex.providerModels.openai || "gpt-5.5";
|
|
20
|
+
}
|
|
21
|
+
function resolveCodexModelContextWindow(settings) {
|
|
22
|
+
return settings.codex.modelProvider === "zai" ? 258400 : null;
|
|
23
|
+
}
|
|
24
|
+
function buildModelProviderConfigArgs(settings) {
|
|
25
|
+
const provider = settings.codex.customProvider;
|
|
26
|
+
const providerId = settings.codex.modelProvider;
|
|
27
|
+
if (!provider || !providerId || provider.id !== providerId) {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
return [
|
|
31
|
+
...buildConfigArg("model_provider", toTomlStringLiteral(provider.id)),
|
|
32
|
+
...buildConfigArg(`model_providers.${provider.id}.name`, toTomlStringLiteral(provider.name)),
|
|
33
|
+
...buildConfigArg(`model_providers.${provider.id}.base_url`, toTomlStringLiteral(provider.baseUrl)),
|
|
34
|
+
...buildConfigArg(`model_providers.${provider.id}.env_key`, toTomlStringLiteral(provider.envKey)),
|
|
35
|
+
...buildConfigArg(`model_providers.${provider.id}.wire_api`, toTomlStringLiteral("responses")),
|
|
36
|
+
];
|
|
37
|
+
}
|
|
13
38
|
async function buildCodexAppServerArgs(args) {
|
|
39
|
+
const codexModel = resolveCodexModel(args.settings);
|
|
40
|
+
const modelContextWindow = resolveCodexModelContextWindow(args.settings);
|
|
14
41
|
const configArgs = [
|
|
15
|
-
...buildConfigArg("model", toTomlStringLiteral(
|
|
42
|
+
...buildConfigArg("model", toTomlStringLiteral(codexModel)),
|
|
43
|
+
...(modelContextWindow ? buildConfigArg("model_context_window", String(modelContextWindow)) : []),
|
|
44
|
+
...buildModelProviderConfigArgs(args.settings),
|
|
16
45
|
...buildConfigArg("model_reasoning_effort", toTomlStringLiteral(args.settings.codex.reasoningEffort)),
|
|
17
46
|
...(args.settings.codex.serviceTier
|
|
18
47
|
? buildConfigArg("service_tier", toTomlStringLiteral(args.settings.codex.serviceTier))
|
|
@@ -56,6 +85,34 @@ async function buildCodexAppServerArgs(args) {
|
|
|
56
85
|
"stdio://",
|
|
57
86
|
];
|
|
58
87
|
}
|
|
88
|
+
async function resolveAppServerSettings(args) {
|
|
89
|
+
const provider = args.settings.codex.customProvider;
|
|
90
|
+
if (args.settings.codex.modelProvider !== "zai" || provider?.id !== "zai") {
|
|
91
|
+
return { settings: args.settings, proxy: null };
|
|
92
|
+
}
|
|
93
|
+
const proxy = await startCodexChatBridge({
|
|
94
|
+
providerApiKey: provider.apiKey ?? "",
|
|
95
|
+
providerId: provider.id,
|
|
96
|
+
providerName: provider.name,
|
|
97
|
+
targetBaseUrl: provider.baseUrl,
|
|
98
|
+
onLog: args.onLog,
|
|
99
|
+
});
|
|
100
|
+
return {
|
|
101
|
+
proxy,
|
|
102
|
+
settings: {
|
|
103
|
+
...args.settings,
|
|
104
|
+
codex: {
|
|
105
|
+
...args.settings.codex,
|
|
106
|
+
customProvider: {
|
|
107
|
+
...provider,
|
|
108
|
+
baseUrl: proxy.baseUrl,
|
|
109
|
+
envKey: proxy.envKey,
|
|
110
|
+
apiKey: proxy.apiKey,
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}
|
|
59
116
|
async function buildCodexAppServerEnv(args) {
|
|
60
117
|
return {
|
|
61
118
|
...process.env,
|
|
@@ -69,18 +126,21 @@ async function buildCodexAppServerEnv(args) {
|
|
|
69
126
|
}
|
|
70
127
|
export function createCodexAppServerManager(args) {
|
|
71
128
|
let client = null;
|
|
129
|
+
let providerProxy = null;
|
|
72
130
|
let createPromise = null;
|
|
73
131
|
let generation = 0;
|
|
74
132
|
const notificationListeners = new Set();
|
|
75
133
|
const createClient = async () => {
|
|
76
134
|
const settings = await args.readAgentSettingsConfig({ workspaceRoot: args.workspaceRoot });
|
|
135
|
+
const resolved = await resolveAppServerSettings({ settings, onLog: args.onLog });
|
|
136
|
+
providerProxy = resolved.proxy;
|
|
77
137
|
const appServerArgs = await buildCodexAppServerArgs({
|
|
78
138
|
agentId: args.agentId,
|
|
79
139
|
agentToken: args.agentToken,
|
|
80
140
|
workspaceRoot: args.workspaceRoot,
|
|
81
141
|
agentProjectDir: args.agentProjectDir,
|
|
82
142
|
serverBaseUrl: args.serverBaseUrl,
|
|
83
|
-
settings,
|
|
143
|
+
settings: resolved.settings,
|
|
84
144
|
userId: args.userId,
|
|
85
145
|
});
|
|
86
146
|
const env = await buildCodexAppServerEnv({
|
|
@@ -89,10 +149,10 @@ export function createCodexAppServerManager(args) {
|
|
|
89
149
|
workspaceRoot: args.workspaceRoot,
|
|
90
150
|
serverBaseUrl: args.serverBaseUrl,
|
|
91
151
|
resolveCodexHomePath: args.resolveCodexHomePath,
|
|
92
|
-
settings,
|
|
152
|
+
settings: resolved.settings,
|
|
93
153
|
userId: args.userId,
|
|
94
154
|
});
|
|
95
|
-
args.onLog?.(`starting codex app-server model=${settings
|
|
155
|
+
args.onLog?.(`starting codex app-server model=${resolveCodexModel(resolved.settings)} reasoningEffort=${resolved.settings.codex.reasoningEffort} personality=${resolved.settings.general.personality} computerUse=${resolved.settings.codex.computerUseEnabled} browserUse=${resolved.settings.codex.browserUseEnabled} mcpServers=${resolved.settings.mcp.servers.filter((server) => server.enabled).length}`);
|
|
96
156
|
return new CodexAppServerClient({
|
|
97
157
|
cwd: args.workspaceRoot,
|
|
98
158
|
args: appServerArgs,
|
|
@@ -144,7 +204,9 @@ export function createCodexAppServerManager(args) {
|
|
|
144
204
|
async restart(reason) {
|
|
145
205
|
generation += 1;
|
|
146
206
|
const activeClient = client;
|
|
207
|
+
const activeProxy = providerProxy;
|
|
147
208
|
client = null;
|
|
209
|
+
providerProxy = null;
|
|
148
210
|
createPromise = null;
|
|
149
211
|
if (!activeClient) {
|
|
150
212
|
args.onLog?.(`codex app-server restart requested before start reason=${reason}`);
|
|
@@ -152,12 +214,20 @@ export function createCodexAppServerManager(args) {
|
|
|
152
214
|
}
|
|
153
215
|
args.onLog?.(`restarting codex app-server reason=${reason}`);
|
|
154
216
|
await activeClient.stop();
|
|
217
|
+
await activeProxy?.stop().catch((error) => {
|
|
218
|
+
args.onLog?.(`failed to stop provider proxy: ${error instanceof Error ? error.message : String(error)}`);
|
|
219
|
+
});
|
|
155
220
|
},
|
|
156
221
|
async stop() {
|
|
157
222
|
const activeClient = client;
|
|
223
|
+
const activeProxy = providerProxy;
|
|
158
224
|
client = null;
|
|
225
|
+
providerProxy = null;
|
|
159
226
|
createPromise = null;
|
|
160
227
|
await activeClient?.stop();
|
|
228
|
+
await activeProxy?.stop().catch((error) => {
|
|
229
|
+
args.onLog?.(`failed to stop provider proxy: ${error instanceof Error ? error.message : String(error)}`);
|
|
230
|
+
});
|
|
161
231
|
},
|
|
162
232
|
};
|
|
163
233
|
}
|