Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15415,7 +15415,8 @@ describe("ClaudeAdapterV2 background wake turns", () => {

yield* harness.offerAndWait(wakeNotification);
assert.lengthOf(harness.continuationRequests, 0);
assert.isFalse(yield* harness.hasPendingBackgroundWork);
// Claude is opening its wake turn: a session release now would kill it.
assert.isTrue(yield* harness.hasPendingBackgroundWork);

yield* Queue.offer(harness.sdkMessages, wakeAssistant);
yield* harness.awaitContinuation(1);
Expand Down Expand Up @@ -16305,7 +16306,13 @@ describe("ClaudeAdapterV2 background wake turns", () => {
yield* harness.offerAndWait(wakeNotification);
if (emptyLevel === "after") yield* harness.offerAndWait(emptyRoster);
// Query replacement reads the internal roster, which the exit already cleared.
assert.isFalse(yield* harness.hasPendingBackgroundWork);
assert.isFalse(
yield* harness.runtime.hasPendingBackgroundWorkForThread!(harness.providerThread, {
includeSubagents: true,
}),
);
// The owed wake still holds the process against a session release.
assert.isTrue(yield* harness.hasPendingBackgroundWork);
yield* harness.offerAndWait(wakeTurnInit);
yield* harness.runtime.startTurn(
makeClaudeTestTurnInput({
Expand Down Expand Up @@ -16357,6 +16364,8 @@ describe("ClaudeAdapterV2 background wake turns", () => {
rosters.at(-1)?.taskIds,
emptyLevel === "sibling" ? [[secondTaskId, true]] : [],
);
// The wake run took the buffered notification, so it no longer holds the session.
if (emptyLevel !== "sibling") assert.isFalse(yield* harness.hasPendingBackgroundWork);
if (emptyLevel === "sibling") {
assert.isTrue(rosters.at(-1)?.pendingWork);
yield* harness.offerAndWait(
Expand Down Expand Up @@ -20966,7 +20975,8 @@ describe("ClaudeAdapterV2 background wake turns", () => {
yield* changes.until(
() => events.filter((event) => event.type === "turn.terminal").length === 2,
);
assert.isFalse(yield* hasPendingBackgroundWork);
// The model switch went through; the wake it carried over is still owed.
assert.isTrue(yield* hasPendingBackgroundWork);
assert.lengthOf(continuationRequests, 0);

yield* Queue.offer(secondProcess, wakeResult);
Expand Down
11 changes: 9 additions & 2 deletions apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13779,13 +13779,20 @@ export const makeClaudeAdapterV2 = Effect.fn("makeClaudeAdapterV2")(function* (
}
}
const buffers = yield* Ref.get(wakeBuffers);
for (const entry of buffers.values()) {
const { reports } = yield* Ref.get(wakeReportsByNativeThread);
for (const [nativeThreadId, entry] of buffers) {
const wakeReports = reports.get(nativeThreadId);
if (
entry.messages.some(
(message) =>
message.type === "user" ||
message.type === "assistant" ||
message.type === "result",
message.type === "result" ||
// Claude opens a wake turn for this notification; closing before its first
// frame arrives kills the turn and loses the wake.
(message.type === "system" &&
message.subtype === "task_notification" &&
wakeReports?.has(message.task_id) === true),
)
) {
return true;
Expand Down
Loading