dsh-model-reasoning-defaults 0.0.2 → 0.0.4
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/README.md +35 -56
- package/cordis.patch.yml +6 -3
- package/lib/client.js +150 -58
- package/lib/client.js.map +1 -1
- package/lib/index.d.mts +40 -55
- package/lib/index.mjs +107 -219
- package/lib/index.mjs.map +1 -1
- package/lib/types/client/index.d.ts +2 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/route-table.d.ts +60 -0
- package/lib/types/client/route-table.d.ts.map +1 -0
- package/package.json +11 -8
package/lib/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * dsh-model-reasoning-defaults\n *\n * 为每个模型配置默认推理等级。请求已显式指定 reasoningEffort 时保持原值;\n * 其余按 provider/model 路由查找默认值并转换为 DSH 的品牌类型。\n *\n * agent-loop 请求在 agent/request waterfall 中注入(此后到达 llm/stream 时\n * 已深冻结);手写调用在 llm.stream 入口复制后再进入 waterfall,调用配置\n * 方法走同一共享包装层。\n *\n * @module dsh-model-reasoning-defaults\n */\nimport type { Context, EventOptions } from '@deepseek-ai/cordis'\nimport { isAgentLoopRequest, ReasoningEffortId } from '@deepseek-ai/dsh-llm'\nimport type {\n LlmCallConfig,\n LlmRuntime,\n} from '@deepseek-ai/dsh-llm'\nimport z from '@deepseek-ai/schemastery'\n\n/** 插件名(同时作为 Cordis 插件 id)。 */\nexport const name = 'dsh-model-reasoning-defaults'\n\n/** 声明依赖的服务:LLM 服务就绪后装配;注册/读取设置命名空间需要设置服务。 */\nexport const inject = ['llm', 'settings'] as const\n\n/** 单个模型的推理等级配置。 */\nexport interface ModelConfig {\n /** 模型 ID(数组形式必填;字典形式以键名为准,可省略)。 */\n id?: string\n /** 默认推理等级(如 off | minimal | low | medium | high | xhigh | max)。 */\n reasoningEffort?: string\n}\n\n/** 单个模型配置输入:既可以是等级字符串简写,也可以是配置对象。 */\nexport type ModelConfigInput = string | ModelConfig\n\n/** 单个 Provider 的推理等级配置。 */\nexport interface ProviderConfig {\n /** 该 Provider 下所有模型的默认推理等级。 */\n reasoningEffort?: string\n /** 该 Provider 下各模型的推理等级配置(字典或对象列表)。 */\n models?: Record<string, ModelConfigInput> | ModelConfigInput[]\n}\n\n/** Provider 配置输入:既可以是等级字符串简写(作用于该 Provider 所有模型),也可以是配置对象。 */\nexport type ProviderConfigInput = string | ProviderConfig\n\n/**\n * 插件配置:支持按 Provider 与模型嵌入式层级配置,也可使用扁平路由字典 defaults。\n * 两种形式是同等的一等配置入口(本仓库无历史版本,不存在\"新旧兼容\"语义),\n * 归一化到同一张路由表后统一参与六级匹配。\n *\n * 合并后的匹配优先级从高到低为:\n * - \"provider:model\":精确匹配(来自 providers[p].models[m] 或 defaults[\"provider:model\"])\n * - \"provider:*\":该 provider 下所有模型(来自 providers[p].reasoningEffort 或 defaults[\"provider:*\"])\n * - \"provider/*\":斜杠写法(来自 defaults[\"provider/*\"])\n * - \"provider\":裸 provider 写法(来自 defaults[\"provider\"])\n * - \"*:model\":跨 provider 的同名模型(来自 top-level models[m] 或 defaults[\"*:model\"])\n * - \"*\":全局匹配(来自 top-level reasoningEffort 或 defaults[\"*\"])\n */\nexport interface Config {\n /** 扁平路由字典:键为上表六级路由键;与结构化配置产生同键时覆盖结构化项。 */\n defaults?: Record<string, string>\n /** 按 Provider 组织的嵌入式配置。 */\n providers?: Record<string, ProviderConfigInput>\n /** 跨 Provider 适用的模型默认配置(等价于 \"*:model\")。 */\n models?: Record<string, ModelConfigInput> | ModelConfigInput[]\n /** 全局默认推理等级(等价于 \"*\")。 */\n reasoningEffort?: string\n}\n\nconst nonBlankPattern = /^\\S+$/\n\n// 已知推理等级集合:llm-pi-ai 的 ModelThinkingLevel(off/minimal/low/medium/high/\n// xhigh/max)与 llm-deepseek(off/low/high/max,为其子集)的并集。仅用于激活期与\n// 提取期的告警提示而不阻断注入——最终合法性由适配器逐字匹配裁决,本地白名单\n// 收窄反而会在上游新增等级时挡住合法配置。\nconst KNOWN_REASONING_EFFORTS: ReadonlySet<string> = new Set([\n 'off',\n 'minimal',\n 'low',\n 'medium',\n 'high',\n 'xhigh',\n 'max',\n])\n\n// llm-deepseek 注册的唯一 provider 路由名(宿主 packages/llm/llm-deepseek 的\n// PROVIDER 常量);llm-pi-ai 家族无法注册同名路由,宿主会拒绝重名 adapter family。\nconst DEEPSEEK_OFFICIAL_PROVIDER_ID = 'deepseek-official'\n\nconst modelConfigSchema = z.object({\n id: z.string().pattern(nonBlankPattern),\n reasoningEffort: z.string().pattern(nonBlankPattern),\n})\n\nconst modelEntrySchema = z.union([\n z.string().pattern(nonBlankPattern),\n modelConfigSchema,\n])\n\nconst modelsFieldSchema = z.union([\n z.dict(modelEntrySchema, z.string().pattern(nonBlankPattern)),\n z.array(modelEntrySchema),\n])\n\nconst providerConfigSchema = z.object({\n reasoningEffort: z.string().pattern(nonBlankPattern),\n models: modelsFieldSchema,\n})\n\nconst providerEntrySchema = z.union([\n z.string().pattern(nonBlankPattern),\n providerConfigSchema,\n])\n\n/** Cordis 配置模式(显式注解接口类型,满足声明产物的可命名要求)。 */\nexport const Config: z<Config> = z.object({\n // 路由键与等级值都要求非空白:空白键永远不会被 candidateKeys 命中,空白值\n // 会被适配器逐字匹配拒绝,都在配置阶段直接报错暴露最省排查成本。\n // .default({}) 与 schemastery 对 dict 的内建空对象默认重复,保留它是为了让\n // 编程直调路径(绕过 cordis resolveConfig)也能拿到确定的形状。\n defaults: z.dict(\n z.string().pattern(nonBlankPattern),\n z.string().pattern(nonBlankPattern),\n ).default({}),\n providers: z.dict(\n providerEntrySchema,\n z.string().pattern(nonBlankPattern),\n ).default({}),\n models: modelsFieldSchema,\n reasoningEffort: z.string().pattern(nonBlankPattern),\n})\n\n/**\n * 从字符串简写或配置对象中提取非空推理等级。\n *\n * 只认单一规范字段 reasoningEffort,不做多字段兜底链:同义多源读取会在字段\n * 冲突时按书写顺序静默裁决(例如 reasoningEffort 与 effort 同时配置时无声地\n * 二选一),掩盖配置错误;确需别名应由用户层显式映射后再传入。\n *\n * @param val - 等级字符串,或 ModelConfig/ProviderConfig 形状的对象。\n * @returns trim 后非空的等级字符串;无法提取时返回 undefined。\n */\nfunction extractEffort(val: unknown): string | undefined {\n const candidate = typeof val === 'string'\n ? val\n : (typeof val === 'object' && val !== null)\n ? (val as { reasoningEffort?: unknown }).reasoningEffort\n : undefined\n if (typeof candidate !== 'string') return undefined\n const trimmed = candidate.trim()\n return trimmed.length > 0 ? trimmed : undefined\n}\n\n/**\n * 将结构化 Config 归一化为统一的扁平路由字典。\n *\n * @param config - 插件配置对象。\n * @returns 归一化后的键值映射;键与值均已去除首尾空白。\n */\nexport function normalizeConfig(config: Config): Record<string, string> {\n const result: Record<string, string> = {}\n\n // 1. 全局默认 (对应 \"*\")\n const globalEffort = extractEffort(config.reasoningEffort)\n if (globalEffort) {\n result['*'] = globalEffort\n }\n\n // 2. 顶层跨 Provider 模型默认 (对应 \"*:model\")\n if (config.models) {\n if (Array.isArray(config.models)) {\n for (const item of config.models) {\n // 数组形式必须携带非空白 id 才能生成路由键;缺失项由 apply() 的\n // 激活期诊断告警上报,这里只负责安静地跳过无效形状。\n const id = typeof item === 'object' && item !== null && typeof item.id === 'string' ? item.id.trim() : ''\n if (id.length === 0) continue\n const effort = extractEffort(item)\n if (effort) result['*:' + id] = effort\n }\n } else if (typeof config.models === 'object') {\n for (const [rawModelId, modelVal] of Object.entries(config.models)) {\n const modelId = rawModelId.trim()\n if (modelId.length === 0) continue\n const effort = extractEffort(modelVal)\n if (effort) result['*:' + modelId] = effort\n }\n }\n }\n\n // 3. Provider 层级配置\n if (config.providers && typeof config.providers === 'object') {\n for (const [rawProviderId, providerVal] of Object.entries(config.providers)) {\n const providerId = rawProviderId.trim()\n if (providerId.length === 0) continue\n\n // 3.1 Provider 级默认 (对应 \"provider:*\")\n const providerEffort = extractEffort(providerVal)\n if (providerEffort) {\n result[providerId + ':*'] = providerEffort\n }\n\n // 3.2 Provider 内的具体模型 (对应 \"provider:model\")\n if (typeof providerVal === 'object' && providerVal !== null && providerVal.models) {\n const models = providerVal.models\n if (Array.isArray(models)) {\n for (const item of models) {\n const id = typeof item === 'object' && item !== null && typeof item.id === 'string' ? item.id.trim() : ''\n if (id.length === 0) continue\n const effort = extractEffort(item)\n if (effort) result[providerId + ':' + id] = effort\n }\n } else if (typeof models === 'object') {\n for (const [rawModelId, modelVal] of Object.entries(models)) {\n const modelId = rawModelId.trim()\n if (modelId.length === 0) continue\n const effort = extractEffort(modelVal)\n if (effort) result[providerId + ':' + modelId] = effort\n }\n }\n }\n }\n }\n\n // 4. 扁平 defaults 字典:与结构化配置同等的一等入口,写在最后使其在与结构化\n // 配置同键冲突时胜出(显式路由键的表达意图更具体)。键值均 trim 后判断,\n // 与结构化路径(id 空则跳过)保持一致:空白键与空白值一样永不命中任何\n // 请求路由(cordis 路径由 schema 拒绝,此处覆盖绕开 schema 的直调路径)。\n if (config.defaults && typeof config.defaults === 'object') {\n for (const [rawKey, value] of Object.entries(config.defaults)) {\n const key = rawKey.trim()\n const trimmedValue = value.trim()\n if (key.length === 0 || trimmedValue.length === 0) continue\n result[key] = trimmedValue\n }\n }\n\n return result\n}\n\ntype ReasoningConfig = Pick<LlmCallConfig, 'provider' | 'model' | 'reasoningEffort'>\n\n/**\n * 静态体检插件配置,返回人类可读的问题清单(纯函数,不修改任何数据)。\n *\n * schemastery 的对象属性全部可选且对未知键透传,\"拼错字段\"\"模型项缺 id\"\n * 这类错误能通过校验却在 normalizeConfig 中被静默忽略;此清单在插件激活时\n * 一次性告警,把这类静默降级变成可见信息。等级值不在已知集合也在此提示,\n * 但仍会注入——最终是否可用交给适配器逐字匹配裁决。\n *\n * @param config - 用户原始配置(未经归一化)。\n * @returns 问题描述列表;无问题时为空数组。\n */\nfunction collectConfigIssues(config: Config): string[] {\n const issues: string[] = []\n const knownLevels = [...KNOWN_REASONING_EFFORTS].join('/')\n\n const checkLevel = (route: string, level: string | undefined): void => {\n if (level !== undefined && !KNOWN_REASONING_EFFORTS.has(level)) {\n issues.push('路由 ' + route + ' 的推理等级 \"' + level + '\" 不在已知集合 (' + knownLevels + ') 内,请确认目标模型支持')\n }\n }\n\n /**\n * 检查单个模型条目:字符串简写直接校验等级;\n * 对象形式要求携带有效等级,数组元素还要求有效 id。\n */\n const checkModelEntry = (route: string, entry: ModelConfigInput, requireId: boolean): void => {\n if (typeof entry === 'string') {\n // 数组位置没有键名可用作 id,字符串简写永远生成不了路由键;字典位置的\n // 字符串值以键名为 id(requireId=false),不受此限制。\n if (requireId) {\n issues.push('数组形式模型条目缺少有效 id(字符串简写无键名可用),已被忽略:' + JSON.stringify(entry))\n return\n }\n checkLevel(route, extractEffort(entry))\n return\n }\n const id = typeof entry.id === 'string' ? entry.id.trim() : ''\n if (requireId && id.length === 0) {\n issues.push('模型条目缺少有效 id,已被忽略:' + JSON.stringify(entry))\n return\n }\n const effort = extractEffort(entry)\n if (effort === undefined) {\n issues.push('模型条目未包含 reasoningEffort,已被忽略:' + JSON.stringify(entry))\n return\n }\n checkLevel(route, effort)\n }\n\n // 全局等级\n checkLevel('*', extractEffort(config.reasoningEffort))\n\n // 顶层跨 Provider 模型\n if (config.models) {\n if (Array.isArray(config.models)) {\n config.models.forEach((entry, index) => {\n checkModelEntry('*:<models[' + index + ']>', entry, true)\n })\n } else if (typeof config.models === 'object') {\n for (const [modelId, entry] of Object.entries(config.models)) {\n checkModelEntry('*:' + modelId, entry, false)\n }\n }\n }\n\n // Provider 层级\n if (config.providers && typeof config.providers === 'object') {\n for (const [providerId, providerVal] of Object.entries(config.providers)) {\n if (typeof providerVal === 'string') {\n checkLevel(providerId + ':*', extractEffort(providerVal))\n continue\n }\n const hasModels = providerVal.models !== undefined\n const providerEffort = extractEffort(providerVal)\n if (!hasModels && providerEffort === undefined) {\n issues.push('provider ' + providerId + ' 未包含 reasoningEffort 或 models,整条配置已被忽略')\n continue\n }\n checkLevel(providerId + ':*', providerEffort)\n if (hasModels) {\n const models = providerVal.models!\n if (Array.isArray(models)) {\n models.forEach((entry, index) => {\n checkModelEntry(providerId + ':<models[' + index + ']>', entry, true)\n })\n } else if (typeof models === 'object') {\n for (const [modelId, entry] of Object.entries(models)) {\n checkModelEntry(providerId + ':' + modelId, entry, false)\n }\n }\n }\n }\n }\n\n // 扁平 defaults 字典:schema 在 cordis 路径直接拒绝空白键值,但编程直调\n // 会绕过校验;这里的空键检查与 normalizeConfig 的跳过逻辑保持一致,把\n // 静默降级变成可见告警。\n if (config.defaults && typeof config.defaults === 'object') {\n for (const [rawKey, value] of Object.entries(config.defaults)) {\n const key = rawKey.trim()\n if (key.length === 0) {\n issues.push('扁平路由键为空白,已被忽略:' + JSON.stringify(rawKey))\n continue\n }\n checkLevel(key, extractEffort(value))\n }\n }\n\n return issues\n}\n\n// agent/request 的 loop 侧 emit 实参是 { turn, step, signal };core/agent 的派发器\n// 会把路由主体 agent(Scoped<Agent>)融合进 payload 并同时作为监听器 this,因此\n// 实收 payload 含 agent 字段。本监听器不读取任何 payload 字段,此处仅按本插件\n// 用到的形状窄化 ctx.on 的签名。\ntype AgentRequestPayload = {\n turn: number\n step: number\n signal: AbortSignal\n}\n\ntype AgentRequestListener = (\n this: object,\n payload: AgentRequestPayload,\n next: () => Promise<LlmCallConfig>,\n) => Promise<LlmCallConfig>\n\ntype AgentRequestRegistrar = (\n name: 'agent/request',\n listener: AgentRequestListener,\n options?: boolean | EventOptions,\n) => () => boolean\n\n/**\n * 注册全局 agent/request waterfall。\n *\n * cordis 的 ctx.on 内部会把监听器注册为当前 fiber 上的 effect(见 events\n * 服务的 register()),无论 global 标志如何都会在 fiber 卸载时自动清理;\n * global 只影响事件派发时的上下文过滤。因此无需再包一层 ctx.effect。\n *\n * 该事件的运行时接收者是 Scoped<Agent>,Cordis 根 Context 的事件泛型表不会\n * 暴露它,因此在最小边界内窄化签名(仅约束本插件用到的事件名与参数)。\n *\n * @param ctx - 当前插件上下文。\n * @param listener - agent/request waterfall 监听器。\n */\nfunction registerAgentRequestListener(ctx: Context, listener: AgentRequestListener): void {\n // 窄化仅覆盖本插件实际使用的事件名与参数;内部转调仍通过 ctx.on 的真实实现。\n const register = ctx.on.bind(ctx) as AgentRequestRegistrar\n register('agent/request', listener, { global: true })\n}\n\n/**\n * 生成一个路由的候选配置键。\n *\n * 兼容键保留在明确的优先级表中,避免不同调用入口各自实现一套匹配规则。\n *\n * @param provider - 请求使用的 provider。\n * @param model - 请求使用的 model。\n * @returns 按匹配优先级排列的候选键。\n */\nfunction candidateKeys(provider: string, model: string): readonly string[] {\n return [\n provider + ':' + model,\n provider + ':*',\n provider + '/*',\n provider,\n '*:' + model,\n '*',\n ]\n}\n\n/**\n * 查找一个路由对应的默认推理等级。\n *\n * @param defaults - 归一化后的扁平路由映射。\n * @param provider - 请求使用的 provider。\n * @param model - 请求使用的 model。\n * @returns 找到的非空推理等级,未找到时返回 undefined。\n */\nfunction lookupEffort(\n defaults: Readonly<Record<string, string>>,\n provider: string,\n model: string,\n): string | undefined {\n for (const key of candidateKeys(provider, model)) {\n const effort = defaults[key]\n if (typeof effort === 'string' && effort.length > 0) return effort\n }\n return undefined\n}\n\n/**\n * 在不修改原对象的前提下应用默认推理等级。\n *\n * 该函数同时用于 GenerateOptions 和 LlmCallConfig,因此调用方可以保留\n * 原请求对象中的 messages、signal 等其它字段,并安全处理深冻结输入。\n *\n * 第二参数只接受归一化后的扁平路由表;结构化 Config 必须先经 normalizeConfig。\n * 曾尝试用对象形状嗅探让本函数同时接纳两种入参,但路由表允许任意非空白键,\n * 含 \"models\"/\"providers\" 等键的路由表会被误判成结构化配置(整表归一化为空、\n * 注入全部失效),反之仅含顶层 reasoningEffort 的最小结构化配置又会漏判——\n * 两类误判都是静默失效,因此彻底拆掉形状嗅探。\n *\n * @param config - 待补齐的 LLM 请求或调用配置。\n * @param defaults - normalizeConfig 产出的扁平路由表。\n * @returns 原配置或带有 reasoningEffort 的浅复制对象。\n */\nexport function applyDefaultReasoningEffort<T extends ReasoningConfig>(\n config: T,\n defaults: Readonly<Record<string, string>>,\n): T {\n if (config.reasoningEffort !== undefined || !config.provider || !config.model) return config\n const effort = lookupEffort(defaults, config.provider, config.model)\n if (effort === undefined) return config\n return { ...config, reasoningEffort: ReasoningEffortId(effort) }\n}\n\ntype ReasoningDefaults = Readonly<Record<string, string>>\n\n/**\n * 设置页 UI 专用命名空间。该命名空间由本插件注册为可写设置项,浏览器设置\n * 面板通过宿主统一的 settings API 编辑它;生效优先级位于自动提取之上、\n * cordis 插件配置之下(见 resolveEffectiveDefaults)。\n */\nexport const UI_DEFAULTS_NAMESPACE = 'model-reasoning-defaults'\n\n/** 设置命名空间的用户层数据形状:与 Config.defaults 同构的扁平路由字典。 */\nexport interface UiDefaultsSection {\n /** 扁平路由字典:键为六级路由键,值为推理等级。 */\n defaults?: Record<string, string>\n}\n\n// 命名空间 schema 与 Config.defaults 复用同一约束(非空白键值),保证两条\n// 配置入口的合法性标准完全一致。\nconst uiDefaultsSectionSchema = z.object({\n defaults: z.dict(\n z.string().pattern(nonBlankPattern),\n z.string().pattern(nonBlankPattern),\n ).default({}),\n})\n\ntype SettingsService = {\n get: (ns: string) => unknown\n /**\n * 注册可写命名空间(真实签名见 @deepseek-ai/dsh-settings 的 SettingsProvider.register;\n * 此处只声明本插件用到的参数面)。可选:设置服务存在才可注册。\n */\n register?: (\n ns: string,\n schema: z<UiDefaultsSection>,\n options?: { applies?: 'live' | 'restart' },\n ) => unknown\n}\n\n/**\n * 取当前上下文上的设置服务;不存在或 get 不可调用时返回 undefined。\n *\n * apply() 的注入门槛判定与本提取路径共用这一个函数,避免两处标准不一致\n * 造成\"装了包装层却永远提取不到数据\"的错位。\n */\nfunction settingsService(ctx: Context): SettingsService | undefined {\n const settings = (ctx as { settings?: SettingsService }).settings\n if (!settings || typeof settings.get !== 'function') return undefined\n return settings\n}\n\n// 提取期告警去重:settings 提取位于每次请求的热路径上,同一问题只告警一次,\n// 避免日志刷屏;进程生命周期内出现一次提示即足以定位配置错误。\nconst warnedMessages = new Set<string>()\n\n/** 经当前上下文的 logger 发出一次性告警。 */\nfunction warnOnce(ctx: Context, message: string): void {\n if (warnedMessages.has(message)) return\n warnedMessages.add(message)\n ctx.logger?.warn?.('[' + name + '] ' + message)\n}\n\n/**\n * 创建一条提取结果的记录器:等级 trim 后写入映射;不在已知集合时一次性告警\n * 但仍注入,让适配器的逐字匹配给出最终裁决(避免本地白名单过期后挡住上游\n * 新增的等级)。设置提取位于每次请求的热路径上,告警按消息去重防止刷屏。\n *\n * @param ctx - Cordis 上下文。\n * @param extracted - 提取结果的目标映射。\n * @returns 记录函数。\n */\nfunction createEffortRecorder(\n ctx: Context,\n extracted: Record<string, string>,\n): (routeKey: string, level: unknown) => void {\n return (routeKey, level) => {\n if (typeof level !== 'string') return\n const trimmedLevel = level.trim()\n if (trimmedLevel.length === 0) return\n if (!KNOWN_REASONING_EFFORTS.has(trimmedLevel)) {\n warnOnce(ctx, '设置中路由 ' + routeKey + ' 的推理等级 \"' + trimmedLevel + '\" 不在已知集合内,请确认目标模型支持')\n }\n extracted[routeKey] = trimmedLevel\n }\n}\n\n/**\n * 从当前 Cordis 上下文的设置服务中读取各 Provider 与模型的默认推理等级。\n *\n * 字段约定(每个来源只读单一规范字段,不做别名兜底):\n * - llm-pi-ai:provider 级 `reasoning` 是宿主原生声明字段;模型级\n * `models[].reasoning` 与 `modelOverrides.<model>.reasoning` 是本插件约定\n * 读取的扩展字段,依赖其设置解析对未声明键的透传行为。宿主在模型层另有\n * 原生字段 `reasoningEfforts`,但那是\"可选等级集合 + 线格式映射\"的能力\n * 声明而非默认值选择,语义不同,本插件不读取;若上游收紧对未声明键的\n * 解析策略,`reasoning` 这部分提取会静默失效。\n * - llm-deepseek:顶层 `reasoningEffort` 为宿主原生字段,映射到其注册的\n * provider 路由 deepseek-official(见 DEEPSEEK_OFFICIAL_PROVIDER_ID)。\n *\n * 整个函数不包 try/catch:宿主的 settings.get 对未注册命名空间返回 undefined\n * 且不会抛错,函数体已对全部外部数据做了形状防御,剩余可能抛错的只有代码\n * 缺陷,应当让它暴露,而不是吞掉后以空映射继续主流程。\n *\n * @param ctx - Cordis 上下文。\n * @returns 提取出的路由默认映射字典。\n */\nexport function extractSettingsDefaults(ctx: Context): Record<string, string> {\n const extracted: Record<string, string> = {}\n const settings = settingsService(ctx)\n if (!settings) return extracted\n const record = createEffortRecorder(ctx, extracted)\n\n // 1. 读取 llm-pi-ai 命名空间设置(涵盖所有 OpenAI-compatible、Anthropic、自定义网关等提供商)\n const piAi = settings.get('llm-pi-ai') as {\n providers?: Record<string, {\n reasoning?: unknown\n models?: Array<{ id?: unknown; reasoning?: unknown }>\n modelOverrides?: Record<string, { reasoning?: unknown }>\n }>\n } | undefined\n\n if (piAi?.providers && typeof piAi.providers === 'object') {\n for (const [providerId, providerProfile] of Object.entries(piAi.providers)) {\n if (!providerId || !providerProfile || typeof providerProfile !== 'object') continue\n\n // pi-ai 家族无法占用 deepseek-official 路由(宿主拒绝重名 adapter family),\n // 这里提取的值永远不会命中;跳过并提示一次,避免稍后被 llm-deepseek\n // 来源的同名键无声覆盖、留下难以解释的死配置。\n if (providerId === DEEPSEEK_OFFICIAL_PROVIDER_ID) {\n warnOnce(ctx, 'llm-pi-ai 中名为 ' + DEEPSEEK_OFFICIAL_PROVIDER_ID + ' 的 provider 无法注册该路由,已跳过其推理等级提取')\n continue\n }\n\n // Provider 级别默认思考等级(原生字段 reasoning)\n record(providerId + ':*', providerProfile.reasoning)\n\n // 模型列表中的思考等级(扩展字段,见函数头注释)\n if (Array.isArray(providerProfile.models)) {\n for (const m of providerProfile.models) {\n const id = m && typeof m === 'object' && typeof m.id === 'string' ? m.id.trim() : ''\n if (id.length === 0) continue\n record(providerId + ':' + id, m.reasoning)\n }\n }\n\n // modelOverrides 中的思考等级(扩展字段,见函数头注释)\n if (providerProfile.modelOverrides && typeof providerProfile.modelOverrides === 'object') {\n for (const [modelId, override] of Object.entries(providerProfile.modelOverrides)) {\n const id = modelId.trim()\n if (id.length === 0 || !override || typeof override !== 'object') continue\n record(providerId + ':' + id, override.reasoning)\n }\n }\n }\n }\n\n // 2. 读取 llm-deepseek 命名空间设置(原生字段 reasoningEffort → deepseek-official 路由)\n const deepseek = settings.get('llm-deepseek') as { reasoningEffort?: unknown } | undefined\n if (deepseek && typeof deepseek === 'object') {\n record(DEEPSEEK_OFFICIAL_PROVIDER_ID + ':*', deepseek.reasoningEffort)\n }\n\n return extracted\n}\n\n/**\n * 从本插件专用的设置命名空间读取设置页 UI 写入的路由表。\n *\n * 该命名空间由 apply() 注册、浏览器设置面板写入,是\"设置里改默认推理强度\"\n * 的存储层;每次请求实时读取,改动即时生效。形状非法(非对象/缺字段)时\n * 返回空映射——schema 校验已保证写入合法,这里的防御只覆盖外部手工编辑\n * settings 文档的场景。\n *\n * @param ctx - Cordis 上下文。\n * @returns 路由映射字典。\n */\nexport function extractUiNamespaceDefaults(ctx: Context): Record<string, string> {\n const extracted: Record<string, string> = {}\n const settings = settingsService(ctx)\n if (!settings) return extracted\n\n const section = settings.get(UI_DEFAULTS_NAMESPACE) as UiDefaultsSection | undefined\n if (!section || typeof section !== 'object') return extracted\n\n const record = createEffortRecorder(ctx, extracted)\n const defaults = section.defaults\n if (defaults && typeof defaults === 'object') {\n for (const [rawKey, level] of Object.entries(defaults)) {\n const key = rawKey.trim()\n if (key.length === 0) continue\n record(key, level)\n }\n }\n return extracted\n}\n\n// 注册重试参数:热重载期间旧代 fiber 仍持有命名空间(注册清理挂在调用方\n// fiber 上,见 SettingsProvider.register 文档),新代直接 register 会撞\n// \"already registered\";旧代卸载后键位释放,轮询即可补上。\nconst UI_NS_RETRY_INTERVAL_MS = 250\nconst UI_NS_RETRY_MAX_ATTEMPTS = 240\n\n/**\n * 在设置服务上注册本插件的可编辑命名空间(跨热重载安全)。\n *\n * 每次激活都先直接尝试注册——不缓存\"已注册\"标记,因为旧代的卸载会把命名空间\n * 一并注销,缓存的真值会在\"停用后再启用\"的场景下变成谎言。撞上\n * \"already registered\" 说明旧代尚未释放,进入短周期轮询直到键位空出;\n * 其它错误告警后放弃,不阻断主流程(patch 层配置仍然生效)。\n *\n * @param ctx - 当前插件上下文。\n * @param settings - 当前上下文的设置服务。\n */\nfunction registerUiDefaultsNamespace(ctx: Context, settings: SettingsService): void {\n if (settings.register === undefined) {\n warnOnce(ctx, '当前设置服务不支持命名空间注册,设置页将无法编辑推理等级默认值')\n return\n }\n\n const attempt = (): 'ok' | 'busy' => {\n try {\n settings.register!(UI_DEFAULTS_NAMESPACE, uiDefaultsSectionSchema, { applies: 'live' })\n return 'ok'\n } catch (error) {\n if (!String(error).includes('already registered')) {\n ctx.logger?.warn?.('[' + name + '] 注册设置命名空间失败,设置页将无法编辑推理等级默认值:' + String(error))\n return 'ok'\n }\n return 'busy'\n }\n }\n\n if (attempt() !== 'busy') return\n\n let attempts = 0\n const timer = setInterval(() => {\n attempts += 1\n if (attempts > UI_NS_RETRY_MAX_ATTEMPTS) {\n clearInterval(timer)\n warnOnce(ctx, '等待旧代释放设置命名空间超时,本次运行设置页不可用;请重启宿主或再次重载本插件')\n return\n }\n if (attempt() === 'ok') clearInterval(timer)\n }, UI_NS_RETRY_INTERVAL_MS)\n ctx.effect(() => () => {\n clearInterval(timer)\n }, name + ': stop UI namespace registration retry')\n}\n\ntype RuntimePatchState = {\n /** 创建共享包装层的 fiber 上下文;热重载复用包装层时随最新 fiber 刷新。 */\n ctx: Context\n defaults: Map<symbol, ReasoningDefaults>\n originalStream: LlmRuntime['stream']\n originalPrepareCall: LlmRuntime['prepareCall']\n originalResolveCallConfig: LlmRuntime['resolveCallConfig']\n stream: LlmRuntime['stream']\n prepareCall: LlmRuntime['prepareCall']\n resolveCallConfig: LlmRuntime['resolveCallConfig']\n}\n\n// Symbol.for 让热重载后的模块副本复用同一层状态,而不是再包一层旧包装。\nconst runtimePatchStateKey = Symbol.for('dsh-model-reasoning-defaults.runtime-patch-state')\n\n/**\n * 取最后激活的配置层。热重载期间新 fiber 覆盖旧 fiber,旧 fiber 卸载后\n * 新配置仍保持生效;最后一个 fiber 卸载时才还原原始服务方法。\n *\n * @param state - 同一 LLM 服务上的包装状态。\n * @returns 当前生效的 defaults;没有活跃层时返回 undefined。\n */\nfunction currentDefaults(state: RuntimePatchState): ReasoningDefaults | undefined {\n let current: ReasoningDefaults | undefined\n for (const defaults of state.defaults.values()) current = defaults\n return current\n}\n\n/**\n * 解析当前生效的完整 defaults 映射。三个配置层按优先级从低到高合并:\n * 设置服务自动提取项(llm-pi-ai / llm-deepseek 原生字段)→ 本插件设置\n * 命名空间(设置页 UI 写入)→ 插件自身 cordis 配置(patch 层)。\n * 同一路由键上高优先级层覆盖低优先级层。\n *\n * @param ctx - 当前共享包装层绑定的上下文(热重载后为新 fiber 的 ctx)。\n * @param state - 同一 LLM 服务上的包装状态。\n * @returns 合并后的路由映射;三层均为空时为空对象。\n */\nfunction resolveEffectiveDefaults(\n ctx: Context,\n state: RuntimePatchState,\n): ReasoningDefaults {\n const pluginDefaults = currentDefaults(state) ?? {}\n const uiStoreDefaults = extractUiNamespaceDefaults(ctx)\n const settingsDefaults = extractSettingsDefaults(ctx)\n return {\n ...settingsDefaults,\n ...uiStoreDefaults,\n ...pluginDefaults,\n }\n}\n\n/**\n * 将当前活跃层应用到配置。保留原对象是卸载后仍被外部持有的旧包装的必要语义,\n * 也避免把一个空对象伪装成真实配置来源。\n *\n * @param state - 同一 LLM 服务上的包装状态(ctx 从 state 读取,保证热重载后\n * 提取路径跟随最新 fiber)。\n * @param config - 待处理的调用配置。\n * @returns 原配置或带默认推理等级的浅复制对象。\n */\nfunction applyCurrentDefault<T extends ReasoningConfig>(\n state: RuntimePatchState,\n config: T,\n): T {\n const defaults = resolveEffectiveDefaults(state.ctx, state)\n return Object.keys(defaults).length === 0 ? config : applyDefaultReasoningEffort(config, defaults)\n}\n\n/**\n * 从当前 stream 包装上恢复跨热重载共享的状态。\n *\n * @param llm - LLM 服务实例。\n * @returns 现有包装状态;服务尚未被本插件包装时返回 undefined。\n */\nfunction existingRuntimePatchState(llm: LlmRuntime): RuntimePatchState | undefined {\n return (llm.stream as unknown as Record<PropertyKey, unknown>)[runtimePatchStateKey] as RuntimePatchState | undefined\n}\n\n/**\n * 创建覆盖三个公开入口的 LLM 服务包装。\n *\n * 手写请求在 stream 入口浅复制补齐后再进 waterfall,保证每个监听器只处理\n * 一次;loop 构建的请求由宿主打 markAgentLoopRequest 进程标识并深冻结,\n * 经 isAgentLoopRequest 判定后按原引用透传——浅复制会丢失该进程标识。\n *\n * @param ctx - 当前插件上下文。\n * @param llm - LLM 服务实例。\n * @returns 可复用的包装状态。\n */\nfunction createRuntimePatchState(ctx: Context, llm: LlmRuntime): RuntimePatchState {\n const originalStream = llm.stream\n const originalPrepareCall = llm.prepareCall\n const originalResolveCallConfig = llm.resolveCallConfig\n let state!: RuntimePatchState\n\n const stream: LlmRuntime['stream'] = (options) => {\n const patched = isAgentLoopRequest(options) ? options : applyCurrentDefault(state, options)\n return originalStream.call(llm, patched)\n }\n const prepareCall: LlmRuntime['prepareCall'] = async (config, signal) => {\n return originalPrepareCall.call(llm, applyCurrentDefault(state, config), signal)\n }\n const resolveCallConfig: LlmRuntime['resolveCallConfig'] = async (config, signal) => {\n return originalResolveCallConfig.call(llm, applyCurrentDefault(state, config), signal)\n }\n\n state = {\n ctx,\n defaults: new Map(),\n originalStream,\n originalPrepareCall,\n originalResolveCallConfig,\n stream,\n prepareCall,\n resolveCallConfig,\n }\n Object.defineProperty(stream, runtimePatchStateKey, { value: state })\n return state\n}\n\n/**\n * 安装一层可卸载的 LLM 服务包装。\n *\n * 每个插件 fiber 只持有自己的配置层。这样新 fiber 先装配、旧 fiber 后卸载时,\n * 不会把服务方法恢复为已经失效的旧包装。\n *\n * @param ctx - 当前插件上下文。\n * @param llm - LLM 服务实例。\n * @param defaults - 默认推理等级映射。\n */\nfunction installRuntimePatches(\n ctx: Context,\n llm: LlmRuntime,\n defaults: ReasoningDefaults,\n): RuntimePatchState {\n const state = existingRuntimePatchState(llm) ?? createRuntimePatchState(ctx, llm)\n // 复用跨热重载共享的包装层时刷新 ctx:设置服务本身是全局单例,但\n // ctx.logger 等 fiber 级能力应跟随最新装配层,保证告警走当前 fiber 的日志。\n state.ctx = ctx\n if (llm.stream !== state.stream) llm.stream = state.stream\n if (llm.prepareCall !== state.prepareCall) llm.prepareCall = state.prepareCall\n if (llm.resolveCallConfig !== state.resolveCallConfig) llm.resolveCallConfig = state.resolveCallConfig\n\n const token = Symbol(name)\n state.defaults.set(token, defaults)\n ctx.effect(() => () => {\n state.defaults.delete(token)\n if (state.defaults.size !== 0) return\n if (llm.stream === state.stream) llm.stream = state.originalStream\n if (llm.prepareCall === state.prepareCall) llm.prepareCall = state.originalPrepareCall\n if (llm.resolveCallConfig === state.resolveCallConfig) llm.resolveCallConfig = state.originalResolveCallConfig\n }, name + ': restore LLM method wrappers')\n return state\n}\n\n/**\n * 安装默认推理等级注入逻辑。\n *\n * @param ctx - 当前插件上下文。\n * @param config - 插件配置。\n */\nexport function apply(ctx: Context, config: Config = {}): void {\n // 默认参数仅为编程直调便利;cordis 配置路径总先经 Config 校验并把可选集合补全。\n const defaults = normalizeConfig(config)\n\n // 结构化条目若因缺 id / 缺等级被归一化忽略,在此一次性上报,\n // 避免\"配了却不生效\"的静默降级无从排查。\n for (const issue of collectConfigIssues(config)) {\n ctx.logger?.warn?.('[' + name + '] ' + issue)\n }\n\n const settings = settingsService(ctx)\n\n // 注册设置页可编辑命名空间;失败不阻断主流程(patch 层配置仍然生效)。\n if (settings) registerUiDefaultsNamespace(ctx, settings)\n\n if (Object.keys(defaults).length === 0 && !settings) {\n ctx.logger?.info?.('[' + name + '] 未配置推理等级默认值且无设置服务,跳过注入')\n return\n }\n\n const llm = ctx.llm\n\n // 先建立共享配置层;agent/request 和三个公开 LLM 入口都从这层读取最新 defaults。\n const state = installRuntimePatches(ctx, llm, defaults)\n\n // agent-loop 在这里仍允许替换配置;此阶段操作的是调用配置种子,loop 随后\n // 才据此构建并深冻结真正的请求对象,loop 识别由 stream 入口的\n // isAgentLoopRequest 完成(见 createRuntimePatchState)。\n registerAgentRequestListener(ctx, async function (_payload, next) {\n return applyCurrentDefault(state, await next())\n })\n\n // 激活日志保留生效路由清单,排障时可直接对照请求的 provider/model。\n ctx.logger?.info?.('[' + name + '] 已激活:routes=' + Object.keys(defaults).join(', '))\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * dsh-model-reasoning-defaults\n *\n * 为每个模型配置默认推理等级。请求已显式指定 reasoningEffort 时保持原值;\n * 其余按 provider/model 路由查找默认值并转换为 DSH 的品牌类型。\n *\n * 路由表存放在插件自身的配置项中(profile patch 里 id 为\n * model-reasoning-defaults 的 `defaults` 字段),DSH 设置页经 settings Remote\n * 写入。该字段声明为 volatile:宿主原地更新配置引用而不重载插件,因此每次\n * 请求都读取当下快照,设置页保存后立即对新请求生效。\n *\n * agent-loop 请求在 agent/request waterfall 中注入(此后到达 llm/stream 时\n * 已深冻结);手写调用在 llm.stream 入口复制后再进入 waterfall,调用配置\n * 方法走同一共享包装层。\n *\n * @module dsh-model-reasoning-defaults\n */\nimport type { Context, EventOptions } from '@deepseek-ai/cordis'\nimport type { Volatile } from '@deepseek-ai/cosmokit'\nimport { isAgentLoopRequest, ReasoningEffortId } from '@deepseek-ai/dsh-llm'\nimport type {\n LlmCallConfig,\n LlmRuntime,\n} from '@deepseek-ai/dsh-llm'\n// Type-only:拉入 ctx.settings 的声明增强。设置在运行时由宿主装载,本插件不做\n// 运行时导入(package.json 里的 peer 声明的是所需的最低宿主版本)。\nimport type {} from '@deepseek-ai/dsh-settings'\nimport z from '@deepseek-ai/schemastery'\n\n/** 插件名(同时作为 Cordis 插件 id)。 */\nexport const name = 'dsh-model-reasoning-defaults'\n\n/** 声明依赖的服务:LLM 服务就绪后装配;声明设置页策略需要设置服务。 */\nexport const inject = ['llm', 'settings'] as const\n\n/** 单个模型的推理等级配置。 */\nexport interface ModelConfig {\n /** 模型 ID(数组形式必填;字典形式以键名为准,可省略)。 */\n id?: string\n /** 默认推理等级(如 off | minimal | low | medium | high | xhigh | max)。 */\n reasoningEffort?: string\n}\n\n/** 单个模型配置输入:既可以是等级字符串简写,也可以是配置对象。 */\nexport type ModelConfigInput = string | ModelConfig\n\n/** 单个 Provider 的推理等级配置。 */\nexport interface ProviderConfig {\n /** 该 Provider 下所有模型的默认推理等级。 */\n reasoningEffort?: string\n /** 该 Provider 下各模型的推理等级配置(字典或对象列表)。 */\n models?: Record<string, ModelConfigInput> | ModelConfigInput[]\n}\n\n/** Provider 配置输入:既可以是等级字符串简写(作用于该 Provider 所有模型),也可以是配置对象。 */\nexport type ProviderConfigInput = string | ProviderConfig\n\n/**\n * 用户书写的插件配置:支持按 Provider 与模型嵌入式层级配置,也可使用扁平路由\n * 字典 defaults。两种形式是同等的一等配置入口,归一化到同一张路由表后统一参与\n * 六级匹配。\n *\n * 合并后的匹配优先级从高到低为:\n * - \"provider:model\":精确匹配(来自 providers[p].models[m] 或 defaults[\"provider:model\"])\n * - \"provider:*\":该 provider 下所有模型(来自 providers[p].reasoningEffort 或 defaults[\"provider:*\"])\n * - \"provider/*\":斜杠写法(来自 defaults[\"provider/*\"])\n * - \"provider\":裸 provider 写法(来自 defaults[\"provider\"])\n * - \"*:model\":跨 provider 的同名模型(来自 top-level models[m] 或 defaults[\"*:model\"])\n * - \"*\":全局匹配(来自 top-level reasoningEffort 或 defaults[\"*\"])\n */\nexport interface Config {\n /**\n * 扁平路由字典:键为上表六级路由键,值为推理等级。该字段是设置页的编辑对象,\n * 与结构化配置产生同键时覆盖结构化项。\n */\n defaults?: Record<string, string>\n /** 按 Provider 组织的嵌入式配置。 */\n providers?: Record<string, ProviderConfigInput>\n /** 跨 Provider 适用的模型默认配置(等价于 \"*:model\")。 */\n models?: Record<string, ModelConfigInput> | ModelConfigInput[]\n /** 全局默认推理等级(等价于 \"*\")。 */\n reasoningEffort?: string\n}\n\nconst nonBlankPattern = /^\\S+$/\n\n// 已知推理等级集合:llm-pi-ai 的 ModelThinkingLevel(off/minimal/low/medium/high/\n// xhigh/max)与 llm-deepseek(off/low/high/max,为其子集)的并集。仅用于告警提示\n// 而不阻断注入——最终合法性由适配器逐字匹配裁决,本地白名单收窄反而会在上游新增\n// 等级时挡住合法配置。\nconst KNOWN_REASONING_EFFORTS: ReadonlySet<string> = new Set([\n 'off',\n 'minimal',\n 'low',\n 'medium',\n 'high',\n 'xhigh',\n 'max',\n])\n\nconst modelConfigSchema = z.object({\n id: z.string().pattern(nonBlankPattern),\n reasoningEffort: z.string().pattern(nonBlankPattern),\n})\n\nconst modelEntrySchema = z.union([\n z.string().pattern(nonBlankPattern),\n modelConfigSchema,\n])\n\nconst modelsFieldSchema = z.union([\n z.dict(modelEntrySchema, z.string().pattern(nonBlankPattern)),\n z.array(modelEntrySchema),\n])\n\nconst providerConfigSchema = z.object({\n reasoningEffort: z.string().pattern(nonBlankPattern),\n models: modelsFieldSchema,\n})\n\nconst providerEntrySchema = z.union([\n z.string().pattern(nonBlankPattern),\n providerConfigSchema,\n])\n\n/**\n * Cordis 解析后的配置形状:`defaults` 已由 schemastery 换成 volatile 引用,\n * 其余字段与书写形状一致。\n *\n * 该接口显式写出而非由 `Schemastery.TypeT` 推导,是为了让 `Config` 的注解保持\n * 可命名(推导会展开成内联结构类型,声明产物随之膨胀且绑死 schemastery 内部\n * 泛型);注解本身由编译器与真实 schema 交叉校验,两者不一致会直接报错。\n */\nexport interface ResolvedConfig {\n /** 设置页编辑的扁平路由表引用。 */\n defaults: Volatile<Record<string, string>>\n /** 按 Provider 组织的嵌入式配置。 */\n providers?: Record<string, ProviderConfigInput>\n /** 跨 Provider 适用的模型默认配置。 */\n models?: Record<string, ModelConfigInput> | ModelConfigInput[]\n /** 全局默认推理等级。 */\n reasoningEffort?: string\n}\n\n/**\n * Cordis 配置模式。\n *\n * `defaults` 声明为 volatile:设置页经宿主 configEditor 改写 profile patch 后,\n * 宿主原地更新该引用(见 cordis-plugin-loader 的 volatile 提交路径),插件无需\n * 重载即可读到新值。其余结构化字段保持普通字段——它们是 patch 层的书写形式,\n * 变更后正常走插件重载。\n */\nexport const Config: z<Config, ResolvedConfig> = z.object({\n // 路由键与等级值都要求非空白:空白键永远不会被 candidateKeys 命中,空白值\n // 会被适配器逐字匹配拒绝,都在配置阶段直接报错暴露最省排查成本。\n // .default({}) 与 schemastery 对 dict 的内建空对象默认重复,保留它是为了让\n // 编程直调路径(绕过 cordis resolveConfig)也能拿到确定的形状。\n defaults: z.dict(\n z.string().pattern(nonBlankPattern),\n z.string().pattern(nonBlankPattern),\n ).default({}).volatile(),\n providers: z.dict(\n providerEntrySchema,\n z.string().pattern(nonBlankPattern),\n ).default({}),\n models: modelsFieldSchema,\n reasoningEffort: z.string().pattern(nonBlankPattern),\n})\n\n/**\n * 从字符串简写或配置对象中提取非空推理等级。\n *\n * 只认单一规范字段 reasoningEffort,不做多字段兜底链:同义多源读取会在字段\n * 冲突时按书写顺序静默裁决(例如 reasoningEffort 与 effort 同时配置时无声地\n * 二选一),掩盖配置错误;确需别名应由用户层显式映射后再传入。\n *\n * @param val - 等级字符串,或 ModelConfig/ProviderConfig 形状的对象。\n * @returns trim 后非空的等级字符串;无法提取时返回 undefined。\n */\nfunction extractEffort(val: unknown): string | undefined {\n const candidate = typeof val === 'string'\n ? val\n : (typeof val === 'object' && val !== null)\n ? (val as { reasoningEffort?: unknown }).reasoningEffort\n : undefined\n if (typeof candidate !== 'string') return undefined\n const trimmed = candidate.trim()\n return trimmed.length > 0 ? trimmed : undefined\n}\n\n/**\n * 归一化扁平路由字典。\n *\n * 键值均 trim 后判断:空白键与空白值一样永不命中任何请求路由(cordis 路径由\n * schema 拒绝,此处覆盖绕开 schema 的直调路径)。\n *\n * @param defaults - 扁平路由字典;未配置时为 undefined。\n * @returns 归一化后的键值映射。\n */\nfunction normalizeFlatDefaults(defaults: Record<string, string> | undefined): Record<string, string> {\n // 空原型累加器:路由键是任意非空白字符串,普通对象上给 __proto__ 赋值不会生成\n // 自有属性。schema 解析本身就会丢弃 __proto__ 键,这里保证的是本函数对任意\n // 普通对象输入(含绕过 schema 的直调)都成立。\n const result: Record<string, string> = Object.create(null)\n if (!defaults || typeof defaults !== 'object') return result\n for (const [rawKey, value] of Object.entries(defaults)) {\n const key = rawKey.trim()\n const trimmedValue = typeof value === 'string' ? value.trim() : ''\n if (key.length === 0 || trimmedValue.length === 0) continue\n result[key] = trimmedValue\n }\n return result\n}\n\n/**\n * 将结构化 Config 归一化为统一的扁平路由字典。\n *\n * @param config - 插件配置对象(defaults 为普通字典形式)。\n * @returns 归一化后的键值映射;键与值均已去除首尾空白。\n */\nexport function normalizeConfig(config: Config): Record<string, string> {\n // 与 normalizeFlatDefaults 一致用空原型:合并 defaults 时若键为 __proto__,\n // 普通对象上的赋值不会生成自有属性,路由会被静默丢掉。\n const result: Record<string, string> = Object.create(null)\n\n // 1. 全局默认 (对应 \"*\")\n const globalEffort = extractEffort(config.reasoningEffort)\n if (globalEffort) {\n result['*'] = globalEffort\n }\n\n // 2. 顶层跨 Provider 模型默认 (对应 \"*:model\")\n if (config.models) {\n if (Array.isArray(config.models)) {\n for (const item of config.models) {\n // 数组形式必须携带非空白 id 才能生成路由键;缺失项由 apply() 的\n // 激活期诊断告警上报,这里只负责安静地跳过无效形状。\n const id = typeof item === 'object' && item !== null && typeof item.id === 'string' ? item.id.trim() : ''\n if (id.length === 0) continue\n const effort = extractEffort(item)\n if (effort) result['*:' + id] = effort\n }\n } else if (typeof config.models === 'object') {\n for (const [rawModelId, modelVal] of Object.entries(config.models)) {\n const modelId = rawModelId.trim()\n if (modelId.length === 0) continue\n const effort = extractEffort(modelVal)\n if (effort) result['*:' + modelId] = effort\n }\n }\n }\n\n // 3. Provider 层级配置\n if (config.providers && typeof config.providers === 'object') {\n for (const [rawProviderId, providerVal] of Object.entries(config.providers)) {\n const providerId = rawProviderId.trim()\n if (providerId.length === 0) continue\n\n // 3.1 Provider 级默认 (对应 \"provider:*\")\n const providerEffort = extractEffort(providerVal)\n if (providerEffort) {\n result[providerId + ':*'] = providerEffort\n }\n\n // 3.2 Provider 内的具体模型 (对应 \"provider:model\")\n if (typeof providerVal === 'object' && providerVal !== null && providerVal.models) {\n const models = providerVal.models\n if (Array.isArray(models)) {\n for (const item of models) {\n const id = typeof item === 'object' && item !== null && typeof item.id === 'string' ? item.id.trim() : ''\n if (id.length === 0) continue\n const effort = extractEffort(item)\n if (effort) result[providerId + ':' + id] = effort\n }\n } else if (typeof models === 'object') {\n for (const [rawModelId, modelVal] of Object.entries(models)) {\n const modelId = rawModelId.trim()\n if (modelId.length === 0) continue\n const effort = extractEffort(modelVal)\n if (effort) result[providerId + ':' + modelId] = effort\n }\n }\n }\n }\n }\n\n // 4. 扁平 defaults 字典:与结构化配置同等的一等入口,写在最后使其在与结构化\n // 配置同键冲突时胜出(显式路由键的表达意图更具体)。\n Object.assign(result, normalizeFlatDefaults(config.defaults))\n\n return result\n}\n\ntype ReasoningConfig = Pick<LlmCallConfig, 'provider' | 'model' | 'reasoningEffort'>\n\n/**\n * 未知推理等级的告警文案。\n *\n * 激活期体检与运行期读取共用同一文案:同一处配置在两条路径上都会被看到\n * (激活时既做体检、又会读一次路由表用于日志),文案一致才能靠 warnOnce\n * 收敛成一条日志,而不是打出两条内容几乎相同、仅差等级清单的告警。\n *\n * @param route - 命中的路由键。\n * @param level - 配置的推理等级。\n * @returns 供 logger 输出的告警文案。\n */\nfunction unknownLevelIssue(route: string, level: string): string {\n return '路由 ' + route + ' 的推理等级 \"' + level + '\" 不在已知集合 ('\n + [...KNOWN_REASONING_EFFORTS].join('/') + ') 内,请确认目标模型支持'\n}\n\n/**\n * 静态体检插件配置,返回人类可读的问题清单(纯函数,不修改任何数据)。\n *\n * schemastery 的对象属性全部可选且对未知键透传,\"拼错字段\"\"模型项缺 id\"\n * 这类错误能通过校验却在 normalizeConfig 中被静默忽略;此清单在插件激活时\n * 一次性告警,把这类静默降级变成可见信息。等级值不在已知集合也在此提示,\n * 但仍会注入——最终是否可用交给适配器逐字匹配裁决。\n *\n * @param config - 用户原始配置(未经归一化)。\n * @returns 问题描述列表;无问题时为空数组。\n */\nfunction collectConfigIssues(config: Config): string[] {\n const issues: string[] = []\n\n const checkLevel = (route: string, level: string | undefined): void => {\n if (level !== undefined && !KNOWN_REASONING_EFFORTS.has(level)) {\n issues.push(unknownLevelIssue(route, level))\n }\n }\n\n /**\n * 检查单个模型条目:字符串简写直接校验等级;\n * 对象形式要求携带有效等级,数组元素还要求有效 id。\n */\n const checkModelEntry = (route: string, entry: ModelConfigInput, requireId: boolean): void => {\n if (typeof entry === 'string') {\n // 数组位置没有键名可用作 id,字符串简写永远生成不了路由键;字典位置的\n // 字符串值以键名为 id(requireId=false),不受此限制。\n if (requireId) {\n issues.push('数组形式模型条目缺少有效 id(字符串简写无键名可用),已被忽略:' + JSON.stringify(entry))\n return\n }\n checkLevel(route, extractEffort(entry))\n return\n }\n const id = typeof entry.id === 'string' ? entry.id.trim() : ''\n if (requireId && id.length === 0) {\n issues.push('模型条目缺少有效 id,已被忽略:' + JSON.stringify(entry))\n return\n }\n const effort = extractEffort(entry)\n if (effort === undefined) {\n issues.push('模型条目未包含 reasoningEffort,已被忽略:' + JSON.stringify(entry))\n return\n }\n checkLevel(route, effort)\n }\n\n // 全局等级\n checkLevel('*', extractEffort(config.reasoningEffort))\n\n // 顶层跨 Provider 模型\n if (config.models) {\n if (Array.isArray(config.models)) {\n config.models.forEach((entry, index) => {\n checkModelEntry('*:<models[' + index + ']>', entry, true)\n })\n } else if (typeof config.models === 'object') {\n for (const [modelId, entry] of Object.entries(config.models)) {\n checkModelEntry('*:' + modelId, entry, false)\n }\n }\n }\n\n // Provider 层级\n if (config.providers && typeof config.providers === 'object') {\n for (const [providerId, providerVal] of Object.entries(config.providers)) {\n if (typeof providerVal === 'string') {\n checkLevel(providerId + ':*', extractEffort(providerVal))\n continue\n }\n const hasModels = providerVal.models !== undefined\n const providerEffort = extractEffort(providerVal)\n if (!hasModels && providerEffort === undefined) {\n issues.push('provider ' + providerId + ' 未包含 reasoningEffort 或 models,整条配置已被忽略')\n continue\n }\n checkLevel(providerId + ':*', providerEffort)\n if (hasModels) {\n const models = providerVal.models!\n if (Array.isArray(models)) {\n models.forEach((entry, index) => {\n checkModelEntry(providerId + ':<models[' + index + ']>', entry, true)\n })\n } else if (typeof models === 'object') {\n for (const [modelId, entry] of Object.entries(models)) {\n checkModelEntry(providerId + ':' + modelId, entry, false)\n }\n }\n }\n }\n }\n\n // 扁平 defaults 字典:schema 在解析阶段就拒绝空白键值,所以这里只对绕过 schema\n // 的直调形态生效(手工构造 ResolvedConfig 直接调用 apply,例如测试或其它插件)。\n // 空键检查与 normalizeFlatDefaults 的跳过逻辑一致,把静默降级变成可见告警。\n if (config.defaults && typeof config.defaults === 'object') {\n for (const [rawKey, value] of Object.entries(config.defaults)) {\n const key = rawKey.trim()\n if (key.length === 0) {\n issues.push('扁平路由键为空白,已被忽略:' + JSON.stringify(rawKey))\n continue\n }\n checkLevel(key, extractEffort(value))\n }\n }\n\n return issues\n}\n\n// agent/request 的 loop 侧 emit 实参是 { turn, step, signal };core/agent 的派发器\n// 会把路由主体 agent(Scoped<Agent>)融合进 payload 并同时作为监听器 this,因此\n// 实收 payload 含 agent 字段。本监听器不读取任何 payload 字段,此处仅按本插件\n// 用到的形状窄化 ctx.on 的签名。\ntype AgentRequestPayload = {\n turn: number\n step: number\n signal: AbortSignal\n}\n\ntype AgentRequestListener = (\n this: object,\n payload: AgentRequestPayload,\n next: () => Promise<LlmCallConfig>,\n) => Promise<LlmCallConfig>\n\ntype AgentRequestRegistrar = (\n name: 'agent/request',\n listener: AgentRequestListener,\n options?: boolean | EventOptions,\n) => () => boolean\n\n/**\n * 注册全局 agent/request waterfall。\n *\n * cordis 的 ctx.on 内部会把监听器注册为当前 fiber 上的 effect(见 events\n * 服务的 register()),无论 global 标志如何都会在 fiber 卸载时自动清理;\n * global 只影响事件派发时的上下文过滤。因此无需再包一层 ctx.effect。\n *\n * 该事件的运行时接收者是 Scoped<Agent>,Cordis 根 Context 的事件泛型表不会\n * 暴露它,因此在最小边界内窄化签名(仅约束本插件用到的事件名与参数)。\n *\n * @param ctx - 当前插件上下文。\n * @param listener - agent/request waterfall 监听器。\n */\nfunction registerAgentRequestListener(ctx: Context, listener: AgentRequestListener): void {\n // 窄化仅覆盖本插件实际使用的事件名与参数;内部转调仍通过 ctx.on 的真实实现。\n const register = ctx.on.bind(ctx) as AgentRequestRegistrar\n register('agent/request', listener, { global: true })\n}\n\n/**\n * 生成一个路由的候选配置键。\n *\n * 兼容键保留在明确的优先级表中,避免不同调用入口各自实现一套匹配规则。\n *\n * @param provider - 请求使用的 provider。\n * @param model - 请求使用的 model。\n * @returns 按匹配优先级排列的候选键。\n */\nfunction candidateKeys(provider: string, model: string): readonly string[] {\n return [\n provider + ':' + model,\n provider + ':*',\n provider + '/*',\n provider,\n '*:' + model,\n '*',\n ]\n}\n\n/**\n * 查找一个路由对应的默认推理等级。\n *\n * @param defaults - 归一化后的扁平路由映射。\n * @param provider - 请求使用的 provider。\n * @param model - 请求使用的 model。\n * @returns 找到的非空推理等级,未找到时返回 undefined。\n */\nfunction lookupEffort(\n defaults: Readonly<Record<string, string>>,\n provider: string,\n model: string,\n): string | undefined {\n for (const key of candidateKeys(provider, model)) {\n const effort = defaults[key]\n if (typeof effort === 'string' && effort.length > 0) return effort\n }\n return undefined\n}\n\n/**\n * 在不修改原对象的前提下应用默认推理等级。\n *\n * 该函数同时用于 GenerateOptions 和 LlmCallConfig,因此调用方可以保留\n * 原请求对象中的 messages、signal 等其它字段,并安全处理深冻结输入。\n *\n * 第二参数只接受归一化后的扁平路由表;结构化 Config 必须先经 normalizeConfig。\n * 曾尝试用对象形状嗅探让本函数同时接纳两种入参,但路由表允许任意非空白键,\n * 含 \"models\"/\"providers\" 等键的路由表会被误判成结构化配置(整表归一化为空、\n * 注入全部失效),反之仅含顶层 reasoningEffort 的最小结构化配置又会漏判——\n * 两类误判都是静默失效,因此彻底拆掉形状嗅探。\n *\n * @param config - 待补齐的 LLM 请求或调用配置。\n * @param defaults - normalizeConfig 产出的扁平路由表。\n * @returns 原配置或带有 reasoningEffort 的浅复制对象。\n */\nexport function applyDefaultReasoningEffort<T extends ReasoningConfig>(\n config: T,\n defaults: Readonly<Record<string, string>>,\n): T {\n if (config.reasoningEffort !== undefined || !config.provider || !config.model) return config\n const effort = lookupEffort(defaults, config.provider, config.model)\n if (effort === undefined) return config\n return { ...config, reasoningEffort: ReasoningEffortId(effort) }\n}\n\n/**\n * 一层插件 fiber 的路由表来源。\n *\n * 结构化字段在激活期归一化一次后不再变化(改动它们会触发插件重载);扁平\n * `defaults` 是设置页的编辑对象,其 volatile 引用被宿主原地更新,因此每次\n * 请求读取当下快照。\n */\ntype RouteTableSource = {\n /** 读取与告警所用的当前 fiber 上下文。 */\n ctx: Context\n /** providers/models/reasoningEffort 归一化结果(激活期一次)。 */\n structured: Record<string, string>\n /** 设置页可编辑的扁平路由表引用。 */\n defaults: Volatile<Record<string, string>>\n}\n\n// 告警去重:路由表读取位于每次请求的热路径上,同一问题只告警一次,避免日志\n// 刷屏;进程生命周期内出现一次提示即足以定位配置错误。激活期体检与运行期读取\n// 共用这里,同一处配置不会既被体检报一次、又被读取报一次。\nconst warnedMessages = new Set<string>()\n\n/** 发出一次性(进程内按文案去重)的插件告警,自动带上插件名前缀。 */\nfunction warnOnce(ctx: Context, message: string): void {\n if (warnedMessages.has(message)) return\n warnedMessages.add(message)\n ctx.logger?.warn?.('[' + name + '] ' + message)\n}\n\n/**\n * 读取一层 fiber 当前生效的路由表。\n *\n * 结构化配置为底、volatile defaults 快照覆盖。手工编辑 profile patch 时\n * defaults 走的也是 volatile 原地更新(不会重载插件、不再有激活期体检),\n * 因此未知等级在这里一次性告警,避免静默降级。\n *\n * @param source - 一层 fiber 的路由表来源。\n * @returns 合并后的扁平路由映射;两层均为空时为空对象。\n */\nfunction readRouteTable(source: RouteTableSource): Record<string, string> {\n const live = normalizeFlatDefaults(source.defaults.get())\n for (const [route, level] of Object.entries(live)) {\n if (!KNOWN_REASONING_EFFORTS.has(level)) {\n warnOnce(source.ctx, unknownLevelIssue(route, level))\n }\n }\n return { ...source.structured, ...live }\n}\n\ntype RuntimePatchState = {\n /** 各活跃 fiber 的路由表来源;热重载期间新 fiber 覆盖旧 fiber。 */\n sources: Map<symbol, RouteTableSource>\n originalStream: LlmRuntime['stream']\n originalPrepareCall: LlmRuntime['prepareCall']\n originalResolveCallConfig: LlmRuntime['resolveCallConfig']\n stream: LlmRuntime['stream']\n prepareCall: LlmRuntime['prepareCall']\n resolveCallConfig: LlmRuntime['resolveCallConfig']\n}\n\n// Symbol.for 让热重载后的模块副本复用同一层状态,而不是再包一层旧包装。\nconst runtimePatchStateKey = Symbol.for('dsh-model-reasoning-defaults.runtime-patch-state')\n\n/**\n * 取最后激活的路由表来源。热重载期间新 fiber 覆盖旧 fiber,旧 fiber 卸载后\n * 新配置仍保持生效;最后一个 fiber 卸载时才还原原始服务方法。\n *\n * @param state - 同一 LLM 服务上的包装状态。\n * @returns 当前生效的来源;没有活跃层时返回 undefined。\n */\nfunction currentSource(state: RuntimePatchState): RouteTableSource | undefined {\n let current: RouteTableSource | undefined\n for (const source of state.sources.values()) current = source\n return current\n}\n\n/**\n * 将当前活跃层的路由表应用到配置。保留原对象是卸载后仍被外部持有的旧包装的\n * 必要语义,也避免把一个空对象伪装成真实配置来源。\n *\n * @param state - 同一 LLM 服务上的包装状态。\n * @param config - 待处理的调用配置。\n * @returns 原配置或带默认推理等级的浅复制对象。\n */\nfunction applyCurrentDefault<T extends ReasoningConfig>(\n state: RuntimePatchState,\n config: T,\n): T {\n const source = currentSource(state)\n if (source === undefined) return config\n const routeTable = readRouteTable(source)\n return Object.keys(routeTable).length === 0 ? config : applyDefaultReasoningEffort(config, routeTable)\n}\n\n/**\n * 从当前 stream 包装上恢复跨热重载共享的状态。\n *\n * @param llm - LLM 服务实例。\n * @returns 现有包装状态;服务尚未被本插件包装时返回 undefined。\n */\nfunction existingRuntimePatchState(llm: LlmRuntime): RuntimePatchState | undefined {\n return (llm.stream as unknown as Record<PropertyKey, unknown>)[runtimePatchStateKey] as RuntimePatchState | undefined\n}\n\n/**\n * 创建覆盖三个公开入口的 LLM 服务包装。\n *\n * 手写请求在 stream 入口浅复制补齐后再进 waterfall,保证每个监听器只处理\n * 一次;loop 构建的请求由宿主打 markAgentLoopRequest 进程标识并深冻结,\n * 经 isAgentLoopRequest 判定后按原引用透传——浅复制会丢失该进程标识。\n *\n * @param llm - LLM 服务实例。\n * @returns 可复用的包装状态。\n */\nfunction createRuntimePatchState(llm: LlmRuntime): RuntimePatchState {\n const originalStream = llm.stream\n const originalPrepareCall = llm.prepareCall\n const originalResolveCallConfig = llm.resolveCallConfig\n let state!: RuntimePatchState\n\n const stream: LlmRuntime['stream'] = (options) => {\n const patched = isAgentLoopRequest(options) ? options : applyCurrentDefault(state, options)\n return originalStream.call(llm, patched)\n }\n const prepareCall: LlmRuntime['prepareCall'] = async (config, signal) => {\n return originalPrepareCall.call(llm, applyCurrentDefault(state, config), signal)\n }\n const resolveCallConfig: LlmRuntime['resolveCallConfig'] = async (config, signal) => {\n return originalResolveCallConfig.call(llm, applyCurrentDefault(state, config), signal)\n }\n\n state = {\n sources: new Map(),\n originalStream,\n originalPrepareCall,\n originalResolveCallConfig,\n stream,\n prepareCall,\n resolveCallConfig,\n }\n Object.defineProperty(stream, runtimePatchStateKey, { value: state })\n return state\n}\n\n/**\n * 安装一层可卸载的 LLM 服务包装。\n *\n * 每个插件 fiber 只持有自己的路由表来源。这样新 fiber 先装配、旧 fiber 后卸载\n * 时,不会把服务方法恢复为已经失效的旧包装。\n *\n * 路由表为空时同样安装:设置页可以在插件运行期间写入新路由,跳过安装会让这些\n * 改动直到宿主重启才生效。\n *\n * @param ctx - 当前插件上下文。\n * @param llm - LLM 服务实例。\n * @param source - 本 fiber 的路由表来源。\n * @returns 共享的包装状态。\n */\nfunction installRuntimePatches(\n ctx: Context,\n llm: LlmRuntime,\n source: RouteTableSource,\n): RuntimePatchState {\n const state = existingRuntimePatchState(llm) ?? createRuntimePatchState(llm)\n if (llm.stream !== state.stream) llm.stream = state.stream\n if (llm.prepareCall !== state.prepareCall) llm.prepareCall = state.prepareCall\n if (llm.resolveCallConfig !== state.resolveCallConfig) llm.resolveCallConfig = state.resolveCallConfig\n\n const token = Symbol(name)\n state.sources.set(token, source)\n ctx.effect(() => () => {\n state.sources.delete(token)\n if (state.sources.size !== 0) return\n if (llm.stream === state.stream) llm.stream = state.originalStream\n if (llm.prepareCall === state.prepareCall) llm.prepareCall = state.originalPrepareCall\n if (llm.resolveCallConfig === state.resolveCallConfig) llm.resolveCallConfig = state.originalResolveCallConfig\n }, name + ': restore LLM method wrappers')\n return state\n}\n\n/**\n * 安装默认推理等级注入逻辑。\n *\n * @param ctx - 当前插件上下文。\n * @param config - Cordis 解析后的插件配置。\n */\nexport function apply(ctx: Context, config: ResolvedConfig): void {\n // 结构化字段只在激活期归一化一次;defaults 是 volatile 引用,留给每次请求读取。\n // 两者必须分开:把激活期的 defaults 快照并进 structured,会让设置页删掉的路由\n // 继续从旧快照命中——运行期的删除只反映在 volatile 快照上。\n const structured = normalizeConfig({\n providers: config.providers,\n models: config.models,\n reasoningEffort: config.reasoningEffort,\n })\n\n // 结构化条目若因缺 id / 缺等级被归一化忽略,在此一次性上报,\n // 避免\"配了却不生效\"的静默降级无从排查。与运行期读取共用 warnOnce:\n // 激活期同时会读一次路由表(见下方日志),同一问题只应出现一条告警。\n for (const issue of collectConfigIssues({\n defaults: config.defaults.get(),\n providers: config.providers,\n models: config.models,\n reasoningEffort: config.reasoningEffort,\n })) {\n warnOnce(ctx, issue)\n }\n\n // 本插件自带设置页 section,声明宿主无需再为该配置项生成通用表单。\n ctx.effect(() => ctx.settings.configure({ auto: false }, ctx.fiber))\n\n const source: RouteTableSource = { ctx, structured, defaults: config.defaults }\n\n // 先建立共享配置层;agent/request 和三个公开 LLM 入口都从这层读取最新路由表。\n const state = installRuntimePatches(ctx, ctx.llm, source)\n\n // agent-loop 在这里仍允许替换配置;此阶段操作的是调用配置种子,loop 随后\n // 才据此构建并深冻结真正的请求对象,loop 识别由 stream 入口的\n // isAgentLoopRequest 完成(见 createRuntimePatchState)。\n registerAgentRequestListener(ctx, async function (_payload, next) {\n return applyCurrentDefault(state, await next())\n })\n\n // 激活日志保留生效路由清单,排障时可直接对照请求的 provider/model。\n ctx.logger?.info?.('[' + name + '] 已激活:routes=' + Object.keys(readRouteTable(source)).join(', '))\n}\n"],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SettingsPathOp } from './route-table.js';
|
|
1
2
|
/** 设置页 section 槽位类型由 ui-settings 壳声明;本插件不依赖该包,本地补齐面。 */
|
|
2
3
|
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
3
4
|
interface SlotMap {
|
|
@@ -26,7 +27,7 @@ export declare const inject: readonly ["slots", "remote", "remote.settings"];
|
|
|
26
27
|
/** settings Remote 的读写方法面(宿主 API Gateway 经 Typert Remote 生成)。 */
|
|
27
28
|
interface RemoteSettings {
|
|
28
29
|
describe(): Promise<RemoteResult<SettingsDescribeValue>>;
|
|
29
|
-
|
|
30
|
+
mutate(ns: string, ops: readonly SettingsPathOp[], expectedRevision: number | undefined): Promise<RemoteResult<SettingsNamespaceView>>;
|
|
30
31
|
}
|
|
31
32
|
/** Typert Remote 统一应答形状。 */
|
|
32
33
|
type RemoteResult<T> = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAY,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAEhE,wDAAwD;AACxD,OAAO,QAAQ,kCAAkC,CAAC;IAChD,UAAU,OAAO;QACf,kBAAkB,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE;gBAAE,KAAK,EAAE,MAAM,IAAI,CAAA;aAAE,CAAA;SAAE,CAAA;KAClF;CACF;AAED,sDAAsD;AACtD,UAAU,YAAY;IACpB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,MAAM,IAAI,GAAG,MAAM,IAAI,CAAA;IAC5D,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,GAAG,MAAM,IAAI,CAAA;CAC3D;AAWD,KAAK,aAAa,GAAG;IACnB,KAAK,EAAE,YAAY,CAAA;IACnB,MAAM,EAAE;QACN,QAAQ,EAAE,cAAc,CAAA;KACzB,CAAA;CACF,CAAA;AAED,wCAAwC;AACxC,eAAO,MAAM,MAAM,iDAAkD,CAAA;AAErE,iEAAiE;AACjE,UAAU,cAAc;IACtB,QAAQ,IAAI,OAAO,CAAC,YAAY,CAAC,qBAAqB,CAAC,CAAC,CAAA;IACxD,MAAM,CACJ,EAAE,EAAE,MAAM,EACV,GAAG,EAAE,SAAS,cAAc,EAAE,EAC9B,gBAAgB,EAAE,MAAM,GAAG,SAAS,GACnC,OAAO,CAAC,YAAY,CAAC,qBAAqB,CAAC,CAAC,CAAA;CAChD;AAED,4BAA4B;AAC5B,KAAK,YAAY,CAAC,CAAC,IACf;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GACtB;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAA;AAE5E,oCAAoC;AACpC,UAAU,qBAAqB;IAC7B,gBAAgB;IAChB,QAAQ,EAAE,OAAO,CAAA;IACjB,mBAAmB;IACnB,WAAW,EAAE,OAAO,CAAA;IACpB,mBAAmB;IACnB,UAAU,EAAE,qBAAqB,EAAE,CAAA;CACpC;AAED,mBAAmB;AACnB,UAAU,qBAAqB;IAC7B,aAAa;IACb,EAAE,EAAE,MAAM,CAAA;IACV,eAAe;IACf,KAAK,EAAE,OAAO,CAAA;IACd,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAA;CACjB;AAycD;;;;;;;GAOG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAc9C"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 路由表的编辑模型(纯函数,不依赖 React 与 UI 组件)。
|
|
3
|
+
*
|
|
4
|
+
* 面板把存储中的 `defaults` 字典渲染成可编辑行,保存时再把行集合与基线做差异,
|
|
5
|
+
* 折叠成宿主 settings Remote 的路径寻址操作。这里的每个函数都只做数据变换,
|
|
6
|
+
* 便于直接覆盖"增删改 / 冲突合并 / 异常键"这些容易静默出错的边界。
|
|
7
|
+
*
|
|
8
|
+
* @module dsh-model-reasoning-defaults/client/route-table
|
|
9
|
+
*/
|
|
10
|
+
/** 一条可编辑的路由行。 */
|
|
11
|
+
export interface RouteRow {
|
|
12
|
+
/** 路由键(provider:model 等六级写法之一)。 */
|
|
13
|
+
key: string;
|
|
14
|
+
/** 该路由的推理等级。 */
|
|
15
|
+
effort: string;
|
|
16
|
+
}
|
|
17
|
+
/** 一条路径寻址的写入操作,与宿主 `settings.mutate` 的入参一致。 */
|
|
18
|
+
export type SettingsPathOp = {
|
|
19
|
+
op: 'set';
|
|
20
|
+
path: readonly string[];
|
|
21
|
+
value: string;
|
|
22
|
+
} | {
|
|
23
|
+
op: 'unset';
|
|
24
|
+
path: readonly string[];
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* 把路由字典展开成按键排序的可编辑行。
|
|
28
|
+
*
|
|
29
|
+
* @param defaults - 路由字典。
|
|
30
|
+
* @returns 稳定排序的行列表。
|
|
31
|
+
*/
|
|
32
|
+
export declare function rowsOf(defaults: Record<string, string>): RouteRow[];
|
|
33
|
+
/**
|
|
34
|
+
* 把存储中"外部新增"的路由键并入当前编辑行,用于冲突后的重试保存。
|
|
35
|
+
*
|
|
36
|
+
* 只补 `latest` 相对 `previous` 新增的键:差异语义是"行里没有即删除",补进来的
|
|
37
|
+
* 外部新增键可避免重试时顺手删掉它们;而用户自己删掉或改名的键本来就在
|
|
38
|
+
* `previous` 里,绝不能再补回来——补回来等于把删除意图覆盖成"键仍在行中",
|
|
39
|
+
* 用户会发现该路由怎么都删不掉,重命名也会退化成"新增"。
|
|
40
|
+
*
|
|
41
|
+
* @param rows - 当前编辑的行。
|
|
42
|
+
* @param previous - 发起本次保存所用的基线,即用户编辑所依据的键集。
|
|
43
|
+
* @param latest - 宿主当前生效的路由表。
|
|
44
|
+
* @returns 合并后的行列表,按键排序(空键行是待填写的残渣,排在末尾)。
|
|
45
|
+
*/
|
|
46
|
+
export declare function mergeStoredRows(rows: RouteRow[], previous: Readonly<Record<string, string>>, latest: Readonly<Record<string, string>>): RouteRow[];
|
|
47
|
+
/**
|
|
48
|
+
* 把编辑后的行集合与存储基线做差异,折叠成路径寻址的写入操作。
|
|
49
|
+
*
|
|
50
|
+
* 只写差异而不是整段覆盖:宿主按路径写入,删除路由才能落盘(省略键不表达删除),
|
|
51
|
+
* 同时不动同一配置项里的结构化字段。
|
|
52
|
+
*
|
|
53
|
+
* @param baseline - 存储中当前生效的路由表。
|
|
54
|
+
* @param rows - 当前编辑的行。
|
|
55
|
+
* @returns 写入操作列表;路由键重复时返回错误消息。
|
|
56
|
+
*/
|
|
57
|
+
export declare function buildRouteOps(baseline: Readonly<Record<string, string>>, rows: RouteRow[]): SettingsPathOp[] | {
|
|
58
|
+
error: string;
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=route-table.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-table.d.ts","sourceRoot":"","sources":["../../../src/client/route-table.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,iBAAiB;AACjB,MAAM,WAAW,QAAQ;IACvB,mCAAmC;IACnC,GAAG,EAAE,MAAM,CAAA;IACX,gBAAgB;IAChB,MAAM,EAAE,MAAM,CAAA;CACf;AAED,+CAA+C;AAC/C,MAAM,MAAM,cAAc,GACtB;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAA;AAK5C;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,QAAQ,EAAE,CAInE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,QAAQ,EAAE,EAChB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAC1C,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACvC,QAAQ,EAAE,CAYZ;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAC1C,IAAI,EAAE,QAAQ,EAAE,GACf,cAAc,EAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAqBtC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-model-reasoning-defaults",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "DSH (DeepSeek Harness) 插件:为每个 LLM 模型配置默认推理等级(reasoningEffort),并在请求进入底层调用链前按路由规则自动补齐",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh",
|
|
@@ -32,16 +32,19 @@
|
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"@deepseek-ai/cordis": ">=4.0.0-rc <5",
|
|
35
|
+
"@deepseek-ai/cosmokit": ">=1.8.5 <2",
|
|
35
36
|
"@deepseek-ai/dsh-llm": ">=0.0.1-rc <2",
|
|
36
|
-
"@deepseek-ai/
|
|
37
|
+
"@deepseek-ai/dsh-settings": ">=0.1.7-alpha.2 <2",
|
|
38
|
+
"@deepseek-ai/schemastery": "^3.18.4"
|
|
37
39
|
},
|
|
38
40
|
"devDependencies": {
|
|
39
|
-
"@deepseek-ai/cordis": "^4.0.
|
|
40
|
-
"@deepseek-ai/cosmokit": "^1.8.
|
|
41
|
-
"@deepseek-ai/dsh-client-ui-primitives": "0.1.
|
|
42
|
-
"@deepseek-ai/dsh-client-ui-slots": "0.1.
|
|
43
|
-
"@deepseek-ai/dsh-llm": "0.1.
|
|
44
|
-
"@deepseek-ai/
|
|
41
|
+
"@deepseek-ai/cordis": "^4.0.4",
|
|
42
|
+
"@deepseek-ai/cosmokit": "^1.8.5",
|
|
43
|
+
"@deepseek-ai/dsh-client-ui-primitives": "0.1.7-alpha.2",
|
|
44
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.1.7-alpha.2",
|
|
45
|
+
"@deepseek-ai/dsh-llm": "0.1.7-alpha.2",
|
|
46
|
+
"@deepseek-ai/dsh-settings": "0.1.7-alpha.2",
|
|
47
|
+
"@deepseek-ai/schemastery": "^3.18.4",
|
|
45
48
|
"@types/node": "^24.13.3",
|
|
46
49
|
"@types/react": "~18.3.1",
|
|
47
50
|
"react": "^18.2.0",
|