repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources16d ago| #1 | import dayjs from 'dayjs'; |
| #2 | import { kebabCase } from 'lodash-es'; |
| #3 | import { format } from 'prettier'; |
| #4 | import { remark } from 'remark'; |
| #5 | import pangu from 'remark-pangu'; |
| #6 | |
| #7 | import { config, meta } from '../core/constants'; |
| #8 | import { ClawdAgent, clawdAgentSchema } from '../schema/agentMeta'; |
| #9 | import { Logger } from '../utils/logger'; |
| #10 | import { calculateTokenUsage } from '../utils/token'; |
| #11 | |
| #12 | /** |
| #13 | * 验证和修复 examples 字段 |
| #14 | * @param agent Agent 配置对象 |
| #15 | * @returns 修复后的 Agent 配置 |
| #16 | */ |
| #17 | export const validateAndFixExamples = (agent: LobeAgent): LobeAgent => { |
| #18 | if (!agent.examples || !Array.isArray(agent.examples)) { |
| #19 | return agent; |
| #20 | } |
| #21 | |
| #22 | let hasIssues = false; |
| #23 | const fixedExamples = agent.examples.map((example, index) => { |
| #24 | const issues: string[] = []; |
| #25 | |
| #26 | // 检查是否有嵌套的对象结构问题 |
| #27 | if (typeof example === 'object' && example !== null) { |
| #28 | // 检查是否有错误的嵌套结构,如 { "assistant": { "content": "..." } } |
| #29 | for (const [key, value] of Object.entries(example)) { |
| #30 | if ( |
| #31 | (key === 'assistant' || key === 'user' || key === 'system' || key === 'function') && |
| #32 | typeof value === 'object' && |
| #33 | value !== null && |
| #34 | value && |
| #35 | 'content' in value |
| #36 | ) { |
| #37 | // 发现嵌套结构错误,修复它 |
| #38 | const fixedExample = { |
| #39 | content: (value as any).content || '', |
| #40 | role: key, |
| #41 | }; |
| #42 | Object.assign(example, fixedExample); |
| #43 | issues.push(`修复了嵌套的 ${key} 结构`); |
| #44 | hasIssues = true; |
| #45 | } |
| #46 | } |
| #47 | |
| #48 | // 检查必需字段 |
| #49 | if (!('role' in example)) { |
| #50 | issues.push('缺少 role 字段'); |
| #51 | hasIssues = true; |
| #52 | } |
| #53 | |
| #54 | if (!('content' in example)) { |
| #55 | issues.push('缺少 content 字段'); |
| #56 | hasIssues = true; |
| #57 | (example as any).content = ''; |
| #58 | } |
| #59 | |
| #60 | // 检查 role 值是否有效 |
| #61 | const validRoles = ['user', 'assistant', 'system', 'function']; |
| #62 | if ('role' in example && !validRoles.includes(example.role as string)) { |
| #63 | issues.push(`无效的 role 值: ${example.role}`); |
| #64 | hasIssues = true; |
| #65 | } |
| #66 | |
| #67 | // 检查 content 是否为字符串 |
| #68 | if ('content' in example && typeof example.content !== 'string') { |
| #69 | issues.push('content 必须是字符串'); |
| #70 | hasIssues = true; |
| #71 | (example as any).content = String(example.content || ''); |
| #72 | } |
| #73 | } |
| #74 | |
| #75 | if (issues.length > 0) { |
| #76 | Logger.warn(`examples[${index}] 存在问题`, `${agent.identifier}: ${issues.join(', ')}`); |
| #77 | } |
| #78 | |
| #79 | return example; |
| #80 | }); |
| #81 | |
| #82 | if (hasIssues) { |
| #83 | Logger.info('已自动修复 examples 字段问题', agent.identifier); |
| #84 | agent.examples = fixedExamples; |
| #85 | } |
| #86 | |
| #87 | return agent; |
| #88 | }; |
| #89 | |
| #90 | /** |
| #91 | * 格式化并检查 Agent Schema |
| #92 | * @param agent Agent 配置对象 |
| #93 | * @returns 验证通过的 Agent 配置 |
| #94 | */ |
| #95 | export const formatAndCheckSchema = (agent: any) => { |
| #96 | // 补充缺失字段 |
| #97 | if (!agent.schemaVersion) agent.schemaVersion = meta.schemaVersion; |
| #98 | if (!agent.createdAt) agent.createdAt = dayjs().format('YYYY-MM-DD'); |
| #99 | |
| #100 | // Schema 验证 |
| #101 | const result = clawdAgentSchema.safeParse(agent); |
| #102 | |
| #103 | if (!result.success) { |
| #104 | Logger.error('Schema 验证失败', agent.identifier); |
| #105 | throw new Error((result as any).error); |
| #106 | } |
| #107 | return agent; |
| #108 | }; |
| #109 | |
| #110 | /** |
| #111 | * 格式化提示词内容 |
| #112 | * @param prompt 提示词文本 |
| #113 | * @param locale 语言代码 |
| #114 | * @returns 格式化后的提示词 |
| #115 | */ |
| #116 | export const formatPrompt = async (prompt: string, locale: string) => { |
| #117 | return locale === 'zh-CN' |
| #118 | ? String(await remark().use(pangu).process(prompt)) // 中文使用 pangu 处理 |
| #119 | : String(await remark().process(prompt)); |
| #120 | }; |
| #121 | |
| #122 | /** |
| #123 | * 格式化 Agent JSON 配置 |
| #124 | * @param agent Agent 配置对象 |
| #125 | * @param locale 语言代码 |
| #126 | * @returns 格式化后的 Agent 配置 |
| #127 | */ |
| #128 | export const formatAgentJSON = async (agent: LobeAgent, locale: string = config.entryLocale) => { |
| #129 | // 计算插件数量(基于 config.plugins 的长度) |
| #130 | agent.pluginCount = agent.config?.plugins?.length || 0; |
| #131 | |
| #132 | // 计算知识库数量(基于 config.knowledgeBases 的长度) |
| #133 | agent.knowledgeCount = agent.config?.knowledgeBases?.length || 0; |
| #134 | |
| #135 | // 验证和修复 examples 字段 |
| #136 | // eslint-disable-next-line no-param-reassign |
| #137 | agent = validateAndFixExamples(agent); |
| #138 | |
| #139 | // 计算 token 使用量(仅在未计算过时才计算) |
| #140 | if (!agent.tokenUsage || agent.tokenUsage === 0) { |
| #141 | agent.tokenUsage = calculateTokenUsage(agent); |
| #142 | Logger.info('已计算 token 使用量', `${agent.identifier}: ${agent.tokenUsage} tokens`); |
| #143 | } |
| #144 | |
| #145 | formatAndCheckSchema(agent); |
| #146 | |
| #147 | // 格式化系统角色描述 |
| #148 | agent.config.systemRole = await formatPrompt(agent.config.systemRole, locale); |
| #149 | agent.config.systemRole = await format(agent.config.systemRole, { parser: 'markdown' }); |
| #150 | |
| #151 | // 格式化标识符和标签 |
| #152 | agent.identifier = kebabCase(agent.identifier); |
| #153 | if (agent?.meta?.tags?.length > 0) { |
| #154 | agent.meta.tags = agent.meta.tags.map((tag) => kebabCase(tag)); |
| #155 | } |
| #156 | |
| #157 | return agent; |
| #158 | }; |
| #159 | |
| #160 | /** |
| #161 | * 检查标识符唯一性 |
| #162 | * @param arr 标识符数组 |
| #163 | */ |
| #164 | export const checkUniqueIdentifier = (arr: string[]) => { |
| #165 | const duplicates = []; |
| #166 | const set = new Set(); |
| #167 | |
| #168 | for (const element of arr) { |
| #169 | if (set.has(element)) { |
| #170 | duplicates.push(element); |
| #171 | } else { |
| #172 | set.add(element); |
| #173 | } |
| #174 | } |
| #175 | |
| #176 | if (duplicates.length > 0) { |
| #177 | Logger.error('发现重复的标识符', JSON.stringify(duplicates)); |
| #178 | // eslint-disable-next-line unicorn/no-process-exit |
| #179 | process.exit(1); |
| #180 | } else { |
| #181 | Logger.success('标识符唯一性检查通过'); |
| #182 | } |
| #183 | }; |
| #184 | |
| #185 | /** |
| #186 | * 检查英文标识符格式 |
| #187 | * @param str 标识符字符串 |
| #188 | * @returns 是否符合英文标识符格式 |
| #189 | */ |
| #190 | export const CheckEnglishIdentifier = (str: string): boolean => { |
| #191 | const regex = /^[\d\sA-Za-z-]+$/; |
| #192 | return regex.test(str); |
| #193 | }; |
| #194 | |
| #195 | |
| #196 |