DeepSeek Harness 本地聊天记忆:按来源保存聊天原文,关键词 + 向量检索,可选大模型重排与检索摘要。源码公开,仅限非商用
浏览文件
main
分支
config.js
39 行 · 2.7 KB历史下载| 1 | import { normalizeProvider } from './models.js'; |
| 2 | import { DEFAULT_ORIGIN_RULES, normalizeRules } from './origin.js'; |
| 3 | import { UserError } from './errors.js'; |
| 4 | |
| 5 | /** Tools whose text arguments count as the companion speaking (glob on the tool name). */ |
| 6 | export const DEFAULT_SPEAK_TOOLS = Object.freeze(['*send_message*', '*send_group_message*', '*send_private_message*', '*reply*']); |
| 7 | /** Tools whose results are chat messages the companion read (glob on the tool name). */ |
| 8 | export const DEFAULT_HEAR_TOOLS = Object.freeze(['*unread*', '*recent_messages*', '*wait_for_messages*', '*message_history*', '*chat_history*', '*get_messages*']); |
| 9 | |
| 10 | const list = (value, fallback) => value === undefined ? [...fallback] |
| 11 | : Array.isArray(value) ? value.map(item => String(item).trim()).filter(Boolean) |
| 12 | : String(value).split(/[,,\s]+/).filter(Boolean); |
| 13 | const bool = (value, fallback) => value === undefined ? fallback : value === true; |
| 14 | |
| 15 | export function normalizeSettings(input = {}) { |
| 16 | const setting = { |
| 17 | autoRecord: bool(input.autoRecord, true), autoRetrieve: bool(input.autoRetrieve, true), tools: bool(input.tools, true), |
| 18 | topK: input.topK ?? 6, maxContextChars: input.maxContextChars ?? 4000, |
| 19 | ownerIds: list(input.ownerIds, []), |
| 20 | // Legacy `shared: true` meant "this is a single-user instance": treat unknown sessions as the owner. |
| 21 | unknownOrigin: input.unknownOrigin ?? (input.shared === true ? 'owner' : 'isolated'), |
| 22 | shareGroups: bool(input.shareGroups, true), shareOwner: bool(input.shareOwner, true), |
| 23 | originRules: normalizeRules(input.originRules ?? DEFAULT_ORIGIN_RULES), |
| 24 | speakTools: list(input.speakTools, DEFAULT_SPEAK_TOOLS), |
| 25 | hearTools: list(input.hearTools, DEFAULT_HEAR_TOOLS), |
| 26 | // Use a suitable embedding model already installed in local Ollama when none is configured. |
| 27 | autoEmbedding: bool(input.autoEmbedding, true), |
| 28 | embedding: normalizeProvider(input.embedding), |
| 29 | reranker: normalizeProvider(input.reranker, 'reranker'), |
| 30 | }; |
| 31 | if (!Number.isInteger(setting.topK) || setting.topK < 1 || setting.topK > 20) throw new UserError('每次检索片段数需为 1–20'); |
| 32 | if (!Number.isInteger(setting.maxContextChars) || setting.maxContextChars < 300 || setting.maxContextChars > 20000) |
| 33 | throw new UserError('上下文预算需为 300–20000 字符'); |
| 34 | if (setting.ownerIds.length > 10 || setting.ownerIds.some(id => !/^[\w.-]{1,64}$/.test(id))) throw new UserError('主人账号最多 10 个,只能含字母数字'); |
| 35 | if (!['isolated', 'owner'].includes(setting.unknownOrigin)) throw new UserError('未识别会话的处理方式无效'); |
| 36 | for (const name of ['speakTools', 'hearTools']) |
| 37 | if (setting[name].length > 20 || setting[name].some(glob => !/^[\w*.:-]{1,80}$/.test(glob))) throw new UserError('工具名格式不正确'); |
| 38 | return setting; |
| 39 | } |

