fix(codex): preserve run session status key

This commit is contained in:
Vincent Koc
2026-05-03 21:19:17 -07:00
parent 90d25d59c6
commit e9ca63cf06
3 changed files with 53 additions and 1 deletions

View File

@@ -46,6 +46,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- Codex: pass the live run session key into app-server dynamic tools when sandbox policy uses a separate session key, so `session_status({ sessionKey: "current" })` reports the active run instead of the sandbox policy key. Thanks @vincentkoc.
- Plugins/tools: mark manifest-optional sibling tools as optional even when they come from a shared non-optional factory, so cached/status/MCP metadata keeps opt-in tool policy accurate. Thanks @vincentkoc.
- Matrix: keep `streaming.progress.toolProgress` scoped to progress draft mode, so partial and quiet Matrix previews do not lose tool progress unless `streaming.preview.toolProgress` is disabled. Thanks @vincentkoc.
- Channels/streaming: keep `streaming.progress.toolProgress` scoped to progress draft mode, so disabling compact progress lines does not silence partial/block preview tool updates. Thanks @vincentkoc.

View File

@@ -465,6 +465,52 @@ describe("runCodexAppServerAttempt", () => {
expect(dynamicToolNames).toContain("message");
});
it("passes the live run session key to Codex dynamic tools when sandbox policy uses another key", async () => {
const workspaceDir = path.join(tempDir, "workspace");
const sessionsPath = path.join(tempDir, "sessions.json");
const params = createParams(path.join(tempDir, "session.jsonl"), workspaceDir);
params.disableTools = false;
params.sessionKey = "agent:main:main";
params.config = {
session: { store: sessionsPath, mainKey: "main", scope: "per-sender" },
tools: { profile: "coding" },
};
await fs.writeFile(
sessionsPath,
JSON.stringify({
"agent:main:main": {
sessionId: "s-main",
updatedAt: 10,
status: "running",
},
"agent:main:telegram:default:direct:1234": {
sessionId: "s-telegram-policy",
updatedAt: 5,
status: "done",
},
}),
);
const dynamicTools = await __testing.buildDynamicTools({
params,
resolvedWorkspace: workspaceDir,
effectiveWorkspace: workspaceDir,
sandboxSessionKey: "agent:main:telegram:default:direct:1234",
sandbox: null,
runAbortController: new AbortController(),
sessionAgentId: "main",
pluginConfig: {},
onYieldDetected: () => undefined,
});
const sessionStatus = dynamicTools.find((tool) => tool.name === "session_status");
expect(sessionStatus).toBeDefined();
const result = await sessionStatus?.execute("call-current", { sessionKey: "current" });
expect((result?.details as { sessionKey?: string } | undefined)?.sessionKey).toBe(
"agent:main:main",
);
});
it("returns a failed dynamic tool response when an app-server tool call exceeds the deadline", async () => {
vi.useFakeTimers();
let capturedSignal: AbortSignal | undefined;

View File

@@ -352,7 +352,8 @@ export async function runCodexAppServerAttempt(
const appServer = resolveCodexAppServerRuntimeOptions({ pluginConfig });
const resolvedWorkspace = resolveUserPath(params.workspaceDir);
await fs.mkdir(resolvedWorkspace, { recursive: true });
const sandboxSessionKey = params.sessionKey?.trim() || params.sessionId;
const sandboxSessionKey =
params.sandboxSessionKey?.trim() || params.sessionKey?.trim() || params.sessionId;
const sandbox = await resolveSandboxContext({
config: params.config,
sessionKey: sandboxSessionKey,
@@ -1472,6 +1473,10 @@ async function buildDynamicTools(input: DynamicToolBuildParams) {
senderIsOwner: params.senderIsOwner,
allowGatewaySubagentBinding: params.allowGatewaySubagentBinding,
sessionKey: input.sandboxSessionKey,
runSessionKey:
params.sessionKey && params.sessionKey !== input.sandboxSessionKey
? params.sessionKey
: undefined,
sessionId: params.sessionId,
runId: params.runId,
agentDir,