Repository navigation
feat(extension): crew_profile asks the user for a model itself - #144
Merged
Merged
Conversation
…ting CREW-87 work
…fore model-ask-dialog gate
The ask was gated on whether the leader supplied a model (input.model === undefined), so a leader-supplied model for a catalogued adapter (claude/codex/copilot) bypassed it entirely and was accepted as though it were the user's own choice -- the orchestration skill's own step-1 example passed one, making that the normal path. Inverts the trigger: the ask now fires whenever no model is configured for the adapter yet, regardless of what (or whether) the leader suggested. With no configured model and an interactive UI attached, crew opens the model-selection dialog itself, offering the current models for that adapter (omp's own catalogue, or the vendor's own model family table when omp has no catalogue entry for that provider -- currentModels() in models.ts, naming which source answered). A leader-supplied model only preselects a row if it resolves to one of the options shown; the human's own pick is what gets used and persisted. Without an interactive UI, on a dialog timeout, or with nothing to offer, registration is refused with a typed model-not-configured error. Once a model is configured, behavior is unchanged: an explicit value is only ever compared to it. ompRpc and other adapters omp does not catalogue are unaffected -- they have no catalogue and no dialog either way, so an explicit model is still used exactly as given, matching prior behavior. Adds a drift guard: VENDOR_ALIASES.claude's values are now also what the dialog offers when omp's catalogue has nothing for claude, so the table silently drifting from the vendor is no longer cosmetic. A test reads the installed claude binary's own baked latest_per_family object directly off its bytes and compares it to the table, skipping visibly when the binary is absent or unreadable. Also fixes a stale comment in models.ts claiming omp's catalogue held 725 models across 7 providers on the machine it was written on -- the catalogue is scoped to providers omp holds credentials for, which can differ from what a vendor CLI itself accepts (the reason currentModels() has a fallback at all). Docs (manual-testing.md, crew-orchestration skill) rewritten to describe the dialog-driven flow in place of the old ask-then-call-back instruction to the leader.
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.
crew_profile's ask was gated on whether the leader supplied a model (input.model === undefined), so a leader-supplied model for a catalogued adapter (claude/codex/copilot) skipped the ask entirely and was accepted as though it were the user's own choice -- the orchestration skill's own step-1 example passed one, making that the normal path.Inverts the trigger: the ask now fires whenever no model is configured for the adapter yet, regardless of what (or whether) the leader suggested. A leader-supplied model only preselects a row in the dialog if it resolves to one of the models offered; the human's own pick is what gets used and persisted. Once a model is configured, behavior is unchanged -- an explicit value is only ever compared to it.
The dialog
With no configured model and an interactive UI attached, crew opens the model-selection dialog itself (
extCtx.ui.select) rather than instructing the leader to ask and call back. The dialog's title names which source answered:readCataloguehas an entry for the adapter's provider.currentModels()inmodels.ts) -- e.g. a machine with noanthropiccredentials in omp has no catalogue entry forclaude, even though theclaudebinary itself works fine.Fail-closed paths
Three distinct situations all return the same
model-not-configurederror code (a caller's retry logic only needs to know registration didn't happen), distinguished by areasonindetailsand adapter-specific message text:no-ui-- no interactive UI is attached to ask through.no-current-models-- neither the catalogue nor a vendor family table has anything to offer.dialog-timeout-- the dialog resolvedundefined(same treatment asplan.ts's existing dialogs).ompRpcand any caller-defined adapter are unaffected by all of this: they have no catalogue and no alias source, so there is no bounded list to build a dialog from. This is checked before thehasUIcheck and is independent of it, so an explicit model for these adapters is used exactly as given whether or not a UI is attached -- matching prior behavior and its existing regression test. This is a deliberate departure from the design draft's pseudocode ordering (which checkedhasUIunconditionally first): that ordering, read literally, would have made non-catalogued adapters fail closed whenever no UI was attached even with an explicit model given, which is a real behavior change with no test coverage calling for it and an existing test asserting the opposite.Drift guard
VENDOR_ALIASES.claude's values are now also what the dialog offers when omp's catalogue has nothing forclaude, so the table silently drifting from the vendor is no longer cosmetic -- it would mean the dialog offering models that no longer exist or omitting the vendor's current one. Added a test that reads the INSTALLEDclaudebinary's own bakedlatest_per_familyobject directly off its raw bytes (greppable, well under a second even at ~200MB) and compares it to the table. Skips visibly (a printed reason) rather than failing when the binary is absent or unreadable -- CI has no vendor CLI. A drift failure names both sides and says what to do; a machine whose installedclaudeis older or newer than the table is the guard working as intended, not a defect in the table.Also fixed
models.tsclaiming omp's catalogue held "725 models across 7 providers on the machine this was written on" -- the catalogue is scoped to providers the local omp installation holds credentials for, which is a different question from whether a vendor CLI itself accepts a given model name (the reasoncurrentModels()'s fallback exists at all).docs/manual-testing.md§3e and thecrew-orchestrationskill's step-1 example, both rewritten to describe the dialog-driven flow in place of the old "ask the user, then call back" instruction to the leader.Verification
bun run typecheck-- clean.bun test packages/extension-- 357/357 pass.bun run format:check-- clean.bun run check-- passed (schema-drift, format, typecheck, build, bun test, full Rust workspace test suite).check-markers.ts) -- zero findings repository-wide.