@nextclaw/ui 0.11.23 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/assets/{ChannelsList-DVDu1xvz.js → ChannelsList-DekMP4a3.js} +1 -1
  3. package/dist/assets/ChatPage-Dgw4vlDt.js +43 -0
  4. package/dist/assets/DocBrowser-CExjX5is.js +1 -0
  5. package/dist/assets/{DocBrowser-BmtBLFU0.js → DocBrowser-DjcghYGO.js} +1 -1
  6. package/dist/assets/{DocBrowserContext-YIKkPb76.js → DocBrowserContext-CLlq7rZQ.js} +1 -1
  7. package/dist/assets/{LogoBadge-F7ZWdxLT.js → LogoBadge-D_dOy5U3.js} +1 -1
  8. package/dist/assets/{MarketplacePage-Buo9HrOz.js → MarketplacePage-BlIeNn3x.js} +2 -2
  9. package/dist/assets/MarketplacePage-DGfzg1LG.js +1 -0
  10. package/dist/assets/{McpMarketplacePage-JnkYwK7p.js → McpMarketplacePage-mz2_IX1O.js} +2 -2
  11. package/dist/assets/{ModelConfig-BYRhgp0c.js → ModelConfig-C_49_a9v.js} +1 -1
  12. package/dist/assets/{ProvidersList-DmLyyHvX.js → ProvidersList-B0RCb_Vg.js} +1 -1
  13. package/dist/assets/{RemoteAccessPage-CDSSvH7Z.js → RemoteAccessPage-CcfQjLtx.js} +1 -1
  14. package/dist/assets/RuntimeConfig-DBWzwoY-.js +1 -0
  15. package/dist/assets/{SearchConfig-D5f1EkLE.js → SearchConfig-jSdwlH4b.js} +1 -1
  16. package/dist/assets/{SecretsConfig-D61IKcYt.js → SecretsConfig-DbiS3txa.js} +1 -1
  17. package/dist/assets/{SessionsConfig-BRIxVTEv.js → SessionsConfig-CbIOcAp8.js} +2 -2
  18. package/dist/assets/{book-open-CXoF5nQC.js → book-open-BLxSL7Dk.js} +1 -1
  19. package/dist/assets/chat-session-display-8yW6-mtm.js +1 -0
  20. package/dist/assets/{chunk-JZWAC4HX-CvRWvTy5.js → chunk-JZWAC4HX-Bp0t5xoO.js} +1 -1
  21. package/dist/assets/{config-DJswxxE8.js → config-C96FWufn.js} +1 -1
  22. package/dist/assets/{createLucideIcon-CjGHOWb6.js → createLucideIcon-B_U7Nq4F.js} +1 -1
  23. package/dist/assets/{dist-Cl2QB-2y.js → dist-BFY-GyT4.js} +1 -1
  24. package/dist/assets/{dist-nqTTbVdA.js → dist-D9pHzW9z.js} +1 -1
  25. package/dist/assets/{external-link-tIO7zING.js → external-link-BydIQTIH.js} +1 -1
  26. package/dist/assets/{hash-JWUyl1pT.js → hash-Djdf0x1C.js} +1 -1
  27. package/dist/assets/i18n-DAekxt_G.js +1 -0
  28. package/dist/assets/index-CHEgQIiO.css +1 -0
  29. package/dist/assets/index-DqSv8Azv.js +6 -0
  30. package/dist/assets/{label-BIpeNu4r.js → label-Bvv4Mrea.js} +1 -1
  31. package/dist/assets/loader-circle-CGXXikVG.js +1 -0
  32. package/dist/assets/{logos-DThdM9lk.js → logos-CGJJRI5_.js} +1 -1
  33. package/dist/assets/{page-layout-D3Xo605Z.js → page-layout-6Nm4Cnvr.js} +1 -1
  34. package/dist/assets/plus-CrW9BJDy.js +1 -0
  35. package/dist/assets/{popover-BJRUGA_H.js → popover-b9rSYI6X.js} +1 -1
  36. package/dist/assets/{provider-models-bz5y28rq.js → provider-models-IJDA940D.js} +1 -1
  37. package/dist/assets/{react-7ZHqQtEV.js → react-CDZz_StC.js} +1 -1
  38. package/dist/assets/{refresh-ccw-CC6-_QuL.js → refresh-ccw-BvSSnnCw.js} +1 -1
  39. package/dist/assets/{save-DJM5RRWW.js → save-CAf0_-b9.js} +1 -1
  40. package/dist/assets/search-DgoXxocn.js +1 -0
  41. package/dist/assets/{security-config-DbUyWcQz.js → security-config-DF66-l25.js} +1 -1
  42. package/dist/assets/{select-DSkTc61S.js → select-CEIMqc0H.js} +1 -1
  43. package/dist/assets/skeleton-BiPUQkOD.js +1 -0
  44. package/dist/assets/{status-dot-LNBlDu3q.js → status-dot-CmQI5Qq2.js} +1 -1
  45. package/dist/assets/{switch-Bo-Y46HZ.js → switch-B7SxDXyR.js} +1 -1
  46. package/dist/assets/{tabs-custom-DXv507_2.js → tabs-custom-Dxt6EJJW.js} +1 -1
  47. package/dist/assets/{trash-2-DFZmW6Gg.js → trash-2-BnQ1PDTw.js} +1 -1
  48. package/dist/assets/{useConfirmDialog-COwYXDKm.js → useConfirmDialog-B-vMOmhG.js} +1 -1
  49. package/dist/assets/{useMutation-DrZrOgVL.js → useMutation-Bi39Z9_J.js} +1 -1
  50. package/dist/assets/x-PBSiWt3l.js +1 -0
  51. package/dist/index.html +18 -18
  52. package/package.json +7 -7
  53. package/src/App.tsx +2 -0
  54. package/src/api/agents.ts +26 -0
  55. package/src/api/types.ts +23 -5
  56. package/src/components/agents/AgentsPage.test.tsx +70 -0
  57. package/src/components/agents/AgentsPage.tsx +353 -0
  58. package/src/components/chat/ChatConversationPanel.test.tsx +172 -13
  59. package/src/components/chat/ChatConversationPanel.tsx +30 -7
  60. package/src/components/chat/ChatSidebar.test.tsx +48 -0
  61. package/src/components/chat/ChatSidebar.tsx +11 -0
  62. package/src/components/chat/ChatWelcome.test.tsx +30 -0
  63. package/src/components/chat/ChatWelcome.tsx +50 -1
  64. package/src/components/chat/adapters/chat-message-part.adapter.ts +5 -0
  65. package/src/components/chat/adapters/chat-message-tool-agent-id.test.ts +102 -0
  66. package/src/components/chat/adapters/chat-message-tool-agent-id.ts +47 -0
  67. package/src/components/chat/adapters/chat-message.adapter.test.ts +6 -0
  68. package/src/components/chat/adapters/chat-message.session-request-tool-card.ts +24 -15
  69. package/src/components/chat/chat-child-session-panel.tsx +115 -49
  70. package/src/components/chat/chat-page-runtime.test.ts +30 -0
  71. package/src/components/chat/chat-page-shell.tsx +8 -17
  72. package/src/components/chat/chat-session-route.ts +0 -14
  73. package/src/components/chat/chat-sidebar-session-item.tsx +20 -1
  74. package/src/components/chat/containers/chat-input-bar.container.tsx +2 -1
  75. package/src/components/chat/containers/chat-message-list.container.tsx +7 -0
  76. package/src/components/chat/ncp/NcpChatPage.tsx +77 -158
  77. package/src/components/chat/ncp/README.md +3 -0
  78. package/src/components/chat/ncp/ncp-chat-page-data.test.ts +2 -0
  79. package/src/components/chat/ncp/ncp-chat-thread.manager.ts +66 -10
  80. package/src/components/chat/ncp/ncp-session-adapter.test.ts +2 -0
  81. package/src/components/chat/ncp/ncp-session-adapter.ts +1 -0
  82. package/src/components/chat/ncp/page/ncp-chat-derived-state.ts +128 -0
  83. package/src/components/chat/ncp/session-conversation/use-ncp-child-session-tabs-view.ts +52 -0
  84. package/src/components/chat/ncp/session-conversation/use-ncp-session-conversation.test.tsx +101 -0
  85. package/src/components/chat/ncp/session-conversation/use-ncp-session-conversation.ts +72 -0
  86. package/src/components/chat/presenter/chat-presenter-context.tsx +1 -0
  87. package/src/components/chat/stores/chat-thread.store.ts +20 -6
  88. package/src/components/common/AgentAvatar.tsx +63 -0
  89. package/src/components/common/agent-identity/agent-identity-avatar.tsx +27 -0
  90. package/src/components/common/agent-identity/index.ts +3 -0
  91. package/src/components/common/agent-identity/use-agent-identity.ts +50 -0
  92. package/src/components/config/RuntimeConfig.tsx +14 -101
  93. package/src/components/config/runtime-config-agent.utils.ts +95 -0
  94. package/src/components/layout/AppLayout.tsx +3 -1
  95. package/src/components/layout/Sidebar.tsx +6 -1
  96. package/src/components/layout/app-layout.test.tsx +30 -0
  97. package/src/components/ui/tabs.tsx +2 -0
  98. package/src/hooks/README.md +3 -0
  99. package/src/hooks/agents/useAgents.ts +44 -0
  100. package/src/lib/i18n.agents.ts +66 -0
  101. package/src/lib/i18n.chat.ts +5 -0
  102. package/src/lib/i18n.ts +4 -6
  103. package/src/lib/ui-document-title.ts +1 -0
  104. package/dist/assets/ChatPage-Z9tRzm_n.js +0 -43
  105. package/dist/assets/DocBrowser-B9OaZjmg.js +0 -1
  106. package/dist/assets/MarketplacePage-D6rVQEQR.js +0 -1
  107. package/dist/assets/RuntimeConfig-v7a7Fe3x.js +0 -1
  108. package/dist/assets/chat-session-display-D0WpnuRZ.js +0 -1
  109. package/dist/assets/i18n-CDHMXlRZ.js +0 -1
  110. package/dist/assets/index-BuwbBgmT.js +0 -6
  111. package/dist/assets/index-bZ8cqQIS.css +0 -1
  112. package/dist/assets/loader-circle-Cs8XVFTw.js +0 -1
  113. package/dist/assets/plus-PHf8q-Ct.js +0 -1
  114. package/dist/assets/search-C91yH_6y.js +0 -1
  115. package/dist/assets/skeleton-Dzg-HOiN.js +0 -1
  116. package/dist/assets/x-D7Q1yqSF.js +0 -1
  117. /package/src/lib/{i18n → i18n-runtime}/i18n-language-owner.ts +0 -0
  118. /package/src/lib/{i18n → i18n-runtime}/i18n.path-picker.ts +0 -0
@@ -1,7 +1,7 @@
1
1
  import { cn } from '@/lib/utils';
2
2
  import { LANGUAGE_OPTIONS, t, type I18nLanguage } from '@/lib/i18n';
3
3
  import { THEME_OPTIONS, type UiTheme } from '@/lib/theme';
4
- import { Cpu, GitBranch, History, MessageCircle, MessageSquare, Sparkles, BookOpen, Plug, BrainCircuit, AlarmClock, Languages, Palette, KeyRound, Settings, ArrowLeft, Search, Shield, Wrench, Wifi } from 'lucide-react';
4
+ import { Cpu, GitBranch, History, MessageCircle, MessageSquare, Sparkles, BookOpen, Plug, BrainCircuit, AlarmClock, Languages, Palette, KeyRound, Settings, ArrowLeft, Search, Shield, Wrench, Wifi, Bot } from 'lucide-react';
5
5
  import { NavLink } from 'react-router-dom';
6
6
  import { useDocBrowser } from '@/components/doc-browser';
7
7
  import { BrandHeader } from '@/components/common/BrandHeader';
@@ -61,6 +61,11 @@ export function Sidebar({ mode }: SidebarProps) {
61
61
  target: '/chat/skills',
62
62
  label: t('marketplaceFilterSkills'),
63
63
  icon: BrainCircuit,
64
+ },
65
+ {
66
+ target: '/agents',
67
+ label: t('agentsPageTitle'),
68
+ icon: Bot,
64
69
  }
65
70
  ];
66
71
 
@@ -0,0 +1,30 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import { MemoryRouter, Route, Routes } from 'react-router-dom';
3
+ import { describe, expect, it } from 'vitest';
4
+ import { AppLayout } from '@/components/layout/AppLayout';
5
+ import { I18nProvider } from '@/components/providers/I18nProvider';
6
+
7
+ describe('AppLayout', () => {
8
+ it('treats /agents as a main workspace route instead of the settings shell', () => {
9
+ const { container } = render(
10
+ <I18nProvider>
11
+ <MemoryRouter initialEntries={['/agents']}>
12
+ <Routes>
13
+ <Route
14
+ path="*"
15
+ element={(
16
+ <AppLayout>
17
+ <div data-testid="agents-content">Agents Content</div>
18
+ </AppLayout>
19
+ )}
20
+ />
21
+ </Routes>
22
+ </MemoryRouter>
23
+ </I18nProvider>
24
+ );
25
+
26
+ expect(screen.getByTestId('agents-content')).toBeTruthy();
27
+ expect(screen.queryByTestId('settings-sidebar-header')).toBeNull();
28
+ expect(container.querySelector('aside')).toBeNull();
29
+ });
30
+ });
@@ -61,6 +61,8 @@ export function TabsTrigger({ value, children, className }: TabsTriggerProps) {
61
61
  <button
62
62
  type="button"
63
63
  onClick={() => context.onValueChange(value)}
64
+ aria-pressed={isActive}
65
+ data-state={isActive ? 'active' : 'inactive'}
64
66
  className={cn(
65
67
  'inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-[13px] font-medium ring-offset-white transition-all duration-fast focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
66
68
  isActive
@@ -0,0 +1,3 @@
1
+ ## 目录预算豁免
2
+
3
+ - 原因:`hooks/` 目录作为 UI 行为接入层,需要并列保留按能力划分的查询、变更和会话辅助 hooks;本次新增 `useAgents.ts` 是为了把 agent 管理职责从 `useConfig.ts` 拆出,属于减债后的职责回收,而不是继续堆叠到单文件。
@@ -0,0 +1,44 @@
1
+ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
2
+ import { createAgent, deleteAgent, fetchAgents } from '@/api/agents';
3
+ import { toast } from 'sonner';
4
+ import { t } from '@/lib/i18n';
5
+
6
+ export function useAgents() {
7
+ return useQuery({
8
+ queryKey: ['agents'],
9
+ queryFn: fetchAgents,
10
+ staleTime: 30_000
11
+ });
12
+ }
13
+
14
+ export function useCreateAgent() {
15
+ const queryClient = useQueryClient();
16
+
17
+ return useMutation({
18
+ mutationFn: ({ data }: { data: Parameters<typeof createAgent>[0] }) => createAgent(data),
19
+ onSuccess: () => {
20
+ queryClient.invalidateQueries({ queryKey: ['agents'] });
21
+ queryClient.invalidateQueries({ queryKey: ['config'] });
22
+ toast.success(t('configSavedApplied'));
23
+ },
24
+ onError: (error: Error) => {
25
+ toast.error(t('configSaveFailed') + ': ' + error.message);
26
+ }
27
+ });
28
+ }
29
+
30
+ export function useDeleteAgent() {
31
+ const queryClient = useQueryClient();
32
+
33
+ return useMutation({
34
+ mutationFn: ({ agentId }: { agentId: string }) => deleteAgent(agentId),
35
+ onSuccess: () => {
36
+ queryClient.invalidateQueries({ queryKey: ['agents'] });
37
+ queryClient.invalidateQueries({ queryKey: ['config'] });
38
+ toast.success(t('configSavedApplied'));
39
+ },
40
+ onError: (error: Error) => {
41
+ toast.error(t('configSaveFailed') + ': ' + error.message);
42
+ }
43
+ });
44
+ }
@@ -0,0 +1,66 @@
1
+ export const AGENT_LABELS: Record<string, { zh: string; en: string }> = {
2
+ agentsPageTitle: { zh: 'Agent 管理', en: 'Agents' },
3
+ agentsPageDescription: {
4
+ zh: '管理可对话的 Agent 身份。每个 Agent 都有自己的主目录、设定、记忆与技能。',
5
+ en: 'Manage conversational agent identities. Each agent owns its home directory, setup, memory, and skills.'
6
+ },
7
+ agentsHeroEyebrow: { zh: 'Agent 管理台', en: 'Agent Gallery' },
8
+ agentsHeroTitle: {
9
+ zh: '让每个 Agent 都像真正的协作者一样存在',
10
+ en: 'Give every agent the presence of a real collaborator'
11
+ },
12
+ agentsHeroDescription: {
13
+ zh: '在这里浏览、创建并切换不同的 Agent 身份。每个 Agent 都有自己的头像、名称、主目录,以及独立的记忆与技能空间。',
14
+ en: 'Browse, create, and choose distinct agent identities. Every agent carries its own avatar, name, home directory, memory, and skills space.'
15
+ },
16
+ agentsCreateButton: { zh: '新增 Agent', en: 'New Agent' },
17
+ agentsCreateDialogTitle: { zh: '创建新的 Agent 身份', en: 'Create a new agent identity' },
18
+ agentsCreateDialogDescription: {
19
+ zh: '默认逻辑保持简单。只填必要信息,其余能力继续走统一配置与主目录模板。',
20
+ en: 'Keep the flow simple. Provide only the essentials and let shared defaults plus the home directory template do the rest.'
21
+ },
22
+ agentsCreateDialogHint: {
23
+ zh: '如果你希望让 AI 自动完成全部自定义,也可以继续使用 `nextclaw agents new`。',
24
+ en: 'If you want AI to automate the full setup, you can still use `nextclaw agents new`.'
25
+ },
26
+ agentsCreateTitle: { zh: '创建 Agent', en: 'Create Agent' },
27
+ agentsCreateDescription: {
28
+ zh: '这里提供轻量入口。完整自动化创建链路也可通过 `nextclaw agents new` 使用。',
29
+ en: 'This is the lightweight UI entry. The full automation path is also available through `nextclaw agents new`.'
30
+ },
31
+ agentsFormIdPlaceholder: { zh: 'Agent ID,例如 engineer', en: 'Agent ID, for example engineer' },
32
+ agentsFormNamePlaceholder: { zh: '显示名称,可选', en: 'Display name, optional' },
33
+ agentsFormDescriptionPlaceholder: { zh: '角色描述,可选', en: 'Role description, optional' },
34
+ agentsFormAvatarPlaceholder: { zh: '头像 URL 或本地路径,可选', en: 'Avatar URL or local path, optional' },
35
+ agentsFormHomePlaceholder: { zh: '主目录,可选', en: 'Home Directory, optional' },
36
+ agentsCreateAction: { zh: '创建 Agent', en: 'Create Agent' },
37
+ agentsRemoveAction: { zh: '移除', en: 'Remove' },
38
+ agentsNewChat: { zh: '新建会话', en: 'New Chat' },
39
+ agentsLoading: { zh: '正在加载 Agent...', en: 'Loading agents...' },
40
+ agentsEmpty: { zh: '当前还没有附加 Agent', en: 'No extra agents yet' },
41
+ agentsEmptyDescription: {
42
+ zh: '先创建第一个专职 Agent,让它拥有自己的名字、头像与主目录。',
43
+ en: 'Create the first specialist agent with its own name, avatar, and home directory.'
44
+ },
45
+ agentsBuiltIn: { zh: '内建', en: 'Built-in' },
46
+ agentsCustom: { zh: '自定义', en: 'Custom' },
47
+ agentsOverviewTotal: { zh: '全部 Agent', en: 'Conversational agents' },
48
+ agentsOverviewBuiltIn: { zh: '系统主 Agent', en: 'System main agents' },
49
+ agentsOverviewCustom: { zh: '专职 Agent', en: 'Specialist agents' },
50
+ agentsCardBuiltInSummary: {
51
+ zh: '系统主 Agent,适合作为默认入口与总控协作者。',
52
+ en: 'The built-in main agent, ideal as the default entry and coordinating collaborator.'
53
+ },
54
+ agentsCardCustomSummary: {
55
+ zh: '专属 Agent 身份,可沉淀自己的记忆、技能与角色风格。',
56
+ en: 'A dedicated identity with its own memory, skills, and role style.'
57
+ },
58
+ agentsCardHomeLabel: { zh: '主目录', en: 'Home Directory' },
59
+ agentsCardAvatarLabel: { zh: 'Avatar', en: 'Avatar' },
60
+ agentsCardStartChat: { zh: '开始对话', en: 'Start Chat' },
61
+ agentsCardBuiltInTag: { zh: '系统主', en: 'Main Agent' },
62
+ agentsCardCustomTag: { zh: '专职', en: 'Specialist' },
63
+ chatDraftAgentTitle: { zh: '本次会话 Agent', en: 'Draft agent' },
64
+ chatDraftAgentDescription: { zh: '创建后不可切换', en: 'Locked after creation' },
65
+ chatDraftAgentCurrent: { zh: '当前 Agent', en: 'Current Agent' }
66
+ };
@@ -42,6 +42,10 @@ export const CHAT_LABELS: Record<string, { zh: string; en: string }> = {
42
42
  chatNoSessionHint: { zh: '创建一个会话并发送第一条消息。', en: 'Create a session and send your first message.' },
43
43
  chatHistoryLoading: { zh: '加载会话历史中...', en: 'Loading session history...' },
44
44
  chatNoMessages: { zh: '暂无消息,发送一条开始对话。', en: 'No messages yet. Send one to start.' },
45
+ chatBackToParent: { zh: '返回父会话', en: 'Back to parent' },
46
+ chatChildSessionLoading: { zh: '正在加载子会话…', en: 'Loading child session…' },
47
+ chatChildSessionEmpty: { zh: '子会话还没有消息。', en: 'No child session messages yet.' },
48
+ chatChildSessionClosePanel: { zh: '关闭子会话侧栏', en: 'Close child session panel' },
45
49
  chatTyping: { zh: 'Agent 正在思考...', en: 'Agent is thinking...' },
46
50
  chatInputPlaceholder: { zh: '输入消息,输入 / 选择技能,Enter 发送,Shift + Enter 换行', en: 'Type a message, type / to select skills, Enter to send, Shift + Enter for newline' },
47
51
  chatInputHint: { zh: '支持多轮上下文,默认走当前会话。', en: 'Multi-turn context is preserved in the current session.' },
@@ -56,6 +60,7 @@ export const CHAT_LABELS: Record<string, { zh: string; en: string }> = {
56
60
  chatSlashHint: { zh: '输入 / 触发命令或技能选择', en: 'Type / to access commands and skills' },
57
61
  chatSlashCommandHint: { zh: '回车插入命令,继续输入参数后发送。', en: 'Press Enter to insert command, then add args and send.' },
58
62
  chatSlashSkillHint: { zh: '回车把该技能加入本轮请求。', en: 'Press Enter to add this skill for the next turn.' },
63
+ chatSkillScopeBuiltin: { zh: '内建', en: 'Built-in' },
59
64
  chatSkillScopeProject: { zh: '项目', en: 'Project' },
60
65
  chatSkillScopeWorkspace: { zh: '工作区', en: 'Workspace' },
61
66
  chatPickerRecent: { zh: '最近使用', en: 'Recent' },
package/src/lib/i18n.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { AGENT_LABELS } from './i18n.agents';
1
2
  import { CHANNEL_LABELS } from './i18n.channels';
2
3
  import { CHANNEL_AUTH_LABELS } from './i18n.channel-auth';
3
4
  import { CHAT_LABELS } from './i18n.chat';
@@ -10,9 +11,9 @@ import {
10
11
  setLanguage,
11
12
  subscribeLanguageChange,
12
13
  type I18nLanguage
13
- } from './i18n/i18n-language-owner';
14
+ } from './i18n-runtime/i18n-language-owner';
14
15
  import { MARKETPLACE_LABELS } from './i18n.marketplace';
15
- import { PATH_PICKER_LABELS } from './i18n/i18n.path-picker';
16
+ import { PATH_PICKER_LABELS } from './i18n-runtime/i18n.path-picker';
16
17
  import { REMOTE_LABELS } from './i18n.remote';
17
18
  export type { I18nLanguage };
18
19
  export {
@@ -24,7 +25,6 @@ export {
24
25
  setLanguage,
25
26
  subscribeLanguageChange
26
27
  };
27
-
28
28
  export function formatDateTime(value?: string | Date, lang: I18nLanguage = getLanguage()): string {
29
29
  if (!value) {
30
30
  return '-';
@@ -381,8 +381,6 @@ export const LABELS: Record<string, { zh: string; en: string }> = {
381
381
  defaultContextTokensHelp: { zh: '当 Agent 未设置单独值时使用该上下文预算。', en: 'Input context budget for agents when no per-agent override is set.' },
382
382
  defaultEngine: { zh: '默认引擎', en: 'Default Engine' },
383
383
  defaultEngineHelp: { zh: '默认使用的 Agent 引擎类型,例如 native 或 codex-sdk。', en: 'Default agent engine kind, for example native or codex-sdk.' },
384
- maxPingPongTurns: { zh: '最大乒乓轮次', en: 'Max Ping-Pong Turns' },
385
- maxPingPongTurnsHelp: { zh: '设为 0 可阻止 Agent 间自动 ping-pong。', en: 'Set to 0 to block automatic agent-to-agent ping-pong loops.' },
386
384
  agentList: { zh: 'Agent 列表', en: 'Agent List' },
387
385
  agentListHelp: { zh: '在同一个网关进程中运行多个固定角色 Agent。', en: 'Run multiple fixed-role agents in one gateway process.' },
388
386
  bindings: { zh: '绑定规则', en: 'Bindings' },
@@ -409,7 +407,6 @@ export const LABELS: Record<string, { zh: string; en: string }> = {
409
407
  peerIdPlaceholder: { zh: '对端 ID(需先设置对端类型)', en: 'Peer ID (requires peer kind)' },
410
408
  addBinding: { zh: '添加绑定', en: 'Add Binding' },
411
409
  saveRuntimeSettings: { zh: '保存运行时设置', en: 'Save Runtime Settings' },
412
-
413
410
  // Secrets
414
411
  secretsPageTitle: { zh: '密钥管理', en: 'Secrets Management' },
415
412
  secretsPageDescription: {
@@ -494,6 +491,7 @@ export const LABELS: Record<string, { zh: string; en: string }> = {
494
491
  },
495
492
 
496
493
  // Chat
494
+ ...AGENT_LABELS,
497
495
  ...CHAT_LABELS,
498
496
 
499
497
  // Cron
@@ -9,6 +9,7 @@ const ROUTE_TITLE_KEYS: Array<{ prefix: string; key: string }> = [
9
9
  { prefix: '/marketplace', key: 'marketplace' },
10
10
  { prefix: '/skills', key: 'marketplaceSkillsPageTitle' },
11
11
  { prefix: '/cron', key: 'cronPageTitle' },
12
+ { prefix: '/agents', key: 'agentsPageTitle' },
12
13
  { prefix: '/chat', key: 'chat' },
13
14
  { prefix: '/model', key: 'modelPageTitle' },
14
15
  { prefix: '/search', key: 'searchPageTitle' },