@cat-factory/app 0.7.4 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/components/board/AddTaskModal.vue +45 -0
- package/app/components/layout/BoardToolbar.vue +0 -16
- package/app/components/layout/CommandBar.vue +4 -4
- package/app/components/layout/SideBar.vue +25 -2
- package/app/components/panels/inspector/TaskRunSettings.vue +59 -0
- package/app/components/pipeline/PipelineBuilder.vue +2 -2
- package/app/components/settings/ModelConfigurationPanel.vue +487 -0
- package/app/components/settings/OpenRouterCatalogPanel.vue +176 -0
- package/app/composables/api/board.ts +1 -0
- package/app/composables/api/models.ts +16 -12
- package/app/composables/api/presets.ts +24 -1
- package/app/pages/index.vue +8 -2
- package/app/stores/board.ts +2 -0
- package/app/stores/modelPresets.ts +65 -0
- package/app/stores/openrouter.ts +52 -0
- package/app/stores/ui.ts +19 -8
- package/app/stores/workspace.ts +2 -3
- package/app/types/domain.ts +5 -11
- package/app/types/model-presets.ts +33 -0
- package/app/types/models.ts +4 -4
- package/app/types/openrouter.ts +45 -0
- package/package.json +2 -2
- package/app/components/settings/ModelDefaultsPanel.vue +0 -250
- package/app/stores/modelDefaults.ts +0 -76
|
@@ -18,6 +18,7 @@ const board = useBoardStore()
|
|
|
18
18
|
const documents = useDocumentsStore()
|
|
19
19
|
const tasks = useTasksStore()
|
|
20
20
|
const mergePresets = useMergePresetsStore()
|
|
21
|
+
const modelPresets = useModelPresetsStore()
|
|
21
22
|
const pipelines = usePipelinesStore()
|
|
22
23
|
const agentConfig = useAgentConfigStore()
|
|
23
24
|
const toast = useToast()
|
|
@@ -94,6 +95,7 @@ const recurringFrameId = computed(() => {
|
|
|
94
95
|
// Run configuration picked up front. Empty string = use the default (workspace
|
|
95
96
|
// default merge preset / no pinned pipeline).
|
|
96
97
|
const mergePresetId = ref('')
|
|
98
|
+
const modelPresetId = ref('')
|
|
97
99
|
const pipelineId = ref('')
|
|
98
100
|
|
|
99
101
|
const presetMenu = computed(() => [
|
|
@@ -121,6 +123,32 @@ const selectedPresetLabel = computed(() => {
|
|
|
121
123
|
return mergePresets.presets.find((p) => p.id === mergePresetId.value)?.name ?? 'Workspace default'
|
|
122
124
|
})
|
|
123
125
|
|
|
126
|
+
// Model preset: which model each agent runs on. Empty = workspace default preset.
|
|
127
|
+
const modelPresetMenu = computed(() => [
|
|
128
|
+
[
|
|
129
|
+
{
|
|
130
|
+
label: modelPresets.defaultPreset
|
|
131
|
+
? `Default (${modelPresets.defaultPreset.name})`
|
|
132
|
+
: 'Workspace default',
|
|
133
|
+
icon: 'i-lucide-rotate-ccw',
|
|
134
|
+
onSelect: () => (modelPresetId.value = ''),
|
|
135
|
+
},
|
|
136
|
+
...modelPresets.presets.map((p) => ({
|
|
137
|
+
label: p.name,
|
|
138
|
+
icon: 'i-lucide-cpu',
|
|
139
|
+
onSelect: () => (modelPresetId.value = p.id),
|
|
140
|
+
})),
|
|
141
|
+
],
|
|
142
|
+
])
|
|
143
|
+
const selectedModelPresetLabel = computed(() => {
|
|
144
|
+
if (!modelPresetId.value) {
|
|
145
|
+
return modelPresets.defaultPreset
|
|
146
|
+
? `Default (${modelPresets.defaultPreset.name})`
|
|
147
|
+
: 'Workspace default'
|
|
148
|
+
}
|
|
149
|
+
return modelPresets.presets.find((p) => p.id === modelPresetId.value)?.name ?? 'Workspace default'
|
|
150
|
+
})
|
|
151
|
+
|
|
124
152
|
const pipelineMenu = computed(() => [
|
|
125
153
|
[
|
|
126
154
|
{
|
|
@@ -172,6 +200,7 @@ watch(open, (isOpen) => {
|
|
|
172
200
|
timeboxHours.value = undefined
|
|
173
201
|
docKind.value = ''
|
|
174
202
|
mergePresetId.value = ''
|
|
203
|
+
modelPresetId.value = ''
|
|
175
204
|
pipelineId.value = ''
|
|
176
205
|
agentConfigValues.value = {}
|
|
177
206
|
pendingContext.value = []
|
|
@@ -208,6 +237,7 @@ async function add() {
|
|
|
208
237
|
taskType: taskType.value as CreateTaskType,
|
|
209
238
|
...(typeFields ? { taskTypeFields: typeFields } : {}),
|
|
210
239
|
...(mergePresetId.value ? { mergePresetId: mergePresetId.value } : {}),
|
|
240
|
+
...(modelPresetId.value ? { modelPresetId: modelPresetId.value } : {}),
|
|
211
241
|
...(pipelineId.value ? { pipelineId: pipelineId.value } : {}),
|
|
212
242
|
...(Object.keys(agentConfigValues.value).length
|
|
213
243
|
? { agentConfig: agentConfigValues.value }
|
|
@@ -381,6 +411,21 @@ async function add() {
|
|
|
381
411
|
</UButton>
|
|
382
412
|
</UDropdownMenu>
|
|
383
413
|
</UFormField>
|
|
414
|
+
|
|
415
|
+
<UFormField label="Model preset">
|
|
416
|
+
<UDropdownMenu :items="modelPresetMenu" class="w-full">
|
|
417
|
+
<UButton
|
|
418
|
+
color="neutral"
|
|
419
|
+
variant="subtle"
|
|
420
|
+
size="sm"
|
|
421
|
+
icon="i-lucide-cpu"
|
|
422
|
+
trailing-icon="i-lucide-chevron-down"
|
|
423
|
+
class="w-full justify-between"
|
|
424
|
+
>
|
|
425
|
+
{{ selectedModelPresetLabel }}
|
|
426
|
+
</UButton>
|
|
427
|
+
</UDropdownMenu>
|
|
428
|
+
</UFormField>
|
|
384
429
|
</div>
|
|
385
430
|
|
|
386
431
|
<div v-if="configDescriptors.length" class="space-y-3">
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { useBoardFlow } from '~/composables/useBoardFlow'
|
|
3
3
|
import NotificationsInbox from '~/components/layout/NotificationsInbox.vue'
|
|
4
|
-
import VendorCredentialsModal from '~/components/providers/VendorCredentialsModal.vue'
|
|
5
|
-
import PersonalCredentialModal from '~/components/providers/PersonalCredentialModal.vue'
|
|
6
4
|
|
|
7
5
|
const ui = useUiStore()
|
|
8
6
|
const board = useBoardStore()
|
|
@@ -127,20 +125,6 @@ const decisionItems = computed(() =>
|
|
|
127
125
|
<!-- human-actionable notifications (merge review, pipeline complete, CI failed) -->
|
|
128
126
|
<NotificationsInbox />
|
|
129
127
|
|
|
130
|
-
<!-- LLM vendor subscriptions (Claude Code / Codex token pool) -->
|
|
131
|
-
<UButton
|
|
132
|
-
color="neutral"
|
|
133
|
-
variant="ghost"
|
|
134
|
-
size="sm"
|
|
135
|
-
icon="i-lucide-key-round"
|
|
136
|
-
title="Connect LLM vendor subscriptions (Claude Code / Codex)"
|
|
137
|
-
@click="ui.openVendorCredentials()"
|
|
138
|
-
>
|
|
139
|
-
Vendors
|
|
140
|
-
</UButton>
|
|
141
|
-
<VendorCredentialsModal />
|
|
142
|
-
<PersonalCredentialModal />
|
|
143
|
-
|
|
144
128
|
<!-- spend safeguard usage -->
|
|
145
129
|
<UButton
|
|
146
130
|
v-if="showSpend"
|
|
@@ -184,12 +184,12 @@ const commands = computed<Command[]>(() => {
|
|
|
184
184
|
run: () => ui.openWorkspaceSettings(),
|
|
185
185
|
})
|
|
186
186
|
list.push({
|
|
187
|
-
id: 'model-
|
|
188
|
-
label: '
|
|
187
|
+
id: 'model-configuration',
|
|
188
|
+
label: 'Model Configuration',
|
|
189
189
|
group: 'Workspace',
|
|
190
190
|
icon: 'i-lucide-cpu',
|
|
191
|
-
keywords: 'model llm routing agent kind default',
|
|
192
|
-
run: () => ui.
|
|
191
|
+
keywords: 'model llm routing agent kind default preset configuration',
|
|
192
|
+
run: () => ui.openModelConfig(),
|
|
193
193
|
})
|
|
194
194
|
list.push({
|
|
195
195
|
id: 'service-fragment-defaults',
|
|
@@ -291,9 +291,9 @@ watch(
|
|
|
291
291
|
size="sm"
|
|
292
292
|
icon="i-lucide-cpu"
|
|
293
293
|
class="justify-start"
|
|
294
|
-
@click="ui.
|
|
294
|
+
@click="ui.openModelConfig()"
|
|
295
295
|
>
|
|
296
|
-
|
|
296
|
+
Model Configuration
|
|
297
297
|
</UButton>
|
|
298
298
|
<UButton
|
|
299
299
|
block
|
|
@@ -306,6 +306,18 @@ watch(
|
|
|
306
306
|
>
|
|
307
307
|
Default service best practices
|
|
308
308
|
</UButton>
|
|
309
|
+
<UButton
|
|
310
|
+
block
|
|
311
|
+
color="primary"
|
|
312
|
+
variant="soft"
|
|
313
|
+
size="sm"
|
|
314
|
+
icon="i-lucide-key-round"
|
|
315
|
+
class="justify-start"
|
|
316
|
+
title="Connect LLM vendor subscriptions + provider API keys"
|
|
317
|
+
@click="ui.openVendorCredentials()"
|
|
318
|
+
>
|
|
319
|
+
Vendors & keys
|
|
320
|
+
</UButton>
|
|
309
321
|
<UButton
|
|
310
322
|
block
|
|
311
323
|
color="primary"
|
|
@@ -317,6 +329,17 @@ watch(
|
|
|
317
329
|
>
|
|
318
330
|
My local runners
|
|
319
331
|
</UButton>
|
|
332
|
+
<UButton
|
|
333
|
+
block
|
|
334
|
+
color="primary"
|
|
335
|
+
variant="soft"
|
|
336
|
+
size="sm"
|
|
337
|
+
icon="i-lucide-waypoints"
|
|
338
|
+
class="justify-start"
|
|
339
|
+
@click="ui.openOpenRouter()"
|
|
340
|
+
>
|
|
341
|
+
OpenRouter models
|
|
342
|
+
</UButton>
|
|
320
343
|
</div>
|
|
321
344
|
</section>
|
|
322
345
|
|
|
@@ -7,6 +7,7 @@ const props = defineProps<{ block: Block }>()
|
|
|
7
7
|
|
|
8
8
|
const board = useBoardStore()
|
|
9
9
|
const mergePresets = useMergePresetsStore()
|
|
10
|
+
const modelPresets = useModelPresetsStore()
|
|
10
11
|
const pipelines = usePipelinesStore()
|
|
11
12
|
const accounts = useAccountsStore()
|
|
12
13
|
const tracker = useTrackerStore()
|
|
@@ -66,6 +67,32 @@ function setPreset(id: string) {
|
|
|
66
67
|
board.updateBlock(props.block.id, { mergePresetId: id })
|
|
67
68
|
}
|
|
68
69
|
|
|
70
|
+
// ---- model preset ----------------------------------------------------------
|
|
71
|
+
// Which model preset decides the model each agent step runs on. None selected → the
|
|
72
|
+
// workspace default preset. Changing it affects only steps that haven't started yet
|
|
73
|
+
// (a running step keeps the model it was dispatched with). A model pinned directly on
|
|
74
|
+
// the task still overrides the preset.
|
|
75
|
+
const selectedModelPreset = computed(() => modelPresets.resolve(props.block.modelPresetId))
|
|
76
|
+
const modelPresetMenu = computed(() => [
|
|
77
|
+
[
|
|
78
|
+
{
|
|
79
|
+
label: modelPresets.defaultPreset
|
|
80
|
+
? `Default (${modelPresets.defaultPreset.name})`
|
|
81
|
+
: 'Workspace default',
|
|
82
|
+
icon: 'i-lucide-rotate-ccw',
|
|
83
|
+
onSelect: () => setModelPreset(''),
|
|
84
|
+
},
|
|
85
|
+
...modelPresets.presets.map((p) => ({
|
|
86
|
+
label: p.name,
|
|
87
|
+
icon: 'i-lucide-cpu',
|
|
88
|
+
onSelect: () => setModelPreset(p.id),
|
|
89
|
+
})),
|
|
90
|
+
],
|
|
91
|
+
])
|
|
92
|
+
function setModelPreset(id: string) {
|
|
93
|
+
board.updateBlock(props.block.id, { modelPresetId: id })
|
|
94
|
+
}
|
|
95
|
+
|
|
69
96
|
// ---- pipeline --------------------------------------------------------------
|
|
70
97
|
// The pipeline this task's Run controls default to. None selected → the user picks
|
|
71
98
|
// at run time (the board falls back to the first defined pipeline).
|
|
@@ -189,6 +216,38 @@ const resolveOnMergeLabel = computed(() =>
|
|
|
189
216
|
</div>
|
|
190
217
|
</div>
|
|
191
218
|
|
|
219
|
+
<!-- model preset -->
|
|
220
|
+
<div>
|
|
221
|
+
<div class="mb-1 flex items-center justify-between">
|
|
222
|
+
<span class="text-[11px] font-semibold uppercase tracking-wide text-slate-400">
|
|
223
|
+
Model preset
|
|
224
|
+
</span>
|
|
225
|
+
<UDropdownMenu :items="modelPresetMenu">
|
|
226
|
+
<UButton
|
|
227
|
+
size="xs"
|
|
228
|
+
variant="ghost"
|
|
229
|
+
color="neutral"
|
|
230
|
+
icon="i-lucide-cpu"
|
|
231
|
+
trailing-icon="i-lucide-chevron-down"
|
|
232
|
+
/>
|
|
233
|
+
</UDropdownMenu>
|
|
234
|
+
</div>
|
|
235
|
+
<div v-if="selectedModelPreset" class="text-[11px] text-slate-400">
|
|
236
|
+
<span class="text-slate-300">{{ selectedModelPreset.name }}</span>
|
|
237
|
+
— base {{ selectedModelPreset.baseModelId
|
|
238
|
+
}}<span v-if="Object.keys(selectedModelPreset.overrides).length">
|
|
239
|
+
, {{ Object.keys(selectedModelPreset.overrides).length }} override(s)</span
|
|
240
|
+
>.
|
|
241
|
+
<span v-if="!block.modelPresetId" class="text-slate-500">(workspace default)</span>
|
|
242
|
+
</div>
|
|
243
|
+
<div v-else class="text-[11px] text-slate-500">
|
|
244
|
+
No preset configured — agents run on the deployment's default routing.
|
|
245
|
+
</div>
|
|
246
|
+
<p class="mt-1 text-[11px] text-slate-500">
|
|
247
|
+
Changing this affects only steps that haven't started yet.
|
|
248
|
+
</p>
|
|
249
|
+
</div>
|
|
250
|
+
|
|
192
251
|
<!-- issue-tracker writeback overrides -->
|
|
193
252
|
<div>
|
|
194
253
|
<div class="mb-1 flex items-center justify-between">
|
|
@@ -234,8 +234,8 @@ async function clone(p: Pipeline) {
|
|
|
234
234
|
variant="soft"
|
|
235
235
|
size="xs"
|
|
236
236
|
icon="i-lucide-cpu"
|
|
237
|
-
title="
|
|
238
|
-
@click="ui.
|
|
237
|
+
title="Manage model presets (which model each agent runs on)"
|
|
238
|
+
@click="ui.openModelConfig()"
|
|
239
239
|
>
|
|
240
240
|
Configure models
|
|
241
241
|
</UButton>
|