Add canonical model selection and Gemini provider#444
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
This PR introduces a canonical ModelSelection abstraction across contracts, persistence, orchestration, and the web app, and adds Gemini as a first-class provider backed by CLI health checks and an adapter.
Changes:
- Add
ModelSelectioncontract + shared normalization utilities, and persist canonical selections for projects/threads. - Replace static web model lists with server-driven provider snapshots (including per-model capability metadata).
- Add Gemini provider integration (health probing + adapter + UI support).
Reviewed changes
Copilot reviewed 43 out of 43 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/shared/src/modelSelection.ts | New shared helpers to normalize/construct canonical ModelSelection and prune unsupported options by capabilities. |
| packages/shared/src/modelSelection.test.ts | Unit tests for canonical selection normalization and capability-based pruning. |
| packages/shared/src/model.ts | Extend provider inference and reasoning-effort helpers to include gemini. |
| packages/shared/package.json | Export new @okcode/shared/modelSelection entrypoint. |
| packages/contracts/src/server.ts | Extend server provider snapshot schema to include auth object + model inventories + capabilities. |
| packages/contracts/src/orchestration.ts | Add gemini to ProviderKind; introduce ModelSelection union and wire it through commands/read models. |
| packages/contracts/src/model.ts | Add Gemini model options placeholder + model capability schemas and Gemini model inventory defaults. |
| apps/web/src/types.ts | Carry ModelSelection through web Project/Thread types. |
| apps/web/src/store.ts | Prefer modelSelection for mapping server read model into web state. |
| apps/web/src/routes/_chat.settings.tsx | Add Gemini install/auth guidance and provider UI state wiring. |
| apps/web/src/routes/_chat.settings.index.tsx | Add Gemini install/auth guidance and provider UI state wiring (index route). |
| apps/web/src/providerModels.ts | New mapping layer from server provider snapshots + custom models into picker-ready options (with capabilities). |
| apps/web/src/modelSelection.ts | New helper to resolve a “live” ModelSelection from snapshots, preferences, and draft inputs. |
| apps/web/src/lib/providerAvailability.ts | Include Gemini in provider ordering/labels; support new auth shape during migration. |
| apps/web/src/components/sme/smeConversationConfig.ts | Add Gemini label + SME auth defaults/options. |
| apps/web/src/components/sme/SmeConversationDialog.tsx | Wire custom Gemini models into SME dialog selection flow. |
| apps/web/src/components/chat/providerStatusPresentation.ts | Update provider setup phase logic for new auth shape; add Gemini label. |
| apps/web/src/components/chat/composerProviderRegistry.tsx | Add Gemini provider registry entry for composer state. |
| apps/web/src/components/chat/ProviderModelPicker.tsx | Switch picker to server-driven provider snapshots and add Gemini icon/labeling. |
| apps/web/src/components/chat/ProviderModelPicker.browser.tsx | Update browser tests to mount picker with server provider snapshots (including Gemini). |
| apps/web/src/components/ChatView.tsx | Move sending/persisting to modelSelection (and snapshot-driven models) instead of static inventories. |
| apps/web/src/appSettings.ts | Add Gemini custom-model persistence and normalization. |
| apps/server/src/sme/authValidation.ts | Allow Gemini SME auth methods and defaults. |
| apps/server/src/serverLayers.ts | Register Gemini adapter and add ChildProcessSpawner requirement for provider layer. |
| apps/server/src/provider/providerCatalog.ts | New built-in provider model catalog with capability metadata + custom model merging. |
| apps/server/src/provider/providerCatalog.test.ts | Tests for provider catalog inventories and merging behavior. |
| apps/server/src/provider/Services/GeminiAdapter.ts | New Gemini adapter service contract. |
| apps/server/src/provider/Layers/ProviderHealth.ts | Add Gemini CLI health probe; refactor statuses to new auth shape + attach model inventories. |
| apps/server/src/provider/Layers/ProviderAdapterRegistry.ts | Allow optional Gemini adapter registration. |
| apps/server/src/provider/Layers/GeminiAdapter.ts | New CLI-backed Gemini provider adapter emitting runtime events. |
| apps/server/src/persistence/Services/ProjectionThreads.ts | Add modelSelection field to persisted thread projection schema. |
| apps/server/src/persistence/Services/ProjectionProjects.ts | Add defaultModelSelection field to persisted project projection schema. |
| apps/server/src/persistence/Migrations/025_CanonicalizeModelSelections.ts | Migration adding JSON model-selection columns and backfilling from legacy model strings. |
| apps/server/src/persistence/Layers/ProjectionThreads.ts | Store/read modelSelection as JSON string in projection_threads. |
| apps/server/src/persistence/Layers/ProjectionProjects.ts | Store/read defaultModelSelection as JSON string in projection_projects. |
| apps/server/src/orchestration/projector.ts | Project defaultModelSelection/modelSelection into read model (plus canonicalization on thread create). |
| apps/server/src/orchestration/decider.ts | Emit canonical selections on create commands; pass through selections on updates/turn start. |
| apps/server/src/orchestration/Layers/ProviderCommandReactor.ts | Prefer modelSelection when starting sessions and sending turns. |
| apps/server/src/orchestration/Layers/ProjectionThreadDetailQuery.ts | Include modelSelection in thread detail query results. |
| apps/server/src/orchestration/Layers/ProjectionSnapshotQuery.ts | Include model selection fields in snapshot query results. |
| apps/server/src/orchestration/Layers/ProjectionPipeline.ts | Persist model selection fields through projection pipeline updates. |
| apps/server/src/orchestration/Layers/ProjectionOverviewQuery.ts | Include model selection fields in overview query results. |
| apps/server/src/doctor.ts | Display auth status via new auth shape, and include Gemini label. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if ( | ||
| input.modelSelection !== undefined && | ||
| JSON.stringify(input.modelSelection) !== JSON.stringify(serverThread.modelSelection ?? null) | ||
| ) { |
There was a problem hiding this comment.
Using JSON.stringify to compare ModelSelection objects is brittle (key order / undefined vs missing fields) and can trigger unnecessary thread.meta.update dispatches. Prefer a stable comparison (e.g., compare provider, model, and a normalized options object) or a dedicated deep-equality helper for model selections.
There was a problem hiding this comment.
@copilot apply changes based on this feedback
| const nextModel = input.model ?? existing.session.model ?? "auto-gemini-3"; | ||
| const currentTurnId = turnId(); | ||
| const prompt = input.input ?? ""; | ||
| const args = [ | ||
| "-p", | ||
| prompt, | ||
| "--output-format", | ||
| "stream-json", | ||
| "--model", | ||
| nextModel, | ||
| "--sandbox", | ||
| "--approval-mode", | ||
| "yolo", | ||
| ]; |
There was a problem hiding this comment.
sendTurn hard-codes --approval-mode yolo, which bypasses the app's runtimeMode (e.g., approval-required) and may allow tool execution without user confirmation. Map Gemini CLI approval behavior to the session/runtimeMode (or omit the flag unless full-access), so approval-required threads can’t run in YOLO mode by default.
There was a problem hiding this comment.
@copilot apply changes based on this feedback
| const ProjectionThreadDbRowSchema = ProjectionThread.mapFields( | ||
| Struct.assign({ | ||
| modelSelection: Schema.fromJsonString(ProjectionThread.fields.modelSelection), | ||
| }), | ||
| ); |
There was a problem hiding this comment.
modelSelection is mapped with Schema.fromJsonString(...) without allowing DB NULL. Rows where model_selection is NULL (e.g., model is NULL/blank, or pre-migration data) will fail decoding. Wrap this field with Schema.NullOr(...) (and consider normalizing undefined to null on upsert, like ProjectionProjects does) so reads/writes are robust.
There was a problem hiding this comment.
@copilot apply changes based on this feedback
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
@copilot apply changes based on the comments in this thread |
…c model/modelSelection fields, map runtimeMode to Gemini approval-mode, fix OpenClaw installed flag, handle NULL modelSelection in DB Agent-Logs-Url: https://github.com/OpenKnots/okcode/sessions/7c26e215-46c1-4d8f-858d-f66de51bdd35 Co-authored-by: BunsDev <68980965+BunsDev@users.noreply.github.com>
…Or pattern in ProjectionThreads Agent-Logs-Url: https://github.com/OpenKnots/okcode/sessions/7c26e215-46c1-4d8f-858d-f66de51bdd35 Co-authored-by: BunsDev <68980965+BunsDev@users.noreply.github.com>
Applied all changes from the review thread in commits
|
Summary
ModelSelectionfoundation across contracts, persistence, orchestration, and the web appValidation
bun run --cwd packages/shared test -- src/modelSelection.test.tsbun run --cwd apps/server test -- src/provider/providerCatalog.test.tsbun fmtbun lintbun typecheckNotes
apps/webignores the individual file filter and starts the broader browser suite; I confirmed the updated picker browser test path passes when that harness starts, then stopped the wrapper instead of treating it as targeted validation