mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-27 21:08:00 +00:00
@@ -0,0 +1,117 @@
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { agentWorkApi, type AgentWorkResponse } from '../../services/api/agentWorkApi';
|
||||
import IntelligenceAgentWorkTab from './IntelligenceAgentWorkTab';
|
||||
|
||||
vi.mock('../../services/api/agentWorkApi', () => ({ agentWorkApi: { list: vi.fn() } }));
|
||||
|
||||
// i18n → echo the key so assertions can target stable strings.
|
||||
vi.mock('../../lib/i18n/I18nContext', () => ({ useT: () => ({ t: (k: string) => k }) }));
|
||||
|
||||
// Navigation + store: the tab only dispatches + navigates on click; stub them.
|
||||
vi.mock('react-router-dom', () => ({ useNavigate: () => vi.fn() }));
|
||||
vi.mock('../../store/hooks', () => ({ useAppDispatch: () => vi.fn() }));
|
||||
vi.mock('../../store/threadSlice', () => ({
|
||||
loadThreadMessages: vi.fn(),
|
||||
loadThreads: vi.fn(),
|
||||
setSelectedThread: vi.fn(),
|
||||
}));
|
||||
|
||||
const mockList = vi.mocked(agentWorkApi.list);
|
||||
|
||||
function emptyResponse(): AgentWorkResponse {
|
||||
return {
|
||||
total: 0,
|
||||
groups: (['needs_input', 'working', 'completed', 'failed', 'stopped'] as const).map(bucket => ({
|
||||
bucket,
|
||||
count: 0,
|
||||
rows: [],
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
function workingResponse(): AgentWorkResponse {
|
||||
return {
|
||||
total: 1,
|
||||
groups: [
|
||||
{ bucket: 'needs_input', count: 0, rows: [] },
|
||||
{
|
||||
bucket: 'working',
|
||||
count: 1,
|
||||
rows: [
|
||||
{
|
||||
runId: 'run-1',
|
||||
kind: 'subagent',
|
||||
agentId: 'agent-a',
|
||||
displayName: 'Researcher',
|
||||
bucket: 'working',
|
||||
status: 'running',
|
||||
workerThreadId: 'thread-w',
|
||||
startedAt: '2026-01-01T00:00:00Z',
|
||||
updatedAt: '2026-01-01T00:01:00Z',
|
||||
elapsedMs: 60000,
|
||||
inputTokens: 1200,
|
||||
outputTokens: 300,
|
||||
costUsd: 0.05,
|
||||
toolCount: 3,
|
||||
},
|
||||
],
|
||||
},
|
||||
{ bucket: 'completed', count: 0, rows: [] },
|
||||
{ bucket: 'failed', count: 0, rows: [] },
|
||||
{ bucket: 'stopped', count: 0, rows: [] },
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
describe('IntelligenceAgentWorkTab', () => {
|
||||
beforeEach(() => {
|
||||
// Reset the queue + implementation so a prior test's resolve/reject can't
|
||||
// leak via the mount setTimeout into the next render (clearMocks only wipes
|
||||
// call history, not queued *Once values / persistent implementations).
|
||||
mockList.mockReset();
|
||||
});
|
||||
|
||||
it('fetches agent work on mount', async () => {
|
||||
mockList.mockResolvedValue(emptyResponse());
|
||||
render(<IntelligenceAgentWorkTab />);
|
||||
await waitFor(() => expect(mockList).toHaveBeenCalledTimes(1));
|
||||
});
|
||||
|
||||
it('shows the loading state before the RPC resolves', () => {
|
||||
mockList.mockReturnValue(new Promise(() => {}));
|
||||
render(<IntelligenceAgentWorkTab />);
|
||||
expect(screen.getByText('intelligence.agentWork.loading')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows the error box when the RPC rejects', async () => {
|
||||
mockList.mockRejectedValue(new Error('boom'));
|
||||
render(<IntelligenceAgentWorkTab />);
|
||||
await waitFor(() =>
|
||||
expect(screen.getByText(/intelligence\.agentWork\.failedToLoad/)).toBeInTheDocument()
|
||||
);
|
||||
expect(screen.getByText(/boom/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows the empty state when total is 0', async () => {
|
||||
mockList.mockResolvedValue(emptyResponse());
|
||||
render(<IntelligenceAgentWorkTab />);
|
||||
await waitFor(() =>
|
||||
expect(screen.getByText('intelligence.agentWork.empty')).toBeInTheDocument()
|
||||
);
|
||||
});
|
||||
|
||||
it('renders a grouped working row with its display name and bucket label', async () => {
|
||||
mockList.mockResolvedValue(workingResponse());
|
||||
render(<IntelligenceAgentWorkTab />);
|
||||
await waitFor(() => expect(screen.getByText('Researcher')).toBeInTheDocument());
|
||||
expect(screen.getByText('intelligence.agentWork.bucket.working')).toBeInTheDocument();
|
||||
// 1200 + 300 input/output tokens → "1.5K"
|
||||
expect(screen.getByText('1.5K')).toBeInTheDocument();
|
||||
// $0.05 cost formatted
|
||||
expect(screen.getByText('$0.05')).toBeInTheDocument();
|
||||
// worker-thread jump button present
|
||||
expect(screen.getByText('intelligence.agentWork.openWorker')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,310 @@
|
||||
/**
|
||||
* IntelligenceAgentWorkTab — the Background Agent Command Center.
|
||||
*
|
||||
* Reads `openhuman.agent_work_list` (via {@link agentWorkApi}) once on mount
|
||||
* and renders every tracked background agent run, grouped into five lifecycle
|
||||
* buckets in a fixed display order: needs_input → working → completed →
|
||||
* failed → stopped. The handler always returns all five groups, so the order
|
||||
* here is authoritative and never needs sorting.
|
||||
*
|
||||
* This tab is read-only and holds no Redux slice — it owns its own
|
||||
* {data, loading, error} state, mirroring {@link IntelligenceTasksTab}'s
|
||||
* mount pattern (mountedRef + a 0ms `setTimeout` so the first paint shows the
|
||||
* loading state before the RPC resolves). Each row offers jumps to the parent
|
||||
* / worker thread via the same navigate('/chat', { openThreadId }) path the
|
||||
* Tasks tab uses for "View session".
|
||||
*/
|
||||
import debug from 'debug';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useT } from '../../lib/i18n/I18nContext';
|
||||
import {
|
||||
agentWorkApi,
|
||||
type AgentWorkBucket,
|
||||
type AgentWorkResponse,
|
||||
type AgentWorkRow,
|
||||
} from '../../services/api/agentWorkApi';
|
||||
import { useAppDispatch } from '../../store/hooks';
|
||||
import { loadThreadMessages, loadThreads, setSelectedThread } from '../../store/threadSlice';
|
||||
|
||||
const log = debug('intelligence:agent-work');
|
||||
|
||||
/** Fixed display order of buckets — matches the handler's group order. */
|
||||
const BUCKET_ORDER: AgentWorkBucket[] = [
|
||||
'needs_input',
|
||||
'working',
|
||||
'completed',
|
||||
'failed',
|
||||
'stopped',
|
||||
];
|
||||
|
||||
/** Per-bucket accent classes (semantic palette from tailwind.config.js). */
|
||||
const BUCKET_ACCENT: Record<AgentWorkBucket, string> = {
|
||||
needs_input:
|
||||
'border-amber-200 bg-amber-50 text-amber-700 dark:border-amber-500/30 dark:bg-amber-500/10 dark:text-amber-300',
|
||||
working:
|
||||
'border-ocean-200 bg-ocean-50 text-ocean-700 dark:border-ocean-500/30 dark:bg-ocean-500/10 dark:text-ocean-300',
|
||||
completed:
|
||||
'border-sage-200 bg-sage-50 text-sage-700 dark:border-sage-500/30 dark:bg-sage-500/10 dark:text-sage-300',
|
||||
failed:
|
||||
'border-coral-200 bg-coral-50 text-coral-700 dark:border-coral-500/30 dark:bg-coral-500/10 dark:text-coral-300',
|
||||
stopped:
|
||||
'border-stone-200 bg-stone-50 text-stone-600 dark:border-neutral-700 dark:bg-neutral-800/60 dark:text-neutral-300',
|
||||
};
|
||||
|
||||
/** i18n key for each bucket's localized label. */
|
||||
const BUCKET_LABEL_KEY: Record<AgentWorkBucket, string> = {
|
||||
needs_input: 'intelligence.agentWork.bucket.needsInput',
|
||||
working: 'intelligence.agentWork.bucket.working',
|
||||
completed: 'intelligence.agentWork.bucket.completed',
|
||||
failed: 'intelligence.agentWork.bucket.failed',
|
||||
stopped: 'intelligence.agentWork.bucket.stopped',
|
||||
};
|
||||
|
||||
/** i18n key for each granular run status (mirrors Rust `AgentRunStatus`). */
|
||||
const STATUS_LABEL_KEY: Record<string, string> = {
|
||||
pending: 'intelligence.agentWork.status.pending',
|
||||
running: 'intelligence.agentWork.status.running',
|
||||
awaiting_user: 'intelligence.agentWork.status.awaitingUser',
|
||||
paused: 'intelligence.agentWork.status.paused',
|
||||
completed: 'intelligence.agentWork.status.completed',
|
||||
failed: 'intelligence.agentWork.status.failed',
|
||||
cancelled: 'intelligence.agentWork.status.cancelled',
|
||||
interrupted: 'intelligence.agentWork.status.interrupted',
|
||||
};
|
||||
|
||||
/** i18n key for each run kind (mirrors Rust `AgentRunKind`). */
|
||||
const KIND_LABEL_KEY: Record<string, string> = {
|
||||
subagent: 'intelligence.agentWork.kind.subagent',
|
||||
worker_thread: 'intelligence.agentWork.kind.workerThread',
|
||||
background_agent: 'intelligence.agentWork.kind.backgroundAgent',
|
||||
team_member: 'intelligence.agentWork.kind.teamMember',
|
||||
workflow_child: 'intelligence.agentWork.kind.workflowChild',
|
||||
};
|
||||
|
||||
/** Format an elapsed millisecond span as a compact "1h 23m" / "45s" string. */
|
||||
export function formatElapsed(ms: number | undefined): string {
|
||||
if (ms === undefined || !Number.isFinite(ms) || ms < 0) return '—';
|
||||
const totalSeconds = Math.floor(ms / 1000);
|
||||
const hours = Math.floor(totalSeconds / 3600);
|
||||
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
||||
const seconds = totalSeconds % 60;
|
||||
if (hours > 0) return `${hours}h ${minutes}m`;
|
||||
if (minutes > 0) return `${minutes}m ${seconds}s`;
|
||||
return `${seconds}s`;
|
||||
}
|
||||
|
||||
/** Human-readable token count: 1234 → "1.2K", 2_500_000 → "2.5M". */
|
||||
export function formatTokens(value: number): string {
|
||||
if (!Number.isFinite(value) || value < 0) return '0';
|
||||
if (value < 1000) return String(value);
|
||||
if (value < 1_000_000) return `${(value / 1000).toFixed(1)}K`;
|
||||
return `${(value / 1_000_000).toFixed(1)}M`;
|
||||
}
|
||||
|
||||
/** Format a USD cost with two decimals, e.g. 0.0123 → "$0.01". */
|
||||
export function formatCost(value: number): string {
|
||||
if (!Number.isFinite(value) || value < 0) return '$0.00';
|
||||
return `$${value.toFixed(2)}`;
|
||||
}
|
||||
|
||||
export default function IntelligenceAgentWorkTab() {
|
||||
const { t } = useT();
|
||||
const dispatch = useAppDispatch();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [data, setData] = useState<AgentWorkResponse | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const mountedRef = useRef(true);
|
||||
|
||||
const fetchWork = useCallback(async () => {
|
||||
log('fetchWork: entry');
|
||||
setError(null);
|
||||
try {
|
||||
const response = await agentWorkApi.list();
|
||||
if (mountedRef.current) {
|
||||
setData(response);
|
||||
log('fetchWork: done total=%d', response.total);
|
||||
}
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
log('fetchWork: error %s', msg);
|
||||
if (mountedRef.current) setError(msg);
|
||||
} finally {
|
||||
if (mountedRef.current) setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
mountedRef.current = true;
|
||||
const handle = window.setTimeout(() => {
|
||||
void fetchWork();
|
||||
}, 0);
|
||||
return () => {
|
||||
window.clearTimeout(handle);
|
||||
mountedRef.current = false;
|
||||
};
|
||||
}, [fetchWork]);
|
||||
|
||||
// Open a thread in /chat — mirrors IntelligenceTasksTab's "View session"
|
||||
// path so the chat surface lands on the requested thread instead of just
|
||||
// the Conversations list. Navigation only; the thread is not marked active.
|
||||
const openThread = useCallback(
|
||||
(threadId: string) => {
|
||||
log('openThread threadId=%s', threadId);
|
||||
dispatch(setSelectedThread(threadId));
|
||||
void dispatch(loadThreads());
|
||||
void dispatch(loadThreadMessages(threadId));
|
||||
navigate('/chat', { state: { openThreadId: threadId } });
|
||||
},
|
||||
[dispatch, navigate]
|
||||
);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="flex items-center justify-center py-10 text-stone-400 dark:text-neutral-500">
|
||||
<div className="mr-2 h-4 w-4 animate-spin rounded-full border-2 border-ocean-500 border-t-transparent" />
|
||||
<span className="text-sm">{t('intelligence.agentWork.loading')}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="rounded-xl border border-coral-200 bg-coral-50 px-4 py-3 text-sm text-coral-700 dark:border-coral-500/30 dark:bg-coral-500/10 dark:text-coral-300">
|
||||
{t('intelligence.agentWork.failedToLoad')}: {error}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!data || data.total === 0) {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<p className="text-xs text-stone-400 dark:text-neutral-500">
|
||||
{t('intelligence.agentWork.subtitle')}
|
||||
</p>
|
||||
<div className="rounded-xl border border-dashed border-stone-200 py-10 text-center text-sm text-stone-400 dark:border-neutral-800 dark:text-neutral-500">
|
||||
{t('intelligence.agentWork.empty')}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const groupByBucket = new Map(data.groups.map(group => [group.bucket, group]));
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<p className="text-xs text-stone-400 dark:text-neutral-500">
|
||||
{t('intelligence.agentWork.subtitle')}
|
||||
</p>
|
||||
|
||||
{BUCKET_ORDER.map(bucket => {
|
||||
const group = groupByBucket.get(bucket);
|
||||
const rows = group?.rows ?? [];
|
||||
if (rows.length === 0) return null;
|
||||
return (
|
||||
<section key={bucket} className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<span
|
||||
className={`inline-flex items-center gap-1.5 rounded-full border px-2.5 py-0.5 text-xs font-medium ${BUCKET_ACCENT[bucket]}`}>
|
||||
{bucket === 'working' && (
|
||||
<span className="h-1.5 w-1.5 animate-pulse rounded-full bg-ocean-500" />
|
||||
)}
|
||||
{t(BUCKET_LABEL_KEY[bucket])}
|
||||
</span>
|
||||
<span className="text-xs text-stone-400 dark:text-neutral-500">
|
||||
{group?.count ?? rows.length}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<ul className="divide-y divide-stone-100 overflow-hidden rounded-xl border border-stone-200 bg-white dark:divide-neutral-800 dark:border-neutral-800 dark:bg-neutral-900">
|
||||
{rows.map(row => (
|
||||
<AgentWorkRowItem key={row.runId} row={row} onOpenThread={openThread} />
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface AgentWorkRowItemProps {
|
||||
row: AgentWorkRow;
|
||||
onOpenThread: (threadId: string) => void;
|
||||
}
|
||||
|
||||
function AgentWorkRowItem({ row, onOpenThread }: AgentWorkRowItemProps) {
|
||||
const { t } = useT();
|
||||
const name = row.displayName || row.agentId || row.runId;
|
||||
const totalTokens = row.inputTokens + row.outputTokens;
|
||||
// Localize the backend enum values, falling back to the raw value for any
|
||||
// status/kind the UI doesn't yet have a key for.
|
||||
const statusLabel = STATUS_LABEL_KEY[row.status] ? t(STATUS_LABEL_KEY[row.status]) : row.status;
|
||||
const kindLabel = KIND_LABEL_KEY[row.kind] ? t(KIND_LABEL_KEY[row.kind]) : row.kind;
|
||||
|
||||
return (
|
||||
<li className="p-3">
|
||||
<div className="flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between">
|
||||
<div className="min-w-0 space-y-1">
|
||||
<div className="flex flex-wrap items-center gap-1.5">
|
||||
<span
|
||||
title={t('intelligence.agentWork.column.agent')}
|
||||
className="truncate text-sm font-medium text-stone-800 dark:text-neutral-100">
|
||||
{name}
|
||||
</span>
|
||||
<span
|
||||
title={t('intelligence.agentWork.column.status')}
|
||||
className="rounded-md border border-stone-200 px-1.5 py-0.5 text-[10px] font-medium text-stone-500 dark:border-neutral-700 dark:text-neutral-400">
|
||||
{statusLabel}
|
||||
</span>
|
||||
<span className="text-[10px] uppercase tracking-wide text-stone-400 dark:text-neutral-500">
|
||||
{kindLabel}
|
||||
</span>
|
||||
</div>
|
||||
{row.summary && (
|
||||
<p className="line-clamp-2 break-words text-xs leading-snug text-stone-500 dark:text-neutral-400">
|
||||
{row.summary}
|
||||
</p>
|
||||
)}
|
||||
{row.error && (
|
||||
<p className="line-clamp-2 break-words text-xs leading-snug text-coral-600 dark:text-coral-300">
|
||||
{row.error}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-none items-center gap-3 text-xs text-stone-500 dark:text-neutral-400">
|
||||
<span title={t('intelligence.agentWork.column.elapsed')}>
|
||||
{formatElapsed(row.elapsedMs)}
|
||||
</span>
|
||||
<span title={t('intelligence.agentWork.column.cost')}>{formatCost(row.costUsd)}</span>
|
||||
<span title={t('intelligence.agentWork.column.tokens')}>{formatTokens(totalTokens)}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{(row.parentThreadId || row.workerThreadId) && (
|
||||
<div className="mt-2 flex flex-wrap items-center gap-2">
|
||||
{row.parentThreadId && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onOpenThread(row.parentThreadId as string)}
|
||||
className="rounded-md border border-stone-200 px-2 py-1 text-[11px] font-medium text-ocean-600 hover:bg-stone-50 dark:border-neutral-800 dark:text-ocean-300 dark:hover:bg-neutral-800">
|
||||
{t('intelligence.agentWork.openThread')}
|
||||
</button>
|
||||
)}
|
||||
{row.workerThreadId && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onOpenThread(row.workerThreadId as string)}
|
||||
className="rounded-md border border-stone-200 px-2 py-1 text-[11px] font-medium text-ocean-600 hover:bg-stone-50 dark:border-neutral-800 dark:text-ocean-300 dark:hover:bg-neutral-800">
|
||||
{t('intelligence.agentWork.openWorker')}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
@@ -306,6 +306,9 @@ const messages: TranslationMap = {
|
||||
'memory.tab.tasksDescription':
|
||||
'أنشئ المهام وتتبعها — مهامك الخاصة بالإضافة إلى اللوحات التي يبنيها وكلاؤك عبر المحادثات.',
|
||||
'memory.tab.subconscious': 'اللاوعي',
|
||||
'memory.tab.agentWork': 'عمل الوكيل',
|
||||
'memory.tab.agentWorkDescription':
|
||||
'مركز قيادة لكل تشغيل وكيل في الخلفية — مُجمّع حسب ما يحتاج إلى مُدخلاتك، وما يعمل الآن، وما اكتمل.',
|
||||
'memory.tab.agents': 'المكتبة',
|
||||
'memory.tab.agentsDescription':
|
||||
'تصفّح وشغّل الوكلاء المتاحين — لكل منهم أدواته وقدراته ومجال تركيزه.',
|
||||
@@ -2766,6 +2769,35 @@ const messages: TranslationMap = {
|
||||
'intelligence.workTask.urlLine': '- الرابط: {url}',
|
||||
'intelligence.workTask.closingInstruction':
|
||||
'ابدأ بإعادة صياغة خطة التنفيذ الملموسة بإيجاز، ثم نفّذها. أبقِ التقدّم مرئيًا في هذا المحادثة وحدّث لوحة المهام عند تغيّر حالة العمل.',
|
||||
'intelligence.agentWork.subtitle': 'كل تشغيل وكيل في الخلفية، مُجمّع حسب حالة دورة الحياة.',
|
||||
'intelligence.agentWork.loading': 'جارٍ تحميل عمل الوكيل…',
|
||||
'intelligence.agentWork.failedToLoad': 'تعذّر تحميل عمل الوكيل',
|
||||
'intelligence.agentWork.empty': 'لا توجد عمليات تشغيل وكيل في الخلفية بعد.',
|
||||
'intelligence.agentWork.bucket.needsInput': 'يحتاج إلى مُدخلات',
|
||||
'intelligence.agentWork.bucket.working': 'قيد العمل',
|
||||
'intelligence.agentWork.bucket.completed': 'مكتمل',
|
||||
'intelligence.agentWork.bucket.failed': 'فشل',
|
||||
'intelligence.agentWork.bucket.stopped': 'متوقف',
|
||||
'intelligence.agentWork.column.agent': 'الوكيل',
|
||||
'intelligence.agentWork.column.status': 'الحالة',
|
||||
'intelligence.agentWork.column.elapsed': 'الوقت المنقضي',
|
||||
'intelligence.agentWork.column.cost': 'التكلفة',
|
||||
'intelligence.agentWork.column.tokens': 'الرموز',
|
||||
'intelligence.agentWork.status.pending': 'قيد الانتظار',
|
||||
'intelligence.agentWork.status.running': 'قيد العمل',
|
||||
'intelligence.agentWork.status.awaitingUser': 'يحتاج إلى مُدخلات',
|
||||
'intelligence.agentWork.status.paused': 'متوقف مؤقتًا',
|
||||
'intelligence.agentWork.status.completed': 'مكتمل',
|
||||
'intelligence.agentWork.status.failed': 'فشل',
|
||||
'intelligence.agentWork.status.cancelled': 'ملغى',
|
||||
'intelligence.agentWork.status.interrupted': 'مقاطَع',
|
||||
'intelligence.agentWork.kind.subagent': 'وكيل فرعي',
|
||||
'intelligence.agentWork.kind.workerThread': 'محادثة عامل',
|
||||
'intelligence.agentWork.kind.backgroundAgent': 'وكيل في الخلفية',
|
||||
'intelligence.agentWork.kind.teamMember': 'عضو الفريق',
|
||||
'intelligence.agentWork.kind.workflowChild': 'عنصر فرعي لسير العمل',
|
||||
'intelligence.agentWork.openThread': 'فتح المحادثة',
|
||||
'intelligence.agentWork.openWorker': 'فتح العامل',
|
||||
'intelligence.refine.objectiveDefault': 'حوّل المهمة المصدر إلى مهمة وكيل جاهزة للتنفيذ: {title}',
|
||||
'intelligence.refine.sourceLine': 'المصدر: {url}',
|
||||
'intelligence.refine.sourceIntake': 'المصدر: استقبال مصدر المهام',
|
||||
|
||||
@@ -310,6 +310,9 @@ const messages: TranslationMap = {
|
||||
'memory.tab.tasksDescription':
|
||||
'টাস্ক তৈরি করুন এবং ট্র্যাক করুন — আপনার নিজের কাজের তালিকা এবং এজেন্টরা কথোপকথন জুড়ে যে বোর্ডগুলি তৈরি করে।',
|
||||
'memory.tab.subconscious': 'সাবকনশাস',
|
||||
'memory.tab.agentWork': 'এজেন্ট কাজ',
|
||||
'memory.tab.agentWorkDescription':
|
||||
'প্রতিটি ব্যাকগ্রাউন্ড এজেন্ট রানের জন্য একটি কমান্ড সেন্টার — আপনার ইনপুট প্রয়োজন এমন, চলমান এবং সম্পন্ন অনুযায়ী গোষ্ঠীবদ্ধ।',
|
||||
'memory.tab.agents': 'লাইব্রেরি',
|
||||
'memory.tab.agentsDescription':
|
||||
'আপনার উপলব্ধ এজেন্টগুলি ব্রাউজ করুন এবং চালান — প্রতিটির নিজস্ব টুল, ক্ষমতা এবং ফোকাস এলাকা রয়েছে।',
|
||||
@@ -2822,6 +2825,36 @@ const messages: TranslationMap = {
|
||||
'intelligence.workTask.urlLine': '- ইউআরএল: {url}',
|
||||
'intelligence.workTask.closingInstruction':
|
||||
'প্রথমে সুনির্দিষ্ট বাস্তবায়ন পরিকল্পনাটি সংক্ষেপে পুনরায় বলুন, তারপর তা সম্পাদন করুন। এই থ্রেডে অগ্রগতি দৃশ্যমান রাখুন এবং কাজের অবস্থা পরিবর্তিত হলে টাস্ক বোর্ড আপডেট করুন।',
|
||||
'intelligence.agentWork.subtitle':
|
||||
'প্রতিটি ব্যাকগ্রাউন্ড এজেন্ট রান, জীবনচক্রের অবস্থা অনুযায়ী গোষ্ঠীবদ্ধ।',
|
||||
'intelligence.agentWork.loading': 'এজেন্ট কাজ লোড হচ্ছে…',
|
||||
'intelligence.agentWork.failedToLoad': 'এজেন্ট কাজ লোড করা যায়নি',
|
||||
'intelligence.agentWork.empty': 'এখনও কোনো ব্যাকগ্রাউন্ড এজেন্ট রান নেই।',
|
||||
'intelligence.agentWork.bucket.needsInput': 'ইনপুট প্রয়োজন',
|
||||
'intelligence.agentWork.bucket.working': 'কাজ চলছে',
|
||||
'intelligence.agentWork.bucket.completed': 'সম্পন্ন',
|
||||
'intelligence.agentWork.bucket.failed': 'ব্যর্থ',
|
||||
'intelligence.agentWork.bucket.stopped': 'বন্ধ',
|
||||
'intelligence.agentWork.column.agent': 'এজেন্ট',
|
||||
'intelligence.agentWork.column.status': 'স্ট্যাটাস',
|
||||
'intelligence.agentWork.column.elapsed': 'অতিবাহিত সময়',
|
||||
'intelligence.agentWork.column.cost': 'ব্যয়',
|
||||
'intelligence.agentWork.column.tokens': 'টোকেন',
|
||||
'intelligence.agentWork.status.pending': 'মুলতুবি',
|
||||
'intelligence.agentWork.status.running': 'চলছে',
|
||||
'intelligence.agentWork.status.awaitingUser': 'ইনপুট প্রয়োজন',
|
||||
'intelligence.agentWork.status.paused': 'বিরতিতে',
|
||||
'intelligence.agentWork.status.completed': 'সম্পন্ন',
|
||||
'intelligence.agentWork.status.failed': 'ব্যর্থ',
|
||||
'intelligence.agentWork.status.cancelled': 'বাতিল',
|
||||
'intelligence.agentWork.status.interrupted': 'বিঘ্নিত',
|
||||
'intelligence.agentWork.kind.subagent': 'সাব-এজেন্ট',
|
||||
'intelligence.agentWork.kind.workerThread': 'ওয়ার্কার থ্রেড',
|
||||
'intelligence.agentWork.kind.backgroundAgent': 'ব্যাকগ্রাউন্ড এজেন্ট',
|
||||
'intelligence.agentWork.kind.teamMember': 'টিম সদস্য',
|
||||
'intelligence.agentWork.kind.workflowChild': 'ওয়ার্কফ্লো চাইল্ড',
|
||||
'intelligence.agentWork.openThread': 'থ্রেড খুলুন',
|
||||
'intelligence.agentWork.openWorker': 'ওয়ার্কার খুলুন',
|
||||
'intelligence.refine.objectiveDefault':
|
||||
'উৎস টাস্কটিকে বাস্তবায়নের জন্য প্রস্তুত একটি এজেন্ট টাস্কে রূপান্তর করুন: {title}',
|
||||
'intelligence.refine.sourceLine': 'উৎস: {url}',
|
||||
|
||||
@@ -319,6 +319,9 @@ const messages: TranslationMap = {
|
||||
'memory.tab.tasksDescription':
|
||||
'Aufgaben erstellen und verfolgen – eigene To-dos sowie die Boards, die Agenten in Gesprächen anlegen.',
|
||||
'memory.tab.subconscious': 'Unterbewusstsein',
|
||||
'memory.tab.agentWork': 'Agentenarbeit',
|
||||
'memory.tab.agentWorkDescription':
|
||||
'Eine Kommandozentrale für jeden Hintergrund-Agentenlauf — gruppiert danach, was deine Eingabe braucht, was läuft und was abgeschlossen ist.',
|
||||
'memory.tab.agents': 'Bibliothek',
|
||||
'memory.tab.agentsDescription':
|
||||
'Verfügbare Agenten durchsuchen und starten — jeder mit eigenen Werkzeugen, Fähigkeiten und Schwerpunkten.',
|
||||
@@ -2892,6 +2895,36 @@ const messages: TranslationMap = {
|
||||
'intelligence.workTask.urlLine': '- Adresse: {url}',
|
||||
'intelligence.workTask.closingInstruction':
|
||||
'Beginne damit, den konkreten Umsetzungsplan kurz zu wiederholen, und führe ihn dann aus. Halte den Fortschritt in diesem Thread sichtbar und aktualisiere das Aufgabenboard, wenn sich der Arbeitsstand ändert.',
|
||||
'intelligence.agentWork.subtitle':
|
||||
'Jeder Hintergrund-Agentenlauf, gruppiert nach Lebenszyklusstatus.',
|
||||
'intelligence.agentWork.loading': 'Agentenarbeit wird geladen…',
|
||||
'intelligence.agentWork.failedToLoad': 'Agentenarbeit konnte nicht geladen werden',
|
||||
'intelligence.agentWork.empty': 'Noch keine Hintergrund-Agentenläufe.',
|
||||
'intelligence.agentWork.bucket.needsInput': 'Eingabe nötig',
|
||||
'intelligence.agentWork.bucket.working': 'In Arbeit',
|
||||
'intelligence.agentWork.bucket.completed': 'Abgeschlossen',
|
||||
'intelligence.agentWork.bucket.failed': 'Fehlgeschlagen',
|
||||
'intelligence.agentWork.bucket.stopped': 'Angehalten',
|
||||
'intelligence.agentWork.column.agent': 'Agent',
|
||||
'intelligence.agentWork.column.status': 'Status',
|
||||
'intelligence.agentWork.column.elapsed': 'Verstrichen',
|
||||
'intelligence.agentWork.column.cost': 'Kosten',
|
||||
'intelligence.agentWork.column.tokens': 'Tokens',
|
||||
'intelligence.agentWork.status.pending': 'Ausstehend',
|
||||
'intelligence.agentWork.status.running': 'Läuft',
|
||||
'intelligence.agentWork.status.awaitingUser': 'Eingabe nötig',
|
||||
'intelligence.agentWork.status.paused': 'Pausiert',
|
||||
'intelligence.agentWork.status.completed': 'Abgeschlossen',
|
||||
'intelligence.agentWork.status.failed': 'Fehlgeschlagen',
|
||||
'intelligence.agentWork.status.cancelled': 'Abgebrochen',
|
||||
'intelligence.agentWork.status.interrupted': 'Unterbrochen',
|
||||
'intelligence.agentWork.kind.subagent': 'Subagent',
|
||||
'intelligence.agentWork.kind.workerThread': 'Worker-Thread',
|
||||
'intelligence.agentWork.kind.backgroundAgent': 'Hintergrundagent',
|
||||
'intelligence.agentWork.kind.teamMember': 'Teammitglied',
|
||||
'intelligence.agentWork.kind.workflowChild': 'Workflow-Unterelement',
|
||||
'intelligence.agentWork.openThread': 'Thread öffnen',
|
||||
'intelligence.agentWork.openWorker': 'Worker öffnen',
|
||||
'intelligence.refine.objectiveDefault':
|
||||
'Verwandle die Quellaufgabe in eine umsetzungsbereite Agentenaufgabe: {title}',
|
||||
'intelligence.refine.sourceLine': 'Quelle: {url}',
|
||||
|
||||
@@ -335,6 +335,9 @@ const en: TranslationMap = {
|
||||
'memory.tab.tasksDescription':
|
||||
'Create and track tasks — your own to-dos plus the boards your agents build across conversations.',
|
||||
'memory.tab.subconscious': 'Subconscious',
|
||||
'memory.tab.agentWork': 'Agent Work',
|
||||
'memory.tab.agentWorkDescription':
|
||||
'A command center for every background agent run — grouped by what needs your input, what is working, and what has finished.',
|
||||
'memory.tab.agents': 'Library',
|
||||
'memory.tab.agentsDescription':
|
||||
'Browse and run your available agents — each with its own tools, capabilities, and focus area.',
|
||||
@@ -3339,6 +3342,35 @@ const en: TranslationMap = {
|
||||
'intelligence.workTask.urlLine': '- URL: {url}',
|
||||
'intelligence.workTask.closingInstruction':
|
||||
'Start by restating the concrete implementation plan briefly, then execute it. Keep progress visible in this thread and update the task board when the work state changes.',
|
||||
'intelligence.agentWork.subtitle': 'Every background agent run, grouped by lifecycle state.',
|
||||
'intelligence.agentWork.loading': 'Loading agent work…',
|
||||
'intelligence.agentWork.failedToLoad': 'Failed to load agent work',
|
||||
'intelligence.agentWork.empty': 'No background agent runs yet.',
|
||||
'intelligence.agentWork.bucket.needsInput': 'Needs input',
|
||||
'intelligence.agentWork.bucket.working': 'Working',
|
||||
'intelligence.agentWork.bucket.completed': 'Completed',
|
||||
'intelligence.agentWork.bucket.failed': 'Failed',
|
||||
'intelligence.agentWork.bucket.stopped': 'Stopped',
|
||||
'intelligence.agentWork.column.agent': 'Agent',
|
||||
'intelligence.agentWork.column.status': 'Status',
|
||||
'intelligence.agentWork.column.elapsed': 'Elapsed',
|
||||
'intelligence.agentWork.column.cost': 'Cost',
|
||||
'intelligence.agentWork.column.tokens': 'Tokens',
|
||||
'intelligence.agentWork.status.pending': 'Pending',
|
||||
'intelligence.agentWork.status.running': 'Running',
|
||||
'intelligence.agentWork.status.awaitingUser': 'Awaiting input',
|
||||
'intelligence.agentWork.status.paused': 'Paused',
|
||||
'intelligence.agentWork.status.completed': 'Completed',
|
||||
'intelligence.agentWork.status.failed': 'Failed',
|
||||
'intelligence.agentWork.status.cancelled': 'Cancelled',
|
||||
'intelligence.agentWork.status.interrupted': 'Interrupted',
|
||||
'intelligence.agentWork.kind.subagent': 'Subagent',
|
||||
'intelligence.agentWork.kind.workerThread': 'Worker thread',
|
||||
'intelligence.agentWork.kind.backgroundAgent': 'Background agent',
|
||||
'intelligence.agentWork.kind.teamMember': 'Team member',
|
||||
'intelligence.agentWork.kind.workflowChild': 'Workflow child',
|
||||
'intelligence.agentWork.openThread': 'Open thread',
|
||||
'intelligence.agentWork.openWorker': 'Open worker',
|
||||
'intelligence.refine.objectiveDefault':
|
||||
'Turn the source task into an implementation-ready agent task: {title}',
|
||||
'intelligence.refine.sourceLine': 'Source: {url}',
|
||||
|
||||
@@ -319,6 +319,9 @@ const messages: TranslationMap = {
|
||||
'memory.tab.tasksDescription':
|
||||
'Crea y realiza un seguimiento de tareas: tus propios pendientes más los tableros que tus agentes crean a lo largo de las conversaciones.',
|
||||
'memory.tab.subconscious': 'Subconsciente',
|
||||
'memory.tab.agentWork': 'Trabajo del agente',
|
||||
'memory.tab.agentWorkDescription':
|
||||
'Un centro de mando para cada ejecución de agente en segundo plano, agrupado según lo que necesita tu intervención, lo que está en curso y lo que ha terminado.',
|
||||
'memory.tab.agents': 'Biblioteca',
|
||||
'memory.tab.agentsDescription':
|
||||
'Explora y ejecuta los agentes disponibles — cada uno con sus propias herramientas, capacidades y área de enfoque.',
|
||||
@@ -2876,6 +2879,36 @@ const messages: TranslationMap = {
|
||||
'intelligence.workTask.urlLine': '- Dirección: {url}',
|
||||
'intelligence.workTask.closingInstruction':
|
||||
'Empieza reformulando brevemente el plan de implementación concreto y luego ejecútalo. Mantén el progreso visible en este hilo y actualiza el tablero de tareas cuando cambie el estado del trabajo.',
|
||||
'intelligence.agentWork.subtitle':
|
||||
'Cada ejecución de agente en segundo plano, agrupada por estado del ciclo de vida.',
|
||||
'intelligence.agentWork.loading': 'Cargando trabajo del agente…',
|
||||
'intelligence.agentWork.failedToLoad': 'No se pudo cargar el trabajo del agente',
|
||||
'intelligence.agentWork.empty': 'Aún no hay ejecuciones de agente en segundo plano.',
|
||||
'intelligence.agentWork.bucket.needsInput': 'Requiere intervención',
|
||||
'intelligence.agentWork.bucket.working': 'En curso',
|
||||
'intelligence.agentWork.bucket.completed': 'Completado',
|
||||
'intelligence.agentWork.bucket.failed': 'Fallido',
|
||||
'intelligence.agentWork.bucket.stopped': 'Detenido',
|
||||
'intelligence.agentWork.column.agent': 'Agente',
|
||||
'intelligence.agentWork.column.status': 'Estado',
|
||||
'intelligence.agentWork.column.elapsed': 'Transcurrido',
|
||||
'intelligence.agentWork.column.cost': 'Costo',
|
||||
'intelligence.agentWork.column.tokens': 'Fichas',
|
||||
'intelligence.agentWork.status.pending': 'Pendiente',
|
||||
'intelligence.agentWork.status.running': 'En ejecución',
|
||||
'intelligence.agentWork.status.awaitingUser': 'Requiere intervención',
|
||||
'intelligence.agentWork.status.paused': 'Pausado',
|
||||
'intelligence.agentWork.status.completed': 'Completado',
|
||||
'intelligence.agentWork.status.failed': 'Fallido',
|
||||
'intelligence.agentWork.status.cancelled': 'Cancelado',
|
||||
'intelligence.agentWork.status.interrupted': 'Interrumpido',
|
||||
'intelligence.agentWork.kind.subagent': 'Subagente',
|
||||
'intelligence.agentWork.kind.workerThread': 'Hilo de worker',
|
||||
'intelligence.agentWork.kind.backgroundAgent': 'Agente en segundo plano',
|
||||
'intelligence.agentWork.kind.teamMember': 'Miembro del equipo',
|
||||
'intelligence.agentWork.kind.workflowChild': 'Hijo de flujo de trabajo',
|
||||
'intelligence.agentWork.openThread': 'Abrir hilo',
|
||||
'intelligence.agentWork.openWorker': 'Abrir trabajador',
|
||||
'intelligence.refine.objectiveDefault':
|
||||
'Convierte la tarea de origen en una tarea de agente lista para implementar: {title}',
|
||||
'intelligence.refine.sourceLine': 'Origen: {url}',
|
||||
|
||||
@@ -318,6 +318,9 @@ const messages: TranslationMap = {
|
||||
'memory.tab.tasksDescription':
|
||||
'Créez et suivez des tâches — vos propres listes de choses à faire ainsi que les tableaux que vos agents construisent au fil des conversations.',
|
||||
'memory.tab.subconscious': 'Subconscient',
|
||||
'memory.tab.agentWork': "Travail de l'agent",
|
||||
'memory.tab.agentWorkDescription':
|
||||
"Un centre de commande pour chaque exécution d'agent en arrière-plan, regroupée selon ce qui nécessite votre intervention, ce qui est en cours et ce qui est terminé.",
|
||||
'memory.tab.agents': 'Bibliothèque',
|
||||
'memory.tab.agentsDescription':
|
||||
'Parcourez et exécutez vos agents disponibles — chacun avec ses propres outils, capacités et domaine de spécialisation.',
|
||||
@@ -2890,6 +2893,36 @@ const messages: TranslationMap = {
|
||||
'intelligence.refine.objectiveDefault':
|
||||
"Transformez la tâche source en une tâche d'agent prête à être implémentée : {title}",
|
||||
'intelligence.refine.sourceLine': 'Source : {url}',
|
||||
'intelligence.agentWork.subtitle':
|
||||
"Chaque exécution d'agent en arrière-plan, regroupée par état du cycle de vie.",
|
||||
'intelligence.agentWork.loading': "Chargement du travail de l'agent…",
|
||||
'intelligence.agentWork.failedToLoad': "Impossible de charger le travail de l'agent",
|
||||
'intelligence.agentWork.empty': "Aucune exécution d'agent en arrière-plan pour l'instant.",
|
||||
'intelligence.agentWork.bucket.needsInput': 'Intervention requise',
|
||||
'intelligence.agentWork.bucket.working': 'En cours',
|
||||
'intelligence.agentWork.bucket.completed': 'Terminé',
|
||||
'intelligence.agentWork.bucket.failed': 'Échoué',
|
||||
'intelligence.agentWork.bucket.stopped': 'Arrêté',
|
||||
'intelligence.agentWork.column.agent': 'Agent',
|
||||
'intelligence.agentWork.column.status': 'Statut',
|
||||
'intelligence.agentWork.column.elapsed': 'Écoulé',
|
||||
'intelligence.agentWork.column.cost': 'Coût',
|
||||
'intelligence.agentWork.column.tokens': 'Jetons',
|
||||
'intelligence.agentWork.status.pending': 'En attente',
|
||||
'intelligence.agentWork.status.running': 'En cours',
|
||||
'intelligence.agentWork.status.awaitingUser': 'Intervention requise',
|
||||
'intelligence.agentWork.status.paused': 'En pause',
|
||||
'intelligence.agentWork.status.completed': 'Terminé',
|
||||
'intelligence.agentWork.status.failed': 'Échoué',
|
||||
'intelligence.agentWork.status.cancelled': 'Annulé',
|
||||
'intelligence.agentWork.status.interrupted': 'Interrompu',
|
||||
'intelligence.agentWork.kind.subagent': 'Sous-agent',
|
||||
'intelligence.agentWork.kind.workerThread': 'Fil worker',
|
||||
'intelligence.agentWork.kind.backgroundAgent': 'Agent en arrière-plan',
|
||||
'intelligence.agentWork.kind.teamMember': 'Membre de l’équipe',
|
||||
'intelligence.agentWork.kind.workflowChild': 'Élément enfant de workflow',
|
||||
'intelligence.agentWork.openThread': 'Ouvrir le fil',
|
||||
'intelligence.agentWork.openWorker': 'Ouvrir le worker',
|
||||
'intelligence.refine.sourceIntake': 'Source : réception des sources de tâches',
|
||||
'intelligence.refine.repositoryLine': 'Dépôt : {repo}',
|
||||
'intelligence.refine.externalTaskLine': 'Tâche externe : {externalId}',
|
||||
|
||||
@@ -309,6 +309,9 @@ const messages: TranslationMap = {
|
||||
'memory.tab.tasksDescription':
|
||||
'कार्य बनाएं और ट्रैक करें — आपके अपने टू-डू और साथ ही वे बोर्ड जो आपके एजेंट वार्तालापों में बनाते हैं।',
|
||||
'memory.tab.subconscious': 'सबकॉन्शस',
|
||||
'memory.tab.agentWork': 'एजेंट कार्य',
|
||||
'memory.tab.agentWorkDescription':
|
||||
'हर पृष्ठभूमि एजेंट रन के लिए एक कमांड सेंटर — इस आधार पर समूहित कि किसे आपकी जानकारी चाहिए, क्या चल रहा है और क्या पूरा हो चुका है।',
|
||||
'memory.tab.agents': 'लाइब्रेरी',
|
||||
'memory.tab.agentsDescription':
|
||||
'अपने उपलब्ध एजेंट ब्राउज़ करें और चलाएं — प्रत्येक के पास अपने टूल, क्षमताएं और फोकस क्षेत्र हैं।',
|
||||
@@ -2827,6 +2830,35 @@ const messages: TranslationMap = {
|
||||
'intelligence.workTask.urlLine': '- यूआरएल: {url}',
|
||||
'intelligence.workTask.closingInstruction':
|
||||
'पहले ठोस कार्यान्वयन योजना को संक्षेप में दोहराएँ, फिर उसे निष्पादित करें। इस थ्रेड में प्रगति दिखती रहे और कार्य की स्थिति बदलने पर कार्य बोर्ड अपडेट करें।',
|
||||
'intelligence.agentWork.subtitle': 'हर पृष्ठभूमि एजेंट रन, जीवनचक्र स्थिति के अनुसार समूहित।',
|
||||
'intelligence.agentWork.loading': 'एजेंट कार्य लोड हो रहा है…',
|
||||
'intelligence.agentWork.failedToLoad': 'एजेंट कार्य लोड नहीं हो सका',
|
||||
'intelligence.agentWork.empty': 'अभी तक कोई पृष्ठभूमि एजेंट रन नहीं।',
|
||||
'intelligence.agentWork.bucket.needsInput': 'इनपुट चाहिए',
|
||||
'intelligence.agentWork.bucket.working': 'काम जारी',
|
||||
'intelligence.agentWork.bucket.completed': 'पूरा हुआ',
|
||||
'intelligence.agentWork.bucket.failed': 'विफल',
|
||||
'intelligence.agentWork.bucket.stopped': 'रुका हुआ',
|
||||
'intelligence.agentWork.column.agent': 'एजेंट',
|
||||
'intelligence.agentWork.column.status': 'स्टेटस',
|
||||
'intelligence.agentWork.column.elapsed': 'बीता समय',
|
||||
'intelligence.agentWork.column.cost': 'लागत',
|
||||
'intelligence.agentWork.column.tokens': 'टोकन',
|
||||
'intelligence.agentWork.status.pending': 'लंबित',
|
||||
'intelligence.agentWork.status.running': 'चल रहा है',
|
||||
'intelligence.agentWork.status.awaitingUser': 'इनपुट चाहिए',
|
||||
'intelligence.agentWork.status.paused': 'रुका हुआ',
|
||||
'intelligence.agentWork.status.completed': 'पूरा हुआ',
|
||||
'intelligence.agentWork.status.failed': 'विफल',
|
||||
'intelligence.agentWork.status.cancelled': 'रद्द हुआ',
|
||||
'intelligence.agentWork.status.interrupted': 'बाधित',
|
||||
'intelligence.agentWork.kind.subagent': 'सब-एजेंट',
|
||||
'intelligence.agentWork.kind.workerThread': 'वर्कर थ्रेड',
|
||||
'intelligence.agentWork.kind.backgroundAgent': 'बैकग्राउंड एजेंट',
|
||||
'intelligence.agentWork.kind.teamMember': 'टीम सदस्य',
|
||||
'intelligence.agentWork.kind.workflowChild': 'वर्कफ़्लो चाइल्ड',
|
||||
'intelligence.agentWork.openThread': 'थ्रेड खोलें',
|
||||
'intelligence.agentWork.openWorker': 'वर्कर खोलें',
|
||||
'intelligence.refine.objectiveDefault':
|
||||
'स्रोत कार्य को कार्यान्वयन के लिए तैयार एजेंट कार्य में बदलें: {title}',
|
||||
'intelligence.refine.sourceLine': 'स्रोत: {url}',
|
||||
|
||||
@@ -311,6 +311,9 @@ const messages: TranslationMap = {
|
||||
'memory.tab.tasksDescription':
|
||||
'Buat dan lacak tugas — to-do Anda sendiri beserta papan yang dibangun agen Anda di berbagai percakapan.',
|
||||
'memory.tab.subconscious': 'Bawah sadar',
|
||||
'memory.tab.agentWork': 'Kerja agen',
|
||||
'memory.tab.agentWorkDescription':
|
||||
'Pusat kendali untuk setiap proses agen latar belakang — dikelompokkan berdasarkan apa yang butuh masukan Anda, apa yang sedang berjalan, dan apa yang sudah selesai.',
|
||||
'memory.tab.agents': 'Perpustakaan',
|
||||
'memory.tab.agentsDescription':
|
||||
'Telusuri dan jalankan agen yang tersedia — masing-masing dengan alat, kemampuan, dan area fokusnya sendiri.',
|
||||
@@ -2829,6 +2832,36 @@ const messages: TranslationMap = {
|
||||
'intelligence.workTask.urlLine': '- Tautan: {url}',
|
||||
'intelligence.workTask.closingInstruction':
|
||||
'Mulailah dengan menyatakan kembali rencana implementasi konkret secara singkat, lalu jalankan. Jaga agar kemajuan tetap terlihat di utas ini dan perbarui papan tugas ketika status pekerjaan berubah.',
|
||||
'intelligence.agentWork.subtitle':
|
||||
'Setiap proses agen latar belakang, dikelompokkan menurut status siklus hidup.',
|
||||
'intelligence.agentWork.loading': 'Memuat kerja agen…',
|
||||
'intelligence.agentWork.failedToLoad': 'Gagal memuat kerja agen',
|
||||
'intelligence.agentWork.empty': 'Belum ada proses agen latar belakang.',
|
||||
'intelligence.agentWork.bucket.needsInput': 'Perlu masukan',
|
||||
'intelligence.agentWork.bucket.working': 'Berjalan',
|
||||
'intelligence.agentWork.bucket.completed': 'Selesai',
|
||||
'intelligence.agentWork.bucket.failed': 'Gagal',
|
||||
'intelligence.agentWork.bucket.stopped': 'Berhenti',
|
||||
'intelligence.agentWork.column.agent': 'Agen',
|
||||
'intelligence.agentWork.column.status': 'Status',
|
||||
'intelligence.agentWork.column.elapsed': 'Berlalu',
|
||||
'intelligence.agentWork.column.cost': 'Biaya',
|
||||
'intelligence.agentWork.column.tokens': 'Token',
|
||||
'intelligence.agentWork.status.pending': 'Tertunda',
|
||||
'intelligence.agentWork.status.running': 'Berjalan',
|
||||
'intelligence.agentWork.status.awaitingUser': 'Perlu masukan',
|
||||
'intelligence.agentWork.status.paused': 'Dijeda',
|
||||
'intelligence.agentWork.status.completed': 'Selesai',
|
||||
'intelligence.agentWork.status.failed': 'Gagal',
|
||||
'intelligence.agentWork.status.cancelled': 'Dibatalkan',
|
||||
'intelligence.agentWork.status.interrupted': 'Terputus',
|
||||
'intelligence.agentWork.kind.subagent': 'Subagen',
|
||||
'intelligence.agentWork.kind.workerThread': 'Thread worker',
|
||||
'intelligence.agentWork.kind.backgroundAgent': 'Agen latar belakang',
|
||||
'intelligence.agentWork.kind.teamMember': 'Anggota tim',
|
||||
'intelligence.agentWork.kind.workflowChild': 'Anak alur kerja',
|
||||
'intelligence.agentWork.openThread': 'Buka utas',
|
||||
'intelligence.agentWork.openWorker': 'Buka pekerja',
|
||||
'intelligence.refine.objectiveDefault':
|
||||
'Ubah tugas sumber menjadi tugas agen yang siap diimplementasikan: {title}',
|
||||
'intelligence.refine.sourceLine': 'Sumber: {url}',
|
||||
|
||||
@@ -316,6 +316,9 @@ const messages: TranslationMap = {
|
||||
'memory.tab.tasksDescription':
|
||||
'Crea e monitora le attività — i tuoi to-do personali e le board create dagli agenti nelle conversazioni.',
|
||||
'memory.tab.subconscious': 'Subconscio',
|
||||
'memory.tab.agentWork': "Lavoro dell'agente",
|
||||
'memory.tab.agentWorkDescription':
|
||||
'Un centro di comando per ogni esecuzione di agente in background, raggruppata in base a ciò che richiede il tuo intervento, ciò che è in corso e ciò che è terminato.',
|
||||
'memory.tab.agents': 'Libreria',
|
||||
'memory.tab.agentsDescription':
|
||||
'Sfoglia e avvia gli agenti disponibili — ognuno con i propri strumenti, capacità e area di specializzazione.',
|
||||
@@ -2870,6 +2873,36 @@ const messages: TranslationMap = {
|
||||
'intelligence.workTask.urlLine': '- Indirizzo: {url}',
|
||||
'intelligence.workTask.closingInstruction':
|
||||
'Inizia riformulando brevemente il piano di implementazione concreto, poi eseguilo. Mantieni i progressi visibili in questo thread e aggiorna la bacheca delle attività quando cambia lo stato del lavoro.',
|
||||
'intelligence.agentWork.subtitle':
|
||||
'Ogni esecuzione di agente in background, raggruppata per stato del ciclo di vita.',
|
||||
'intelligence.agentWork.loading': "Caricamento del lavoro dell'agente…",
|
||||
'intelligence.agentWork.failedToLoad': "Impossibile caricare il lavoro dell'agente",
|
||||
'intelligence.agentWork.empty': 'Ancora nessuna esecuzione di agente in background.',
|
||||
'intelligence.agentWork.bucket.needsInput': 'Richiede intervento',
|
||||
'intelligence.agentWork.bucket.working': 'In corso',
|
||||
'intelligence.agentWork.bucket.completed': 'Completato',
|
||||
'intelligence.agentWork.bucket.failed': 'Fallito',
|
||||
'intelligence.agentWork.bucket.stopped': 'Fermato',
|
||||
'intelligence.agentWork.column.agent': 'Agente',
|
||||
'intelligence.agentWork.column.status': 'Stato',
|
||||
'intelligence.agentWork.column.elapsed': 'Trascorso',
|
||||
'intelligence.agentWork.column.cost': 'Costo',
|
||||
'intelligence.agentWork.column.tokens': 'Gettoni',
|
||||
'intelligence.agentWork.status.pending': 'In sospeso',
|
||||
'intelligence.agentWork.status.running': 'In esecuzione',
|
||||
'intelligence.agentWork.status.awaitingUser': 'Richiede intervento',
|
||||
'intelligence.agentWork.status.paused': 'In pausa',
|
||||
'intelligence.agentWork.status.completed': 'Completato',
|
||||
'intelligence.agentWork.status.failed': 'Fallito',
|
||||
'intelligence.agentWork.status.cancelled': 'Annullato',
|
||||
'intelligence.agentWork.status.interrupted': 'Interrotto',
|
||||
'intelligence.agentWork.kind.subagent': 'Sottoagente',
|
||||
'intelligence.agentWork.kind.workerThread': 'Thread worker',
|
||||
'intelligence.agentWork.kind.backgroundAgent': 'Agente in background',
|
||||
'intelligence.agentWork.kind.teamMember': 'Membro del team',
|
||||
'intelligence.agentWork.kind.workflowChild': 'Figlio del flusso di lavoro',
|
||||
'intelligence.agentWork.openThread': 'Apri thread',
|
||||
'intelligence.agentWork.openWorker': 'Apri worker',
|
||||
'intelligence.refine.objectiveDefault':
|
||||
"Trasforma l'attività di origine in un'attività dell'agente pronta per l'implementazione: {title}",
|
||||
'intelligence.refine.sourceLine': 'Origine: {url}',
|
||||
|
||||
@@ -309,6 +309,9 @@ const messages: TranslationMap = {
|
||||
'memory.tab.tasksDescription':
|
||||
'작업을 만들고 추적하세요 — 본인의 할 일 목록과 에이전트가 대화를 통해 구성한 보드가 모두 포함됩니다.',
|
||||
'memory.tab.subconscious': '잠재의식',
|
||||
'memory.tab.agentWork': '에이전트 작업',
|
||||
'memory.tab.agentWorkDescription':
|
||||
'모든 백그라운드 에이전트 실행을 위한 명령 센터 — 입력이 필요한 것, 진행 중인 것, 완료된 것별로 그룹화됩니다.',
|
||||
'memory.tab.agents': '라이브러리',
|
||||
'memory.tab.agentsDescription':
|
||||
'사용 가능한 에이전트를 탐색하고 실행하세요 — 각 에이전트는 고유한 도구, 기능 및 전문 분야를 갖추고 있습니다.',
|
||||
@@ -2800,6 +2803,36 @@ const messages: TranslationMap = {
|
||||
'intelligence.workTask.urlLine': '- 링크: {url}',
|
||||
'intelligence.workTask.closingInstruction':
|
||||
'먼저 구체적인 구현 계획을 간략히 다시 설명한 다음 실행하세요. 이 스레드에서 진행 상황을 계속 보이게 하고 작업 상태가 바뀌면 작업 보드를 업데이트하세요.',
|
||||
'intelligence.agentWork.subtitle':
|
||||
'모든 백그라운드 에이전트 실행을 수명 주기 상태별로 그룹화합니다.',
|
||||
'intelligence.agentWork.loading': '에이전트 작업 불러오는 중…',
|
||||
'intelligence.agentWork.failedToLoad': '에이전트 작업을 불러오지 못했습니다',
|
||||
'intelligence.agentWork.empty': '아직 백그라운드 에이전트 실행이 없습니다.',
|
||||
'intelligence.agentWork.bucket.needsInput': '입력 필요',
|
||||
'intelligence.agentWork.bucket.working': '작업 중',
|
||||
'intelligence.agentWork.bucket.completed': '완료됨',
|
||||
'intelligence.agentWork.bucket.failed': '실패',
|
||||
'intelligence.agentWork.bucket.stopped': '중지됨',
|
||||
'intelligence.agentWork.column.agent': '에이전트',
|
||||
'intelligence.agentWork.column.status': '상태',
|
||||
'intelligence.agentWork.column.elapsed': '경과 시간',
|
||||
'intelligence.agentWork.column.cost': '비용',
|
||||
'intelligence.agentWork.column.tokens': '토큰',
|
||||
'intelligence.agentWork.status.pending': '대기 중',
|
||||
'intelligence.agentWork.status.running': '실행 중',
|
||||
'intelligence.agentWork.status.awaitingUser': '입력 필요',
|
||||
'intelligence.agentWork.status.paused': '일시 중지됨',
|
||||
'intelligence.agentWork.status.completed': '완료됨',
|
||||
'intelligence.agentWork.status.failed': '실패',
|
||||
'intelligence.agentWork.status.cancelled': '취소됨',
|
||||
'intelligence.agentWork.status.interrupted': '중단됨',
|
||||
'intelligence.agentWork.kind.subagent': '하위 에이전트',
|
||||
'intelligence.agentWork.kind.workerThread': '워커 스레드',
|
||||
'intelligence.agentWork.kind.backgroundAgent': '백그라운드 에이전트',
|
||||
'intelligence.agentWork.kind.teamMember': '팀 구성원',
|
||||
'intelligence.agentWork.kind.workflowChild': '워크플로 하위 항목',
|
||||
'intelligence.agentWork.openThread': '스레드 열기',
|
||||
'intelligence.agentWork.openWorker': '워커 열기',
|
||||
'intelligence.refine.objectiveDefault':
|
||||
'소스 작업을 구현 준비가 된 에이전트 작업으로 전환하세요: {title}',
|
||||
'intelligence.refine.sourceLine': '소스: {url}',
|
||||
|
||||
@@ -314,6 +314,9 @@ const messages: TranslationMap = {
|
||||
'memory.tab.tasksDescription':
|
||||
'Twórz i śledź zadania — własne listy do zrobienia oraz tablice, które Twoi agenci budują w rozmowach.',
|
||||
'memory.tab.subconscious': 'Podświadomość',
|
||||
'memory.tab.agentWork': 'Praca agenta',
|
||||
'memory.tab.agentWorkDescription':
|
||||
'Centrum dowodzenia dla każdego przebiegu agenta w tle — pogrupowane według tego, co wymaga Twojej reakcji, co działa i co zostało ukończone.',
|
||||
'memory.tab.agents': 'Biblioteka',
|
||||
'memory.tab.agentsDescription':
|
||||
'Przeglądaj i uruchamiaj dostępnych agentów — każdy z własnymi narzędziami, możliwościami i obszarem specjalizacji.',
|
||||
@@ -2861,6 +2864,36 @@ const messages: TranslationMap = {
|
||||
'intelligence.workTask.urlLine': '- Adres: {url}',
|
||||
'intelligence.workTask.closingInstruction':
|
||||
'Zacznij od krótkiego powtórzenia konkretnego planu wdrożenia, a następnie go zrealizuj. Utrzymuj widoczność postępów w tym wątku i aktualizuj tablicę zadań, gdy zmienia się stan pracy.',
|
||||
'intelligence.agentWork.subtitle':
|
||||
'Każdy przebieg agenta w tle, pogrupowany według stanu cyklu życia.',
|
||||
'intelligence.agentWork.loading': 'Ładowanie pracy agenta…',
|
||||
'intelligence.agentWork.failedToLoad': 'Nie udało się załadować pracy agenta',
|
||||
'intelligence.agentWork.empty': 'Brak przebiegów agenta w tle.',
|
||||
'intelligence.agentWork.bucket.needsInput': 'Wymaga reakcji',
|
||||
'intelligence.agentWork.bucket.working': 'W toku',
|
||||
'intelligence.agentWork.bucket.completed': 'Ukończone',
|
||||
'intelligence.agentWork.bucket.failed': 'Niepowodzenie',
|
||||
'intelligence.agentWork.bucket.stopped': 'Zatrzymane',
|
||||
'intelligence.agentWork.column.agent': 'Agent',
|
||||
'intelligence.agentWork.column.status': 'Status',
|
||||
'intelligence.agentWork.column.elapsed': 'Czas trwania',
|
||||
'intelligence.agentWork.column.cost': 'Koszt',
|
||||
'intelligence.agentWork.column.tokens': 'Tokeny',
|
||||
'intelligence.agentWork.status.pending': 'Oczekujące',
|
||||
'intelligence.agentWork.status.running': 'W toku',
|
||||
'intelligence.agentWork.status.awaitingUser': 'Wymaga reakcji',
|
||||
'intelligence.agentWork.status.paused': 'Wstrzymane',
|
||||
'intelligence.agentWork.status.completed': 'Ukończone',
|
||||
'intelligence.agentWork.status.failed': 'Niepowodzenie',
|
||||
'intelligence.agentWork.status.cancelled': 'Anulowane',
|
||||
'intelligence.agentWork.status.interrupted': 'Przerwane',
|
||||
'intelligence.agentWork.kind.subagent': 'Podagent',
|
||||
'intelligence.agentWork.kind.workerThread': 'Wątek workera',
|
||||
'intelligence.agentWork.kind.backgroundAgent': 'Agent w tle',
|
||||
'intelligence.agentWork.kind.teamMember': 'Członek zespołu',
|
||||
'intelligence.agentWork.kind.workflowChild': 'Element podrzędny przepływu',
|
||||
'intelligence.agentWork.openThread': 'Otwórz wątek',
|
||||
'intelligence.agentWork.openWorker': 'Otwórz proces',
|
||||
'intelligence.refine.objectiveDefault':
|
||||
'Przekształć zadanie źródłowe w gotowe do wdrożenia zadanie agenta: {title}',
|
||||
'intelligence.refine.sourceLine': 'Źródło: {url}',
|
||||
|
||||
@@ -318,6 +318,9 @@ const messages: TranslationMap = {
|
||||
'memory.tab.tasksDescription':
|
||||
'Crie e acompanhe tarefas — seus próprios afazeres e os painéis que seus agentes constroem ao longo das conversas.',
|
||||
'memory.tab.subconscious': 'Subconsciente',
|
||||
'memory.tab.agentWork': 'Trabalho do agente',
|
||||
'memory.tab.agentWorkDescription':
|
||||
'Um centro de comando para cada execução de agente em segundo plano, agrupada conforme o que precisa da sua intervenção, o que está em andamento e o que foi concluído.',
|
||||
'memory.tab.agents': 'Biblioteca',
|
||||
'memory.tab.agentsDescription':
|
||||
'Navegue e execute os agentes disponíveis — cada um com suas próprias ferramentas, capacidades e área de foco.',
|
||||
@@ -2873,6 +2876,36 @@ const messages: TranslationMap = {
|
||||
'intelligence.workTask.urlLine': '- Endereço: {url}',
|
||||
'intelligence.workTask.closingInstruction':
|
||||
'Comece reformulando brevemente o plano de implementação concreto e depois execute-o. Mantenha o progresso visível neste tópico e atualize o quadro de tarefas quando o estado do trabalho mudar.',
|
||||
'intelligence.agentWork.subtitle':
|
||||
'Cada execução de agente em segundo plano, agrupada por estado do ciclo de vida.',
|
||||
'intelligence.agentWork.loading': 'Carregando trabalho do agente…',
|
||||
'intelligence.agentWork.failedToLoad': 'Não foi possível carregar o trabalho do agente',
|
||||
'intelligence.agentWork.empty': 'Ainda não há execuções de agente em segundo plano.',
|
||||
'intelligence.agentWork.bucket.needsInput': 'Requer intervenção',
|
||||
'intelligence.agentWork.bucket.working': 'Em andamento',
|
||||
'intelligence.agentWork.bucket.completed': 'Concluído',
|
||||
'intelligence.agentWork.bucket.failed': 'Falhou',
|
||||
'intelligence.agentWork.bucket.stopped': 'Parado',
|
||||
'intelligence.agentWork.column.agent': 'Agente',
|
||||
'intelligence.agentWork.column.status': 'Status',
|
||||
'intelligence.agentWork.column.elapsed': 'Decorrido',
|
||||
'intelligence.agentWork.column.cost': 'Custo',
|
||||
'intelligence.agentWork.column.tokens': 'Tokens',
|
||||
'intelligence.agentWork.status.pending': 'Pendente',
|
||||
'intelligence.agentWork.status.running': 'Em andamento',
|
||||
'intelligence.agentWork.status.awaitingUser': 'Requer intervenção',
|
||||
'intelligence.agentWork.status.paused': 'Pausado',
|
||||
'intelligence.agentWork.status.completed': 'Concluído',
|
||||
'intelligence.agentWork.status.failed': 'Falhou',
|
||||
'intelligence.agentWork.status.cancelled': 'Cancelado',
|
||||
'intelligence.agentWork.status.interrupted': 'Interrompido',
|
||||
'intelligence.agentWork.kind.subagent': 'Subagente',
|
||||
'intelligence.agentWork.kind.workerThread': 'Thread de worker',
|
||||
'intelligence.agentWork.kind.backgroundAgent': 'Agente em segundo plano',
|
||||
'intelligence.agentWork.kind.teamMember': 'Membro da equipe',
|
||||
'intelligence.agentWork.kind.workflowChild': 'Filho de fluxo de trabalho',
|
||||
'intelligence.agentWork.openThread': 'Abrir tópico',
|
||||
'intelligence.agentWork.openWorker': 'Abrir trabalhador',
|
||||
'intelligence.refine.objectiveDefault':
|
||||
'Transforme a tarefa de origem em uma tarefa de agente pronta para implementação: {title}',
|
||||
'intelligence.refine.sourceLine': 'Origem: {url}',
|
||||
|
||||
@@ -311,6 +311,9 @@ const messages: TranslationMap = {
|
||||
'memory.tab.tasksDescription':
|
||||
'Создавайте и отслеживайте задачи — ваши личные дела и доски, которые агенты формируют в ходе разговоров.',
|
||||
'memory.tab.subconscious': 'Подсознание',
|
||||
'memory.tab.agentWork': 'Работа агента',
|
||||
'memory.tab.agentWorkDescription':
|
||||
'Центр управления для каждого фонового запуска агента — сгруппировано по тому, что требует вашего участия, что выполняется и что завершено.',
|
||||
'memory.tab.agents': 'Библиотека',
|
||||
'memory.tab.agentsDescription':
|
||||
'Просматривайте и запускайте доступных агентов — у каждого свои инструменты, возможности и область специализации.',
|
||||
@@ -2846,6 +2849,36 @@ const messages: TranslationMap = {
|
||||
'intelligence.workTask.urlLine': '- Ссылка: {url}',
|
||||
'intelligence.workTask.closingInstruction':
|
||||
'Начните с краткого повторения конкретного плана реализации, затем выполните его. Поддерживайте видимость прогресса в этой ветке и обновляйте доску задач при изменении состояния работы.',
|
||||
'intelligence.agentWork.subtitle':
|
||||
'Каждый фоновый запуск агента, сгруппированный по состоянию жизненного цикла.',
|
||||
'intelligence.agentWork.loading': 'Загрузка работы агента…',
|
||||
'intelligence.agentWork.failedToLoad': 'Не удалось загрузить работу агента',
|
||||
'intelligence.agentWork.empty': 'Фоновых запусков агента пока нет.',
|
||||
'intelligence.agentWork.bucket.needsInput': 'Нужны данные',
|
||||
'intelligence.agentWork.bucket.working': 'В работе',
|
||||
'intelligence.agentWork.bucket.completed': 'Завершено',
|
||||
'intelligence.agentWork.bucket.failed': 'Ошибка',
|
||||
'intelligence.agentWork.bucket.stopped': 'Остановлено',
|
||||
'intelligence.agentWork.column.agent': 'Агент',
|
||||
'intelligence.agentWork.column.status': 'Статус',
|
||||
'intelligence.agentWork.column.elapsed': 'Прошло',
|
||||
'intelligence.agentWork.column.cost': 'Расходы',
|
||||
'intelligence.agentWork.column.tokens': 'Токены',
|
||||
'intelligence.agentWork.status.pending': 'В ожидании',
|
||||
'intelligence.agentWork.status.running': 'В работе',
|
||||
'intelligence.agentWork.status.awaitingUser': 'Нужны данные',
|
||||
'intelligence.agentWork.status.paused': 'Приостановлено',
|
||||
'intelligence.agentWork.status.completed': 'Завершено',
|
||||
'intelligence.agentWork.status.failed': 'Ошибка',
|
||||
'intelligence.agentWork.status.cancelled': 'Отменено',
|
||||
'intelligence.agentWork.status.interrupted': 'Прервано',
|
||||
'intelligence.agentWork.kind.subagent': 'Субагент',
|
||||
'intelligence.agentWork.kind.workerThread': 'Чат воркера',
|
||||
'intelligence.agentWork.kind.backgroundAgent': 'Фоновый агент',
|
||||
'intelligence.agentWork.kind.teamMember': 'Участник команды',
|
||||
'intelligence.agentWork.kind.workflowChild': 'Дочерний элемент рабочего процесса',
|
||||
'intelligence.agentWork.openThread': 'Открыть тред',
|
||||
'intelligence.agentWork.openWorker': 'Открыть воркер',
|
||||
'intelligence.refine.objectiveDefault':
|
||||
'Превратите исходную задачу в готовую к реализации задачу агента: {title}',
|
||||
'intelligence.refine.sourceLine': 'Источник: {url}',
|
||||
|
||||
@@ -296,6 +296,9 @@ const messages: TranslationMap = {
|
||||
'memory.tab.tasksDescription':
|
||||
'创建并跟踪任务——包括您自己的待办事项以及智能体在对话中创建的看板。',
|
||||
'memory.tab.subconscious': '潜意识',
|
||||
'memory.tab.agentWork': '智能体工作',
|
||||
'memory.tab.agentWorkDescription':
|
||||
'所有后台智能体运行的指挥中心——按需要你处理的、正在运行的和已完成的进行分组。',
|
||||
'memory.tab.agents': '资料库',
|
||||
'memory.tab.agentsDescription':
|
||||
'浏览并运行可用的智能体——每个智能体都有自己的工具、能力和专注领域。',
|
||||
@@ -2685,6 +2688,35 @@ const messages: TranslationMap = {
|
||||
'intelligence.workTask.urlLine': '- 网址:{url}',
|
||||
'intelligence.workTask.closingInstruction':
|
||||
'先简要重述具体的实施计划,然后执行它。在此线程中保持进度可见,并在工作状态变化时更新任务看板。',
|
||||
'intelligence.agentWork.subtitle': '所有后台智能体运行,按生命周期状态分组。',
|
||||
'intelligence.agentWork.loading': '正在加载智能体工作…',
|
||||
'intelligence.agentWork.failedToLoad': '无法加载智能体工作',
|
||||
'intelligence.agentWork.empty': '暂无后台智能体运行。',
|
||||
'intelligence.agentWork.bucket.needsInput': '需要输入',
|
||||
'intelligence.agentWork.bucket.working': '进行中',
|
||||
'intelligence.agentWork.bucket.completed': '已完成',
|
||||
'intelligence.agentWork.bucket.failed': '失败',
|
||||
'intelligence.agentWork.bucket.stopped': '已停止',
|
||||
'intelligence.agentWork.column.agent': '智能体',
|
||||
'intelligence.agentWork.column.status': '状态',
|
||||
'intelligence.agentWork.column.elapsed': '已用时间',
|
||||
'intelligence.agentWork.column.cost': '成本',
|
||||
'intelligence.agentWork.column.tokens': '令牌',
|
||||
'intelligence.agentWork.status.pending': '待定',
|
||||
'intelligence.agentWork.status.running': '进行中',
|
||||
'intelligence.agentWork.status.awaitingUser': '需要输入',
|
||||
'intelligence.agentWork.status.paused': '已暂停',
|
||||
'intelligence.agentWork.status.completed': '已完成',
|
||||
'intelligence.agentWork.status.failed': '失败',
|
||||
'intelligence.agentWork.status.cancelled': '已取消',
|
||||
'intelligence.agentWork.status.interrupted': '已中断',
|
||||
'intelligence.agentWork.kind.subagent': '子智能体',
|
||||
'intelligence.agentWork.kind.workerThread': '工作线程',
|
||||
'intelligence.agentWork.kind.backgroundAgent': '后台智能体',
|
||||
'intelligence.agentWork.kind.teamMember': '团队成员',
|
||||
'intelligence.agentWork.kind.workflowChild': '工作流子项',
|
||||
'intelligence.agentWork.openThread': '打开会话',
|
||||
'intelligence.agentWork.openWorker': '打开工作线程',
|
||||
'intelligence.refine.objectiveDefault': '将来源任务转化为可立即实施的智能体任务:{title}',
|
||||
'intelligence.refine.sourceLine': '来源:{url}',
|
||||
'intelligence.refine.sourceIntake': '来源:任务来源接收',
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
import { ConfirmationModal } from '../components/intelligence/ConfirmationModal';
|
||||
import IntelligenceAgentsTab from '../components/intelligence/IntelligenceAgentsTab';
|
||||
import IntelligenceAgentWorkTab from '../components/intelligence/IntelligenceAgentWorkTab';
|
||||
import IntelligenceSubconsciousTab from '../components/intelligence/IntelligenceSubconsciousTab';
|
||||
import IntelligenceTasksTab from '../components/intelligence/IntelligenceTasksTab';
|
||||
import MemorySection from '../components/intelligence/MemorySection';
|
||||
@@ -22,12 +23,20 @@ import type {
|
||||
} from '../types/intelligence';
|
||||
import { IS_DEV } from '../utils/config';
|
||||
|
||||
type IntelligenceTab = 'memory' | 'subconscious' | 'tasks' | 'agents' | 'workflows' | 'council';
|
||||
type IntelligenceTab =
|
||||
| 'memory'
|
||||
| 'subconscious'
|
||||
| 'tasks'
|
||||
| 'agent-work'
|
||||
| 'agents'
|
||||
| 'workflows'
|
||||
| 'council';
|
||||
|
||||
const INTELLIGENCE_TABS: IntelligenceTab[] = [
|
||||
'memory',
|
||||
'subconscious',
|
||||
'tasks',
|
||||
'agent-work',
|
||||
'agents',
|
||||
'workflows',
|
||||
'council',
|
||||
@@ -128,6 +137,11 @@ export default function Intelligence() {
|
||||
devOnly?: boolean;
|
||||
}[] = [
|
||||
{ id: 'tasks', label: t('memory.tab.tasks'), description: t('memory.tab.tasksDescription') },
|
||||
{
|
||||
id: 'agent-work',
|
||||
label: t('memory.tab.agentWork'),
|
||||
description: t('memory.tab.agentWorkDescription'),
|
||||
},
|
||||
{ id: 'memory', label: t('memory.tab.memory') },
|
||||
{ id: 'subconscious', label: t('memory.tab.subconscious') },
|
||||
{
|
||||
@@ -215,6 +229,8 @@ export default function Intelligence() {
|
||||
|
||||
{activeTab === 'tasks' && <IntelligenceTasksTab />}
|
||||
|
||||
{activeTab === 'agent-work' && <IntelligenceAgentWorkTab />}
|
||||
|
||||
{activeTab === 'agents' && <IntelligenceAgentsTab />}
|
||||
|
||||
{activeTab === 'workflows' && <WorkflowsTab />}
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { callCoreRpc } from '../coreRpcClient';
|
||||
import { agentWorkApi, type AgentWorkResponse } from './agentWorkApi';
|
||||
|
||||
vi.mock('../coreRpcClient', () => ({ callCoreRpc: vi.fn() }));
|
||||
|
||||
const mockCall = vi.mocked(callCoreRpc);
|
||||
|
||||
function response(): AgentWorkResponse {
|
||||
return {
|
||||
total: 2,
|
||||
groups: [
|
||||
{ bucket: 'needs_input', count: 0, rows: [] },
|
||||
{
|
||||
bucket: 'working',
|
||||
count: 1,
|
||||
rows: [
|
||||
{
|
||||
runId: 'run-1',
|
||||
kind: 'subagent',
|
||||
agentId: 'agent-a',
|
||||
displayName: 'Researcher',
|
||||
bucket: 'working',
|
||||
status: 'running',
|
||||
workerThreadId: 'thread-w',
|
||||
startedAt: '2026-01-01T00:00:00Z',
|
||||
updatedAt: '2026-01-01T00:01:00Z',
|
||||
elapsedMs: 60000,
|
||||
inputTokens: 100,
|
||||
outputTokens: 50,
|
||||
costUsd: 0.01,
|
||||
toolCount: 2,
|
||||
},
|
||||
],
|
||||
},
|
||||
{ bucket: 'completed', count: 1, rows: [] },
|
||||
{ bucket: 'failed', count: 0, rows: [] },
|
||||
{ bucket: 'stopped', count: 0, rows: [] },
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
describe('agentWorkApi', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('list calls the agent_work_list RPC with no params when limit is omitted', async () => {
|
||||
mockCall.mockResolvedValueOnce(response());
|
||||
await agentWorkApi.list();
|
||||
expect(mockCall).toHaveBeenCalledWith({ method: 'openhuman.agent_work_list', params: {} });
|
||||
});
|
||||
|
||||
it('list forwards an explicit limit', async () => {
|
||||
mockCall.mockResolvedValueOnce(response());
|
||||
await agentWorkApi.list(25);
|
||||
expect(mockCall).toHaveBeenCalledWith({
|
||||
method: 'openhuman.agent_work_list',
|
||||
params: { limit: 25 },
|
||||
});
|
||||
});
|
||||
|
||||
it('list rejects a non-positive or non-integer limit without calling core', async () => {
|
||||
await expect(agentWorkApi.list(0)).rejects.toThrow('positive integer');
|
||||
await expect(agentWorkApi.list(-5)).rejects.toThrow('positive integer');
|
||||
await expect(agentWorkApi.list(1.5)).rejects.toThrow('positive integer');
|
||||
expect(mockCall).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('list returns the grouped response unchanged (wire is already camelCase)', async () => {
|
||||
mockCall.mockResolvedValueOnce(response());
|
||||
const result = await agentWorkApi.list();
|
||||
expect(result.total).toBe(2);
|
||||
expect(result.groups).toHaveLength(5);
|
||||
expect(result.groups.map(g => g.bucket)).toEqual([
|
||||
'needs_input',
|
||||
'working',
|
||||
'completed',
|
||||
'failed',
|
||||
'stopped',
|
||||
]);
|
||||
const working = result.groups.find(g => g.bucket === 'working');
|
||||
expect(working?.count).toBe(1);
|
||||
expect(working?.rows[0].displayName).toBe('Researcher');
|
||||
expect(working?.rows[0].workerThreadId).toBe('thread-w');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Frontend client for the Background Agent Command Center surface
|
||||
* (`openhuman.agent_work_list`). The Rust handler aggregates every tracked
|
||||
* background agent run into five lifecycle buckets and returns the rows
|
||||
* pre-grouped so the UI renders them in a stable order.
|
||||
*
|
||||
* The wire payload is already camelCase (the Rust controller serializes with
|
||||
* `#[serde(rename_all = "camelCase")]`), so this client only types the shape
|
||||
* and forwards the optional `limit`. No snake/camel transform is needed.
|
||||
*/
|
||||
import debug from 'debug';
|
||||
|
||||
import { callCoreRpc } from '../coreRpcClient';
|
||||
|
||||
const log = debug('agentWorkApi');
|
||||
|
||||
/**
|
||||
* Lifecycle bucket a run is sorted into. The handler always emits all five,
|
||||
* in this display order, even when a bucket has zero rows.
|
||||
*/
|
||||
export type AgentWorkBucket = 'needs_input' | 'working' | 'completed' | 'failed' | 'stopped';
|
||||
|
||||
/** A single background agent run. Mirrors the Rust `AgentWorkRow`. */
|
||||
export interface AgentWorkRow {
|
||||
runId: string;
|
||||
kind: string;
|
||||
agentId?: string;
|
||||
displayName?: string;
|
||||
bucket: AgentWorkBucket;
|
||||
status: string;
|
||||
parentThreadId?: string;
|
||||
workerThreadId?: string;
|
||||
summary?: string;
|
||||
error?: string;
|
||||
startedAt: string;
|
||||
updatedAt: string;
|
||||
elapsedMs?: number;
|
||||
inputTokens: number;
|
||||
outputTokens: number;
|
||||
costUsd: number;
|
||||
toolCount: number;
|
||||
}
|
||||
|
||||
/** A bucket of rows plus its precomputed count. Mirrors the Rust group. */
|
||||
export interface AgentWorkGroup {
|
||||
bucket: AgentWorkBucket;
|
||||
count: number;
|
||||
rows: AgentWorkRow[];
|
||||
}
|
||||
|
||||
/** Full response from `openhuman.agent_work_list`. */
|
||||
export interface AgentWorkResponse {
|
||||
groups: AgentWorkGroup[];
|
||||
total: number;
|
||||
}
|
||||
|
||||
export const agentWorkApi = {
|
||||
/**
|
||||
* List all tracked background agent runs, grouped by lifecycle bucket.
|
||||
*
|
||||
* @param limit Optional cap on the number of rows returned (newest first,
|
||||
* applied server-side). Omit to use the handler default.
|
||||
*/
|
||||
list: async (limit?: number): Promise<AgentWorkResponse> => {
|
||||
if (limit !== undefined && (!Number.isInteger(limit) || limit <= 0)) {
|
||||
throw new Error('agentWorkApi.list: limit must be a positive integer');
|
||||
}
|
||||
log('list limit=%o', limit);
|
||||
const response = await callCoreRpc<AgentWorkResponse>({
|
||||
method: 'openhuman.agent_work_list',
|
||||
params: limit === undefined ? {} : { limit },
|
||||
});
|
||||
log('list received groups=%d total=%d', response.groups.length, response.total);
|
||||
return response;
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user