feat(agent-manager): effort selection in compare models, fix worktree prompt scrollbars

This commit is contained in:
marius-kilocode
2026-07-20 12:09:31 +02:00
parent 79fe75745f
commit 210a6bbf9b
31 changed files with 204 additions and 13 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"kilo-code": minor
---
Support choosing a reasoning effort per model in the Agent Manager Compare Models picker, so compared worktrees can run the same prompt at different effort levels. The selected effort is shown next to the model name in the collapsed selector.
+5
View File
@@ -0,0 +1,5 @@
---
"kilo-code": patch
---
Fix double scrollbars in the Agent Manager new-worktree prompt field and widen the dialog so longer prompts stay readable. The prompt box now grows with its content like the sidebar chat input, the textarea is the only element that scrolls, and manual resize of the prompt area keeps working.
@@ -4,11 +4,13 @@ export interface ModelAllocation {
providerID: string
modelID: string
count: number
variant?: string
}
interface ModelRef {
providerID: string
modelID: string
variant?: string
}
/**
@@ -32,7 +34,7 @@ export function resolveVersionModels(
for (const alloc of allocations) {
const clamped = Math.min(Math.max(Math.floor(alloc.count) || 0, 0), MAX_MULTI_VERSIONS)
for (let c = 0; c < clamped; c++) {
models.push({ providerID: alloc.providerID, modelID: alloc.modelID })
models.push({ providerID: alloc.providerID, modelID: alloc.modelID, variant: alloc.variant })
}
if (models.length >= MAX_MULTI_VERSIONS) break
}
@@ -98,7 +100,8 @@ export function buildInitialMessages(
if (prompt) {
msg.text = prompt
msg.agent = agent
msg.variant = variant
// A per-allocation effort pick wins over the dialog-level variant.
msg.variant = model?.variant ?? variant
msg.files = files
}
return msg
@@ -445,7 +445,7 @@ interface CreateMultiVersionIn {
files?: Array<{ mime: string; url: string }>
baseBranch?: string
branchName?: string
modelAllocations?: Array<{ providerID: string; modelID: string; count: number }>
modelAllocations?: Array<{ providerID: string; modelID: string; count: number; variant?: string }>
/** When set, reconcile each created session's sandbox override to this state. */
sandbox?: boolean
}
@@ -7,6 +7,7 @@ import {
remaining,
toggleModel,
setAllocationCount,
setAllocationVariant,
maxAllocationCount,
MAX_MULTI_VERSIONS,
} from "../../webview-ui/agent-manager/multi-model-utils"
@@ -41,6 +42,24 @@ describe("multi-model-utils", () => {
expect(arr).toContainEqual({ providerID: "b", modelID: "m2", count: 1 })
})
test("allocationsToArray includes variant when set", () => {
const alloc = setAllocationVariant(make(["a", "m1", "Model 1", 1]), "a", "m1", "high")
expect(allocationsToArray(alloc)).toContainEqual({ providerID: "a", modelID: "m1", count: 1, variant: "high" })
})
test("setAllocationVariant sets and clears the variant", () => {
const alloc = make(["a", "m1", "Model 1", 1])
const set = setAllocationVariant(alloc, "a", "m1", "high")
expect(set.get("a/m1")?.variant).toBe("high")
expect(setAllocationVariant(set, "a", "m1", undefined).get("a/m1")?.variant).toBeUndefined()
})
test("setAllocationVariant preserves count and does nothing for unknown models", () => {
const alloc = make(["a", "m1", "Model 1", 2])
expect(setAllocationVariant(alloc, "a", "m1", "high").get("a/m1")?.count).toBe(2)
expect(setAllocationVariant(alloc, "b", "m2", "high")).toBe(alloc)
})
test("remaining returns slots left", () => {
const alloc = make(["a", "m1", "Model 1", 2], ["b", "m2", "Model 2", 1])
expect(remaining(alloc)).toBe(MAX_MULTI_VERSIONS - 3)
@@ -0,0 +1,57 @@
import { describe, expect, test } from "bun:test"
import { resolveVersionModels, buildInitialMessages, type CreatedVersion } from "../../src/agent-manager/multi-version"
const created = (n: number): CreatedVersion[] =>
Array.from({ length: n }, (_, i) => ({
worktreeId: `wt-${i}`,
sessionId: `ses-${i}`,
path: `/tmp/wt-${i}`,
branch: `branch-${i}`,
parentBranch: "main",
versionIndex: i,
}))
describe("resolveVersionModels", () => {
test("expands allocations with per-model variants", () => {
const { models, versions } = resolveVersionModels(
[
{ providerID: "a", modelID: "m1", count: 2, variant: "high" },
{ providerID: "b", modelID: "m2", count: 1 },
],
undefined,
1,
)
expect(versions).toBe(3)
expect(models).toEqual([
{ providerID: "a", modelID: "m1", variant: "high" },
{ providerID: "a", modelID: "m1", variant: "high" },
{ providerID: "b", modelID: "m2", variant: undefined },
])
})
test("non-compare runs carry no per-version variant", () => {
const { models } = resolveVersionModels(undefined, { providerID: "a", modelID: "m1" }, 2)
expect(models).toEqual([])
})
})
describe("buildInitialMessages", () => {
test("per-allocation variant wins over the dialog-level variant", () => {
const models = resolveVersionModels(
[
{ providerID: "a", modelID: "m1", count: 1, variant: "high" },
{ providerID: "b", modelID: "m2", count: 1 },
],
undefined,
1,
).models
const msgs = buildInitialMessages(created(2), models, {}, "do it", undefined, "low")
expect(msgs[0]?.variant).toBe("high")
expect(msgs[1]?.variant).toBe("low")
})
test("falls back to the dialog-level variant when no allocation variant is set", () => {
const msgs = buildInitialMessages(created(1), [], { providerID: "a", modelID: "m1" }, "do it", undefined, "medium")
expect(msgs[0]?.variant).toBe("medium")
})
})
@@ -18,6 +18,7 @@ import {
totalAllocations,
toggleModel,
setAllocationCount,
setAllocationVariant,
maxAllocationCount,
} from "./multi-model-utils"
@@ -96,6 +97,7 @@ export const MultiModelSelector: Component<{
const checked = () => props.allocations.has(key())
const entry = () => props.allocations.get(key())
const disabled = () => !checked() && totalAllocations(props.allocations) >= MAX_MULTI_VERSIONS
const efforts = () => Object.keys(model.variants ?? {})
return (
<div
@@ -135,6 +137,27 @@ export const MultiModelSelector: Component<{
</Show>
</label>
<Show when={checked()}>
<Show when={efforts().length > 0}>
<select
class="am-mm-count-select am-mm-variant-select"
value={entry()?.variant ?? ""}
title={t("agentManager.dialog.compareModels.effort")}
aria-label={t("agentManager.dialog.compareModels.effort")}
onChange={(e) =>
props.onChange(
setAllocationVariant(
props.allocations,
model.providerID,
model.id,
e.currentTarget.value || undefined,
),
)
}
>
<option value="">{t("agentManager.dialog.compareModels.effortDefault")}</option>
<For each={efforts()}>{(v) => <option value={v}>{v}</option>}</For>
</select>
</Show>
<select
class="am-mm-count-select"
value={entry()?.count ?? 1}
@@ -245,6 +245,7 @@ export const NewWorktreeDialog: Component<{ onClose: () => void; defaultBaseBran
createEffect(() => persistImages(imageAttach.images()))
let textareaRef: HTMLTextAreaElement | undefined
let containerRef: HTMLDivElement | undefined
onMount(() => {
setBranchesLoading(true)
@@ -340,9 +341,16 @@ export const NewWorktreeDialog: Component<{ onClose: () => void; defaultBaseBran
}
const adjustHeight = () => {
if (!textareaRef) return
textareaRef.style.height = "auto"
textareaRef.style.height = `${Math.min(textareaRef.scrollHeight, 200)}px`
const box = containerRef
const area = textareaRef
if (!box || !area) return
// Grow the container with the prompt (same 200px auto-grow cap as the
// sidebar prompt), never the textarea: it fills the container and is the
// only element that scrolls. A manual container resize persists until the
// next input re-fits the height.
box.style.height = "auto"
const chrome = box.offsetHeight - area.offsetHeight
box.style.height = `${Math.min(area.scrollHeight, 200) + chrome}px`
}
const insertSpeechText = (value: string) => {
@@ -491,6 +499,7 @@ export const NewWorktreeDialog: Component<{ onClose: () => void; defaultBaseBran
/>
{/* Prompt input — reuses the sidebar chat-input base classes for consistent styling */}
<div
ref={containerRef}
class="prompt-input-container am-prompt-input-container"
classList={{ "prompt-input-container--dragging": imageAttach.dragging() }}
onDragOver={imageAttach.handleDragOver}
@@ -841,7 +850,9 @@ export const NewWorktreeDialog: Component<{ onClose: () => void; defaultBaseBran
}
>
<span class="am-selector-value">
{[...modelAllocations().values()].map((e) => e.name).join(", ")}
{[...modelAllocations().values()]
.map((e) => (e.variant ? `${e.name} (${e.variant})` : e.name))
.join(", ")}
</span>
</Show>
</span>
@@ -2658,10 +2658,13 @@ body.am-wt-dragging-active * {
min-height: 0;
}
/* Allow portal-based dropdowns to escape the dialog bounds */
/* Allow portal-based dropdowns to escape the dialog bounds.
Wider than the kilo-ui default so the prompt stays readable for long input. */
[data-component="dialog"]:has(.am-nv-dialog) [data-slot="dialog-content"] {
overflow: visible;
max-height: 85vh;
width: 640px;
max-width: 92vw;
}
/* Scrollable form content area — keeps submit button always visible */
@@ -2702,7 +2705,10 @@ body.am-wt-dragging-active * {
color: var(--vscode-input-placeholderForeground, var(--text-weaker));
}
/* Dialog overrides for prompt-input-container — resizable from bottom edge */
/* Dialog overrides for prompt-input-container — resizable from bottom edge.
The container is the only element that changes size (auto-grow + manual
resize); the textarea always fills it and is the only element that scrolls,
so long prompts never produce nested scrollbars. */
.am-nv-dialog .am-prompt-input-container {
margin: 0;
resize: vertical;
@@ -2716,8 +2722,7 @@ body.am-wt-dragging-active * {
.am-nv-dialog .am-prompt-input-wrapper {
flex: 1;
min-height: 0;
overflow-x: hidden;
overflow-y: auto;
overflow: hidden;
}
/* While any inline (non-portaled) selector popover is open, let it escape the
@@ -2740,8 +2745,9 @@ body.am-wt-dragging-active * {
color: var(--vscode-input-foreground, var(--text-base));
resize: none;
width: 100%;
min-height: 100%;
height: 100%;
max-height: none;
overflow-y: auto;
}
.am-nv-config-label {
@@ -2918,6 +2924,7 @@ body.am-wt-dragging-active * {
display: flex;
align-items: center;
justify-content: space-between;
gap: 6px;
padding: 4px 10px;
min-height: 30px;
transition: background 80ms;
@@ -3014,6 +3021,11 @@ body.am-wt-dragging-active * {
border-color: var(--border-focus);
}
.am-mm-variant-select {
max-width: 110px;
text-overflow: ellipsis;
}
.am-nv-spinner {
width: 14px;
height: 14px;
@@ -121,6 +121,8 @@ export const dict = {
"agentManager.dialog.compareModels.tooltip": "تشغيل الوكلاء على نماذج مختلفة بالتوازي لمقارنة النتائج",
"agentManager.dialog.compareModels.searchModels": "البحث عن النماذج...",
"agentManager.dialog.compareModels.selectModels": "اختر النماذج...",
"agentManager.dialog.compareModels.effort": "جهد الاستدلال",
"agentManager.dialog.compareModels.effortDefault": "افتراضي",
"agentManager.dialog.creating": "جارٍ الإنشاء...",
"agentManager.dialog.createWorktree": "إنشاء شجرة العمل",
"agentManager.dialog.removeImage": "إزالة الصورة",
@@ -124,6 +124,8 @@ export const dict = {
"Execute agentes em diferentes modelos em paralelo para comparar resultados",
"agentManager.dialog.compareModels.searchModels": "Pesquisar modelos...",
"agentManager.dialog.compareModels.selectModels": "Selecionar modelos...",
"agentManager.dialog.compareModels.effort": "Esforço de raciocínio",
"agentManager.dialog.compareModels.effortDefault": "Padrão",
"agentManager.dialog.creating": "Criando...",
"agentManager.dialog.createWorktree": "Criar Worktree",
"agentManager.dialog.removeImage": "Remover imagem",
@@ -124,6 +124,8 @@ export const dict = {
"Pokrenite agente na različitim modelima paralelno radi usporedbe rezultata",
"agentManager.dialog.compareModels.searchModels": "Pretraži modele...",
"agentManager.dialog.compareModels.selectModels": "Odaberi modele...",
"agentManager.dialog.compareModels.effort": "Napor zaključivanja",
"agentManager.dialog.compareModels.effortDefault": "Zadano",
"agentManager.dialog.creating": "Kreiranje...",
"agentManager.dialog.createWorktree": "Kreiraj worktree",
"agentManager.dialog.removeImage": "Ukloni sliku",
@@ -125,6 +125,8 @@ export const dict = {
"Kør agenter på forskellige modeller parallelt for at sammenligne resultater",
"agentManager.dialog.compareModels.searchModels": "Søg modeller...",
"agentManager.dialog.compareModels.selectModels": "Vælg modeller...",
"agentManager.dialog.compareModels.effort": "Ræsonnementsindsats",
"agentManager.dialog.compareModels.effortDefault": "Standard",
"agentManager.dialog.creating": "Opretter...",
"agentManager.dialog.createWorktree": "Opret Worktree",
"agentManager.dialog.removeImage": "Fjern billede",
@@ -125,6 +125,8 @@ export const dict = {
"Agenten parallel auf verschiedenen Modellen ausführen, um Ergebnisse zu vergleichen",
"agentManager.dialog.compareModels.searchModels": "Modelle suchen...",
"agentManager.dialog.compareModels.selectModels": "Modelle auswählen...",
"agentManager.dialog.compareModels.effort": "Reasoning-Aufwand",
"agentManager.dialog.compareModels.effortDefault": "Standard",
"agentManager.dialog.creating": "Wird erstellt...",
"agentManager.dialog.createWorktree": "Worktree erstellen",
"agentManager.dialog.removeImage": "Bild entfernen",
@@ -127,6 +127,8 @@ export const dict = {
"agentManager.dialog.compareModels.tooltip": "Run agents on different models in parallel to compare results",
"agentManager.dialog.compareModels.searchModels": "Search models...",
"agentManager.dialog.compareModels.selectModels": "Select models...",
"agentManager.dialog.compareModels.effort": "Reasoning effort",
"agentManager.dialog.compareModels.effortDefault": "Default",
"agentManager.dialog.creating": "Creating...",
"agentManager.dialog.createWorktree": "Create Worktree",
"agentManager.dialog.removeImage": "Remove image",
@@ -124,6 +124,8 @@ export const dict = {
"Ejecuta agentes en diferentes modelos en paralelo para comparar resultados",
"agentManager.dialog.compareModels.searchModels": "Buscar modelos...",
"agentManager.dialog.compareModels.selectModels": "Seleccionar modelos...",
"agentManager.dialog.compareModels.effort": "Esfuerzo de razonamiento",
"agentManager.dialog.compareModels.effortDefault": "Predeterminado",
"agentManager.dialog.creating": "Creando...",
"agentManager.dialog.createWorktree": "Crear Worktree",
"agentManager.dialog.removeImage": "Eliminar imagen",
@@ -124,6 +124,8 @@ export const dict = {
"Exécutez des agents sur différents modèles en parallèle pour comparer les résultats",
"agentManager.dialog.compareModels.searchModels": "Rechercher des modèles...",
"agentManager.dialog.compareModels.selectModels": "Sélectionner des modèles...",
"agentManager.dialog.compareModels.effort": "Effort de raisonnement",
"agentManager.dialog.compareModels.effortDefault": "Par défaut",
"agentManager.dialog.creating": "Création...",
"agentManager.dialog.createWorktree": "Créer un worktree",
"agentManager.dialog.removeImage": "Supprimer l'image",
@@ -129,6 +129,8 @@ export const dict = {
"Esegui agenti su modelli diversi in parallelo per confrontare i risultati",
"agentManager.dialog.compareModels.searchModels": "Cerca modelli...",
"agentManager.dialog.compareModels.selectModels": "Seleziona modelli...",
"agentManager.dialog.compareModels.effort": "Sforzo di ragionamento",
"agentManager.dialog.compareModels.effortDefault": "Predefinito",
"agentManager.dialog.creating": "Creazione...",
"agentManager.dialog.createWorktree": "Crea worktree",
"agentManager.dialog.removeImage": "Rimuovi immagine",
@@ -123,6 +123,8 @@ export const dict = {
"agentManager.dialog.compareModels.tooltip": "異なるモデルでエージェントを並行実行し、結果を比較します",
"agentManager.dialog.compareModels.searchModels": "モデルを検索...",
"agentManager.dialog.compareModels.selectModels": "モデルを選択...",
"agentManager.dialog.compareModels.effort": "推論エフォート",
"agentManager.dialog.compareModels.effortDefault": "デフォルト",
"agentManager.dialog.creating": "作成中...",
"agentManager.dialog.createWorktree": "ワークツリーを作成",
"agentManager.dialog.removeImage": "画像を削除",
@@ -122,6 +122,8 @@ export const dict = {
"agentManager.dialog.compareModels.tooltip": "서로 다른 모델에서 에이전트를 병렬로 실행하여 결과를 비교합니다",
"agentManager.dialog.compareModels.searchModels": "모델 검색...",
"agentManager.dialog.compareModels.selectModels": "모델 선택...",
"agentManager.dialog.compareModels.effort": "추론 노력",
"agentManager.dialog.compareModels.effortDefault": "기본",
"agentManager.dialog.creating": "생성 중...",
"agentManager.dialog.createWorktree": "워크트리 생성",
"agentManager.dialog.removeImage": "이미지 제거",
@@ -129,6 +129,8 @@ export const dict = {
"Draai agents parallel op verschillende modellen om resultaten te vergelijken",
"agentManager.dialog.compareModels.searchModels": "Zoeken naar modellen...",
"agentManager.dialog.compareModels.selectModels": "Modellen selecteren...",
"agentManager.dialog.compareModels.effort": "Redeneerinspanning",
"agentManager.dialog.compareModels.effortDefault": "Standaard",
"agentManager.dialog.creating": "Maken...",
"agentManager.dialog.createWorktree": "Worktree maken",
"agentManager.dialog.removeImage": "Afbeelding verwijderen",
@@ -123,6 +123,8 @@ export const dict = {
"Kjør agenter på forskjellige modeller parallelt for å sammenligne resultater",
"agentManager.dialog.compareModels.searchModels": "Søk modeller...",
"agentManager.dialog.compareModels.selectModels": "Velg modeller...",
"agentManager.dialog.compareModels.effort": "Resonneringsinnsats",
"agentManager.dialog.compareModels.effortDefault": "Standard",
"agentManager.dialog.creating": "Oppretter...",
"agentManager.dialog.createWorktree": "Opprett worktree",
"agentManager.dialog.removeImage": "Fjern bilde",
@@ -123,6 +123,8 @@ export const dict = {
"agentManager.dialog.compareModels.tooltip": "Uruchom agentów na różnych modelach równolegle, aby porównać wyniki",
"agentManager.dialog.compareModels.searchModels": "Szukaj modeli...",
"agentManager.dialog.compareModels.selectModels": "Wybierz modele...",
"agentManager.dialog.compareModels.effort": "Wysiłek rozumowania",
"agentManager.dialog.compareModels.effortDefault": "Domyślny",
"agentManager.dialog.creating": "Tworzenie...",
"agentManager.dialog.createWorktree": "Utwórz Worktree",
"agentManager.dialog.removeImage": "Usuń obraz",
@@ -124,6 +124,8 @@ export const dict = {
"Запустите агентов на разных моделях параллельно для сравнения результатов",
"agentManager.dialog.compareModels.searchModels": "Поиск моделей...",
"agentManager.dialog.compareModels.selectModels": "Выбрать модели...",
"agentManager.dialog.compareModels.effort": "Усилие рассуждения",
"agentManager.dialog.compareModels.effortDefault": "По умолчанию",
"agentManager.dialog.creating": "Создание...",
"agentManager.dialog.createWorktree": "Создать worktree",
"agentManager.dialog.removeImage": "Удалить изображение",
@@ -119,6 +119,8 @@ export const dict = {
"agentManager.dialog.compareModels.tooltip": "เรียกใช้เอเจนต์บนโมเดลต่าง ๆ พร้อมกันเพื่อเปรียบเทียบผลลัพธ์",
"agentManager.dialog.compareModels.searchModels": "ค้นหาโมเดล...",
"agentManager.dialog.compareModels.selectModels": "เลือกโมเดล...",
"agentManager.dialog.compareModels.effort": "ระดับการใช้เหตุผล",
"agentManager.dialog.compareModels.effortDefault": "ค่าเริ่มต้น",
"agentManager.dialog.creating": "กำลังสร้าง...",
"agentManager.dialog.createWorktree": "สร้าง Worktree",
"agentManager.dialog.removeImage": "ลบรูปภาพ",
@@ -130,6 +130,8 @@ export const dict = {
"Sonuçları karşılaştırmak için agent'ları paralel olarak farklı modellerde çalıştırın",
"agentManager.dialog.compareModels.searchModels": "Modelleri ara...",
"agentManager.dialog.compareModels.selectModels": "Modelleri seç...",
"agentManager.dialog.compareModels.effort": "Akıl yürütme çabası",
"agentManager.dialog.compareModels.effortDefault": "Varsayılan",
"agentManager.dialog.creating": "Oluşturuluyor...",
"agentManager.dialog.createWorktree": "Worktree Oluştur",
"agentManager.dialog.removeImage": "Görüntüyü kaldır",
@@ -131,6 +131,8 @@ export const dict = {
"Запустіть агентів на різних моделях паралельно для порівняння результатів",
"agentManager.dialog.compareModels.searchModels": "Пошук моделей...",
"agentManager.dialog.compareModels.selectModels": "Оберіть моделі...",
"agentManager.dialog.compareModels.effort": "Зусилля міркування",
"agentManager.dialog.compareModels.effortDefault": "За замовчуванням",
"agentManager.dialog.creating": "Створення...",
"agentManager.dialog.createWorktree": "Створити робоче дерево",
"agentManager.dialog.removeImage": "Видалити зображення",
@@ -118,6 +118,8 @@ export const dict = {
"agentManager.dialog.compareModels.tooltip": "在不同模型上并行运行代理以比较结果",
"agentManager.dialog.compareModels.searchModels": "搜索模型...",
"agentManager.dialog.compareModels.selectModels": "选择模型...",
"agentManager.dialog.compareModels.effort": "推理强度",
"agentManager.dialog.compareModels.effortDefault": "默认",
"agentManager.dialog.creating": "创建中...",
"agentManager.dialog.createWorktree": "创建工作树",
"agentManager.dialog.removeImage": "移除图片",
@@ -118,6 +118,8 @@ export const dict = {
"agentManager.dialog.compareModels.tooltip": "在不同模型上並行執行代理以比較結果",
"agentManager.dialog.compareModels.searchModels": "搜尋模型...",
"agentManager.dialog.compareModels.selectModels": "選擇模型...",
"agentManager.dialog.compareModels.effort": "推理強度",
"agentManager.dialog.compareModels.effortDefault": "預設",
"agentManager.dialog.creating": "建立中...",
"agentManager.dialog.createWorktree": "建立工作樹",
"agentManager.dialog.removeImage": "移除圖片",
@@ -8,6 +8,7 @@ export interface ModelAllocationEntry {
modelID: string
name: string
count: number
variant?: string
}
export type ModelAllocations = Map<string, ModelAllocationEntry>
@@ -25,7 +26,7 @@ export function totalAllocations(allocations: ModelAllocations): number {
export function allocationsToArray(allocations: ModelAllocations): ModelAllocation[] {
const result: ModelAllocation[] = []
for (const entry of allocations.values()) {
result.push({ providerID: entry.providerID, modelID: entry.modelID, count: entry.count })
result.push({ providerID: entry.providerID, modelID: entry.modelID, count: entry.count, variant: entry.variant })
}
return result
}
@@ -67,6 +68,20 @@ export function setAllocationCount(
return next
}
export function setAllocationVariant(
allocations: ModelAllocations,
providerID: string,
modelID: string,
variant: string | undefined,
): ModelAllocations {
const key = allocationKey(providerID, modelID)
const existing = allocations.get(key)
if (!existing) return allocations
const next = new Map(allocations)
next.set(key, { ...existing, variant })
return next
}
export function maxAllocationCount(allocations: ModelAllocations, providerID: string, modelID: string): number {
const key = allocationKey(providerID, modelID)
const existing = allocations.get(key)
@@ -195,6 +195,7 @@ export interface ModelAllocation {
providerID: string
modelID: string
count: number
variant?: string
}
export type ContinueInWorktreeStatus =