Skip to content

Commit 018f165

Browse files
committed
fix(task): keep new_task delegation alive when the fallback effort say rejects
1 parent 4a6ee69 commit 018f165

2 files changed

Lines changed: 67 additions & 4 deletions

File tree

‎src/__tests__/provider-delegation.spec.ts‎

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,57 @@ describe("ClineProvider.delegateParentAndOpenChild()", () => {
519519
expect(childRun).toHaveBeenCalledTimes(1)
520520
})
521521

522+
it("does not abort delegation when the fallback say rejects after the parent is disposed (DTE series 5/5)", async () => {
523+
const parentTask = makeParentTask()
524+
const setRuntimeThinkingEffort = vi.fn()
525+
// The parent is already disposed when this say runs, so the webview state can be
526+
// gone and the say rejects (e.g. posting to a removed task).
527+
const say = vi.fn().mockRejectedValue(new Error("task disposed"))
528+
const childRun = vi.fn().mockResolvedValue(undefined)
529+
const createTask = vi.fn().mockResolvedValue({
530+
taskId: "child-1",
531+
start: vi.fn(),
532+
run: childRun,
533+
setRuntimeThinkingEffort,
534+
say,
535+
api: { getModel: () => ({ id: "child-model", info: { supportsReasoningEffort: ["low", "high"] } }) },
536+
})
537+
const taskHistoryStore = makeStoreStub()
538+
const providerLog = vi.fn()
539+
540+
const provider = {
541+
taskScheduler: new TaskScheduler(),
542+
emit: vi.fn(),
543+
getCurrentTask: vi.fn(() => parentTask),
544+
removeClineFromStack: vi.fn().mockResolvedValue(undefined),
545+
createTask,
546+
handleModeSwitch: vi.fn().mockResolvedValue(undefined),
547+
log: providerLog,
548+
isViewLaunched: false,
549+
recentTasksCache: undefined,
550+
taskHistoryStore,
551+
} as unknown as ClineProvider
552+
553+
// Must NOT reject: the failing notification is non-fatal.
554+
await ClineProvider.prototype.delegateParentAndOpenChild.call(provider, {
555+
parentTaskId: "parent-1",
556+
message: "Do something",
557+
initialTodos: [],
558+
mode: "code",
559+
thinkingEffort: "xhigh",
560+
})
561+
await Promise.resolve()
562+
563+
// The say rejection is surfaced through the provider log, not thrown.
564+
expect(providerLog).toHaveBeenCalledWith(expect.stringContaining("non-fatal"))
565+
expect(providerLog).toHaveBeenCalledWith(expect.stringContaining("task disposed"))
566+
// Delegation metadata is still persisted for the (already disposed) parent.
567+
expect(taskHistoryStore.atomicReadAndUpdate).toHaveBeenCalledTimes(1)
568+
expect(taskHistoryStore.atomicReadAndUpdate.mock.calls[0][0]).toBe("parent-1")
569+
// And the child is still scheduled despite the failed notification.
570+
expect(childRun).toHaveBeenCalledTimes(1)
571+
})
572+
522573
it("applies the effort when the child model (post mode switch) has a boolean-true capability (DTE series 5/5)", async () => {
523574
const parentTask = makeParentTask()
524575
const setRuntimeThinkingEffort = vi.fn()

‎src/core/webview/ClineProvider.ts‎

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3885,10 +3885,22 @@ export class ClineProvider
38853885
// orchestrator, not the child's own settings.
38863886
child.setRuntimeThinkingEffort(thinkingEffort, "parent")
38873887
} else {
3888-
await child.say(
3889-
"error",
3890-
`new_task thinking_effort '${thinkingEffort}' is not supported by the child model (${childModel.id}); the child starts without the effort override.`,
3891-
)
3888+
// Non-fatal: the parent is already disposed at this point, so a rejecting
3889+
// say must not abort the delegation — the metadata transaction and child
3890+
// scheduling below are the recovery path, and losing them would leave the
3891+
// child active while the parent has no delegation metadata.
3892+
await child
3893+
.say(
3894+
"error",
3895+
`new_task thinking_effort '${thinkingEffort}' is not supported by the child model (${childModel.id}); the child starts without the effort override.`,
3896+
)
3897+
.catch((error) => {
3898+
this.log(
3899+
`[delegateParentAndOpenChild] Failed to notify child of unsupported thinking_effort (non-fatal): ${
3900+
error instanceof Error ? error.message : String(error)
3901+
}`,
3902+
)
3903+
})
38923904
}
38933905
}
38943906

0 commit comments

Comments
 (0)