fix: session_status 'current' resolves to live run session instead of stale sandbox key (#76708)

This commit is contained in:
Alex Knight
2026-05-04 09:26:08 +10:00
committed by Alex Knight
parent 12af95a55e
commit 066980d5a5
7 changed files with 75 additions and 1 deletions

View File

@@ -134,6 +134,7 @@ Docs: https://docs.openclaw.ai
- Channels/streaming: expose `streaming.progress.label`, `labels`, `maxLines`, and `toolProgress` in bundled channel config metadata so progress draft settings appear in config, docs, and control surfaces. Thanks @vincentkoc.
- Channels/streaming: normalize whitespace and case for `streaming.progress.label: "auto"` so progress draft labels keep using the built-in label pool instead of rendering a literal `auto` title. Thanks @vincentkoc.
- Plugins/Codex: preserve Codex-native OAuth routing for `/codex bind` app-server turns so bound sessions keep the selected Codex auth profile instead of falling back to public OpenAI credentials. (#76714) Thanks @keshavbotagent.
- Fix `session_status` with `sessionKey: "current"` resolving to stale Telegram direct session instead of live run session (#76708). Thanks @amknight.
- Gateway/install: prefer supported system Node over nvm/fnm/volta/asdf/mise when regenerating managed gateway services, so `gateway install --force` no longer recreates service definitions that doctor immediately flags as version-manager-backed. Fixes #76339. Thanks @brokemac79.
- Cron/status: render explicit `delivery.mode: "none"` jobs as no-delivery previews and label cron session history distinctly instead of showing fallback delivery or direct-session rows. Fixes #76945.
- Gateway/usage: serve `usage.cost` and `sessions.usage` from a durable transcript aggregate cache with lock-safe background refreshes and localized stale-cache status, so large usage views avoid repeated full scans. (#76650) Thanks @Marvinthebored.

View File

@@ -492,6 +492,37 @@ describe("session_status tool", () => {
expect(details.sessionKey).toBe("main");
});
it("resolves sessionKey=current to runSessionKey when sandbox key differs from live session (#76708)", async () => {
resetSessionStore({
"agent:main:telegram:default:direct:1234": {
sessionId: "s-tg-direct",
updatedAt: 5,
status: "done",
},
"agent:main:main": {
sessionId: "s-main",
updatedAt: 10,
status: "running",
},
});
// The tool is constructed with the Telegram sandbox key as agentSessionKey
// but the actual live run session key as runSessionKey.
const tool = createSessionStatusTool({
agentSessionKey: "agent:main:telegram:default:direct:1234",
runSessionKey: "agent:main:main",
config: {
...mockConfig,
tools: { ...mockConfig.tools, sessions: { visibility: "all" } },
} as never,
});
const result = await tool.execute("call-current-run-session", { sessionKey: "current" });
const details = result.details as { ok?: boolean; sessionKey?: string };
expect(details.ok).toBe(true);
expect(details.sessionKey).toBe("agent:main:main");
});
it("treats the TUI client label as the current requester session", async () => {
resetSessionStore({
"agent:main:main": {

View File

@@ -260,6 +260,12 @@ export function createOpenClawTools(
sandboxBrowserBridgeUrl?: string;
allowHostBrowserControl?: boolean;
agentSessionKey?: string;
/**
* The actual live run session key. When the tool is constructed with a sandbox/policy
* session key, this allows `session_status({sessionKey:"current"})` to resolve to
* the live run session instead of the stale sandbox key.
*/
runSessionKey?: string;
agentChannel?: GatewayMessageChannel;
agentAccountId?: string;
/** Delivery target for topic/thread routing. */
@@ -588,6 +594,7 @@ export function createOpenClawTools(
}),
createSessionStatusTool({
agentSessionKey: options?.agentSessionKey,
runSessionKey: options?.runSessionKey,
config: resolvedConfig,
sandboxed: options?.sandboxed,
}),

View File

@@ -664,6 +664,10 @@ async function compactEmbeddedPiSessionDirectOnce(
messageProvider: resolvedMessageProvider,
agentAccountId: params.agentAccountId,
sessionKey: sandboxSessionKey,
runSessionKey:
params.sessionKey && params.sessionKey !== sandboxSessionKey
? params.sessionKey
: undefined,
sessionId: params.sessionId,
runId: params.runId,
groupId: params.groupId,

View File

@@ -885,6 +885,13 @@ export async function runEmbeddedAttempt(
ownerOnlyToolAllowlist: params.ownerOnlyToolAllowlist,
allowGatewaySubagentBinding: params.allowGatewaySubagentBinding,
sessionKey: sandboxSessionKey,
// When sandboxSessionKey differs from the real run session key (e.g. Telegram
// direct peer key vs agent:main:main), pass the live key so session_status
// "current" resolves to the active run session, not the stale sandbox key.
runSessionKey:
params.sessionKey && params.sessionKey !== sandboxSessionKey
? params.sessionKey
: undefined,
sessionId: params.sessionId,
runId: params.runId,
agentDir,

View File

@@ -274,6 +274,12 @@ export function createOpenClawCodingTools(options?: {
messageThreadId?: string | number;
sandbox?: SandboxContext | null;
sessionKey?: string;
/**
* The actual live run session key. When the tool set is constructed with a
* sandbox/policy session key, this allows `session_status({sessionKey:"current"})`
* to resolve to the live run session instead of the stale sandbox key.
*/
runSessionKey?: string;
/** Ephemeral session UUID — regenerated on /new and /reset. */
sessionId?: string;
/** Stable run identifier for this agent invocation. */
@@ -698,6 +704,7 @@ export function createOpenClawCodingTools(options?: {
sandboxBrowserBridgeUrl: sandbox?.browser?.bridgeUrl,
allowHostBrowserControl: sandbox ? sandbox.browserAllowHostControl : true,
agentSessionKey: options?.sessionKey,
runSessionKey: options?.runSessionKey,
agentChannel: resolveGatewayMessageChannel(options?.messageProvider),
agentAccountId: options?.agentAccountId,
agentTo: options?.messageTo,

View File

@@ -276,6 +276,12 @@ async function resolveModelOverride(params: {
export function createSessionStatusTool(opts?: {
agentSessionKey?: string;
/**
* The actual live run session key. When the tool is constructed with a sandbox/policy
* session key (e.g. a Telegram direct peer key), this allows `session_status({sessionKey:
* "current"})` to resolve to the live run session instead of the stale sandbox key.
*/
runSessionKey?: string;
config?: OpenClawConfig;
sandboxed?: boolean;
}): AnyAgentTool {
@@ -346,12 +352,23 @@ export function createSessionStatusTool(opts?: {
const requestedKeyParam = readStringParam(params, "sessionKey");
let requestedKeyRaw = requestedKeyParam ?? opts?.agentSessionKey;
// When sessionKey is literally "current" and a runSessionKey is provided,
// resolve directly to the live run session instead of falling through to
// stale sandbox/policy key resolution (#76708).
if (requestedKeyRaw === "current" && opts?.runSessionKey) {
requestedKeyRaw = opts.runSessionKey;
}
const currentSessionAlias = resolveCurrentSessionClientAlias({
key: requestedKeyRaw ?? "",
requesterInternalKey: effectiveRequesterKey,
});
if (currentSessionAlias) {
requestedKeyRaw = currentSessionAlias;
// When a runSessionKey is provided (e.g. the live run session key), prefer it
// over the sandbox/policy key so "current" resolves to the active run session
// instead of a stale sandbox key (e.g. a Telegram direct peer key).
requestedKeyRaw = opts?.runSessionKey ?? currentSessionAlias;
}
const requestedKeyInput = requestedKeyRaw?.trim() ?? "";
let resolvedViaSessionId = false;