8 patches trên 3 files, chia thành 3 nhóm chức năng:
- ModelStore (BTPDcoPQ.js): Fetch models từ tất cả providers, group theo provider
- AgentFactory (agent-factory.js): Parse provider từ model ID, safety-net alignment
- ModelPicker (CfKn743W.js): Vô hiệu per-provider fetch, dùng unified list
| Symbol | Ý nghĩa |
|---|---|
H |
activeProviderStore |
Et |
ACP_PROVIDERS (provider config map) |
Ce |
parseCompoundModelId |
Ue |
getDefaultProviderId |
We |
getProviderConfigById |
h |
unifiedStateStore |
I |
Logger instance |
Me |
localStorage key "workspaces-selected-model" |
Se |
UI constants (model preference key, etc.) |
yt |
getPreferredModel utility |
| Symbol | Ý nghĩa |
|---|---|
be |
effectiveProviderId (computed) |
Ie |
isAgentProviderOverride (computed) |
xe |
agentProviderModels (signal, Y=signal constructor) |
re |
isLoadingAgentModels (signal) |
se |
agentModelError (signal) |
we |
displayedModels (computed: xe ?? ce.availableModels) |
ce |
modelStore instance |
mt |
activeProviderStore |
nt |
effect (reactive side-effect) |
H |
computed (reactive derived value) |
h |
set signal value |
t |
get signal value |
Et |
getProviderConfigById |
File: BTPDcoPQ.js
Function: async loadModels()
async loadModels(){
const e = H.activeProviderId;
if (this.modelsLoaded && this.loadedForProviderId === e || this.isLoadingModels) {
return;
}
// ... fetch chỉ 1 provider (e), prefix models với provider ID
const t = await this.fetchModelsForProvider(e);
// ... set availableModels, modelsLoaded, loadedForProviderId = e
}async loadModels(){
if (this.modelsLoaded && this.loadedForProviderId === "__all__" || this.isLoadingModels) {
return;
}
// ... fetch TẤT CẢ providers bằng Promise.allSettled
const e = Object.keys(Et); // Tất cả provider IDs
const s = await Promise.allSettled(e.map(async n => {
const o = await this.fetchModelsForProvider(n);
return { providerId: n, models: o };
}));
// Merge tất cả models, prefix với {providerId}: (trừ default provider)
// Set loadedForProviderId = "__all__"
}Object.keys(Et)lấy tất cả provider IDs từ ACP_PROVIDERS configPromise.allSettledfetch song song, provider không cài sẽ trả về empty (catch trong fetchModelsForProvider)- Mỗi model được prefix với
{providerId}:trừ default provider (giữ backwards-compatible) - Cache key là
"__all__"thay vì 1 provider ID cụ thể
File: BTPDcoPQ.js
Function: async reloadModelsForProvider()
async reloadModelsForProvider(){
const e = H.activeProviderId;
// ... save/restore model per provider, clear workspace models
this.modelsLoaded = false;
this.loadedForProviderId = null;
await this.loadModels(); // → chỉ load provider e
}async reloadModelsForProvider(){
// Đơn giản: reset và reload tất cả
this.modelsLoaded = false;
this.loadedForProviderId = null;
this.availableModels = [];
this.loadError = null;
await this.loadModels(); // → load tất cả providers
}- Không cần save/restore model per provider nữa vì danh sách luôn chứa tất cả
- Bỏ workspace model cache clear (không cần thiết khi unified list)
File: BTPDcoPQ.js
Function: selectModel(e)
selectModel(e){
// ...
const t = H.activeProviderId; // Lấy từ active provider store
this.providerModels.set(t, e); // Lưu model cho active provider
}selectModel(e){
// ...
const t = Ce(e).providerId; // Parse provider từ model ID
this.providerModels.set(t, e); // Lưu model cho provider của model
}- Khi user chọn
codex:gpt-5.3-codex/high, provider được parse từ model ID (codex) - Trước đây nó lưu cho active provider (có thể là
auggie), gây lệch
File: BTPDcoPQ.js
Function: getGroupedModels()
getGroupedModels(){
const e = H.activeProviderId, t = Et[e];
return !t || this.availableModels.length === 0
? []
: [{ providerId: t.id, providerDisplayName: t.displayName,
models: this.availableModels }];
}getGroupedModels(){
if (this.availableModels.length === 0) return [];
const e = new Map;
for (const s of this.availableModels) {
const r = Ce(s.value).providerId;
e.has(r) || e.set(r, []);
e.get(r).push(s);
}
const t = [];
for (const [s, r] of e) {
const i = Et[s];
t.push({
providerId: i ? i.id : s,
providerDisplayName: i ? i.displayName : s,
models: r
});
}
return t;
}- Trước: 1 group duy nhất cho active provider
- Sau: nhiều groups, mỗi group 1 provider, parse từ model compound ID
- Dropdown hiển thị headers theo tên provider
File: BTPDcoPQ.js
Inline trong: scheduleAutoRetry(e)
!this.modelsLoaded && H.activeProviderId === e &&!this.modelsLoaded &&- Trước: chỉ retry nếu active provider vẫn là
e(provider lúc bắt đầu) - Sau: retry bất kể provider nào active (vì load tất cả)
File: agent-factory.js (dòng 20)
-import { getDefaultModelForProvider, getDefaultProviderId, ...
+import { ACP_PROVIDERS, getDefaultModelForProvider, getDefaultProviderId, ...File: agent-factory.js (dòng 274-281)
let provider = config.provider;
if (!provider && !isBackend) {
provider = providerStore.activeProviderId; // Luôn dùng active provider
}let provider = config.provider;
// Thử parse provider từ model ID trước
if (!provider && config.model) {
const { providerId } = parseCompoundModelId(config.model);
if (ACP_PROVIDERS[providerId]) {
provider = providerId;
}
}
// Fallback về active provider nếu không parse được
if (!provider && !isBackend) {
provider = providerStore.activeProviderId;
}- Khi user chọn
codex:gpt-5.3-codex/high, provider =codex(từ model) - Khi user chọn
gpt-5.3-turbo(không prefix), provider = default provider (từ parseCompoundModelId) - Chỉ fallback về activeProviderStore nếu model không có hoặc provider không hợp lệ
File: agent-factory.js (dòng 314-342)
if (!isModelValidForProvider(resolvedModel, provider)) {
// Reset model về default của provider → MẤT model user đã chọn
resolvedModel = getDefaultModelForProvider(provider, 'balanced');
}if (!isModelValidForProvider(resolvedModel, provider)) {
const { providerId: modelProvider } = parseCompoundModelId(resolvedModel);
if (ACP_PROVIDERS[modelProvider]) {
// Align provider theo model (giữ model user đã chọn)
provider = modelProvider;
// Re-validate; fallback nếu vẫn invalid
if (!isModelValidForProvider(resolvedModel, provider) && provider in PROVIDER_MODEL_TIERS) {
resolvedModel = getDefaultModelForProvider(provider, 'balanced');
}
} else {
// Provider không biết → fallback model
resolvedModel = getDefaultModelForProvider(provider, 'balanced');
}
}- Trước: mismatch → reset model (mất lựa chọn của user)
- Sau: mismatch → đổi provider theo model (giữ lựa chọn của user)
- Chỉ reset model khi provider trong model ID không tồn tại
File: CfKn743W.js
Ie = H(() => t(be) !== mt.activeProviderId)Ie = H(() => !1)Ie(isAgentProviderOverride) kiểm tra nếu agent đang dùng provider khác active- Khi true, ModelPicker fetch models riêng cho provider đó thay vì dùng unified list
- Đặt luôn false → luôn dùng unified list từ ModelStore
File: CfKn743W.js
nt(() => {
const r = t(be);
if (r === mt.activeProviderId) {
h(xe, null); h(re, !1); h(se, null);
return;
}
// Fetch models riêng cho provider khác
h(re, !0); h(se, null);
ce.getModelsForProvider(r).then(_ => {
h(xe, _, !0); h(re, !1);
}).catch(_ => {
h(se, _.message || "Failed to load models", !0); h(re, !1);
});
});nt(() => {
t(be); // Giữ reactive subscription
h(xe, null); // agentProviderModels = null
h(re, !1); // loading = false
h(se, null); // error = null
});- Luôn clear
xe(agentProviderModels) →we(displayedModels) fallback vềce.availableModels(unified list) - Vẫn read
t(be)để giữ Svelte reactive subscription (tránh warning)
-
endsWith false-positive: Trong loadModels (BTPDcoPQ.js), kiểm tra model tồn tại dùng
endsWith(modelId)có thể match nhầm giữa providers nếu trùng suffix. Xác suất rất thấp và chỉ ảnh hưởng auto-select fallback. -
Version lock: Tên file minified là content hashes. Khi Intent update, tên file sẽ khác và cần re-identify các chunks tương ứng.
-
Provider chưa cài:
Object.keys(Et)fetch cả providers chưa cài.fetchModelsForProvidercó.catch(() => [])nên providers không có sẽ trả về empty nhanh.