-
Notifications
You must be signed in to change notification settings - Fork 331
fix(desktop): relink Codex thread across providers #3543
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
zqchris
wants to merge
37
commits into
makecindy:main
Choose a base branch
from
zqchris:codex-provider-thread-reset
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 2 commits
Commits
Show all changes
37 commits
Select commit
Hold shift + click to select a range
e5dd4d7
fix(desktop): relink Codex thread across providers
zqchris 239d279
fix(desktop): close Codex relink races
zqchris 3cb26b1
fix(desktop): roll back stale Codex relinks
zqchris 4c9b5c3
Merge remote-tracking branch 'upstream/main' into codex-provider-thre…
zqchris fe2aa3b
fix(desktop): relink persisted Codex threads without live handles
zqchris 7319ce0
fix(desktop): recalculate deferred Codex thread relink
zqchris 8fc9608
fix(codex): preserve committed relink recovery state
zqchris ad849fa
fix(codex): roll back relink across owner changes
zqchris 7b74e31
fix(codex): fence relink during app teardown
zqchris 88dcd72
fix(codex): discard stale owner pending switches
zqchris c0d129a
fix(desktop): roll back persisted Codex route atomically
zqchris 7337ac6
fix(desktop): compensate stale pending Codex routes
zqchris 31b9c02
fix(desktop): restore live runtime after route rollback
zqchris 45e8e96
fix(desktop): preserve IM switch source route
zqchris 9f5c3a9
fix(desktop): compensate resolved pending route
zqchris 1c3763d
fix(desktop): reconcile retained runtime after close failure
zqchris 9e4a695
fix(desktop): compensate stale pending registration
zqchris feccf41
fix(desktop): gate deferred relink on close failure
zqchris 0f75b86
fix(desktop): keep deferred relink route restart-safe
zqchris ee44907
fix(desktop): compensate unpersisted relink failures
zqchris 7bb48a6
test(desktop): guard deferred switch registration
zqchris 8f4d246
test(desktop): preload Codex proxy host suite
zqchris 821566a
fix(desktop): complete deferred remote selections
zqchris 6f3ef30
fix(desktop): compensate superseded deferred routes
zqchris 53f5125
fix(desktop): restore cancelled deferred runtime route
zqchris 78876ec
fix(desktop): await deferred switch restoration
zqchris de01489
fix(desktop): retry stale owner route compensation
zqchris 12b3750
fix(desktop): await hot switch pending recovery
zqchris 04663bf
fix(desktop): atomically persist IM Codex relinks
zqchris a1bdaa9
fix(desktop): atomically restore stale Codex routes
zqchris 0fc8d8e
fix(desktop): cancel failed deferred runtime switches
zqchris 06f8b79
fix(desktop): atomically persist immediate Codex relinks
zqchris 013cc17
fix(desktop): retain post-commit relink compensation
zqchris 75ef786
fix(desktop): isolate relink compensation retries
zqchris 2792222
fix(desktop): persist non-user Codex relink routes
zqchris 2324134
fix(desktop): atomically persist deferred Codex relinks
zqchris 7f47950
fix(desktop): stabilize Windows startup barrier
zqchris File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
142 changes: 142 additions & 0 deletions
142
apps/desktop/src/main/maker-ipc/__tests__/codexProviderThreadRelink.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,142 @@ | ||
| import { describe, expect, it, vi } from 'vitest'; | ||
|
|
||
| import { relinkCodexProviderThread } from '../codexProviderThreadRelink.js'; | ||
|
|
||
| describe('relinkCodexProviderThread', () => { | ||
| it('forks a provider-neutral history and CAS-relinks the Cindy session', async () => { | ||
| const fork = vi.fn(async () => ({ newSdkSessionId: 'thread-openai' })); | ||
| const commit = vi.fn(async () => true); | ||
| const onCommitted = vi.fn(); | ||
|
|
||
| await expect( | ||
| relinkCodexProviderThread( | ||
| { | ||
| readSource: vi.fn(async () => ({ | ||
| sdkSessionId: 'thread-xd', | ||
| workingDir: '/work', | ||
| })), | ||
| fork, | ||
| commit, | ||
| onCommitted, | ||
| }, | ||
| { | ||
| sessionId: 'session-1', | ||
| sourceModel: 'codex/gpt-5.6-sol', | ||
| sourceProviderId: 'xd', | ||
| }, | ||
| ), | ||
| ).resolves.toEqual({ | ||
| previousSdkSessionId: 'thread-xd', | ||
| newSdkSessionId: 'thread-openai', | ||
| }); | ||
|
|
||
| expect(fork).toHaveBeenCalledWith({ | ||
| sourceSdkSessionId: 'thread-xd', | ||
| sourceModel: 'codex/gpt-5.6-sol', | ||
| sourceProviderId: 'xd', | ||
| workingDir: '/work', | ||
| }); | ||
| expect(commit).toHaveBeenCalledWith({ | ||
| sessionId: 'session-1', | ||
| expectedSdkSessionId: 'thread-xd', | ||
| newSdkSessionId: 'thread-openai', | ||
| }); | ||
| expect(onCommitted).toHaveBeenCalledWith({ | ||
| sessionId: 'session-1', | ||
| previousSdkSessionId: 'thread-xd', | ||
| newSdkSessionId: 'thread-openai', | ||
| }); | ||
| }); | ||
|
|
||
| it('does nothing when the Cindy session has no native thread yet', async () => { | ||
| const fork = vi.fn(); | ||
| const commit = vi.fn(); | ||
|
|
||
| await expect( | ||
| relinkCodexProviderThread( | ||
| { | ||
| readSource: vi.fn(async () => ({ sdkSessionId: null, workingDir: '/work' })), | ||
| fork, | ||
| commit, | ||
| }, | ||
| { | ||
| sessionId: 'session-1', | ||
| sourceModel: 'codex/gpt-5.6-sol', | ||
| sourceProviderId: 'xd', | ||
| }, | ||
| ), | ||
| ).resolves.toBeNull(); | ||
| expect(fork).not.toHaveBeenCalled(); | ||
| expect(commit).not.toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it('fails closed when another owner replaces the thread before CAS commit', async () => { | ||
| await expect( | ||
| relinkCodexProviderThread( | ||
| { | ||
| readSource: vi.fn(async () => ({ | ||
| sdkSessionId: 'thread-xd', | ||
| workingDir: null, | ||
| })), | ||
| fork: vi.fn(async () => ({ newSdkSessionId: 'thread-openai' })), | ||
| commit: vi.fn(async () => false), | ||
| }, | ||
| { | ||
| sessionId: 'session-1', | ||
| sourceModel: 'codex/gpt-5.6-sol', | ||
| sourceProviderId: 'xd', | ||
| }, | ||
| ), | ||
| ).rejects.toThrow(/superseded/); | ||
| }); | ||
|
|
||
| it('passes the pending generation guard into the CAS commit', async () => { | ||
| const isCurrent = vi.fn(() => true); | ||
| const commit = vi.fn(async () => true); | ||
|
|
||
| await relinkCodexProviderThread( | ||
| { | ||
| readSource: vi.fn(async () => ({ sdkSessionId: 'thread-old', workingDir: null })), | ||
| fork: vi.fn(async () => ({ newSdkSessionId: 'thread-new' })), | ||
| commit, | ||
| }, | ||
| { | ||
| sessionId: 'session-1', | ||
| sourceModel: 'gpt-5.6-sol', | ||
| sourceProviderId: 'openai', | ||
| isCurrent, | ||
| }, | ||
| ); | ||
|
|
||
| expect(commit).toHaveBeenCalledWith({ | ||
| sessionId: 'session-1', | ||
| expectedSdkSessionId: 'thread-old', | ||
| newSdkSessionId: 'thread-new', | ||
| isCurrent, | ||
| }); | ||
| }); | ||
|
|
||
| it('uses the source thread identity when the route store already contains the target', async () => { | ||
| const fork = vi.fn(async () => ({ newSdkSessionId: 'thread-gateway' })); | ||
|
|
||
| await relinkCodexProviderThread( | ||
| { | ||
| readSource: vi.fn(async () => ({ sdkSessionId: 'thread-openai', workingDir: null })), | ||
| fork, | ||
| commit: vi.fn(async () => true), | ||
| }, | ||
| { | ||
| sessionId: 'session-1', | ||
| sourceModel: 'deepseek/deepseek-v4-pro', | ||
| sourceProviderId: 'deepseek', | ||
| sourceThreadModelProviderId: 'cindy_openai', | ||
| }, | ||
| ); | ||
|
|
||
| expect(fork).toHaveBeenCalledWith({ | ||
| sourceSdkSessionId: 'thread-openai', | ||
| sourceModel: 'deepseek/deepseek-v4-pro', | ||
| sourceProviderId: 'openai', | ||
| }); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.