Remove separate chain concept - fallback is now determined by OpenCode models order

- Removed opencodeChain variable entirely
- Removed chain form/list from admin UI
- Fallback now uses the order of models in the OpenCode models list
- Updated buildOpencodeAttemptChain to iterate through opencodeModels
- Removed chain-related API endpoints
- Simplified to just two lists: opencodeModels and publicModels
This commit is contained in:
southseact-3d
2026-02-18 16:18:31 +00:00
parent 4bb54d38ad
commit 828a9dad41
3 changed files with 60 additions and 321 deletions

View File

@@ -1,19 +1,16 @@
(() => {
const DEFAULT_PROVIDERS = ['openrouter', 'mistral', 'google', 'groq', 'nvidia', 'chutes', 'cerebras', 'ollama', 'cohere'];
const PLANNING_PROVIDERS = ['openrouter', 'mistral', 'google', 'groq', 'nvidia', 'chutes', 'cerebras', 'ollama', 'cohere'];
const pageType = document?.body?.dataset?.page || 'build';
console.log('Admin JS loaded, pageType:', pageType);
// Clean state structure
// Clean state structure - just two things
const state = {
opencodeModels: [], // Models from OpenCode
opencodeChain: [], // Fallback chain for OpenCode
opencodeModels: [], // Models from OpenCode (order determines fallback)
publicModels: [], // User-facing models (completely separate)
icons: [],
availableOpencodeModels: [], // Loaded from OpenCode
};
// Element references - clean structure matching the HTML
// Element references
const el = {
// OpenCode Models
opencodeModelForm: document.getElementById('opencode-model-form'),
@@ -27,14 +24,6 @@
opencodeModelsList: document.getElementById('opencode-models-list'),
opencodeModelsCount: document.getElementById('opencode-models-count'),
// OpenCode Chain
chainForm: document.getElementById('chain-form'),
chainProvider: document.getElementById('chain-provider'),
chainModel: document.getElementById('chain-model'),
chainStatus: document.getElementById('chain-status'),
chainList: document.getElementById('chain-list'),
chainCount: document.getElementById('chain-count'),
// Public Models
publicModelForm: document.getElementById('public-model-form'),
publicModelName: document.getElementById('public-model-name'),
@@ -158,10 +147,8 @@
try {
const data = await api('/api/admin/models');
state.opencodeModels = data.opencodeModels || [];
state.opencodeChain = data.opencodeChain || [];
state.publicModels = data.publicModels || [];
renderOpencodeModels();
renderOpencodeChain();
renderPublicModels();
} catch (err) {
console.error('Failed to load models:', err);
@@ -212,46 +199,6 @@
});
}
// Render OpenCode Chain
function renderOpencodeChain() {
if (!el.chainList) return;
el.chainList.innerHTML = '';
if (el.chainCount) {
el.chainCount.textContent = state.opencodeChain.length.toString();
}
if (!state.opencodeChain.length) {
el.chainList.innerHTML = '<div class="muted">No fallback chain configured. Add providers above.</div>';
return;
}
state.opencodeChain.forEach((entry, idx) => {
const row = document.createElement('div');
row.className = 'provider-row slim';
row.innerHTML = `
<div class="provider-row-header">
<div class="model-chip">
<span class="pill" style="background: ${idx === 0 ? 'var(--shopify-green)' : 'var(--primary)'}; font-weight: 700;">${idx === 0 ? 'Primary' : `#${idx + 1}`}</span>
<span class="pill" style="background: var(--primary);">${entry.provider}</span>
<span>${entry.model}</span>
</div>
<div class="provider-row-actions">
<button class="ghost move-up" ${idx === 0 ? 'disabled' : ''}>↑</button>
<button class="ghost move-down" ${idx === state.opencodeChain.length - 1 ? 'disabled' : ''}>↓</button>
<button class="ghost delete-btn">Remove</button>
</div>
</div>
`;
row.querySelector('.move-up')?.addEventListener('click', () => moveChainItem(idx, -1));
row.querySelector('.move-down')?.addEventListener('click', () => moveChainItem(idx, 1));
row.querySelector('.delete-btn')?.addEventListener('click', () => removeChainItem(idx));
el.chainList.appendChild(row);
});
}
// Render Public Models
function renderPublicModels() {
if (!el.publicModelsList) return;
@@ -316,27 +263,6 @@
}
}
// Move Chain Item
async function moveChainItem(fromIdx, direction) {
const toIdx = fromIdx + direction;
if (toIdx < 0 || toIdx >= state.opencodeChain.length) return;
const newOrder = [...state.opencodeChain];
const [item] = newOrder.splice(fromIdx, 1);
newOrder.splice(toIdx, 0, item);
try {
await api('/api/admin/chain/reorder', {
method: 'POST',
body: JSON.stringify({ chain: newOrder }),
});
state.opencodeChain = newOrder;
renderOpencodeChain();
} catch (err) {
console.error('Failed to reorder chain:', err);
}
}
// Move Public Model
async function movePublicModel(fromIdx, direction) {
const toIdx = fromIdx + direction;
@@ -368,21 +294,6 @@
}
}
// Remove Chain Item
async function removeChainItem(idx) {
const newChain = state.opencodeChain.filter((_, i) => i !== idx);
try {
await api('/api/admin/chain', {
method: 'POST',
body: JSON.stringify({ chain: newChain }),
});
state.opencodeChain = newChain;
renderOpencodeChain();
} catch (err) {
console.error('Failed to remove from chain:', err);
}
}
// Form Handlers
if (el.opencodeModelForm) {
el.opencodeModelForm.addEventListener('submit', async (e) => {
@@ -425,33 +336,6 @@
});
}
if (el.chainForm) {
el.chainForm.addEventListener('submit', async (e) => {
e.preventDefault();
const provider = el.chainProvider.value;
const model = el.chainModel.value.trim();
if (!model) {
setStatus(el.chainStatus, 'Model ID is required', true);
return;
}
const newChain = [...state.opencodeChain, { provider, model }];
try {
await api('/api/admin/chain', {
method: 'POST',
body: JSON.stringify({ chain: newChain }),
});
setStatus(el.chainStatus, 'Added to chain');
el.chainModel.value = '';
await loadModels();
} catch (err) {
setStatus(el.chainStatus, err.message, true);
}
});
}
if (el.publicModelForm) {
el.publicModelForm.addEventListener('submit', async (e) => {
e.preventDefault();