Skip to content

Commit a325efe

Browse files
fix: replace JSON.stringify comparison with structural deep-equal for ProviderModelOptions
JSON.stringify is sensitive to property insertion order, so two semantically identical ProviderModelOptions objects constructed with keys in different orders would serialize to different strings. This caused sameModelOptions to return false incorrectly, triggering unnecessary Claude session restarts that cleared the resume cursor and lost conversation context. Replace with a recursive structural equality check that compares objects by their defined (non-undefined) keys and values regardless of key ordering. Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>
1 parent 5c9cfcd commit a325efe

File tree

1 file changed

+14
-1
lines changed

1 file changed

+14
-1
lines changed

apps/server/src/orchestration/Layers/ProviderCommandReactor.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,23 @@ const DEFAULT_RUNTIME_MODE: RuntimeMode = "full-access";
7575
const WORKTREE_BRANCH_PREFIX = "t3code";
7676
const TEMP_WORKTREE_BRANCH_PATTERN = new RegExp(`^${WORKTREE_BRANCH_PREFIX}\\/[0-9a-f]{8}$`);
7777

78+
function structuralEqual(a: unknown, b: unknown): boolean {
79+
if (a === b) return true;
80+
if (a == null || b == null) return a === b;
81+
if (typeof a !== typeof b) return false;
82+
if (typeof a !== "object") return false;
83+
const objA = a as Record<string, unknown>;
84+
const objB = b as Record<string, unknown>;
85+
const keysA = Object.keys(objA).filter((k) => objA[k] !== undefined);
86+
const keysB = Object.keys(objB).filter((k) => objB[k] !== undefined);
87+
if (keysA.length !== keysB.length) return false;
88+
return keysA.every((key) => objB[key] !== undefined && structuralEqual(objA[key], objB[key]));
89+
}
90+
7891
const sameModelOptions = (
7992
left: ProviderModelOptions | undefined,
8093
right: ProviderModelOptions | undefined,
81-
): boolean => JSON.stringify(left ?? null) === JSON.stringify(right ?? null);
94+
): boolean => structuralEqual(left ?? null, right ?? null);
8295

8396
function isUnknownPendingApprovalRequestError(cause: Cause.Cause<ProviderServiceError>): boolean {
8497
const error = Cause.squash(cause);

0 commit comments

Comments
 (0)