Files
nexus/frontend/src/stores/agents.ts
T
AzuTear f5552218bc
CI - Build & Test / Backend (.NET) (push) Successful in 42s
CI - Build & Test / Frontend (Vue/TS) (push) Successful in 2m46s
CI - Build & Test / Security Check (push) Successful in 3s
CI - Build & Test / Deploy Nexus (push) Successful in 56s
feat: ship agent-first mission control v0.2.57
2026-07-31 22:39:47 +02:00

101 lines
3.3 KiB
TypeScript

/**
* 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<Record<string, unknown>> = 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
},
},
})