mirror of
https://github.com/YspCoder/clawgo.git
synced 2026-05-16 09:07:36 +08:00
fix: enforce subagent prompt files and refine webui
This commit is contained in:
@@ -147,15 +147,11 @@ const Dashboard: React.FC = () => {
|
||||
</div>
|
||||
<div className="brand-card rounded-[28px] border border-zinc-800 p-5 min-h-[148px]">
|
||||
<div className="flex items-center gap-2 text-zinc-200 mb-2">
|
||||
<Workflow className="w-4 h-4 text-sky-400" />
|
||||
<div className="text-sm font-medium">{t('nodeP2P')}</div>
|
||||
</div>
|
||||
<div className="text-2xl font-semibold text-zinc-100 truncate">
|
||||
{p2pEnabled ? `${p2pConfiguredIce} ICE · ${p2pConfiguredStun} STUN` : t('disabled')}
|
||||
</div>
|
||||
<div className="mt-2 text-xs text-zinc-500">
|
||||
{t('dashboardNodeP2PDetail', { transport: p2pTransport, sessions: p2pSessions, retries: p2pRetryCount })}
|
||||
<Sparkles className="w-4 h-4 text-sky-400" />
|
||||
<div className="text-sm font-medium">{t('ekgTopProvidersWorkload')}</div>
|
||||
</div>
|
||||
<div className="text-2xl font-semibold text-zinc-100 truncate">{ekgTopProvider}</div>
|
||||
<div className="mt-2 text-xs text-zinc-500">{t('dashboardWorkloadSnapshot')}</div>
|
||||
</div>
|
||||
<div className="brand-card rounded-[28px] border border-zinc-800 p-5 min-h-[148px]">
|
||||
<div className="flex items-center gap-2 text-zinc-200 mb-2">
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Check } from 'lucide-react';
|
||||
import { useAppContext } from '../context/AppContext';
|
||||
import { formatLocalDateTime } from '../utils/time';
|
||||
|
||||
@@ -247,20 +248,29 @@ const Nodes: React.FC = () => {
|
||||
<button
|
||||
key={nodeID}
|
||||
onClick={() => setSelectedNodeID(nodeID)}
|
||||
className={`w-full text-left px-3 py-3 border-b border-zinc-800/60 hover:bg-zinc-800/20 ${active ? 'bg-indigo-500/15' : ''}`}
|
||||
className={`w-full text-left px-3 py-3 border-b border-zinc-800/60 transition-colors ${active ? 'bg-indigo-500/15' : ''}`}
|
||||
>
|
||||
<div className="text-sm font-medium text-zinc-100 truncate">{String(node?.name || nodeID)}</div>
|
||||
<div className="text-xs text-zinc-400 truncate">{nodeID} · {String(node?.os || '-')} / {String(node?.arch || '-')}</div>
|
||||
<div className="text-[11px] text-zinc-500 truncate">{String(node?.online ? t('online') : t('offline'))} · {String(node?.version || '-')}</div>
|
||||
{tags.length > 0 && (
|
||||
<div className="flex flex-wrap gap-1 mt-2">
|
||||
{tags.slice(0, 4).map((tag: string) => (
|
||||
<span key={`${nodeID}-${tag}`} className="rounded-full border border-zinc-700 bg-zinc-900/60 px-2 py-0.5 text-[10px] text-zinc-300">
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-sm font-medium text-zinc-100 truncate">{String(node?.name || nodeID)}</div>
|
||||
<div className="text-xs text-zinc-400 truncate">{nodeID} · {String(node?.os || '-')} / {String(node?.arch || '-')}</div>
|
||||
<div className="text-[11px] text-zinc-500 truncate">{String(node?.online ? t('online') : t('offline'))} · {String(node?.version || '-')}</div>
|
||||
{tags.length > 0 && (
|
||||
<div className="flex flex-wrap gap-1 mt-2">
|
||||
{tags.slice(0, 4).map((tag: string) => (
|
||||
<span key={`${nodeID}-${tag}`} className="rounded-full border border-zinc-700 bg-zinc-900/60 px-2 py-0.5 text-[10px] text-zinc-300">
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{active && (
|
||||
<span className="mt-0.5 inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-indigo-500/15 text-indigo-300">
|
||||
<Check className="w-3.5 h-3.5" />
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
@@ -416,10 +426,19 @@ const Nodes: React.FC = () => {
|
||||
<button
|
||||
key={key || `dispatch-${index}`}
|
||||
onClick={() => setSelectedDispatchKey(key)}
|
||||
className={`w-full text-left px-3 py-2 border-b border-zinc-800/60 hover:bg-zinc-800/20 ${active ? 'bg-indigo-500/15' : ''}`}
|
||||
className={`w-full text-left px-3 py-2 border-b border-zinc-800/60 transition-colors ${active ? 'bg-indigo-500/15' : ''}`}
|
||||
>
|
||||
<div className="text-sm font-medium text-zinc-100 truncate">{`${item?.action || '-'} · ${item?.used_transport || '-'}`}</div>
|
||||
<div className="text-xs text-zinc-400 truncate">{formatLocalDateTime(item?.time)} · {Number(item?.duration_ms || 0)}ms · {Number(item?.artifact_count || 0)} {t('dashboardNodeDispatchArtifacts')}</div>
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-sm font-medium text-zinc-100 truncate">{`${item?.action || '-'} · ${item?.used_transport || '-'}`}</div>
|
||||
<div className="text-xs text-zinc-400 truncate">{formatLocalDateTime(item?.time)} · {Number(item?.duration_ms || 0)}ms · {Number(item?.artifact_count || 0)} {t('dashboardNodeDispatchArtifacts')}</div>
|
||||
</div>
|
||||
{active && (
|
||||
<span className="mt-0.5 inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-indigo-500/15 text-indigo-300">
|
||||
<Check className="w-3.5 h-3.5" />
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -202,13 +202,13 @@ const Skills: React.FC = () => {
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex items-center gap-3 flex-wrap">
|
||||
<div className={`text-xs px-2 py-1 rounded-md border ${clawhubInstalled ? 'text-emerald-300 border-emerald-700/50 bg-emerald-900/20' : 'text-amber-300 border-amber-700/50 bg-amber-900/20'}`} title={clawhubPath || t('skillsClawhubNotFound')}>
|
||||
<div className={`text-xs px-2 py-1 rounded-md border font-medium ${clawhubInstalled ? 'text-emerald-200 border-emerald-500/35 bg-emerald-500/12' : 'text-amber-100 border-amber-500/45 bg-amber-500/14 shadow-[inset_0_1px_0_rgba(255,255,255,0.04)]'}`} title={clawhubPath || t('skillsClawhubNotFound')}>
|
||||
{t('skillsClawhubStatus')}: {clawhubInstalled ? t('installed') : t('notInstalled')}
|
||||
</div>
|
||||
{!clawhubInstalled && (
|
||||
<button
|
||||
onClick={installClawHubIfNeeded}
|
||||
className="flex items-center gap-2 px-4 py-2 bg-amber-600 hover:bg-amber-500 text-white rounded-xl text-sm font-medium transition-colors shadow-sm"
|
||||
className="flex items-center gap-2 px-4 py-2 rounded-xl text-sm font-medium transition-colors shadow-sm bg-cyan-500/15 text-cyan-200 border border-cyan-400/25 hover:bg-cyan-500/25 hover:border-cyan-300/35"
|
||||
>
|
||||
<Zap className="w-4 h-4" /> {t('skillsInstallNow')}
|
||||
</button>
|
||||
@@ -223,9 +223,16 @@ const Skills: React.FC = () => {
|
||||
</div>
|
||||
|
||||
{!clawhubInstalled && (
|
||||
<div className="rounded-2xl border border-amber-700/40 bg-amber-950/20 p-4 text-sm text-amber-100">
|
||||
<div className="font-medium mb-1">{t('skillsClawhubMissingTitle')}</div>
|
||||
<div className="text-amber-200/90">{t('skillsInstallPanelHint')}</div>
|
||||
<div className="rounded-2xl border border-zinc-800/80 bg-zinc-950/45 p-4 text-sm shadow-sm">
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="mt-0.5 flex h-9 w-9 shrink-0 items-center justify-center rounded-xl border border-amber-400/20 bg-amber-500/10 text-amber-300">
|
||||
<Zap className="w-4 h-4" />
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<div className="font-medium text-zinc-100 mb-1">{t('skillsClawhubMissingTitle')}</div>
|
||||
<div className="text-zinc-400 leading-6">{t('skillsInstallPanelHint')}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Check } from 'lucide-react';
|
||||
import { useAppContext } from '../context/AppContext';
|
||||
import { useUI } from '../context/UIContext';
|
||||
|
||||
@@ -8,7 +9,6 @@ type SubagentProfile = {
|
||||
name?: string;
|
||||
notify_main_policy?: string;
|
||||
role?: string;
|
||||
system_prompt?: string;
|
||||
system_prompt_file?: string;
|
||||
tool_allowlist?: string[];
|
||||
memory_namespace?: string;
|
||||
@@ -33,7 +33,6 @@ const emptyDraft: SubagentProfile = {
|
||||
name: '',
|
||||
notify_main_policy: 'final_only',
|
||||
role: '',
|
||||
system_prompt: '',
|
||||
system_prompt_file: '',
|
||||
memory_namespace: '',
|
||||
status: 'active',
|
||||
@@ -81,7 +80,6 @@ const SubagentProfiles: React.FC = () => {
|
||||
name: next.name || '',
|
||||
notify_main_policy: next.notify_main_policy || 'final_only',
|
||||
role: next.role || '',
|
||||
system_prompt: next.system_prompt || '',
|
||||
system_prompt_file: next.system_prompt_file || '',
|
||||
memory_namespace: next.memory_namespace || '',
|
||||
status: (next.status as string) || 'active',
|
||||
@@ -142,7 +140,6 @@ const SubagentProfiles: React.FC = () => {
|
||||
name: p.name || '',
|
||||
notify_main_policy: p.notify_main_policy || 'final_only',
|
||||
role: p.role || '',
|
||||
system_prompt: p.system_prompt || '',
|
||||
system_prompt_file: p.system_prompt_file || '',
|
||||
memory_namespace: p.memory_namespace || '',
|
||||
status: (p.status as string) || 'active',
|
||||
@@ -195,7 +192,6 @@ const SubagentProfiles: React.FC = () => {
|
||||
name: draft.name || '',
|
||||
notify_main_policy: draft.notify_main_policy || 'final_only',
|
||||
role: draft.role || '',
|
||||
system_prompt: draft.system_prompt || '',
|
||||
system_prompt_file: draft.system_prompt_file || '',
|
||||
memory_namespace: draft.memory_namespace || '',
|
||||
status: draft.status || 'active',
|
||||
@@ -295,11 +291,20 @@ const SubagentProfiles: React.FC = () => {
|
||||
<button
|
||||
key={it.agent_id}
|
||||
onClick={() => onSelect(it)}
|
||||
className={`w-full text-left px-3 py-2 border-b border-zinc-800/50 hover:bg-zinc-800/20 ${selectedId === it.agent_id ? 'bg-indigo-500/15' : ''}`}
|
||||
className={`w-full text-left px-3 py-2 border-b border-zinc-800/50 transition-colors ${selectedId === it.agent_id ? 'bg-indigo-500/15' : ''}`}
|
||||
>
|
||||
<div className="text-sm text-zinc-100 truncate">{it.agent_id || '-'}</div>
|
||||
<div className="text-xs text-zinc-400 truncate">
|
||||
{(it.status || 'active')} · {it.role || '-'} · {(it.memory_namespace || '-')}
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-sm text-zinc-100 truncate">{it.agent_id || '-'}</div>
|
||||
<div className="text-xs text-zinc-400 truncate">
|
||||
{(it.status || 'active')} · {it.role || '-'} · {(it.memory_namespace || '-')}
|
||||
</div>
|
||||
</div>
|
||||
{selectedId === it.agent_id && (
|
||||
<span className="mt-0.5 inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-indigo-500/15 text-indigo-300">
|
||||
<Check className="w-3.5 h-3.5" />
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
@@ -409,15 +414,6 @@ const SubagentProfiles: React.FC = () => {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="md:col-span-2">
|
||||
<div className="text-xs text-zinc-400 mb-1">System Prompt</div>
|
||||
<textarea
|
||||
value={draft.system_prompt || ''}
|
||||
onChange={(e) => setDraft({ ...draft, system_prompt: e.target.value })}
|
||||
className="w-full px-2 py-1 text-xs bg-zinc-900 border border-zinc-700 rounded min-h-[140px]"
|
||||
placeholder="You are a coding specialist..."
|
||||
/>
|
||||
</div>
|
||||
<div className="md:col-span-2">
|
||||
<div className="flex items-center justify-between mb-1 gap-3">
|
||||
<div className="text-xs text-zinc-400">system_prompt_file content</div>
|
||||
|
||||
@@ -91,7 +91,6 @@ type RegistrySubagent = {
|
||||
display_name?: string;
|
||||
role?: string;
|
||||
description?: string;
|
||||
system_prompt?: string;
|
||||
system_prompt_file?: string;
|
||||
prompt_file_found?: boolean;
|
||||
memory_namespace?: string;
|
||||
@@ -392,7 +391,6 @@ const Subagents: React.FC = () => {
|
||||
const [configAgentID, setConfigAgentID] = useState('');
|
||||
const [configRole, setConfigRole] = useState('');
|
||||
const [configDisplayName, setConfigDisplayName] = useState('');
|
||||
const [configSystemPrompt, setConfigSystemPrompt] = useState('');
|
||||
const [configSystemPromptFile, setConfigSystemPromptFile] = useState('');
|
||||
const [configToolAllowlist, setConfigToolAllowlist] = useState('');
|
||||
const [configRoutingKeywords, setConfigRoutingKeywords] = useState('');
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Check } from 'lucide-react';
|
||||
import { useAppContext } from '../context/AppContext';
|
||||
import { formatLocalDateTime } from '../utils/time';
|
||||
|
||||
@@ -143,11 +144,20 @@ const TaskAudit: React.FC = () => {
|
||||
<button
|
||||
key={`${it.task_id || idx}-${it.time || idx}`}
|
||||
onClick={() => setSelected(it)}
|
||||
className={`w-full text-left px-3 py-2 border-b border-zinc-800/60 hover:bg-zinc-800/20 ${active ? 'bg-indigo-500/15' : ''}`}
|
||||
className={`w-full text-left px-3 py-2 border-b border-zinc-800/60 transition-colors ${active ? 'bg-indigo-500/15' : ''}`}
|
||||
>
|
||||
<div className="text-sm font-medium text-zinc-100 truncate">{it.task_id || `task-${idx + 1}`}</div>
|
||||
<div className="text-xs text-zinc-400 truncate">{it.channel || '-'} · {it.status} · attempts:{it.attempts || 1} · {it.duration_ms || 0}ms · retry:{it.retry_count || 0} · {it.source || '-'} · {it.provider || '-'} / {it.model || '-'}</div>
|
||||
<div className="text-[11px] text-zinc-500 truncate">{formatLocalDateTime(it.time)}</div>
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-sm font-medium text-zinc-100 truncate">{it.task_id || `task-${idx + 1}`}</div>
|
||||
<div className="text-xs text-zinc-400 truncate">{it.channel || '-'} · {it.status} · attempts:{it.attempts || 1} · {it.duration_ms || 0}ms · retry:{it.retry_count || 0} · {it.source || '-'} · {it.provider || '-'} / {it.model || '-'}</div>
|
||||
<div className="text-[11px] text-zinc-500 truncate">{formatLocalDateTime(it.time)}</div>
|
||||
</div>
|
||||
{active && (
|
||||
<span className="mt-0.5 inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-indigo-500/15 text-indigo-300">
|
||||
<Check className="w-3.5 h-3.5" />
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
@@ -240,11 +250,20 @@ const TaskAudit: React.FC = () => {
|
||||
<button
|
||||
key={`${it.time || idx}-${it.node || idx}-${it.action || idx}`}
|
||||
onClick={() => setSelectedNode(it)}
|
||||
className={`w-full text-left px-3 py-2 border-b border-zinc-800/60 hover:bg-zinc-800/20 ${active ? 'bg-indigo-500/15' : ''}`}
|
||||
className={`w-full text-left px-3 py-2 border-b border-zinc-800/60 transition-colors ${active ? 'bg-indigo-500/15' : ''}`}
|
||||
>
|
||||
<div className="text-sm font-medium text-zinc-100 truncate">{`${it.node || '-'} · ${it.action || '-'}`}</div>
|
||||
<div className="text-xs text-zinc-400 truncate">{it.used_transport || '-'} · {(it.duration_ms || 0)}ms · {(it.artifact_count || 0)} {t('dashboardNodeDispatchArtifacts')}</div>
|
||||
<div className="text-[11px] text-zinc-500 truncate">{formatLocalDateTime(it.time)}</div>
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-sm font-medium text-zinc-100 truncate">{`${it.node || '-'} · ${it.action || '-'}`}</div>
|
||||
<div className="text-xs text-zinc-400 truncate">{it.used_transport || '-'} · {(it.duration_ms || 0)}ms · {(it.artifact_count || 0)} {t('dashboardNodeDispatchArtifacts')}</div>
|
||||
<div className="text-[11px] text-zinc-500 truncate">{formatLocalDateTime(it.time)}</div>
|
||||
</div>
|
||||
{active && (
|
||||
<span className="mt-0.5 inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-indigo-500/15 text-indigo-300">
|
||||
<Check className="w-3.5 h-3.5" />
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user