惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Jina AI
Jina AI
大猫的无限游戏
大猫的无限游戏
Microsoft Security Blog
Microsoft Security Blog
C
Check Point Blog
云风的 BLOG
云风的 BLOG
J
Java Code Geeks
阮一峰的网络日志
阮一峰的网络日志
MongoDB | Blog
MongoDB | Blog
Engineering at Meta
Engineering at Meta
H
Help Net Security
Microsoft Azure Blog
Microsoft Azure Blog
Recent Announcements
Recent Announcements
Google DeepMind News
Google DeepMind News
F
Fortinet All Blogs
宝玉的分享
宝玉的分享
H
Hackread – Cybersecurity News, Data Breaches, AI and More
腾讯CDC
A
About on SuperTechFans
酷 壳 – CoolShell
酷 壳 – CoolShell
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
S
SegmentFault 最新的问题
Vercel News
Vercel News
aimingoo的专栏
aimingoo的专栏
B
Blog RSS Feed

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
fix(agents): release embedded-attempt session lock on eve...
openperf · 2026-05-25 · via Recent Commits to openclaw:main

File tree

  • src/agents/pi-embedded-runner/run

Original file line numberDiff line numberDiff line change

@@ -18,6 +18,7 @@ Docs: https://docs.openclaw.ai

1818

- Discord/OpenAI voice: accept longer leading wake-name mistranscripts such as "Open Club" for OpenClaw.

1919

- Discord/OpenAI voice: accept leading fuzzy wake-name transcripts such as "Monty" or "Moti" for a Molty agent while keeping ambient speech gated.

2020

- Media understanding: convert HEIC and HEIF images to JPEG before image description providers run so iPhone photos work in direct and configured image-description flows. (#86037)

21+

- Agents: release embedded-attempt session locks from outer teardown so post-prompt exceptions cannot wedge later requests behind `SessionWriteLockTimeoutError`. Fixes #86014. Thanks @openperf.

2122

- Discord/OpenAI voice: rotate Realtime sessions at provider max duration without logging the expected session-expiry event as an error.

2223

- Agents/media: derive bundled plugin local-media trust from plugin tool metadata instead of importing the full plugin registry on subscription paths. (#84409) Thanks @samzong.

2324

- Memory/local embeddings: run local GGUF embeddings in an isolated worker sidecar and degrade to configured fallback or keyword search on worker failure so native embedding crashes do not take down the Gateway. (#85348) Thanks @osolmaz.

Original file line numberDiff line numberDiff line change

@@ -68,6 +68,45 @@ describe("embedded attempt session lock lifecycle", () => {

6868

expect(releases).toEqual(["prep", "cleanup"]);

6969

});

7070
71+

it("releases the eagerly-held attempt lock on dispose when cleanup is skipped (#86014)", async () => {

72+

const releases: string[] = [];

73+

const acquireSessionWriteLock = vi

74+

.fn()

75+

.mockResolvedValueOnce({ release: vi.fn(async () => releases.push("held")) });

76+
77+

const controller = await createEmbeddedAttemptSessionLockController({

78+

acquireSessionWriteLock,

79+

lockOptions,

80+

});

81+
82+

// An exception on the post-prompt path skips acquireForCleanup; the run's outer finally

83+

// must still release the eagerly-held lock or it leaks to the live process.

84+

await controller.dispose();

85+

await controller.dispose(); // idempotent

86+
87+

expect(acquireSessionWriteLock).toHaveBeenCalledTimes(1);

88+

expect(releases).toEqual(["held"]);

89+

});

90+
91+

it("dispose does not double-release a lock already handed to cleanup", async () => {

92+

const releases: string[] = [];

93+

const acquireSessionWriteLock = vi

94+

.fn()

95+

.mockResolvedValueOnce({ release: vi.fn(async () => releases.push("held")) });

96+
97+

const controller = await createEmbeddedAttemptSessionLockController({

98+

acquireSessionWriteLock,

99+

lockOptions,

100+

});

101+
102+

const cleanupLock = await controller.acquireForCleanup();

103+

await cleanupLock.release();

104+

await controller.dispose();

105+
106+

expect(acquireSessionWriteLock).toHaveBeenCalledTimes(1);

107+

expect(releases).toEqual(["held"]);

108+

});

109+
71110

it("runs post-prompt transcript writes under a short reacquired lock", async () => {

72111

const events: string[] = [];

73112

const acquireSessionWriteLock = vi

Original file line numberDiff line numberDiff line change

@@ -630,6 +630,7 @@ export type EmbeddedAttemptSessionLockController = {

630630

): Promise<T>;

631631

acquireForCleanup(params?: { session?: unknown }): Promise<SessionLock>;

632632

hasSessionTakeover(): boolean;

633+

dispose(): Promise<void>;

633634

};

634635
635636

export async function createEmbeddedAttemptSessionLockController(params: {

@@ -872,6 +873,14 @@ export async function createEmbeddedAttemptSessionLockController(params: {

872873

hasSessionTakeover(): boolean {

873874

return takeoverDetected;

874875

},

876+

async dispose(): Promise<void> {

877+

if (!heldLock) {

878+

return;

879+

}

880+

const lock = heldLock;

881+

heldLock = undefined;

882+

await lock.release();

883+

},

875884

};

876885

}

877886
Original file line numberDiff line numberDiff line change

@@ -1302,6 +1302,8 @@ export async function runEmbeddedAttempt(

13021302

| undefined;

13031303

let beforeAgentRunBlocked = false;

13041304

let beforeAgentRunBlockedBy: string | undefined;

1305+

// Releases the eager session lock if post-prompt code exits before cleanup.

1306+

let releaseRetainedSessionLock: (() => Promise<void>) | undefined;

13051307

try {

13061308

const skillsSnapshotForRun =

13071309

sandbox?.enabled && sandbox.workspaceAccess !== "rw" ? undefined : params.skillsSnapshot;

@@ -2140,6 +2142,7 @@ export async function runEmbeddedAttempt(

21402142

...sessionWriteLockOptions,

21412143

},

21422144

});

2145+

releaseRetainedSessionLock = () => sessionLockController.dispose();

21432146
21442147

let sessionManager: ReturnType<typeof guardSessionManager> | undefined;

21452148

let session: Awaited<ReturnType<typeof createAgentSession>>["session"] | undefined;

@@ -5070,6 +5073,13 @@ export async function runEmbeddedAttempt(

50705073

}

50715074

}

50725075

} finally {

5076+

try {

5077+

await releaseRetainedSessionLock?.();

5078+

} catch (releaseErr) {

5079+

log.error(

5080+

`failed to release retained session lock on attempt teardown: runId=${params.runId} ${String(releaseErr)}`,

5081+

);

5082+

}

50735083

emitDiagnosticRunCompleted?.(

50745084

aborted ? "aborted" : "error",

50755085

promptError ?? new Error("run exited before diagnostic completion"),