/** * Dashboard-local agent UI state and agent mutations. * * Canonical agent, model and runtime reads live in the OpenClaw Vue Query * boundary. This store intentionally owns only modal selection and the * model-change command used by the orchestration canvas. */ import { defineStore } from 'pinia' import { apiFetch } from '../services/api' import type { AgentNodeData } from '../composables/useFlowLayout' import type { AgentDetailData } from '../components/dashboard/v2/types' import type { OpenClawOperation } from '../types/openclaw' import { createMutationRequestContext } from '../services/mutationContext' import { reportOperationEnvelope } from '../services/operationResults' import { invalidateOpenClawRuntime } from '../api/openclawRuntime' export function buildAgentDetail( data: AgentNodeData, models: { id: string; alias: string }[], ): AgentDetailData { const tokenNum = data.tokens ? parseFloat(data.tokens.replace(/[^0-9.]/g, '')) : Number.NaN const tokenMultiplier = data.tokens?.includes('M') ? 1_000_000 : data.tokens?.includes('k') ? 1_000 : 1 const tokensToday = Number.isFinite(tokenNum) ? Math.round(tokenNum * tokenMultiplier) : null const costNum = data.cost ? parseFloat(data.cost) : Number.NaN const matchingModel = models.find(model => model.id === data.model || model.alias === data.model, ) return { id: data.id, name: data.name, role: data.role, roleBadge: data.roleBadge || 'badge-slate', model: matchingModel?.alias ?? data.model, status: data.status === 'block' ? 'idle' : data.status, statusLabel: data.statusLabel, task: data.task, goal: data.goal, progress: data.progress, elapsed: data.elapsed, next: data.next, tokens: data.tokens, cost: data.cost, statusDetail: data.statusDetail, md: data.md, tokensToday, costToday: Number.isFinite(costNum) ? costNum : null, workload: null, uptime: data.elapsed, lastActive: data.elapsed ? `Vor ${data.elapsed}` : 'Nicht gemeldet', activeTaskCount: data.task ? 1 : 0, activity: [], availableModels: models, } } export const useAgentStore = defineStore('agents', { state: () => ({ selectedAgentId: null as string | null, error: null as string | null, }), actions: { async changeModel(agentId: string, modelId: string) { this.error = null try { const requestContext = createMutationRequestContext('openclaw-session-model') const response = await apiFetch('/api/v1/openclaw/sessions/model', { method: 'POST', headers: requestContext.headers, body: JSON.stringify({ sessionKey: `agent:${agentId}:main`, model: modelId, }), }) const result: OpenClawOperation> = await response.json() reportOperationEnvelope(result, 'Agent-Modell aktualisiert') if (!response.ok || !result.ok) { throw new Error(result.recovery || result.message) } await invalidateOpenClawRuntime() } catch (error) { console.warn('[AgentStore] changeModel failed', error) this.error = error instanceof Error ? error.message : 'OpenClaw model update failed' } }, selectAgent(id: string | null) { this.selectedAgentId = id }, }, })