101 lines
3.3 KiB
TypeScript
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
|
|
},
|
|
},
|
|
})
|