doer-agent 0.3.2 → 0.3.5
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 +129 -32
- package/package.json +1 -1
package/dist/agent.js
CHANGED
|
@@ -609,7 +609,6 @@ function createDefaultAgentSettingsConfig() {
|
|
|
609
609
|
codex: {
|
|
610
610
|
model: "gpt-5.4",
|
|
611
611
|
authMode: "api_key",
|
|
612
|
-
apiKey: null,
|
|
613
612
|
},
|
|
614
613
|
realtime: {
|
|
615
614
|
model: process.env.OPENAI_REALTIME_MODEL?.trim() || "gpt-realtime",
|
|
@@ -687,7 +686,6 @@ function normalizeAgentSettingsConfig(value, fallback) {
|
|
|
687
686
|
codex: {
|
|
688
687
|
model: typeof codex.model === "string" && codex.model.trim() ? codex.model.trim() : base.codex.model,
|
|
689
688
|
authMode: codex.authMode === "oauth" ? "oauth" : codex.authMode === "api_key" ? "api_key" : base.codex.authMode,
|
|
690
|
-
apiKey: codex.apiKey === null ? null : normalizeNullableString(codex.apiKey) ?? base.codex.apiKey,
|
|
691
689
|
},
|
|
692
690
|
realtime: {
|
|
693
691
|
model: typeof realtime.model === "string" && realtime.model.trim() ? realtime.model.trim() : base.realtime.model,
|
|
@@ -768,7 +766,6 @@ function toMaskedSecret(value) {
|
|
|
768
766
|
return { has: true, masked: maskSecretPreview(value), length: value.length };
|
|
769
767
|
}
|
|
770
768
|
function toAgentSettingsPublic(config) {
|
|
771
|
-
const codexKey = toMaskedSecret(config.codex.apiKey);
|
|
772
769
|
const realtimeKey = toMaskedSecret(config.realtime.apiKey);
|
|
773
770
|
const gitOauth = toMaskedSecret(config.git.oauthToken);
|
|
774
771
|
const awsSecret = toMaskedSecret(config.aws.secretAccessKey);
|
|
@@ -784,9 +781,9 @@ function toAgentSettingsPublic(config) {
|
|
|
784
781
|
codex: {
|
|
785
782
|
model: config.codex.model,
|
|
786
783
|
authMode: config.codex.authMode,
|
|
787
|
-
hasApiKey:
|
|
788
|
-
apiKeyMasked:
|
|
789
|
-
apiKeyLength:
|
|
784
|
+
hasApiKey: false,
|
|
785
|
+
apiKeyMasked: null,
|
|
786
|
+
apiKeyLength: null,
|
|
790
787
|
},
|
|
791
788
|
realtime: {
|
|
792
789
|
model: config.realtime.model,
|
|
@@ -874,7 +871,6 @@ function normalizeAgentSettingsPatch(value) {
|
|
|
874
871
|
move("firstTurnPrompt", "general", "firstTurnPrompt");
|
|
875
872
|
move("codexModel", "codex", "model");
|
|
876
873
|
move("codexAuthMode", "codex", "authMode");
|
|
877
|
-
move("codexApiKey", "codex", "apiKey");
|
|
878
874
|
move("realtimeModel", "realtime", "model");
|
|
879
875
|
move("realtimeVoice", "realtime", "voice");
|
|
880
876
|
move("realtimeWakeName", "realtime", "wakeName");
|
|
@@ -915,9 +911,6 @@ async function resolveAgentSettingsConfig(args) {
|
|
|
915
911
|
}
|
|
916
912
|
function buildAgentSettingsEnvPatch(config) {
|
|
917
913
|
const envPatch = {};
|
|
918
|
-
if (config.codex.authMode === "api_key" && config.codex.apiKey) {
|
|
919
|
-
envPatch.OPENAI_API_KEY = config.codex.apiKey;
|
|
920
|
-
}
|
|
921
914
|
if (config.git.enabled) {
|
|
922
915
|
if (config.git.name)
|
|
923
916
|
envPatch.GIT_AUTHOR_NAME = config.git.name;
|
|
@@ -1113,6 +1106,7 @@ async function startManagedRun(args) {
|
|
|
1113
1106
|
userId: args.userId,
|
|
1114
1107
|
taskId: args.runId,
|
|
1115
1108
|
codexAuthBundle: args.codexAuthBundle,
|
|
1109
|
+
runtimeEnvPatch: args.runtimeEnvPatch,
|
|
1116
1110
|
});
|
|
1117
1111
|
const child = spawnManagedCodexCommand({
|
|
1118
1112
|
codexArgs: args.codexArgs,
|
|
@@ -1312,6 +1306,62 @@ async function runLocalCodexCli(args, timeoutMs, envPatch) {
|
|
|
1312
1306
|
});
|
|
1313
1307
|
});
|
|
1314
1308
|
}
|
|
1309
|
+
async function runLocalCodexCliWithInput(args, input, timeoutMs, envPatch) {
|
|
1310
|
+
const command = buildLocalCodexCliCommand(args);
|
|
1311
|
+
const workspaceRoot = workspaceRootOverride ?? (process.env.WORKSPACE?.trim() || process.cwd());
|
|
1312
|
+
const env = {
|
|
1313
|
+
...process.env,
|
|
1314
|
+
...(envPatch ?? {}),
|
|
1315
|
+
WORKSPACE: workspaceRoot,
|
|
1316
|
+
CODEX_HOME: resolveCodexHomePath(),
|
|
1317
|
+
};
|
|
1318
|
+
return await new Promise((resolve, reject) => {
|
|
1319
|
+
const child = spawn(command, {
|
|
1320
|
+
cwd: workspaceRoot,
|
|
1321
|
+
shell: resolveShellPath(),
|
|
1322
|
+
env,
|
|
1323
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
1324
|
+
});
|
|
1325
|
+
let stdout = "";
|
|
1326
|
+
let stderr = "";
|
|
1327
|
+
let done = false;
|
|
1328
|
+
let timedOut = false;
|
|
1329
|
+
child.stdout.setEncoding("utf8");
|
|
1330
|
+
child.stderr.setEncoding("utf8");
|
|
1331
|
+
child.stdout.on("data", (chunk) => {
|
|
1332
|
+
stdout += chunk;
|
|
1333
|
+
});
|
|
1334
|
+
child.stderr.on("data", (chunk) => {
|
|
1335
|
+
stderr += chunk;
|
|
1336
|
+
});
|
|
1337
|
+
child.stdin?.write(input);
|
|
1338
|
+
if (!input.endsWith("\n")) {
|
|
1339
|
+
child.stdin?.write("\n");
|
|
1340
|
+
}
|
|
1341
|
+
child.stdin?.end();
|
|
1342
|
+
const timer = setTimeout(() => {
|
|
1343
|
+
timedOut = true;
|
|
1344
|
+
sendSignalToTaskProcess(child, "SIGTERM");
|
|
1345
|
+
setTimeout(() => sendSignalToTaskProcess(child, "SIGKILL"), 1000);
|
|
1346
|
+
}, Math.max(500, timeoutMs));
|
|
1347
|
+
child.once("error", (error) => {
|
|
1348
|
+
if (done) {
|
|
1349
|
+
return;
|
|
1350
|
+
}
|
|
1351
|
+
done = true;
|
|
1352
|
+
clearTimeout(timer);
|
|
1353
|
+
reject(error);
|
|
1354
|
+
});
|
|
1355
|
+
child.once("exit", (code) => {
|
|
1356
|
+
if (done) {
|
|
1357
|
+
return;
|
|
1358
|
+
}
|
|
1359
|
+
done = true;
|
|
1360
|
+
clearTimeout(timer);
|
|
1361
|
+
resolve({ code, stdout, stderr, timedOut });
|
|
1362
|
+
});
|
|
1363
|
+
});
|
|
1364
|
+
}
|
|
1315
1365
|
function buildSkillGeneratorPrompt(userPrompt) {
|
|
1316
1366
|
return [
|
|
1317
1367
|
"Create a Codex skill from the user's description.",
|
|
@@ -1663,6 +1713,20 @@ async function startLocalCodexLogin() {
|
|
|
1663
1713
|
}
|
|
1664
1714
|
throw new Error(normalized || `Codex login failed with code ${result.code ?? "null"}`);
|
|
1665
1715
|
}
|
|
1716
|
+
async function loginLocalCodexWithApiKey(apiKey) {
|
|
1717
|
+
const result = await runLocalCodexCliWithInput(["login", "--with-api-key"], apiKey, 15000);
|
|
1718
|
+
const normalized = stripAnsi([result.stdout, result.stderr].filter(Boolean).join("\n")).trim();
|
|
1719
|
+
if ((result.code ?? 1) !== 0) {
|
|
1720
|
+
throw new Error(normalized || `Codex API key login failed with code ${result.code ?? "null"}`);
|
|
1721
|
+
}
|
|
1722
|
+
const status = await getLocalCodexLoginStatus().catch(() => null);
|
|
1723
|
+
return {
|
|
1724
|
+
loggedIn: status?.loggedIn === true,
|
|
1725
|
+
output: status?.output || normalized || "Logged in",
|
|
1726
|
+
verificationUri: null,
|
|
1727
|
+
userCode: null,
|
|
1728
|
+
};
|
|
1729
|
+
}
|
|
1666
1730
|
async function logoutLocalCodexAuth() {
|
|
1667
1731
|
if (pendingCodexDeviceAuth && pendingCodexDeviceAuth.child.exitCode === null) {
|
|
1668
1732
|
sendSignalToTaskProcess(pendingCodexDeviceAuth.child, "SIGTERM");
|
|
@@ -1694,11 +1758,15 @@ function normalizeCodexAuthRpcRequest(args) {
|
|
|
1694
1758
|
const responseSubject = typeof args.request.responseSubject === "string" ? args.request.responseSubject.trim() : "";
|
|
1695
1759
|
const requestAgentId = typeof args.request.agentId === "string" ? args.request.agentId.trim() : "";
|
|
1696
1760
|
const actionRaw = typeof args.request.action === "string" ? args.request.action.trim() : "";
|
|
1697
|
-
const action = actionRaw === "start" || actionRaw === "logout" ? actionRaw : "status";
|
|
1761
|
+
const action = actionRaw === "start" || actionRaw === "logout" || actionRaw === "login_api_key" ? actionRaw : "status";
|
|
1762
|
+
const apiKey = typeof args.request.apiKey === "string" && args.request.apiKey.trim() ? args.request.apiKey.trim() : null;
|
|
1698
1763
|
if (!requestId || !responseSubject || !requestAgentId || requestAgentId !== args.agentId) {
|
|
1699
1764
|
throw new Error("invalid codex auth rpc request");
|
|
1700
1765
|
}
|
|
1701
|
-
|
|
1766
|
+
if (action === "login_api_key" && !apiKey) {
|
|
1767
|
+
throw new Error("api key is required");
|
|
1768
|
+
}
|
|
1769
|
+
return { requestId, responseSubject, action, apiKey };
|
|
1702
1770
|
}
|
|
1703
1771
|
function publishCodexAuthRpcResponse(args) {
|
|
1704
1772
|
args.nc.publish(args.responseSubject, codexAuthRpcCodec.encode(JSON.stringify(args.payload)));
|
|
@@ -1712,7 +1780,10 @@ async function handleCodexAuthRpcMessage(args) {
|
|
|
1712
1780
|
requestId = request.requestId;
|
|
1713
1781
|
responseSubject = request.responseSubject;
|
|
1714
1782
|
let result = null;
|
|
1715
|
-
if (request.action === "
|
|
1783
|
+
if (request.action === "login_api_key") {
|
|
1784
|
+
result = await loginLocalCodexWithApiKey(request.apiKey ?? "");
|
|
1785
|
+
}
|
|
1786
|
+
else if (request.action === "start") {
|
|
1716
1787
|
const status = await getLocalCodexLoginStatus();
|
|
1717
1788
|
if (status.loggedIn) {
|
|
1718
1789
|
result = { loggedIn: true, output: status.output };
|
|
@@ -2596,12 +2667,13 @@ async function executeFsRpc(args) {
|
|
|
2596
2667
|
if (!uploadUrl || !agentId) {
|
|
2597
2668
|
throw new Error("missing upload parameters");
|
|
2598
2669
|
}
|
|
2670
|
+
const resolvedUploadUrl = new URL(uploadUrl, `${args.serverBaseUrl}/`).toString();
|
|
2599
2671
|
const data = await readFile(abs);
|
|
2600
2672
|
const fileName = path.basename(abs) || "file";
|
|
2601
2673
|
const form = new FormData();
|
|
2602
2674
|
form.append("file", new File([data], fileName));
|
|
2603
2675
|
form.append("agentId", agentId);
|
|
2604
|
-
const response = await fetch(
|
|
2676
|
+
const response = await fetch(resolvedUploadUrl, {
|
|
2605
2677
|
method: "POST",
|
|
2606
2678
|
headers: { Authorization: `Bearer ${args.agentToken}` },
|
|
2607
2679
|
body: form,
|
|
@@ -3559,16 +3631,18 @@ function normalizeShellRpcCodexAuthBundle(value) {
|
|
|
3559
3631
|
}
|
|
3560
3632
|
const row = value;
|
|
3561
3633
|
const authJson = typeof row.authJson === "string" ? row.authJson : null;
|
|
3562
|
-
|
|
3634
|
+
const authMode = row.authMode === "oauth" ? "oauth" : row.authMode === "api_key" ? "api_key" : undefined;
|
|
3635
|
+
const apiKey = typeof row.apiKey === "string" || row.apiKey === null ? row.apiKey : undefined;
|
|
3636
|
+
if (!authJson && authMode !== "api_key" && apiKey === undefined) {
|
|
3563
3637
|
return null;
|
|
3564
3638
|
}
|
|
3565
3639
|
return {
|
|
3566
3640
|
taskId: typeof row.taskId === "string" ? row.taskId : undefined,
|
|
3567
|
-
authMode
|
|
3641
|
+
authMode,
|
|
3568
3642
|
issuedAt: typeof row.issuedAt === "string" ? row.issuedAt : undefined,
|
|
3569
3643
|
expiresAt: typeof row.expiresAt === "string" ? row.expiresAt : undefined,
|
|
3570
|
-
authJson,
|
|
3571
|
-
apiKey
|
|
3644
|
+
authJson: authJson ?? undefined,
|
|
3645
|
+
apiKey,
|
|
3572
3646
|
};
|
|
3573
3647
|
}
|
|
3574
3648
|
async function postJson(url, body) {
|
|
@@ -3733,27 +3807,49 @@ async function checkCancelRequested(args) {
|
|
|
3733
3807
|
const response = await getJson(`${args.serverBaseUrl}/api/agent/tasks/${encodeURIComponent(args.taskId)}/events?${query.toString()}`);
|
|
3734
3808
|
return Boolean(response.task?.cancelRequested);
|
|
3735
3809
|
}
|
|
3736
|
-
async function
|
|
3737
|
-
|
|
3810
|
+
async function syncCodexAuthState(args) {
|
|
3811
|
+
const envPatch = {};
|
|
3812
|
+
const synced = false;
|
|
3813
|
+
if (args.authMode === "api_key") {
|
|
3814
|
+
if (args.apiKey) {
|
|
3815
|
+
envPatch.OPENAI_API_KEY = args.apiKey;
|
|
3816
|
+
}
|
|
3817
|
+
}
|
|
3738
3818
|
return {
|
|
3739
|
-
envPatch
|
|
3819
|
+
envPatch,
|
|
3740
3820
|
cleanup: async () => { },
|
|
3741
3821
|
meta: {
|
|
3742
|
-
codexAuthSource:
|
|
3743
|
-
|
|
3822
|
+
codexAuthSource: args.source,
|
|
3823
|
+
codexAuthMode: args.authMode ?? null,
|
|
3824
|
+
codexAuthHasApiKey: Boolean(args.apiKey),
|
|
3825
|
+
codexAuthHasAuthJson: Boolean(args.authJson),
|
|
3826
|
+
codexAuthIssuedAt: args.issuedAt ?? null,
|
|
3827
|
+
codexAuthExpiresAt: args.expiresAt ?? null,
|
|
3828
|
+
codexAuthSynced: synced,
|
|
3744
3829
|
},
|
|
3745
3830
|
};
|
|
3746
3831
|
}
|
|
3832
|
+
async function prepareTaskCodexAuth(args) {
|
|
3833
|
+
void args;
|
|
3834
|
+
return await syncCodexAuthState({
|
|
3835
|
+
source: "agent_local",
|
|
3836
|
+
authJson: null,
|
|
3837
|
+
issuedAt: null,
|
|
3838
|
+
expiresAt: null,
|
|
3839
|
+
});
|
|
3840
|
+
}
|
|
3747
3841
|
async function prepareCodexAuthBundle(bundle) {
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3842
|
+
if (!bundle) {
|
|
3843
|
+
return null;
|
|
3844
|
+
}
|
|
3845
|
+
return await syncCodexAuthState({
|
|
3846
|
+
source: "server_bundle",
|
|
3847
|
+
authMode: bundle.authMode,
|
|
3848
|
+
apiKey: bundle.apiKey,
|
|
3849
|
+
authJson: bundle.authJson ?? null,
|
|
3850
|
+
issuedAt: bundle.issuedAt ?? null,
|
|
3851
|
+
expiresAt: bundle.expiresAt ?? null,
|
|
3852
|
+
});
|
|
3757
3853
|
}
|
|
3758
3854
|
async function prepareCommandExecution(args) {
|
|
3759
3855
|
const shellPath = resolveShellPath();
|
|
@@ -3767,6 +3863,7 @@ async function prepareCommandExecution(args) {
|
|
|
3767
3863
|
DOER_USER_ID: args.userId,
|
|
3768
3864
|
DOER_AGENT_TASK_ID: args.taskId,
|
|
3769
3865
|
...buildAgentSettingsEnvPatch(localAgentSettings),
|
|
3866
|
+
...args.runtimeEnvPatch,
|
|
3770
3867
|
...(codexAuth?.envPatch ?? {}),
|
|
3771
3868
|
WORKSPACE: taskWorkspace,
|
|
3772
3869
|
};
|