Keep provider diagnostics and model lists in sync#1660
Conversation
|
| Filename | Overview |
|---|---|
| packages/server/src/server/agent/agent-sdk-types.ts | Replaces ListModelsOptions/ListModesOptions with FetchCatalogOptions and introduces ProviderCatalog, cleanly unifying the discovery interface. |
| packages/server/src/server/agent/provider-registry.ts | createRegistryEntry now skips runtime model discovery when replacement models are configured, calling fetchCatalog only for modes; wrapClientProvider and the existing mergeModels path are preserved correctly. |
| packages/server/src/server/agent/provider-snapshot-manager.ts | getProviderDiagnostic force-refreshes the snapshot via fetchCatalog before appending Models/Status; loadProvider correctly passes the live client to definition.fetchCatalog. |
| packages/app/src/components/provider-diagnostic-sheet.tsx | Switches stableDiscoveredRef management from render-phase assignment to useEffect, returns [] after terminal errors when not refreshing, preventing stale model display. |
| packages/server/src/server/agent/providers/opencode-agent.ts | fetchCatalog acquires the OpenCode server once and runs fetchModelsFromClient/fetchModesFromClient in parallel; getDiagnostic stripped of model probe and server-status row. |
| packages/server/src/server/agent/providers/acp-agent.ts | Consolidates listModels + listModes into a single fetchCatalog that spawns one ACP process and issues one newSession call, returning both models and modes. |
| packages/server/src/server/agent/providers/pi/agent.ts | fetchCatalog passes PI_CATALOG_REQUEST_TIMEOUT_MS to getAvailableModels; isAvailable simplified to binary-only check; getDiagnostic stripped of runtime session probe. |
| packages/server/src/server/agent/providers/generic-acp-agent.ts | getDiagnostic simplified to binary/version checks only; runDiagnosticACPProbe removed in favor of centralized snapshot-based reporting. |
Sequence Diagram
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant UI as ProviderDiagnosticSheet
participant PSM as ProviderSnapshotManager
participant REG as ProviderRegistry
participant CLI as AgentClient
Note over UI,CLI: Model Sheet / Background Refresh
UI->>PSM: "listProviders({wait:true})"
PSM->>REG: "definition.fetchCatalog({cwd, force}, client)"
REG->>CLI: client.fetchCatalog(options)
CLI-->>REG: "{models, modes}"
REG-->>PSM: "{models: merged, modes: decorated}"
PSM-->>UI: ProviderSnapshotEntry
Note over UI,CLI: Provider Diagnostics
UI->>PSM: getProviderDiagnostic(provider)
PSM->>PSM: refreshSnapshotForCwd (force)
PSM->>CLI: client.isAvailable()
CLI-->>PSM: true/false
PSM->>REG: "definition.fetchCatalog({cwd, force}, client)"
REG->>CLI: client.fetchCatalog(options)
CLI-->>REG: "{models, modes}"
REG-->>PSM: catalog
PSM->>CLI: client.getDiagnostic()
CLI-->>PSM: baseDiagnostic
PSM-->>UI: baseDiagnostic + Models/Status
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant UI as ProviderDiagnosticSheet
participant PSM as ProviderSnapshotManager
participant REG as ProviderRegistry
participant CLI as AgentClient
Note over UI,CLI: Model Sheet / Background Refresh
UI->>PSM: "listProviders({wait:true})"
PSM->>REG: "definition.fetchCatalog({cwd, force}, client)"
REG->>CLI: client.fetchCatalog(options)
CLI-->>REG: "{models, modes}"
REG-->>PSM: "{models: merged, modes: decorated}"
PSM-->>UI: ProviderSnapshotEntry
Note over UI,CLI: Provider Diagnostics
UI->>PSM: getProviderDiagnostic(provider)
PSM->>PSM: refreshSnapshotForCwd (force)
PSM->>CLI: client.isAvailable()
CLI-->>PSM: true/false
PSM->>REG: "definition.fetchCatalog({cwd, force}, client)"
REG->>CLI: client.fetchCatalog(options)
CLI-->>REG: "{models, modes}"
REG-->>PSM: catalog
PSM->>CLI: client.getDiagnostic()
CLI-->>PSM: baseDiagnostic
PSM-->>UI: baseDiagnostic + Models/Status
Reviews (5): Last reviewed commit: "refactor(app): update stable discovered ..." | Re-trigger Greptile
|
On the Pi-specific diagnostic rows: removing those runtime-derived rows is intentional for this PR. |
|
Confirming this resolves a concrete, reproducible case on Windows. Symptom: Pi showed as not installed / no models in the provider list, while the diagnostic panel simultaneously reported Root cause (matches this PR): Environment / measurements:
Confirms the fix's direction: as a stopgap I raised only that single literal ( Closely related: #1541 (its "Root Cause 1" is this same Thanks for the fix! |
…alog Remove listModels/listModes from AgentClient and fetchModels/fetchModes from ProviderDefinition. All provider runtime discovery now flows through a single fetchCatalog(options) => ProviderCatalog API. ProviderSnapshotManager.listModels/listModes remain as cached snapshot conveniences only. Provider implementations (acp, codex, opencode, pi, claude, mock) updated accordingly; agent-manager default model resolution now calls fetchCatalog. Reshape step toward issue pi-model-list-empty.
…residue Migrate remaining AgentClient/provider-client implementations and tests to fetchCatalog. Remove obsolete ListModelsOptions/ListModesOptions interfaces. Update ProviderSnapshotManager.getProviderDiagnostic to materialize clients via ensureClient(provider, definition) so diagnostics self-heal the settings sheet instead of failing when providerClients[provider] is absent. Allowed to remain: ProviderSnapshotManager.listModels/listModes as cached snapshot readers; protocol/client legacy list_provider_models names; unrelated local helper in create-agent-mode.
- Restore TestAgentClient.fetchCatalog with proper model list and resumeSession. - Restore NativeArchiveRecordingClient and EnvProbeAgentClient removed during refactor. - Fix ResumeCaptureClient.fetchCatalog and resumeSession. - Fix stream-coalescing TestAgentClient.fetchCatalog shape and isAvailable. - Mock accessible OpenCode provider in full-access mode tests so fetchCatalog does not throw.
…tHub 面板工具栏与加载态)
冲突解决(5 文件,均融合双方):
- explorer-sidebar.tsx:保留 fork 的 git tab 与 resolveVisibleExplorerTab,并入上游 PR 加载态 showPrTab(PR 加载中保持 PR tab 可见)
- claude/agent.ts:listModels→fetchCatalog 返回 ProviderCatalog {models,modes},保留 fork 的 SDK effort 装饰与 Ultracode 逻辑
- claude/models.test.ts & agent.test.ts:测试迁移到 fetchCatalog+解构;保留 fork bedrock test,丢弃与 fork 模型表示不兼容的上游 ultracode-thinking-option test(fork 不把 ultracode 作 thinking option)
- pi/agent.ts:采纳上游简化的 isAvailable(fork 未改动该方法),删除随之失效的 withTimeout import
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Linked issue
N/A
Type of change
What does this PR do
Provider diagnostics now refresh and report from the same provider snapshot used by the model list. Availability checks stay cheap and only answer whether the provider binary is present; model and mode discovery happen through one catalog refresh path.
This also removes provider-specific diagnostic model probes, lets providers fetch models and modes together where possible, keeps custom added models visible when replacement models are configured, and prevents the model sheet from showing stale discovered models after a terminal refresh error or empty catalog.
How did you verify it
npm run formatnpm run typechecknpm run typechecknpm run lintpackages/server/src/server/agent/provider-registry.test.tspackages/server/src/server/agent/provider-snapshot-manager.test.tspackages/server/src/server/agent/providers/opencode-agent.test.tspackages/server/src/server/agent/providers/generic-acp-agent.diagnostic.test.tsNo screenshot attached: the app change is state consistency in the existing provider model sheet, not a visual layout change.
Checklist
npm run typecheckpassesnpm run lintpassesnpm run formatran (Biome)