@crazx/dsh-llm-pi-ai
v0.1.6-alpha.2.zw.2
Published
pi-ai-backed DeepSeek adapter for the DeepSeek Harness LLM seam (design-verification twin of dsh-llm-deepseek)
Readme
description: "面向用户与维护者的 pi-ai 多提供方适配器说明:通过 pi-ai 目录与手工声明网关路由 harness LLM(大语言模型)服务。" kind: "package-reference"
@deepseek-ai/dsh-llm-pi-ai
English | 中文
概述
@deepseek-ai/dsh-llm-pi-ai 通过一份配置把模型请求路由到多个 pi-ai 提供方、OpenAI 兼容网关或自托管服务器。已安装的 pi-ai 提供方会提供端点、协议和模型目录默认值;自定义路由可以直接声明这些值,无需修改代码。profile 与凭据按请求解析,因此设置变更会在下一个请求生效,无需重启。受支持的提供方可以使用已存储的 OAuth 或交互式密钥登录,并通过跨进程锁刷新凭据。本包可以在没有路由时启动,并在用户设置添加路由后将其激活。
目录
使用本包
当组合需要通过 pi-ai 的提供方目录、或通过 pi-ai 已安装目录未描述的网关路由模型请求时挂载本插件。providers 字典就是整个配置面:每个键都是请求用 GenerateOptions.provider 选择的提供方路由名。
何时选择
当同一组合服务多个提供方、某条路由需要 pi-ai 目录默认值并修正少数字段、或必须通过自有端点与协议到达手工声明网关时,选择本适配器。当部署不需要其他提供方时,选择 dsh-llm-deepseek 直连 DeepSeek 路由。两个适配器可以同时挂载,因为它们的路由名不冲突;注册其他适配器已拥有的路由会导致插件加载失败。
配置提供方路由
每个 profile 都可以设置 retryPolicy;省略时使用 normal mode、最多重试五次。apiKeyEnv 是按请求经 harness 凭据 seam 解析的凭据引用,因此配置文件绝不包含密钥;解析为空的引用会让请求以 MISSING_CREDENTIAL 失败。省略它会让路由保持已配置但无密钥(configured-but-keyless)状态,对已安装目录路由而言即交由 pi-ai 提供方原生的环境发现。
- name: '@deepseek-ai/dsh-llm-pi-ai'
config:
providers:
openai:
apiKeyEnv: OPENAI_API_KEY
baseURL: https://proxy.example.com:8443
reasoning: high
requestImagePixelBudget: 4194304 # total pixels; 2048 by 2048 default
requestImageMaxBytes: 1048576 # raw bytes before base64 expansion
maxRequestImageBytes: 20971520 # accumulated base64 payload
retryPolicy:
mode: normal
maxRetries: 3
anthropic:
apiKeyEnv: ANTHROPIC_API_KEY
models:
- id: claude-sonnet-4-5
contextWindow: 200000
acme-gateway:
displayName: Acme Gateway
apiKeyEnv: ACME_GATEWAY_API_KEY
api: openai-completions
baseURL: https://gateway.acme.example/v1
compat:
thinkingFormat: deepseek
models:
- id: acme-think
name: Acme Think
contextWindow: 262144
reasoningEfforts:
off:
high: high
opencode-go:
apiKeyEnv: OPENCODE_API_KEY
sessionAffinityHeaders:
- x-opencode-session
- x-client-request-id| 字段 | 默认值 | 含义 |
|---|---|---|
| apiKeyEnv | 无 | 按请求解析的凭据引用;省略时交由 pi-ai 环境发现 |
| displayName | 提供方名 | 选择器界面显示的标签 |
| api | 目录协议 | 协议格式;仅目录不提供的路由需要 |
| baseURL | 目录端点 | 路由上所有模型的端点 |
| models | 已安装目录 | 整体替换路由目录;每个条目从已安装模型取默认值 |
| modelOverrides | 无 | 重塑个别已安装目录模型,而不替换其余模型 |
| compat | 目录检测 | 无法识别端点的协议兼容开关 |
| defaultContextWindow | 262,144 | 未描述模型的容量回退 |
| defaultMaxTokens | 32,768 | 未描述模型的输出上限回退 |
| requestImagePixelBudget | 4,194,304 | 每张确定性请求图片的总像素预算 |
| requestImageMaxBytes | 1 MiB | 每张请求图片在 base64 扩展前的编码字节目标 |
| maxRequestImageBytes | 20 MiB | base64 图片载荷总上限,保留图片超过时请求以 IMAGE_OFFLOAD_REQUIRED 失败 |
| retryPolicy | normal,5 次重试 | 由 dsh-llm-retry 执行的提供方自有重试策略 |
| sessionAffinityHeaders | 缺省 | 该路由每次请求携带的会话亲和头名列表,值为当前会话 ID,用于亲和网关的按会话路由与提示词缓存;opencode-go 目录路由及 opencode.ai 端点默认发送 x-opencode-session + x-client-request-id,显式空数组表示退出,其它路由不发送;attribution 保留名被拒绝 |
生成的配置目录是每个受支持字段及其 JSDoc 的穷尽式真源。
登录提供方
pi-ai 提供登录的提供方可以通过 harness 授权 seam 登录:流程提供 OAuth 或交互式密钥提示(密钥键入 pi-ai 自己的登录提示,而非设置表单),得到的凭据存储在 harness 凭据存储的 llm-pi-ai/<provider id> 记录中。存储的登录在其路由的 apiKeyEnv 覆盖之下完成认证,并在存储的跨进程锁下自行刷新;退出登录即删除存储记录。落在记录文法之外——小写连字符标识符——的手工声明路由键无法登录,因为对它的记录写入会以 LlmError('UNSTORABLE_PROVIDER_ID') 拒绝;这类路由改用 apiKeyEnv 或提供方 ambient 设置认证。
解析模型目录
profile 的 models 列表会替换而非扩展路由的已安装目录;每个条目从同 id 已安装模型取未设置字段的默认值,因此把路由收窄到两个模型、修正一个容量或添加比已安装目录更新的模型都是一行编辑。modelOverrides 无需该代价即可重塑个别已安装目录模型——修正一个模型,保留其余三十七个——当它与 models 列表并存、位于手工声明路由上、或点名目录未描述的模型时会被拒绝,因为静默不变的模型会成为别人日后寻找的拼写错误。
带推理(reasoning)与协议兼容运行
reasoningEfforts 声明模型可选择的 thinking 等级:每个键都是选择器提供的等级,其值是分派时在协议中发送的拼写,因此 max: ultra 可以为拥有自有词汇的网关重命名等级。省略该字段时保留已安装目录条目的能力;false 声明非推理模型。对于 pi-ai 无法识别的端点,compat 开关重塑请求——哪个角色携带系统提示词、哪个字段限制输出、thinking 等级如何传递——可逐路由、逐模型配置。条目与已安装目录都没有尺寸的模型,会采用路由的 defaultContextWindow 与 defaultMaxTokens 回退值。
对于自托管 Chat Completions 端点,thinkingTokenBudgetField 选择推理预算参数,vllmPriority 在服务端启用优先级调度时设置整数调度优先级。模板参数接受 $var: thinking.budget。openai-responses 网关可设置 supportsMaxOutputTokens: false 来省略 max_output_tokens;Azure 与 Codex 传输会忽略这个共享兼容字段。这些控制均需显式启用;目录拥有的 Anthropic effort 和回退能力不是可配置开关。
运行时更改配置
profile 通过可选 settings seam 每次操作重新读取:base 与用户的 llm-pi-ai: 设置分节按提供方合并,因此用户可以新增路由、覆盖组合路由的一个字段或把路由指向另一个代理,全部在下一个请求生效、无需重启。适配器无法服务的分节会在写入处被拒绝——settings.mutate 回答 settings-rejected——之后失效的已存储分节会保留 namespace 最后有效值。当路由集合或某路由的重试策略变化时,插件会原子地重新注册:冲突路由会让此前路由继续服务。
从端点发现模型
插件会回答「该提供方可以提供哪些模型?」,供配置界面正在编辑或起草的路由使用。已安装目录提供的路由直接由目录回答,不发网络请求,并将其 input 数组保留为发现结果的 inputModalities;只有目录未描述的路由才会经网络询问。openai-completions 与 openai-responses 使用带 bearer 鉴权的 GET {baseURL}/models,anthropic-messages 则以 x-api-key 和 anthropic-version 使用原生 GET /v1/models?limit=1000 语义;其列表 URL 接受带或不带末尾 /v1 的 API 根地址,因为网关文档两种写法都会发布,且只有该列表 URL 会归一化这一段,模型请求收到的仍是配置原样的 baseURL。已配置且具名的路由会在 Host 内部提供已存凭据与 profile headers,因此通过 settings.yaml 或 Cordis 配置设置的部署标头可以到达模型发现请求,但不会成为发现请求或 Models 页面的字段;表单中新键入的密钥仍优先于已存凭据。解析器接受标准 data 数组或富信息 models 对象,并归一化每个候选的 id、显示名、上下文窗口与最大输出 token 数;Anthropic 的 max_input_tokens 与 max_tokens 会进入相同容量字段,即使对象条目点名了另一个规范 id,对象键仍是请求 id,原始类型的对象属性会被忽略,缺失的显示名则回退到该请求 id。回答是界面可以提供给用户采纳的候选元数据——不存储任何内容,settings.yaml 仍然是决定路由服务内容的唯一事实。
失败与恢复
pi-ai 不提供的路由需要 api、baseURL 与非空 models 列表;无法服务的 profile 会在写入处被拒绝,并点名路由与模型。失败携带稳定 code:无法使用的凭据以 INVALID_CREDENTIAL 失败并点名路由与引用,apiKeyEnv 引用解析为空的路由以 MISSING_CREDENTIAL 失败,未配置模型以 UNKNOWN_MODEL 失败,终止性提供方失败则区分 QUOTA 与暂时性 RATE_LIMIT。GenerateOptions.stop 以 UNSUPPORTED_OPTION 被拒绝,因为 pi-ai 的通用流式 UI 无法跨提供方保证它。
Settings 写入会在合并组合层与用户层后严格校验每个新增或修改的提供方。命名空间注册时,已存储配置的目录解析错误会保留命名空间与提供方行,并通过 LlmConfigurableProvider.error 优先返回首个模型诊断,无模型诊断时返回路由错误;未修改的错误提供方不会阻止其他编辑。可解析的模型仍可选择,无法解析的模型保留在可编辑配置中,直接请求时会在网络 I/O 前以 INVALID_CONFIG 失败。修复或删除错误配置会清除诊断。Schema 与 profile 自身的约束错误仍会拒绝加载。后续外部文件编辑会校验变化的提供方,失败时保留最后一次接受的分节。
只修改 displayName、apiKeyEnv 或 baseURL 而未解决提供方的模型配置错误时,保存仍会被拒绝。例如,OpenRouter 路由的模型 111 缺少 api 时,不能单独保存路由名称的修改:需要在同一份编辑草稿中修复或删除该模型,再保存完整的提供方配置。中间修复状态保留在草稿中,直到整条提供方配置通过校验;其他提供方可以独立保存。
理解实现
本节解释适配器背后的设计;可观察行为已在使用本包中完整说明。
设计理念
适配器建立在不可变快照与按操作解析之上。每个操作都会在第一次 await 前捕获整个快照——profile 加一个持有每条路由所构建 Provider 的 createModels() 集合——配置变更会构建新集合而非修改使用中的集合,因此在一个配置下开始的请求绝不会在另一个配置下结束。路由自己的凭据引用经 harness seam 解析,并以请求 apiKey 选项传入,pi-ai 将其视为优先级最高的 auth 覆盖——这正是明确失败引用语义的所在。该覆盖未覆盖的一切都经集合自身的 auth 到达 pi-ai:凭据存储持有登录写入、刷新轮换的记录(以 llm-pi-ai/<provider id> 寻址),auth context 回答提供方解析时提出的 ambient 问题。两者跨快照保持稳定,因此配置变更重建集合时不会忘记谁已登录。运行时 import 使用 pi-ai 的 provider、API 与 utility 入口;src/models.ts 提供本适配器所需的少量 model helper,而不会求值 pi-ai 聚合入口。
源码地图
| 文件 | 职责 |
|---|---|
| src/index.ts | 插件入口:profile 解析、settings 接线、目录与路由注册 |
| src/auth.ts | 覆盖 harness 凭据平面的凭据存储与 ambient auth context |
| src/login.ts | 面向提供登录的已安装提供方的授权流程 |
| src/config.ts | Profile schema、解析与可服务性校验 |
| src/catalog.ts | 已安装目录集成与漂移门禁 |
| src/models.ts | 基于 pi-ai 窄入口的 model collection、静态 provider 与 reasoning level |
| src/provider.ts | 受支持协议表与提供方构建 |
| src/context.ts | Harness 到 pi-ai 的上下文转换、图片处理、回放恢复 |
| src/stream.ts | 把 pi-ai 事件转换为 harness StreamChunk 值 |
| src/replay.ts | 带版本的 ReplayEnvelope 存储与校验 |
| src/discovery.ts | 面向配置界面的端点询问 |
注册与目录
插件会在可配置提供方目录中声明它能认证的每个已安装目录提供方,并加入当前 profile 声明的每条路由,因此配置界面可以在任何路由存在之前提供完整目录。每个条目都携带 declared——pi-ai 是否在该键下不提供任何内容——因为只有适配器能区分手工声明路由与收窄目录路由。路由注册具有原子性:与其他适配器冲突的候选集合会让此前路由继续服务。零路由的裸挂载即休眠姿态:settings 分节提供 profile 前不注册任何内容,分节清空时路由随之消失。
回放与词汇
成功 assistant 响应会存储带版本的、无损 JSON 回放状态,与产生它们的提供方和模型放在一起——响应级事实加每个流式块一条逐块条目。请求时,LlmRuntime 仅当同一适配器实例拥有两条路由时才传递回放状态;适配器校验它并恢复原生响应 id、提供方签名与可选的 providerThinkingLevel effort 元数据,缺失的 effort 元数据仍保持缺失。回放会对照 assistant 来源校验请求模型身份,并在提供方解析别名或回退时单独恢复 Anthropic 响应模型。无法使用的状态会降级为提供方无关内容而不是让请求失败。pi-ai 工具调用参数是解析后的对象,因此适配器解析输入并重新字符串化输出,以符合 harness 原始 JSON 约定;pi-ai 流内错误事件映射为终止 finish 分片。
进一步探索
当包级约定不够用时阅读以下页面。它们从服务约定逐步进入孪生适配器与共享类型。
- dsh-llm 服务——本适配器注册其上的提供方无关服务。
- llm-deepseek 适配器——
deepseek-official路由的 DeepSeek 直连孪生。 - LLM 流式子系统——
StreamChunk协议与适配器约定。 - llm-retry——应用每个 profile
retryPolicy的重试执行器。 - 孪生 LLM 适配器——为什么 DeepSeek 路由交付两个结构不同的适配器。
- 生成配置目录——每个受支持配置字段及其源声明。
模型体验
经 pi-ai 的提供方请求
模型看到什么
所选目录模型会收到一条系统提示词(GenerateOptions.system,否则取历史中首条 system 消息的文本;首条 system 消息文本为空时不发送系统提示词)、其余历史、工具与 pi-ai 通用流式 API 支持的采样字段。每张保留图片前都会有文本,注明其完整附件 id 与实际请求尺寸。当前执行文件系统可以映射附件提供方的宿主对象时,该文本还会携带只读规范化对象路径,并警告规范化或请求投影可能缩放或重新编码上传内容。日志中的图片省略决策选中的每个出现位置都会在替换文本中保留自己的身份与当前已解析访问方式,其规范化附件不会读取或变换。当保留的出现位置按精确 base64 载荷仍超过路由的 maxRequestImageBytes 时,调用以 IMAGE_OFFLOAD_REQUIRED 失败,由 dsh-compaction-image-offload 用 image/offload 事件记录所选位置并重试步骤。提供方原生回放元数据只在适配器针对历史内容校验通过后恢复。
Token 影响
提供方分词决定精确输入。保留图片会添加稳定的附件与坐标描述符;卸载占位符会替代省略图片的视觉 token。回放元数据可能让原生 API 复用提供方侧状态。
KV Cache 影响
转换保持逻辑请求顺序,图片句柄与卸载占位符则会添加模型可见文本。即使附件身份与请求字节保持稳定,执行世界路径变化也会改写历史句柄,并可能从该图片起阻止复用。更换适配器实例、提供方、模型或其他上游 token 具有相同的后缀影响。一次省略决策会把较早图片换成占位文本,因此复用在该消息处结束;省略永不回退,此后前缀保持稳定。
提供方响应
模型看到什么
pi-ai 事件变成 harness 的推理、文本、工具调用、用量与 finish 分片。适配器把解析后的工具参数以原始 JSON 字符串传给 harness。
Token 影响
生成内容只在 loop 记录后才影响后续输入。提供方未单独报告推理 token 时,pi-ai 会把推理 token 并入输出用量,并原样保留其精确 totalTokens 值。
KV Cache 影响
已记录的响应内容会追加到下一个请求,不会使其更早可复用前缀失效。未记录的传输元数据与用量计量不影响缓存标识。
已知限制与延期工作
这些限制说明适配器在哪里停止、由未来工作接续。它们是当前包约束,不是通用 pi-ai 对比或任务积压。
maxRequestImageBytes只计算 base64 图片载荷,文本、工具、描述符与 JSON 结构在该上限之外,因此它必须留有余量地低于网关请求体上限。- 登录只存在于发起它的进程中——授权尝试不持久,因此登录中途刷新页面会放弃它,用户需要重新开始。退出登录是对已存储记录执行
deleteRecord,只在本地忘记它,不会告知签发方。 - 提供方原生发现经本插件的 ambient context 回答——不点名凭据的路由交由目录提供方自身解析,它会询问环境值(
AZURE_OPENAI_API_KEY、AWS_PROFILE及各提供方自有集合)与本地凭据文件。两个问题都在这里得到回答:凭据 seam 先于进程环境被查询,文件存在性则针对宿主进程的文件系统以~展开后检查。它做不到的是读取凭据文件内容——自行解析~/.aws/credentials的提供方会直接读取,不经该 seam。 - 设置可以新增或覆盖路由,不能移除组合路由——用户层覆盖组合 base,因此删除
cordis.yml提供的提供方属于组合变更。 - 分层合并对字典键没有删除——base 声明的
reasoningEfforts等级、modelOverrides条目或compat字段可以被用户层覆盖,但不能被移除。 headers可以携带 redactor 永远看不到的凭据——profile 解析会拒绝 Fetch 无法表示的名称与值,但该字典仍是纯字符串;以apiKeyEnv引用存储凭据。- 路由目录不会自行刷新——目录就是
settings.yaml的内容;这里没有任何机制向提供方查询它提供的模型。 - Anthropic 模型发现最多读取 1,000 个模型——请求使用 API 的最大页大小,但不会遍历
has_more;第一页之外的条目需要手工添加。 - 每条路由一种协议格式——混合协议目录路由无法承载另一协议格式的模型;把提供方拆到两个路由键是变通办法。
- 模态声明不受校验——声明
image而其网关不支持的模型会在提示词准入后被提供方拒绝。持久图片仍留在历史中,同一误声明模型可能再次失败;切换到纯文本模型仍然可行,因为共享 LLM 运行时会针对该请求把图片引用投影为稳定文本。 - 未认证路由取决于其协议——不点名凭据的路由解析为已配置但无密钥,但 pi-ai 的 OpenAI 兼容实现仍要求 API 密钥或
Authorization标头,因此无密钥本地服务器需要由apiKeyEnv引用或headers中的Authorization条目提供的占位凭据。 - 不支持
GenerateOptions.stop——pi-ai 的通用流式选项无法跨提供方保证停止序列行为。 - 只有历史中首条
system消息会成为 pi-ai 的systemPrompt——pi-ai 只有一个系统槽位,因此后续的system消息,或在同时设置了GenerateOptions.system时的首条消息,会在原位置折叠为user消息;系统提示词的提供方专属放置遵循 pi-ai,而非 harness 自有的协议覆盖。system 或 assistant 历史中的图片(包括首条系统消息中的图片)在两条转换路径上都会以UNSUPPORTED_CONTENT失败。 - 提供方 HTTP 状态不可用——pi-ai 错误事件不跨提供方暴露稳定 HTTP 状态。
- 重试策略由提供方自有,而非 SDK 重试——pi-ai SDK 重试保持禁用,因此持久 agent(智能体)步骤与
llm/retry事件拥有每个可见尝试,直接ctx.llm.stream()调用仍是单次尝试。
开发备注
本开发备注是不具权威性的工作上下文:尚未决定的探索方向与维护者备注。已交付的行为与既定理由以上文、包代码和相关 Agent Note 为准。
- 提供的协议集合刻意比 pi-ai 的完整 API 集合更窄:Bedrock、Vertex、Azure 与 Codex 通过 profile 无法以密钥、端点与标头完整描述的流程认证;目录路由仍可经自有提供方到达它们,只有显式覆盖会被拒绝。Codex 可经授权流程的 OAuth grant 登录。
compat开关集合由漂移门禁钉在 pi-ai 的 compat 类型上;上游升级若新增字段、为更多协议赋予 compat 类型或扩大值联合,会在有人分类前让构建失败。
运行时不变式: 不发布伴生入口。本包没有独立事件序列或可变数据关系,相关约定在所属 seam 强制执行。
