mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 08:00:42 +00:00
fix: select Codex OAuth profile for bound app-server turns
This commit is contained in:
committed by
Peter Steinberger
parent
05d11a4318
commit
71f55214ec
@@ -387,6 +387,40 @@ describe("bridgeCodexAppServerStartOptions", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("applies the default OpenAI Codex OAuth profile when no profile id is explicit", async () => {
|
||||
const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-app-server-"));
|
||||
const request = vi.fn(async () => ({ type: "chatgptAuthTokens" }));
|
||||
try {
|
||||
upsertAuthProfile({
|
||||
agentDir,
|
||||
profileId: "openai-codex:default",
|
||||
credential: {
|
||||
type: "oauth",
|
||||
provider: "openai-codex",
|
||||
access: "default-access-token",
|
||||
refresh: "default-refresh-token",
|
||||
expires: Date.now() + 24 * 60 * 60_000,
|
||||
accountId: "account-default",
|
||||
email: "codex-default@example.test",
|
||||
},
|
||||
});
|
||||
|
||||
await applyCodexAppServerAuthProfile({
|
||||
client: { request } as never,
|
||||
agentDir,
|
||||
});
|
||||
|
||||
expect(request).toHaveBeenCalledWith("account/login/start", {
|
||||
type: "chatgptAuthTokens",
|
||||
accessToken: "default-access-token",
|
||||
chatgptAccountId: "account-default",
|
||||
chatgptPlanType: null,
|
||||
});
|
||||
} finally {
|
||||
await fs.rm(agentDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("refreshes an expired OpenAI Codex OAuth profile before app-server login", async () => {
|
||||
const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-app-server-"));
|
||||
const request = vi.fn(async () => ({ type: "chatgptAuthTokens" }));
|
||||
|
||||
@@ -3,8 +3,10 @@ import path from "node:path";
|
||||
import {
|
||||
ensureAuthProfileStore,
|
||||
loadAuthProfileStoreForSecretsRuntime,
|
||||
resolveAuthProfileOrder,
|
||||
resolveProviderIdForAuth,
|
||||
resolveApiKeyForProfile,
|
||||
resolveOpenClawAgentDir,
|
||||
resolvePersistedAuthProfileOwnerAgentDir,
|
||||
saveAuthProfileStore,
|
||||
type AuthProfileCredential,
|
||||
@@ -28,6 +30,8 @@ const OPENAI_API_KEY_ENV_VAR = "OPENAI_API_KEY";
|
||||
const CODEX_APP_SERVER_API_KEY_ENV_VARS = [CODEX_API_KEY_ENV_VAR, OPENAI_API_KEY_ENV_VAR];
|
||||
const CODEX_APP_SERVER_ISOLATION_ENV_VARS = [CODEX_HOME_ENV_VAR, HOME_ENV_VAR];
|
||||
|
||||
type AuthProfileOrderConfig = Parameters<typeof resolveAuthProfileOrder>[0]["cfg"];
|
||||
|
||||
export async function bridgeCodexAppServerStartOptions(params: {
|
||||
startOptions: CodexAppServerStartOptions;
|
||||
agentDir: string;
|
||||
@@ -41,15 +45,49 @@ export async function bridgeCodexAppServerStartOptions(params: {
|
||||
params.agentDir,
|
||||
);
|
||||
const store = ensureAuthProfileStore(params.agentDir, { allowKeychainPrompt: false });
|
||||
const authProfileId = resolveCodexAppServerAuthProfileId({
|
||||
authProfileId: params.authProfileId,
|
||||
store,
|
||||
});
|
||||
const shouldClearInheritedOpenAiApiKey = shouldClearOpenAiApiKeyForCodexAuthProfile({
|
||||
store,
|
||||
authProfileId: params.authProfileId,
|
||||
authProfileId,
|
||||
});
|
||||
return shouldClearInheritedOpenAiApiKey
|
||||
? withClearedEnvironmentVariables(isolatedStartOptions, CODEX_APP_SERVER_API_KEY_ENV_VARS)
|
||||
: isolatedStartOptions;
|
||||
}
|
||||
|
||||
export function resolveCodexAppServerAuthProfileId(params: {
|
||||
authProfileId?: string;
|
||||
store: ReturnType<typeof ensureAuthProfileStore>;
|
||||
config?: AuthProfileOrderConfig;
|
||||
}): string | undefined {
|
||||
const requested = params.authProfileId?.trim();
|
||||
if (requested) {
|
||||
return requested;
|
||||
}
|
||||
return resolveAuthProfileOrder({
|
||||
cfg: params.config,
|
||||
store: params.store,
|
||||
provider: CODEX_APP_SERVER_AUTH_PROVIDER,
|
||||
})[0]?.trim();
|
||||
}
|
||||
|
||||
export function resolveCodexAppServerAuthProfileIdForAgent(params: {
|
||||
authProfileId?: string;
|
||||
agentDir?: string;
|
||||
config?: AuthProfileOrderConfig;
|
||||
}): string | undefined {
|
||||
const agentDir = params.agentDir?.trim() || resolveOpenClawAgentDir();
|
||||
const store = ensureAuthProfileStore(agentDir, { allowKeychainPrompt: false });
|
||||
return resolveCodexAppServerAuthProfileId({
|
||||
authProfileId: params.authProfileId,
|
||||
store,
|
||||
config: params.config,
|
||||
});
|
||||
}
|
||||
|
||||
export function resolveCodexAppServerHomeDir(agentDir: string): string {
|
||||
return path.join(path.resolve(agentDir), CODEX_APP_SERVER_HOME_DIRNAME);
|
||||
}
|
||||
@@ -153,11 +191,14 @@ async function resolveCodexAppServerAuthProfileLoginParamsInternal(params: {
|
||||
authProfileId?: string;
|
||||
forceOAuthRefresh?: boolean;
|
||||
}): Promise<LoginAccountParams | undefined> {
|
||||
const profileId = params.authProfileId?.trim();
|
||||
const store = ensureAuthProfileStore(params.agentDir, { allowKeychainPrompt: false });
|
||||
const profileId = resolveCodexAppServerAuthProfileId({
|
||||
authProfileId: params.authProfileId,
|
||||
store,
|
||||
});
|
||||
if (!profileId) {
|
||||
return undefined;
|
||||
}
|
||||
const store = ensureAuthProfileStore(params.agentDir, { allowKeychainPrompt: false });
|
||||
const credential = store.profiles[profileId];
|
||||
if (!credential) {
|
||||
throw new Error(`Codex app-server auth profile "${profileId}" was not found.`);
|
||||
|
||||
@@ -40,7 +40,11 @@ import {
|
||||
} from "openclaw/plugin-sdk/agent-harness-runtime";
|
||||
import { emitTrustedDiagnosticEvent } from "openclaw/plugin-sdk/diagnostic-runtime";
|
||||
import { handleCodexAppServerApprovalRequest } from "./approval-bridge.js";
|
||||
import { refreshCodexAppServerAuthTokens } from "./auth-bridge.js";
|
||||
import {
|
||||
refreshCodexAppServerAuthTokens,
|
||||
resolveCodexAppServerAuthProfileId,
|
||||
resolveCodexAppServerAuthProfileIdForAgent,
|
||||
} from "./auth-bridge.js";
|
||||
import {
|
||||
createCodexAppServerClientFactoryTestHooks,
|
||||
defaultCodexAppServerClientFactory,
|
||||
@@ -377,16 +381,31 @@ export async function runCodexAppServerAttempt(
|
||||
agentId: params.agentId,
|
||||
});
|
||||
const agentDir = params.agentDir ?? resolveOpenClawAgentDir();
|
||||
const runtimeParams = { ...params, sessionKey: sandboxSessionKey };
|
||||
const startupBinding = await readCodexAppServerBinding(params.sessionFile);
|
||||
const startupAuthProfileCandidate =
|
||||
params.runtimePlan?.auth.forwardedAuthProfileId ??
|
||||
params.authProfileId ??
|
||||
startupBinding?.authProfileId;
|
||||
const startupAuthProfileId = params.authProfileStore
|
||||
? resolveCodexAppServerAuthProfileId({
|
||||
authProfileId: startupAuthProfileCandidate,
|
||||
store: params.authProfileStore,
|
||||
config: params.config,
|
||||
})
|
||||
: resolveCodexAppServerAuthProfileIdForAgent({
|
||||
authProfileId: startupAuthProfileCandidate,
|
||||
agentDir,
|
||||
config: params.config,
|
||||
});
|
||||
const runtimeParams = {
|
||||
...params,
|
||||
sessionKey: sandboxSessionKey,
|
||||
...(startupAuthProfileId ? { authProfileId: startupAuthProfileId } : {}),
|
||||
};
|
||||
const activeContextEngine = isActiveHarnessContextEngine(params.contextEngine)
|
||||
? params.contextEngine
|
||||
: undefined;
|
||||
let yieldDetected = false;
|
||||
const startupBinding = await readCodexAppServerBinding(params.sessionFile);
|
||||
const startupAuthProfileId =
|
||||
params.runtimePlan?.auth.forwardedAuthProfileId ??
|
||||
params.authProfileId ??
|
||||
startupBinding?.authProfileId;
|
||||
const tools = await buildDynamicTools({
|
||||
params,
|
||||
resolvedWorkspace,
|
||||
@@ -553,7 +572,7 @@ export async function runCodexAppServerAttempt(
|
||||
});
|
||||
const startupThread = await startOrResumeThread({
|
||||
client: startupClient,
|
||||
params,
|
||||
params: runtimeParams,
|
||||
cwd: effectiveWorkspace,
|
||||
dynamicTools: toolBridge.specs,
|
||||
appServer,
|
||||
|
||||
@@ -1,5 +1,70 @@
|
||||
import type { EmbeddedRunAttemptParams } from "openclaw/plugin-sdk/agent-harness-runtime";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { resolveReasoningEffort } from "./thread-lifecycle.js";
|
||||
import {
|
||||
buildThreadResumeParams,
|
||||
buildThreadStartParams,
|
||||
resolveReasoningEffort,
|
||||
} from "./thread-lifecycle.js";
|
||||
|
||||
function createAttemptParams(params: {
|
||||
provider: string;
|
||||
authProfileId?: string;
|
||||
}): EmbeddedRunAttemptParams {
|
||||
return {
|
||||
provider: params.provider,
|
||||
modelId: "gpt-5.4",
|
||||
authProfileId: params.authProfileId,
|
||||
} as EmbeddedRunAttemptParams;
|
||||
}
|
||||
|
||||
function createAppServerOptions() {
|
||||
return {
|
||||
approvalPolicy: "on-request",
|
||||
approvalsReviewer: "user",
|
||||
sandbox: "workspace-write",
|
||||
} as const;
|
||||
}
|
||||
|
||||
describe("Codex app-server model provider selection", () => {
|
||||
it.each(["openai", "openai-codex"])(
|
||||
"omits public %s modelProvider when forwarding native Codex auth on thread/start",
|
||||
(provider) => {
|
||||
const request = buildThreadStartParams(
|
||||
createAttemptParams({ provider, authProfileId: "openai-codex:work" }),
|
||||
{
|
||||
cwd: "/repo",
|
||||
dynamicTools: [],
|
||||
appServer: createAppServerOptions() as never,
|
||||
developerInstructions: "test instructions",
|
||||
},
|
||||
);
|
||||
|
||||
expect(request).not.toHaveProperty("modelProvider");
|
||||
},
|
||||
);
|
||||
|
||||
it("uses the bound native Codex auth profile when deciding thread/resume modelProvider", () => {
|
||||
const request = buildThreadResumeParams(createAttemptParams({ provider: "openai" }), {
|
||||
threadId: "thread-1",
|
||||
authProfileId: "openai-codex:bound",
|
||||
appServer: createAppServerOptions() as never,
|
||||
developerInstructions: "test instructions",
|
||||
});
|
||||
|
||||
expect(request).not.toHaveProperty("modelProvider");
|
||||
});
|
||||
|
||||
it("keeps public OpenAI modelProvider when no native Codex auth profile is selected", () => {
|
||||
const request = buildThreadStartParams(createAttemptParams({ provider: "openai" }), {
|
||||
cwd: "/repo",
|
||||
dynamicTools: [],
|
||||
appServer: createAppServerOptions() as never,
|
||||
developerInstructions: "test instructions",
|
||||
});
|
||||
|
||||
expect(request).toMatchObject({ modelProvider: "openai" });
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveReasoningEffort (#71946)", () => {
|
||||
describe("modern Codex models (none/low/medium/high/xhigh enum)", () => {
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
} from "./protocol.js";
|
||||
import {
|
||||
clearCodexAppServerBinding,
|
||||
isCodexAppServerNativeAuthProfileId,
|
||||
readCodexAppServerBinding,
|
||||
writeCodexAppServerBinding,
|
||||
type CodexAppServerThreadBinding,
|
||||
@@ -57,19 +58,24 @@ export async function startOrResumeThread(params: {
|
||||
await clearCodexAppServerBinding(params.params.sessionFile);
|
||||
} else {
|
||||
try {
|
||||
const authProfileId = params.params.authProfileId ?? binding.authProfileId;
|
||||
const response = assertCodexThreadResumeResponse(
|
||||
await params.client.request(
|
||||
"thread/resume",
|
||||
buildThreadResumeParams(params.params, {
|
||||
threadId: binding.threadId,
|
||||
authProfileId,
|
||||
appServer: params.appServer,
|
||||
developerInstructions: params.developerInstructions,
|
||||
config: params.config,
|
||||
}),
|
||||
),
|
||||
);
|
||||
const boundAuthProfileId = params.params.authProfileId ?? binding.authProfileId;
|
||||
const fallbackModelProvider = resolveCodexAppServerModelProvider(params.params.provider);
|
||||
const boundAuthProfileId = authProfileId;
|
||||
const fallbackModelProvider = resolveCodexAppServerModelProvider({
|
||||
provider: params.params.provider,
|
||||
authProfileId: boundAuthProfileId,
|
||||
});
|
||||
await writeCodexAppServerBinding(params.params.sessionFile, {
|
||||
threadId: response.thread.id,
|
||||
cwd: params.cwd,
|
||||
@@ -112,7 +118,10 @@ export async function startOrResumeThread(params: {
|
||||
}),
|
||||
),
|
||||
);
|
||||
const modelProvider = resolveCodexAppServerModelProvider(params.params.provider);
|
||||
const modelProvider = resolveCodexAppServerModelProvider({
|
||||
provider: params.params.provider,
|
||||
authProfileId: params.params.authProfileId,
|
||||
});
|
||||
const createdAt = new Date().toISOString();
|
||||
await writeCodexAppServerBinding(params.params.sessionFile, {
|
||||
threadId: response.thread.id,
|
||||
@@ -147,7 +156,10 @@ export function buildThreadStartParams(
|
||||
config?: JsonObject;
|
||||
},
|
||||
): CodexThreadStartParams {
|
||||
const modelProvider = resolveCodexAppServerModelProvider(params.provider);
|
||||
const modelProvider = resolveCodexAppServerModelProvider({
|
||||
provider: params.provider,
|
||||
authProfileId: params.authProfileId,
|
||||
});
|
||||
return {
|
||||
model: params.modelId,
|
||||
...(modelProvider ? { modelProvider } : {}),
|
||||
@@ -169,12 +181,16 @@ export function buildThreadResumeParams(
|
||||
params: EmbeddedRunAttemptParams,
|
||||
options: {
|
||||
threadId: string;
|
||||
authProfileId?: string;
|
||||
appServer: CodexAppServerRuntimeOptions;
|
||||
developerInstructions?: string;
|
||||
config?: JsonObject;
|
||||
},
|
||||
): CodexThreadResumeParams {
|
||||
const modelProvider = resolveCodexAppServerModelProvider(params.provider);
|
||||
const modelProvider = resolveCodexAppServerModelProvider({
|
||||
provider: params.provider,
|
||||
authProfileId: options.authProfileId ?? params.authProfileId,
|
||||
});
|
||||
return {
|
||||
threadId: options.threadId,
|
||||
model: params.modelId,
|
||||
@@ -326,14 +342,28 @@ function buildUserInput(
|
||||
];
|
||||
}
|
||||
|
||||
function resolveCodexAppServerModelProvider(provider: string): string | undefined {
|
||||
const normalized = provider.trim();
|
||||
if (!normalized || normalized === "codex") {
|
||||
function resolveCodexAppServerModelProvider(params: {
|
||||
provider: string;
|
||||
authProfileId?: string;
|
||||
}): string | undefined {
|
||||
const normalized = params.provider.trim();
|
||||
const normalizedLower = normalized.toLowerCase();
|
||||
if (!normalized || normalizedLower === "codex") {
|
||||
// `codex` is OpenClaw's virtual provider; let Codex app-server keep its
|
||||
// native provider/auth selection instead of forcing the legacy OpenAI path.
|
||||
return undefined;
|
||||
}
|
||||
return normalized === "openai-codex" ? "openai" : normalized;
|
||||
if (
|
||||
isCodexAppServerNativeAuthProfileId(params.authProfileId) &&
|
||||
(normalizedLower === "openai" || normalizedLower === "openai-codex")
|
||||
) {
|
||||
// When OpenClaw is forwarding ChatGPT/Codex OAuth, forcing the public
|
||||
// OpenAI model provider makes app-server call api.openai.com without the
|
||||
// ChatGPT bearer and fails with "Missing bearer or basic authentication".
|
||||
// Omit the provider so app-server keeps its native account-backed route.
|
||||
return undefined;
|
||||
}
|
||||
return normalizedLower === "openai-codex" ? "openai" : normalized;
|
||||
}
|
||||
|
||||
// Modern Codex models (gpt-5.5, gpt-5.4, gpt-5.4-mini, gpt-5.2) use the
|
||||
|
||||
@@ -339,6 +339,7 @@ async function bindConversation(
|
||||
const authProfileId = existingBinding?.authProfileId;
|
||||
const startParams: Parameters<CodexCommandDeps["startCodexConversationThread"]>[0] = {
|
||||
pluginConfig,
|
||||
config: ctx.config,
|
||||
sessionFile: ctx.sessionFile,
|
||||
workspaceDir,
|
||||
threadId: parsed.threadId,
|
||||
|
||||
@@ -1422,6 +1422,7 @@ describe("codex command", () => {
|
||||
});
|
||||
expect(startCodexConversationThread).toHaveBeenCalledWith({
|
||||
pluginConfig: undefined,
|
||||
config: {},
|
||||
sessionFile,
|
||||
workspaceDir: "/repo",
|
||||
threadId: "thread-123",
|
||||
|
||||
@@ -7,7 +7,19 @@ const sharedClientMocks = vi.hoisted(() => ({
|
||||
getSharedCodexAppServerClient: vi.fn(),
|
||||
}));
|
||||
|
||||
const agentRuntimeMocks = vi.hoisted(() => ({
|
||||
ensureAuthProfileStore: vi.fn(),
|
||||
loadAuthProfileStoreForSecretsRuntime: vi.fn(),
|
||||
resolveApiKeyForProfile: vi.fn(),
|
||||
resolveAuthProfileOrder: vi.fn(),
|
||||
resolveOpenClawAgentDir: vi.fn(() => "/agent"),
|
||||
resolvePersistedAuthProfileOwnerAgentDir: vi.fn(),
|
||||
resolveProviderIdForAuth: vi.fn((provider: string) => provider),
|
||||
saveAuthProfileStore: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("./app-server/shared-client.js", () => sharedClientMocks);
|
||||
vi.mock("openclaw/plugin-sdk/agent-runtime", () => agentRuntimeMocks);
|
||||
|
||||
import {
|
||||
handleCodexConversationBindingResolved,
|
||||
@@ -24,9 +36,74 @@ describe("codex conversation binding", () => {
|
||||
|
||||
afterEach(async () => {
|
||||
sharedClientMocks.getSharedCodexAppServerClient.mockReset();
|
||||
agentRuntimeMocks.ensureAuthProfileStore.mockReset();
|
||||
agentRuntimeMocks.loadAuthProfileStoreForSecretsRuntime.mockReset();
|
||||
agentRuntimeMocks.resolveApiKeyForProfile.mockReset();
|
||||
agentRuntimeMocks.resolveAuthProfileOrder.mockReset();
|
||||
agentRuntimeMocks.resolveOpenClawAgentDir.mockClear();
|
||||
agentRuntimeMocks.resolvePersistedAuthProfileOwnerAgentDir.mockReset();
|
||||
agentRuntimeMocks.resolveProviderIdForAuth.mockClear();
|
||||
agentRuntimeMocks.saveAuthProfileStore.mockReset();
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
agentRuntimeMocks.ensureAuthProfileStore.mockReturnValue({ version: 1, profiles: {} });
|
||||
agentRuntimeMocks.resolveAuthProfileOrder.mockReturnValue([]);
|
||||
agentRuntimeMocks.resolveOpenClawAgentDir.mockReturnValue("/agent");
|
||||
agentRuntimeMocks.resolveProviderIdForAuth.mockImplementation((provider: string) => provider);
|
||||
});
|
||||
|
||||
it("uses the default Codex auth profile and omits the public OpenAI provider for new binds", async () => {
|
||||
const sessionFile = path.join(tempDir, "session.jsonl");
|
||||
const config = { auth: { order: { "openai-codex": ["openai-codex:default"] } } };
|
||||
const requests: Array<{ method: string; params: Record<string, unknown> }> = [];
|
||||
agentRuntimeMocks.ensureAuthProfileStore.mockReturnValue({
|
||||
version: 1,
|
||||
profiles: {
|
||||
"openai-codex:default": {
|
||||
type: "oauth",
|
||||
provider: "openai-codex",
|
||||
access: "access-token",
|
||||
},
|
||||
},
|
||||
});
|
||||
agentRuntimeMocks.resolveAuthProfileOrder.mockReturnValue(["openai-codex:default"]);
|
||||
sharedClientMocks.getSharedCodexAppServerClient.mockResolvedValue({
|
||||
request: vi.fn(async (method: string, requestParams: Record<string, unknown>) => {
|
||||
requests.push({ method, params: requestParams });
|
||||
return {
|
||||
thread: { id: "thread-new", cwd: tempDir },
|
||||
model: "gpt-5.4-mini",
|
||||
};
|
||||
}),
|
||||
});
|
||||
|
||||
await startCodexConversationThread({
|
||||
config: config as never,
|
||||
sessionFile,
|
||||
workspaceDir: tempDir,
|
||||
model: "gpt-5.4-mini",
|
||||
modelProvider: "openai",
|
||||
});
|
||||
|
||||
expect(agentRuntimeMocks.resolveAuthProfileOrder).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ cfg: config, provider: "openai-codex" }),
|
||||
);
|
||||
expect(sharedClientMocks.getSharedCodexAppServerClient).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ authProfileId: "openai-codex:default" }),
|
||||
);
|
||||
expect(requests).toHaveLength(1);
|
||||
expect(requests[0]).toMatchObject({
|
||||
method: "thread/start",
|
||||
params: expect.objectContaining({ model: "gpt-5.4-mini" }),
|
||||
});
|
||||
expect(requests[0]?.params).not.toHaveProperty("modelProvider");
|
||||
await expect(fs.readFile(`${sessionFile}.codex-app-server.json`, "utf8")).resolves.toContain(
|
||||
'"authProfileId": "openai-codex:default"',
|
||||
);
|
||||
});
|
||||
|
||||
it("preserves Codex auth and omits the public OpenAI provider for native bind threads", async () => {
|
||||
const sessionFile = path.join(tempDir, "session.jsonl");
|
||||
await fs.writeFile(
|
||||
|
||||
@@ -5,6 +5,7 @@ import type {
|
||||
PluginHookInboundClaimEvent,
|
||||
} from "openclaw/plugin-sdk/plugin-entry";
|
||||
import type { ReplyPayload } from "openclaw/plugin-sdk/reply-payload";
|
||||
import { resolveCodexAppServerAuthProfileIdForAgent } from "./app-server/auth-bridge.js";
|
||||
import { CODEX_CONTROL_METHODS } from "./app-server/capabilities.js";
|
||||
import {
|
||||
codexSandboxPolicyForTurn,
|
||||
@@ -49,6 +50,7 @@ type CodexConversationRunOptions = {
|
||||
|
||||
type CodexConversationStartParams = {
|
||||
pluginConfig?: unknown;
|
||||
config?: Parameters<typeof resolveCodexAppServerAuthProfileIdForAgent>[0]["config"];
|
||||
sessionFile: string;
|
||||
workspaceDir?: string;
|
||||
threadId?: string;
|
||||
@@ -81,7 +83,10 @@ export async function startCodexConversationThread(
|
||||
const workspaceDir =
|
||||
params.workspaceDir?.trim() || resolveCodexDefaultWorkspaceDir(params.pluginConfig);
|
||||
const existingBinding = await readCodexAppServerBinding(params.sessionFile);
|
||||
const authProfileId = params.authProfileId ?? existingBinding?.authProfileId;
|
||||
const authProfileId = resolveCodexAppServerAuthProfileIdForAgent({
|
||||
authProfileId: params.authProfileId ?? existingBinding?.authProfileId,
|
||||
config: params.config,
|
||||
});
|
||||
if (params.threadId?.trim()) {
|
||||
await attachExistingThread({
|
||||
pluginConfig: params.pluginConfig,
|
||||
|
||||
Reference in New Issue
Block a user