diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c8c3ddde82..88da0849748 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. diff --git a/extensions/codex/src/app-server/run-attempt.test.ts b/extensions/codex/src/app-server/run-attempt.test.ts index 86eea3a0a86..36b3d026f15 100644 --- a/extensions/codex/src/app-server/run-attempt.test.ts +++ b/extensions/codex/src/app-server/run-attempt.test.ts @@ -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; diff --git a/extensions/codex/src/app-server/run-attempt.ts b/extensions/codex/src/app-server/run-attempt.ts index a8f391a8ff8..cfdd72e417b 100644 --- a/extensions/codex/src/app-server/run-attempt.ts +++ b/extensions/codex/src/app-server/run-attempt.ts @@ -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,