@peonai/swarm 0.1.0
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.
- package/.dockerignore +6 -0
- package/Dockerfile +9 -0
- package/README.md +29 -0
- package/app/api/health/route.ts +2 -0
- package/app/api/v1/admin/agents/[id]/route.ts +12 -0
- package/app/api/v1/admin/agents/route.ts +31 -0
- package/app/api/v1/admin/audit/route.ts +23 -0
- package/app/api/v1/admin/cleanup/route.ts +21 -0
- package/app/api/v1/admin/export/route.ts +15 -0
- package/app/api/v1/admin/history/route.ts +23 -0
- package/app/api/v1/admin/profile/route.ts +23 -0
- package/app/api/v1/admin/settings/route.ts +44 -0
- package/app/api/v1/auth/route.ts +5 -0
- package/app/api/v1/memory/route.ts +105 -0
- package/app/api/v1/persona/[agentId]/route.ts +13 -0
- package/app/api/v1/persona/me/route.ts +12 -0
- package/app/api/v1/profile/observe/route.ts +34 -0
- package/app/api/v1/profile/route.ts +72 -0
- package/app/api/v1/reflect/route.ts +96 -0
- package/app/globals.css +190 -0
- package/app/i18n.ts +161 -0
- package/app/layout.tsx +12 -0
- package/app/page.tsx +561 -0
- package/docker-compose.yml +34 -0
- package/docs/DEBATE-ROUND1.md +244 -0
- package/docs/DEBATE-ROUND2.md +158 -0
- package/docs/REQUIREMENTS.md +162 -0
- package/docs/docs.html +272 -0
- package/docs/index.html +228 -0
- package/docs/script.js +103 -0
- package/docs/style.css +418 -0
- package/lib/auth.ts +63 -0
- package/lib/db.ts +63 -0
- package/lib/embedding.ts +29 -0
- package/lib/schema.ts +134 -0
- package/mcp-server.ts +56 -0
- package/next-env.d.ts +6 -0
- package/next.config.ts +5 -0
- package/package.json +34 -0
- package/packages/cli/README.md +33 -0
- package/packages/cli/bin/swarm.mjs +274 -0
- package/packages/cli/package.json +10 -0
- package/postcss.config.mjs +2 -0
- package/skill/CLAUDE.md +40 -0
- package/skill/CODEX.md +43 -0
- package/skill/GEMINI.md +38 -0
- package/skill/IFLOW.md +38 -0
- package/skill/OPENCODE.md +38 -0
- package/skill/swarm-ai-skill/SKILL.md +74 -0
- package/skill/swarm-ai-skill/env.sh +4 -0
- package/skill/swarm-ai-skill/scripts/bootstrap.sh +21 -0
- package/skill/swarm-ai-skill/scripts/env.sh +4 -0
- package/skill/swarm-ai-skill/scripts/env.sh.example +3 -0
- package/skill/swarm-ai-skill/scripts/memory-read.sh +8 -0
- package/skill/swarm-ai-skill/scripts/memory-write.sh +10 -0
- package/skill/swarm-ai-skill/scripts/observe.sh +9 -0
- package/skill/swarm-ai-skill/scripts/profile-read.sh +9 -0
- package/skill/swarm-ai-skill/scripts/profile-update.sh +9 -0
- package/skill/swarm-ai-skill/scripts/session-start.sh +19 -0
- package/tsconfig.json +21 -0
- package/tsconfig.tsbuildinfo +1 -0
package/app/globals.css
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
|
|
3
|
+
|
|
4
|
+
:root {
|
|
5
|
+
--bg: #0a0a0f;
|
|
6
|
+
--bg2: #12121a;
|
|
7
|
+
--surface: #1a1a25;
|
|
8
|
+
--border: #2a2a3a;
|
|
9
|
+
--text: #e8e8ed;
|
|
10
|
+
--text2: #9898a8;
|
|
11
|
+
--amber: #f0a830;
|
|
12
|
+
--amber2: #d4922a;
|
|
13
|
+
--amber-glow: rgba(240,168,48,0.15);
|
|
14
|
+
--green: #34d399;
|
|
15
|
+
--blue: #60a5fa;
|
|
16
|
+
--red: #f87171;
|
|
17
|
+
--mono: 'JetBrains Mono', monospace;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
body {
|
|
21
|
+
font-family: 'Inter', -apple-system, sans-serif;
|
|
22
|
+
background: var(--bg);
|
|
23
|
+
color: var(--text);
|
|
24
|
+
-webkit-font-smoothing: antialiased;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/* Scrollbar */
|
|
28
|
+
::-webkit-scrollbar { width: 5px; }
|
|
29
|
+
::-webkit-scrollbar-track { background: transparent; }
|
|
30
|
+
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
|
|
31
|
+
::-webkit-scrollbar-thumb:hover { background: var(--text2); }
|
|
32
|
+
|
|
33
|
+
/* ── Hex grid background ── */
|
|
34
|
+
.hex-bg {
|
|
35
|
+
position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden;
|
|
36
|
+
}
|
|
37
|
+
.hex-bg::before {
|
|
38
|
+
content: '';
|
|
39
|
+
position: absolute; inset: -50%; width: 200%; height: 200%;
|
|
40
|
+
background-image:
|
|
41
|
+
linear-gradient(30deg, transparent 48.5%, rgba(240,168,48,0.03) 49%, rgba(240,168,48,0.03) 51%, transparent 51.5%),
|
|
42
|
+
linear-gradient(150deg, transparent 48.5%, rgba(240,168,48,0.03) 49%, rgba(240,168,48,0.03) 51%, transparent 51.5%),
|
|
43
|
+
linear-gradient(90deg, transparent 48.5%, rgba(240,168,48,0.02) 49%, rgba(240,168,48,0.02) 51%, transparent 51.5%);
|
|
44
|
+
background-size: 60px 104px;
|
|
45
|
+
animation: hexDrift 40s linear infinite;
|
|
46
|
+
}
|
|
47
|
+
@keyframes hexDrift {
|
|
48
|
+
from { transform: translate(0, 0); }
|
|
49
|
+
to { transform: translate(30px, 52px); }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* ── Animated gradient border ── */
|
|
53
|
+
.glow-card {
|
|
54
|
+
position: relative;
|
|
55
|
+
background: var(--surface);
|
|
56
|
+
border-radius: 12px;
|
|
57
|
+
overflow: hidden;
|
|
58
|
+
}
|
|
59
|
+
.glow-card::before {
|
|
60
|
+
content: ''; position: absolute; inset: 0; border-radius: 12px; padding: 1px;
|
|
61
|
+
background: linear-gradient(135deg, transparent 40%, rgba(240,168,48,0.2) 50%, transparent 60%);
|
|
62
|
+
background-size: 300% 300%;
|
|
63
|
+
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
|
|
64
|
+
-webkit-mask-composite: xor; mask-composite: exclude;
|
|
65
|
+
animation: borderShimmer 6s ease-in-out infinite;
|
|
66
|
+
opacity: 0; transition: opacity 0.3s;
|
|
67
|
+
}
|
|
68
|
+
.glow-card:hover::before { opacity: 1; }
|
|
69
|
+
@keyframes borderShimmer {
|
|
70
|
+
0%, 100% { background-position: 0% 50%; }
|
|
71
|
+
50% { background-position: 100% 50%; }
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* ── Stat card ── */
|
|
75
|
+
.stat-card {
|
|
76
|
+
position: relative; overflow: hidden; cursor: pointer;
|
|
77
|
+
background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
|
|
78
|
+
padding: 20px; transition: all 0.3s ease;
|
|
79
|
+
}
|
|
80
|
+
.stat-card:hover {
|
|
81
|
+
border-color: rgba(240,168,48,0.3);
|
|
82
|
+
transform: translateY(-2px);
|
|
83
|
+
box-shadow: 0 8px 24px rgba(0,0,0,0.3), 0 0 0 1px rgba(240,168,48,0.1);
|
|
84
|
+
}
|
|
85
|
+
.stat-card::after {
|
|
86
|
+
content: ''; position: absolute; inset: 0;
|
|
87
|
+
background: radial-gradient(circle at var(--mx, 80%) var(--my, 20%), rgba(240,168,48,0.06) 0%, transparent 60%);
|
|
88
|
+
opacity: 0; transition: opacity 0.3s;
|
|
89
|
+
}
|
|
90
|
+
.stat-card:hover::after { opacity: 1; }
|
|
91
|
+
.stat-value {
|
|
92
|
+
font-size: 2rem; font-weight: 700; line-height: 1;
|
|
93
|
+
background: linear-gradient(135deg, var(--text) 30%, var(--amber));
|
|
94
|
+
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* ── Sidebar ── */
|
|
98
|
+
.sidebar {
|
|
99
|
+
background: var(--bg2); border-right: 1px solid var(--border);
|
|
100
|
+
backdrop-filter: blur(12px);
|
|
101
|
+
}
|
|
102
|
+
.sidebar-link {
|
|
103
|
+
position: relative; transition: all 0.2s;
|
|
104
|
+
}
|
|
105
|
+
.sidebar-link.active::before {
|
|
106
|
+
content: ''; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
|
|
107
|
+
width: 3px; height: 20px; border-radius: 0 3px 3px 0;
|
|
108
|
+
background: var(--amber);
|
|
109
|
+
box-shadow: 0 0 8px var(--amber), 0 0 16px rgba(240,168,48,0.3);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* ── Data row ── */
|
|
113
|
+
.data-row {
|
|
114
|
+
display: flex; align-items: center; gap: 12px;
|
|
115
|
+
padding: 8px 12px; border-radius: 8px;
|
|
116
|
+
transition: background 0.15s;
|
|
117
|
+
}
|
|
118
|
+
.data-row:hover { background: rgba(240,168,48,0.04); }
|
|
119
|
+
|
|
120
|
+
/* ── Layer accordion ── */
|
|
121
|
+
.layer-content {
|
|
122
|
+
display: grid; grid-template-rows: 0fr;
|
|
123
|
+
transition: grid-template-rows 0.25s ease;
|
|
124
|
+
}
|
|
125
|
+
.layer-content.open { grid-template-rows: 1fr; }
|
|
126
|
+
.layer-content > div { overflow: hidden; }
|
|
127
|
+
|
|
128
|
+
/* ── Tab content fade ── */
|
|
129
|
+
.tab-content {
|
|
130
|
+
animation: tabIn 0.25s ease-out;
|
|
131
|
+
}
|
|
132
|
+
@keyframes tabIn {
|
|
133
|
+
from { opacity: 0; transform: translateY(8px); }
|
|
134
|
+
to { opacity: 1; transform: translateY(0); }
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/* ── Entrance stagger ── */
|
|
138
|
+
.stagger-in > * {
|
|
139
|
+
opacity: 0; transform: translateY(12px);
|
|
140
|
+
animation: staggerUp 0.35s ease-out forwards;
|
|
141
|
+
}
|
|
142
|
+
.stagger-in > *:nth-child(1) { animation-delay: 0.05s; }
|
|
143
|
+
.stagger-in > *:nth-child(2) { animation-delay: 0.1s; }
|
|
144
|
+
.stagger-in > *:nth-child(3) { animation-delay: 0.15s; }
|
|
145
|
+
.stagger-in > *:nth-child(4) { animation-delay: 0.2s; }
|
|
146
|
+
.stagger-in > *:nth-child(5) { animation-delay: 0.25s; }
|
|
147
|
+
.stagger-in > *:nth-child(6) { animation-delay: 0.3s; }
|
|
148
|
+
@keyframes staggerUp {
|
|
149
|
+
to { opacity: 1; transform: translateY(0); }
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/* ── Logo pulse ── */
|
|
153
|
+
.logo-hex { animation: logoPulse 4s ease-in-out infinite; }
|
|
154
|
+
@keyframes logoPulse {
|
|
155
|
+
0%, 100% { filter: drop-shadow(0 0 4px rgba(240,168,48,0.2)); }
|
|
156
|
+
50% { filter: drop-shadow(0 0 12px rgba(240,168,48,0.5)); }
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/* ── Badge ── */
|
|
160
|
+
.badge {
|
|
161
|
+
display: inline-flex; align-items: center; gap: 4px;
|
|
162
|
+
padding: 2px 8px; border-radius: 4px;
|
|
163
|
+
font-size: 0.7rem; font-weight: 500; font-family: var(--mono);
|
|
164
|
+
white-space: nowrap;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/* ── Input focus ── */
|
|
168
|
+
input:focus, textarea:focus, select:focus {
|
|
169
|
+
outline: none;
|
|
170
|
+
border-color: rgba(240,168,48,0.5) !important;
|
|
171
|
+
box-shadow: 0 0 0 2px rgba(240,168,48,0.1);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/* ── Button hover ── */
|
|
175
|
+
.btn-amber {
|
|
176
|
+
background: var(--amber); color: var(--bg);
|
|
177
|
+
font-weight: 600; border-radius: 8px;
|
|
178
|
+
transition: all 0.2s;
|
|
179
|
+
}
|
|
180
|
+
.btn-amber:hover {
|
|
181
|
+
background: var(--amber2);
|
|
182
|
+
box-shadow: 0 4px 16px rgba(240,168,48,0.3);
|
|
183
|
+
transform: translateY(-1px);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/* ── Empty state ── */
|
|
187
|
+
.empty-state {
|
|
188
|
+
text-align: center; padding: 48px 24px; color: var(--text2);
|
|
189
|
+
}
|
|
190
|
+
.empty-state svg { margin: 0 auto 16px; opacity: 0.3; }
|
package/app/i18n.ts
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
export const locales = {
|
|
2
|
+
en: {
|
|
3
|
+
brand: 'Swarm AI',
|
|
4
|
+
dashboard: 'Dashboard',
|
|
5
|
+
nav: { overview: 'Overview', profile: 'Profiles', agents: 'Agents', memory: 'Memory', audit: 'Audit Log', settings: 'Settings' },
|
|
6
|
+
status: { running: 'Running', offline: 'Offline' },
|
|
7
|
+
auth: {
|
|
8
|
+
title: 'Swarm AI',
|
|
9
|
+
subtitle: 'Cross-agent user profile hub',
|
|
10
|
+
email: 'Email', password: 'Password', name: 'Name (optional)',
|
|
11
|
+
login: 'Sign In', register: 'Create Account',
|
|
12
|
+
switchToRegister: 'No account? Register', switchToLogin: 'Have an account? Sign in',
|
|
13
|
+
error: 'Authentication failed', logout: 'Logout', export: 'Export',
|
|
14
|
+
},
|
|
15
|
+
overview: {
|
|
16
|
+
title: 'Overview',
|
|
17
|
+
subtitle: 'Swarm AI system status at a glance',
|
|
18
|
+
agents: 'Agents', profiles: 'Profile Entries', layers: 'Profile Layers', memories: 'Memories',
|
|
19
|
+
recent: 'Recent Profile Updates',
|
|
20
|
+
noData: 'No profile data yet',
|
|
21
|
+
},
|
|
22
|
+
profile: {
|
|
23
|
+
title: 'User Profiles',
|
|
24
|
+
subtitle: 'Browse all profile data by layer',
|
|
25
|
+
noData: 'No data yet — write via Agent API',
|
|
26
|
+
items: 'items',
|
|
27
|
+
},
|
|
28
|
+
agents: {
|
|
29
|
+
title: 'Agent Management',
|
|
30
|
+
subtitle: 'Register, view and manage agents',
|
|
31
|
+
idPlaceholder: 'Agent ID',
|
|
32
|
+
namePlaceholder: 'Name',
|
|
33
|
+
add: '+ Add',
|
|
34
|
+
delete: 'Delete',
|
|
35
|
+
noAgents: 'No agents registered',
|
|
36
|
+
keyAlert: (k: string) => `API Key: ${k}\n\nSave it now — it won't be shown again!`,
|
|
37
|
+
confirmDelete: (id: string) => `Delete agent "${id}"?`,
|
|
38
|
+
editPersona: 'Edit Persona',
|
|
39
|
+
persona: 'Persona',
|
|
40
|
+
personaPlaceholder: '{"personality":"...","instructions":"..."}',
|
|
41
|
+
save: 'Save', cancel: 'Cancel',
|
|
42
|
+
},
|
|
43
|
+
memory: {
|
|
44
|
+
title: 'Memory',
|
|
45
|
+
subtitle: 'Cross-agent shared memories — FTS5 full-text search',
|
|
46
|
+
searchPlaceholder: 'Search memories (full-text)...',
|
|
47
|
+
search: 'Search',
|
|
48
|
+
clear: 'Clear',
|
|
49
|
+
contentPlaceholder: 'Memory content...',
|
|
50
|
+
tagsPlaceholder: 'Tags (comma-separated)',
|
|
51
|
+
write: '+ Write',
|
|
52
|
+
importance: 'Importance',
|
|
53
|
+
results: (n: number) => `${n} results found`,
|
|
54
|
+
noMatch: 'No matching results',
|
|
55
|
+
noMemory: 'No memories yet',
|
|
56
|
+
types: { observation: 'Observation', fact: 'Fact', preference: 'Preference', experience: 'Experience' },
|
|
57
|
+
},
|
|
58
|
+
audit: {
|
|
59
|
+
title: 'Audit Log',
|
|
60
|
+
subtitle: 'Track all API actions and profile changes',
|
|
61
|
+
noData: 'No audit entries yet',
|
|
62
|
+
action: 'Action', agent: 'Agent', target: 'Target', detail: 'Detail', time: 'Time',
|
|
63
|
+
historyTitle: 'Profile Change History',
|
|
64
|
+
oldValue: 'Old', newValue: 'New',
|
|
65
|
+
},
|
|
66
|
+
settings: {
|
|
67
|
+
title: 'Settings',
|
|
68
|
+
subtitle: 'Server and embedding configuration',
|
|
69
|
+
embedding: 'Embedding API',
|
|
70
|
+
embedDesc: 'OpenAI-compatible embedding API for semantic memory search',
|
|
71
|
+
url: 'API URL', key: 'API Key', model: 'Model',
|
|
72
|
+
urlPlaceholder: 'https://api.openai.com/v1/embeddings',
|
|
73
|
+
keyPlaceholder: 'sk-...',
|
|
74
|
+
modelPlaceholder: 'text-embedding-3-small',
|
|
75
|
+
save: 'Save', saved: 'Saved! Restart server to apply.',
|
|
76
|
+
enabled: 'Enabled', disabled: 'Not configured',
|
|
77
|
+
test: 'Test', testing: 'Testing...', testOk: 'Connection OK', testFail: 'Failed',
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
zh: {
|
|
81
|
+
brand: '蜂群 AI',
|
|
82
|
+
dashboard: '管理面板',
|
|
83
|
+
nav: { overview: '概览', profile: '画像', agents: 'Agents', memory: '记忆', audit: '审计日志', settings: '设置' },
|
|
84
|
+
status: { running: '运行中', offline: '离线' },
|
|
85
|
+
auth: {
|
|
86
|
+
title: '蜂群 AI',
|
|
87
|
+
subtitle: '跨 Agent 用户画像中心',
|
|
88
|
+
email: '邮箱', password: '密码', name: '名称(可选)',
|
|
89
|
+
login: '登录', register: '注册',
|
|
90
|
+
switchToRegister: '没有账号?注册', switchToLogin: '已有账号?登录',
|
|
91
|
+
error: '认证失败', logout: '退出', export: '导出',
|
|
92
|
+
},
|
|
93
|
+
overview: {
|
|
94
|
+
title: '概览',
|
|
95
|
+
subtitle: '蜂群 AI 运行状态一览',
|
|
96
|
+
agents: 'Agents', profiles: '画像条目', layers: '画像层', memories: '记忆',
|
|
97
|
+
recent: '最近画像更新',
|
|
98
|
+
noData: '暂无画像数据',
|
|
99
|
+
},
|
|
100
|
+
profile: {
|
|
101
|
+
title: '用户画像',
|
|
102
|
+
subtitle: '按层级浏览所有画像数据',
|
|
103
|
+
noData: '暂无数据,通过 Agent API 写入',
|
|
104
|
+
items: '条',
|
|
105
|
+
},
|
|
106
|
+
agents: {
|
|
107
|
+
title: 'Agent 管理',
|
|
108
|
+
subtitle: '注册、查看和管理 Agent',
|
|
109
|
+
idPlaceholder: 'Agent ID',
|
|
110
|
+
namePlaceholder: '名称',
|
|
111
|
+
add: '+ 添加',
|
|
112
|
+
delete: '删除',
|
|
113
|
+
noAgents: '暂无 Agent',
|
|
114
|
+
keyAlert: (k: string) => `API Key: ${k}\n\n请保存,不会再显示!`,
|
|
115
|
+
confirmDelete: (id: string) => `删除 agent "${id}"?`,
|
|
116
|
+
editPersona: '编辑人设',
|
|
117
|
+
persona: '人设',
|
|
118
|
+
personaPlaceholder: '{"personality":"...","instructions":"..."}',
|
|
119
|
+
save: '保存', cancel: '取消',
|
|
120
|
+
},
|
|
121
|
+
memory: {
|
|
122
|
+
title: '记忆',
|
|
123
|
+
subtitle: '跨 Agent 共享的记忆条目 — FTS5 全文检索',
|
|
124
|
+
searchPlaceholder: '搜索记忆(支持全文检索)...',
|
|
125
|
+
search: '搜索',
|
|
126
|
+
clear: '清除',
|
|
127
|
+
contentPlaceholder: '记忆内容...',
|
|
128
|
+
tagsPlaceholder: '标签(逗号分隔)',
|
|
129
|
+
write: '+ 写入',
|
|
130
|
+
importance: '重要度',
|
|
131
|
+
results: (n: number) => `找到 ${n} 条结果`,
|
|
132
|
+
noMatch: '无匹配结果',
|
|
133
|
+
noMemory: '暂无记忆',
|
|
134
|
+
types: { observation: '观察', fact: '事实', preference: '偏好', experience: '经历' },
|
|
135
|
+
},
|
|
136
|
+
audit: {
|
|
137
|
+
title: '审计日志',
|
|
138
|
+
subtitle: '追踪所有 API 操作和画像变更',
|
|
139
|
+
noData: '暂无审计记录',
|
|
140
|
+
action: '操作', agent: 'Agent', target: '目标', detail: '详情', time: '时间',
|
|
141
|
+
historyTitle: '画像变更历史',
|
|
142
|
+
oldValue: '旧值', newValue: '新值',
|
|
143
|
+
},
|
|
144
|
+
settings: {
|
|
145
|
+
title: '设置',
|
|
146
|
+
subtitle: '服务器与 Embedding 配置',
|
|
147
|
+
embedding: 'Embedding API',
|
|
148
|
+
embedDesc: 'OpenAI 兼容的 Embedding API,用于记忆语义搜索',
|
|
149
|
+
url: 'API 地址', key: 'API Key', model: '模型',
|
|
150
|
+
urlPlaceholder: 'https://api.openai.com/v1/embeddings',
|
|
151
|
+
keyPlaceholder: 'sk-...',
|
|
152
|
+
modelPlaceholder: 'text-embedding-3-small',
|
|
153
|
+
save: '保存', saved: '已保存!重启服务生效。',
|
|
154
|
+
enabled: '已启用', disabled: '未配置',
|
|
155
|
+
test: '测试', testing: '测试中...', testOk: '连接成功', testFail: '连接失败',
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
} as const;
|
|
159
|
+
|
|
160
|
+
export type Locale = keyof typeof locales;
|
|
161
|
+
export type T = typeof locales.en;
|
package/app/layout.tsx
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Metadata } from 'next';
|
|
2
|
+
import './globals.css';
|
|
3
|
+
|
|
4
|
+
export const metadata: Metadata = { title: '蜂群 AI', description: 'Cross-agent user profile hub' };
|
|
5
|
+
|
|
6
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
7
|
+
return (
|
|
8
|
+
<html lang="zh-CN">
|
|
9
|
+
<body className="min-h-screen">{children}</body>
|
|
10
|
+
</html>
|
|
11
|
+
);
|
|
12
|
+
}
|