fix: atomic provider and model selection with proper cancellation handling #2803
Open
ashprakasan wants to merge 5 commits intoantinomyhq:mainfrom
Open
fix: atomic provider and model selection with proper cancellation handling #2803ashprakasan wants to merge 5 commits intoantinomyhq:mainfrom
ashprakasan wants to merge 5 commits intoantinomyhq:mainfrom
Conversation
|
Aiswarya Prakasan seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account. You have signed the CLA already but the status is still pending? Let us recheck it. |
Contributor
Author
Testing with harness scriptThe following script simulates a new user with a clean home directory: #!/usr/bin/env zsh
set -euo pipefail
FORGE_BIN="${FORGE_BIN:-/Users/aiswaryaprakasan/Projects/forge/target/debug/forge}"
TEST_HOME="$(mktemp -d)"
echo "TEST_HOME created: $TEST_HOME"
TEST_CWD="$(mktemp -d)"
echo "TEST_CWD created: $TEST_CWD"
cleanup() {
echo "--- Config after login ---"
env -i \
HOME="$TEST_HOME" \
PATH="$PATH" \
SHELL="${SHELL:-/bin/zsh}" \
USER="${USER:-$(id -un)}" \
"$FORGE_BIN" config get provider || echo "Provider: Not set"
env -i \
HOME="$TEST_HOME" \
PATH="$PATH" \
SHELL="${SHELL:-/bin/zsh}" \
USER="${USER:-$(id -un)}" \
"$FORGE_BIN" config get model || echo "Model: Not set"
echo "cleanup is called"
rm -rf "$TEST_HOME" "$TEST_CWD"
}
trap cleanup EXIT
cd "$TEST_CWD"
env -i \
HOME="$TEST_HOME" \
PATH="$PATH" \
SHELL="${SHELL:-/bin/zsh}" \
USER="${USER:-$(id -un)}" \
"$FORGE_BIN" -p "hello" "$@"Run: # New user interactive mode, change the last line to
"$FORGE_BIN" commit "$@"
# New user provider login, change the last line to
"$FORGE_BIN" provider login "$@"
|
ee65bd2 to
1f24fe8
Compare
Contributor
Author
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.

Description:
Problem
Several issues existed in the provider and model selection flow:
Non-atomic config writes (fixes [Bug]: Model and provider selction is not atomic on login #2714): When switching providers,
set_default_providerwas called before model selection was confirmed. If the user cancelled model selection, the config was left in an invalid state with a new provider but a model from the old provider.Infinite loop on new user onboarding: When no provider was set,
select_modelhad an internal provider check that ran unconditionally even when called with aprovider_filter. This caused a recursive loop:select_model→on_provider_selection→finalize_provider_activation→on_model_selection→select_model→ loop.Wrong order in
init_state: Provider check ran after model check, causing model selection to be prompted before provider was configured.Cancel not propagated correctly:
on_provider_selectionreturnedOk(())on both cancel and success, making it impossible for callers to detect cancellation.forge commitbypassed init: The commit subcommand bypassedinit_stateentirely, causing a hard error when no provider was set instead of prompting the user.Changes
finalize_provider_activation: Deferredset_default_providerto after model selection is confirmed. Added newset_default_provider_and_modelatomic operation to write both together.select_model: Guarded the internal provider check withprovider_filter.is_none()to prevent recursive loops when called fromfinalize_provider_activation.on_provider_selection: Changed return type fromResult<()>toResult<bool>to signal whether a provider was actually saved. Returnsfalseif the overall flow didn't result in a saved config.init_state: Moved provider check before model check. Added early return if user cancels provider selection.TopLevelCommand::Commit: Addedinit_statecall soforge commitprompts for provider+model if not configured.set_default_provider_and_model: New atomic API method usingConfigOperation::SetModelwhich writes both provider and model in a single operation.Manual Testing
Scenario 1: New user — complete flow
Run forge with no config, select provider, complete auth, select model.
Result: Config shows correct provider and model. ✓
Scenario 2: New user — cancel at provider selection
Run forge with no config, press ESC at provider list.
Result: Exits cleanly, nothing written to config. ✓
Scenario 3: New user — cancel at model selection
Run forge with no config, select provider, complete auth, say yes to default, press ESC at model selection.
Result: Exits cleanly, nothing written to config. ✓
Scenario 4: Existing user — cancel at model selection during provider login
Run
forge provider login, select different provider, complete auth, say yes to default, press ESC at model selection.Result: Config unchanged — original provider and model preserved. ✓
Scenario 5: Existing user — complete provider switch
Run
forge provider login, select different provider, complete auth, say yes, select model.Result: Config shows new provider and model. ✓
Scenario 6: forge commit — no provider set
Run
forge commitwith no config.Result: Provider and model selection prompted before commit proceeds. ✓
Scenario 7: forge commit — provider and model already set
Run
forge commitwith config already set.Result: No prompts, commit proceeds directly. ✓
Scenario 8: New user — interactive mode
Run
forgewith no config, select provider, complete auth, say yes to default, select model.Result: Enters interactive mode successfully, provider and model set correctly. ✓
Scenario 9: New user — interactive mode, cancel at model selection
Run
forgewith no config, select provider, complete auth, say yes to default, press ESC at model selection.Result: Exits cleanly, nothing written to config. ✓
Notes
A follow-up PR will introduce the necessary abstractions to make this flow unit-testable (mockable
ForgeWidgetor extraction of pure logic), as noted in the existing test module comment.Fixes #2714