diff --git a/packages/client-runtime/src/state/threadWorkflows.test.ts b/packages/client-runtime/src/state/threadWorkflows.test.ts index c47b5ed28a73..3fe571e84b5b 100644 --- a/packages/client-runtime/src/state/threadWorkflows.test.ts +++ b/packages/client-runtime/src/state/threadWorkflows.test.ts @@ -62,7 +62,8 @@ describe("thread workflows", () => { ...projection, providerThreads: [{ ...projection.providerThreads[0]!, nativeThreadRef: null }], }), - ).toBe(false); + ).toBe(true); + expect(threadSupportsProviderHandoff({ ...projection, providerThreads: [] })).toBe(false); }); it("sorts queued messages and gates promotion from capabilities", () => { diff --git a/packages/client-runtime/src/state/threadWorkflows.ts b/packages/client-runtime/src/state/threadWorkflows.ts index c96090427c4f..1f50bff8e246 100644 --- a/packages/client-runtime/src/state/threadWorkflows.ts +++ b/packages/client-runtime/src/state/threadWorkflows.ts @@ -109,14 +109,14 @@ export function threadSupportsProviderHandoff(projection: Projection | null | un if (resolveActiveThreadRun(projection) !== null) return false; if (projection.thread.historyOrigin === "v1_import" || projection.runs.length === 0) return true; - // Detaching a stopped session removes it from the projection, but its native - // provider thread remains available for the next turn's portable handoff. + // Detaching a stopped session removes it from the projection. The server still + // hands off from saved app history, which needs the source provider thread but + // not its native ref. return projection.providerThreads.some( (thread) => thread.id === projection.thread.activeProviderThreadId && thread.appThreadId === projection.thread.id && - thread.providerInstanceId === projection.thread.modelSelection.instanceId && - thread.nativeThreadRef !== null, + thread.providerInstanceId === projection.thread.modelSelection.instanceId, ); }