



























@@ -1,4 +1,5 @@
11import crypto from "node:crypto";
2+import { resolveAgentDir, resolveSessionAgentIds } from "openclaw/plugin-sdk/agent-runtime";
23import type { PluginCommandContext, PluginCommandResult } from "openclaw/plugin-sdk/plugin-entry";
34import { CODEX_CONTROL_METHODS, type CodexControlMethod } from "./app-server/capabilities.js";
45import {
@@ -425,14 +426,19 @@ async function bindConversation(
425426text: "Cannot bind Codex because this command did not include an OpenClaw session file.",
426427};
427428}
429+const scope = resolveCodexConversationControlScope(ctx);
428430const workspaceDir = parsed.cwd ?? deps.resolveCodexDefaultWorkspaceDir(pluginConfig);
429-const existingBinding = await deps.readCodexAppServerBinding(ctx.sessionFile);
431+const existingBinding = await deps.readCodexAppServerBinding(ctx.sessionFile, {
432+agentDir: scope.agentDir,
433+config: ctx.config,
434+});
430435const authProfileId = existingBinding?.authProfileId;
431436const startParams: Parameters<CodexCommandDeps["startCodexConversationThread"]>[0] = {
432437 pluginConfig,
433438config: ctx.config,
434439sessionFile: ctx.sessionFile,
435440 workspaceDir,
441+agentDir: scope.agentDir,
436442threadId: parsed.threadId,
437443model: parsed.model,
438444modelProvider: parsed.provider,
@@ -441,7 +447,10 @@ async function bindConversation(
441447startParams.authProfileId = authProfileId;
442448}
443449const data = await deps.startCodexConversationThread(startParams);
444-const binding = await deps.readCodexAppServerBinding(ctx.sessionFile);
450+const binding = await deps.readCodexAppServerBinding(ctx.sessionFile, {
451+agentDir: scope.agentDir,
452+config: ctx.config,
453+});
445454const threadId = binding?.threadId ?? parsed.threadId ?? "new thread";
446455const summary = `Codex app-server thread ${formatCodexDisplayText(threadId)} in ${formatCodexDisplayText(workspaceDir)}`;
447456let request: Awaited<ReturnType<PluginCommandContext["requestConversationBinding"]>>;
@@ -505,7 +514,10 @@ async function describeConversationBinding(
505514"- Active run: not tracked",
506515].join("\n");
507516}
508-const threadBinding = await deps.readCodexAppServerBinding(data.sessionFile);
517+const threadBinding = await deps.readCodexAppServerBinding(data.sessionFile, {
518+agentDir: data.agentDir,
519+config: ctx.config,
520+});
509521const active = deps.readCodexConversationActiveTurn(data.sessionFile);
510522return [
511523"Codex conversation binding:",
@@ -634,11 +646,18 @@ async function stopConversationTurn(
634646ctx: PluginCommandContext,
635647pluginConfig: unknown,
636648): Promise<string> {
637-const sessionFile = await resolveControlSessionFile(ctx);
638-if (!sessionFile) {
649+const target = await resolveControlTarget(ctx);
650+if (!target) {
639651return "Cannot stop Codex because this command did not include an OpenClaw session file.";
640652}
641-return (await deps.stopCodexConversationTurn({ sessionFile, pluginConfig })).message;
653+return (
654+await deps.stopCodexConversationTurn({
655+sessionFile: target.sessionFile,
656+ pluginConfig,
657+agentDir: target.agentDir,
658+config: ctx.config,
659+})
660+).message;
642661}
643662644663async function steerConversationTurn(
@@ -647,15 +666,17 @@ async function steerConversationTurn(
647666pluginConfig: unknown,
648667message: string,
649668): Promise<string> {
650-const sessionFile = await resolveControlSessionFile(ctx);
651-if (!sessionFile) {
669+const target = await resolveControlTarget(ctx);
670+if (!target) {
652671return "Cannot steer Codex because this command did not include an OpenClaw session file.";
653672}
654673return (
655674await deps.steerCodexConversationTurn({
656- sessionFile,
675+sessionFile: target.sessionFile,
657676 pluginConfig,
658677 message,
678+agentDir: target.agentDir,
679+config: ctx.config,
659680})
660681).message;
661682}
@@ -669,22 +690,27 @@ async function setConversationModel(
669690if (args.length > 1) {
670691return "Usage: /codex model <model>";
671692}
672-const sessionFile = await resolveControlSessionFile(ctx);
673-if (!sessionFile) {
693+const target = await resolveControlTarget(ctx);
694+if (!target) {
674695return "Cannot set Codex model because this command did not include an OpenClaw session file.";
675696}
676697const [model = ""] = args;
677698const normalized = model.trim();
678699if (!normalized) {
679-const binding = await deps.readCodexAppServerBinding(sessionFile);
700+const binding = await deps.readCodexAppServerBinding(target.sessionFile, {
701+agentDir: target.agentDir,
702+config: ctx.config,
703+});
680704return binding?.model
681705 ? `Codex model: ${formatCodexDisplayText(binding.model)}`
682706 : "Usage: /codex model <model>";
683707}
684708return await deps.setCodexConversationModel({
685- sessionFile,
709+sessionFile: target.sessionFile,
686710 pluginConfig,
687711model: normalized,
712+agentDir: target.agentDir,
713+config: ctx.config,
688714});
689715}
690716@@ -697,8 +723,8 @@ async function setConversationFastMode(
697723if (args.length > 1) {
698724return "Usage: /codex fast [on|off|status]";
699725}
700-const sessionFile = await resolveControlSessionFile(ctx);
701-if (!sessionFile) {
726+const target = await resolveControlTarget(ctx);
727+if (!target) {
702728return "Cannot set Codex fast mode because this command did not include an OpenClaw session file.";
703729}
704730const value = args[0];
@@ -707,9 +733,11 @@ async function setConversationFastMode(
707733return "Usage: /codex fast [on|off|status]";
708734}
709735return await deps.setCodexConversationFastMode({
710- sessionFile,
736+sessionFile: target.sessionFile,
711737 pluginConfig,
712738enabled: parsed,
739+agentDir: target.agentDir,
740+config: ctx.config,
713741});
714742}
715743@@ -722,8 +750,8 @@ async function setConversationPermissions(
722750if (args.length > 1) {
723751return "Usage: /codex permissions [default|yolo|status]";
724752}
725-const sessionFile = await resolveControlSessionFile(ctx);
726-if (!sessionFile) {
753+const target = await resolveControlTarget(ctx);
754+if (!target) {
727755return "Cannot set Codex permissions because this command did not include an OpenClaw session file.";
728756}
729757const value = args[0];
@@ -732,16 +760,46 @@ async function setConversationPermissions(
732760return "Usage: /codex permissions [default|yolo|status]";
733761}
734762return await deps.setCodexConversationPermissions({
735- sessionFile,
763+sessionFile: target.sessionFile,
736764 pluginConfig,
737765mode: parsed,
766+agentDir: target.agentDir,
767+config: ctx.config,
738768});
739769}
740770741-async function resolveControlSessionFile(ctx: PluginCommandContext): Promise<string | undefined> {
771+type CodexConversationControlTarget = {
772+sessionFile: string;
773+agentDir: string;
774+};
775+776+async function resolveControlTarget(
777+ctx: PluginCommandContext,
778+): Promise<CodexConversationControlTarget | undefined> {
742779const binding = await ctx.getCurrentConversationBinding();
743780const data = readCodexConversationBindingData(binding);
744-return data?.kind === "codex-app-server-session" ? data.sessionFile : ctx.sessionFile;
781+const scope = resolveCodexConversationControlScope(ctx);
782+if (data?.kind === "codex-app-server-session") {
783+return {
784+sessionFile: data.sessionFile,
785+agentDir: data.agentDir ?? scope.agentDir,
786+};
787+}
788+return ctx.sessionFile ? { sessionFile: ctx.sessionFile, agentDir: scope.agentDir } : undefined;
789+}
790+791+async function resolveControlSessionFile(ctx: PluginCommandContext): Promise<string | undefined> {
792+return (await resolveControlTarget(ctx))?.sessionFile;
793+}
794+795+function resolveCodexConversationControlScope(ctx: PluginCommandContext): { agentDir: string } {
796+const { sessionAgentId } = resolveSessionAgentIds({
797+sessionKey: ctx.sessionKey,
798+config: ctx.config,
799+});
800+return {
801+agentDir: resolveAgentDir(ctx.config, sessionAgentId),
802+};
745803}
746804747805async function handleCodexDiagnosticsFeedback(
@@ -1603,21 +1661,42 @@ async function startThreadAction(
16031661if (args.length > 0) {
16041662return `Usage: /codex ${label === "compaction" ? "compact" : label}`;
16051663}
1606-const sessionFile = await resolveControlSessionFile(ctx);
1607-if (!sessionFile) {
1664+const target = await resolveControlTarget(ctx);
1665+if (!target) {
16081666return `Cannot start Codex ${label} because this command did not include an OpenClaw session file.`;
16091667}
1610-const binding = await deps.readCodexAppServerBinding(sessionFile);
1668+const binding = await deps.readCodexAppServerBinding(target.sessionFile, {
1669+agentDir: target.agentDir,
1670+config: ctx.config,
1671+});
16111672if (!binding?.threadId) {
16121673return `No Codex thread is attached to this OpenClaw session yet.`;
16131674}
16141675if (method === CODEX_CONTROL_METHODS.review) {
1615-await deps.codexControlRequest(pluginConfig, method, {
1616-threadId: binding.threadId,
1617-target: { type: "uncommittedChanges" },
1618-});
1676+await deps.codexControlRequest(
1677+pluginConfig,
1678+method,
1679+{
1680+threadId: binding.threadId,
1681+target: { type: "uncommittedChanges" },
1682+},
1683+{
1684+agentDir: target.agentDir,
1685+authProfileId: binding.authProfileId,
1686+config: ctx.config,
1687+},
1688+);
16191689} else {
1620-await deps.codexControlRequest(pluginConfig, method, { threadId: binding.threadId });
1690+await deps.codexControlRequest(
1691+pluginConfig,
1692+method,
1693+{ threadId: binding.threadId },
1694+{
1695+agentDir: target.agentDir,
1696+authProfileId: binding.authProfileId,
1697+config: ctx.config,
1698+},
1699+);
16211700}
16221701return `Started Codex ${label} for thread ${formatCodexDisplayText(binding.threadId)}.`;
16231702}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。