Files
modelstudioai__cli/docs/token-plan-profile-integration.md
T
若麒 de9f1a3889 feat(config): add active profile selection
- persist the active profile in config.json
- resolve config with --config > active_config > default
- add config list and config use commands
- make auth and config writes target the selected profile
- reset activation to default when deleting the active profile
- update config UI with profile activation controls
- keep token refresh and pipeline execution profile-aware
- add loader, UI, auth, and CLI interaction coverage
2026-07-16 11:05:59 +08:00

20 KiB
Raw Blame History

Token Plan Profile 与激活配置接入方案

状态:Token Plan 模型消费 MVP 与 Config 激活状态已实现;通用 Base URL 归一化待实现。

目标分支:feat/cli-access-token。

结论摘要

Token Plan 的模型消费能力继续使用现有 apiKey 鉴权域和模型 Client,不新增 Token Plan 鉴权模式或专用 Client。

本次接入拆为三类相互独立的能力,并按业务紧急度而不是最终调用链顺序交付:

  1. 优先完成 token-plan 内置 Profile 预设、登录和文本/图片消费。
  2. 然后完成 Config 激活状态,允许用户选择未传 --config 时默认使用的命名配置。
  3. 最后以独立 commit 完成通用模型 Base URL 归一化,覆盖所有输入来源,不只服务 Token Plan。

token-plan 是有默认值的内置 Profile 名,不是 active_auth_mode,也不是新的 AuthRequirement。

背景与边界

当前分支已经包含以下 Token Plan 管控命令:

token-plan list-seats
token-plan create-key
token-plan assign-seats
token-plan add-member

这些命令属于管理面,继续使用 OpenAPI AK/SK。本方案增加的是模型消费面:用户把 create-key 获得的 PlainApiKey 保存到 Profile,然后通过现有文本和图片命令调用模型。

OpenAPI AK/SK
  -> token-plan create-key
  -> PlainApiKey
  -> auth login --config token-plan
  -> text/image model command

目标

  • 将 Token Plan 模型 API Key 作为普通 apiKey credential 使用。
  • 将 token-plan 作为内置命名 Profile 管理。
  • 支持 Config 激活状态和默认切换。
  • 复用现有文本、图片命令与 Client。
  • 对所有来源的模型 Base URL 做统一归一化。
  • 登录验证成功后原子保存 API Key 和 Base URL。
  • 服务端错误保持原消息,不在 CLI 内翻译。

非目标

  • 不重写现有 Token Plan 管控命令。
  • 不把模型消费 API Key 合并到 OpenAPI AK/SK 鉴权域。
  • 不新增 Token Plan 专用 Client。
  • 基础阶段不承诺视频、语音和音频模型消费。
  • 暂不维护会阻断请求的本地模型白名单。
  • 暂不把服务端错误翻译成 CLI 自定义错误。

用户交互

1. 配置 Token Plan

token-plan 提供默认 Base URL,因此推荐登录命令不要求用户输入地址:

bl auth login \
  --config token-plan \
  --api-key sk-sp-xxx

CLI 应解析并保存以下配置:

{
  "token-plan": {
    "api_key": "<TOKEN_PLAN_API_KEY>",
    "base_url": "https://token-plan.cn-beijing.maas.aliyuncs.com",
    "default_text_model": "qwen3.7-max",
    "default_image_model": "qwen-image-2.0"
  }
}

用户仍可显式覆盖 Base URL,用于代理、测试或未来新增地域:

bl auth login \
  --config token-plan \
  --api-key sk-sp-xxx \
  --base-url https://proxy.example.com/bailian/compatible-mode/v1

显式地址归一化后应保存为:

https://proxy.example.com/bailian

紧急交付阶段以“不传 --base-url”的推荐登录路径为准,直接使用 token-plan 预设中的 canonical 根地址。完整的 SDK Base URL、自定义代理前缀和其他输入来源归一化在独立的通用 Base URL commit 中完成。在该 commit 合入前,如需显式覆盖,用户必须传入已经规范化的根地址,不能传 /compatible-mode/v1 或 /apps/anthropic 后缀。

2. 单次选择 Config

--config 只影响当前命令,不修改激活状态:

bl text chat --config token-plan --message "你好"
bl image generate --config token-plan --prompt "一只猫"

3. 激活 Config

新增命令:

bl config use --name token-plan

激活后,未传 --config 的命令默认使用 token-plan:

bl text chat --message "你好"
bl image generate --prompt "一只猫"

切回顶层默认配置:

bl config use --name default

单次绕过当前激活项、临时使用其他 Profile:

bl text chat --config staging --message "你好"

单次显式使用顶层默认配置:

bl text chat --config default --message "你好"

上述两种单次覆盖都不得改变持久化的激活状态。

4. 查看 Config

新增列表能力,用于展示所有 Profile 和当前激活项:

bl config list

示例输出:

NAME         ACTIVE
default
staging
token-plan   *

config show 和 auth status 的行为:

  • 未传 --config:展示当前激活的 Config。
  • 传 --config <name>:展示指定 Config,不改变激活状态。
  • 输出中包含最终选择的 config 和 config_file;激活状态统一由 config list / config ui 展示。

config ui 应展示当前激活项,并提供激活操作。

Config 激活状态设计

存储形状

激活状态保存在 ~/.bailian/config.json 顶层元数据中:

{
  "active_config": "token-plan",
  "api_key": "<DEFAULT_API_KEY>",
  "token-plan": {
    "api_key": "<TOKEN_PLAN_API_KEY>",
    "base_url": "https://token-plan.cn-beijing.maas.aliyuncs.com"
  }
}

active_config 只允许出现在顶层,不属于单个 Profile 的业务字段。允许值为:

  • default:顶层默认配置。
  • 一个实际存在的命名 Profile。

旧配置没有 active_config 时等价于:

{
  "active_config": "default"
}

因此该能力对现有用户向后兼容。

选择优先级

Config block 的选择顺序为:

显式 --config <name>
  > active_config
  > default

需要保留“参数是否出现”的信息:

  • 未传 --config:读取 active_config。
  • --config default:明确选择顶层配置,不能被 active_config 替换。
  • --config <name>:明确选择该命名 Profile。

当前 normalizeConfigName("default") 会返回 undefined,实现时不能只根据归一化结果判断参数是否出现。

Config 激活只改变配置文件 block 的选择,--config 本身不提升所选 block 的字段优先级。运行时和 Base URL 登录验证保持“具体字段 flag > 环境变量 > selected config file > Profile 预设或系统默认值”。环境变量只影响本次有效值,不复制进 Profile;登录成功时,如果 Token Plan Profile 尚未保存 base_url,仍物化写入官方预设地址。Token Plan 默认模型是例外:每次登录都重置为内置版本。config show / auth status 应展示最终生效来源,避免用户误判套餐流量去向。

异常状态

  • 激活不存在的 Profile:config use 返回 usage error,不写入状态。
  • 配置文件中的 active_config 指向不存在的 Profile:命令失败并提示切回 default,不得静默使用其他凭证。
  • 删除当前激活的 Profile:删除操作同时切回 default,或者要求用户先切换;不能保留悬空引用。
  • config use --name token-plan 只切换状态,不创建 Profile,也不执行登录。
  • auth login --config token-plan 只写入指定 Profile,不自动激活,避免登录命令产生隐藏的全局状态变化。

token-plan 内置 Profile 预设

token-plan 是允许用户选择的内置 Profile 名,不应加入非法名称列表。它提供以下默认值:

base_url:           https://token-plan.cn-beijing.maas.aliyuncs.com
default_text_model: qwen3.7-max
default_image_model: qwen-image-2.0

Token Plan Base URL 预设只在登录写入阶段提供最低优先级的缺省值:

显式命令参数
  > 环境变量
  > 已保存的 Profile 字段
  > token-plan 预设值

登录成功时应把显式 Base URL 或缺失的预设 Base URL,以及默认模型写入 Profile,使 config show --config token-plan 能看到完整配置。环境变量不复制进 Profile。运行时不再合并预设;如果手工删除字段,则按统一的环境变量、配置文件和系统默认值链继续解析。

默认模型采用更简单的固定策略:每次执行 auth login --config token-plan,都将 default_text_model 重置为 qwen3.7-max,将 default_image_model 重置为 qwen-image-2.0。登录不保留用户之前写入的其他 Profile 默认模型;用户需要临时调用其他 Token Plan 模型时,通过具体模型命令的 --model 覆盖,不修改这两个内置默认值。

预设建议通过集中 registry 表达,不在 resolver、命令和 Client 中散落名称判断:

const MODEL_PROFILE_PRESETS = {
  "token-plan": {
    baseUrl: "https://token-plan.cn-beijing.maas.aliyuncs.com",
    defaultTextModel: "qwen3.7-max",
    defaultImageModel: "qwen-image-2.0",
  },
};

Profile 预设不改变命令协议:

Selected Profile
  -> API Key Credential
  -> Client
  -> Command Endpoint

通用模型 Base URL 归一化

Base URL 归一化是独立的通用能力,必须在 Token Plan 接入前完成,不能只针对 Token Plan hostname 实现。

语义

CLI 中 base_url 表示模型服务根地址或自定义网关前缀,不包含 CLI 已知的 SDK/API Base 后缀。

建议新增统一函数:

normalizeModelBaseUrl(input) -> canonical base URL

通用规则:

  1. 去除首尾空白。
  2. 使用 URL 解析,只接受 http: 和 https:。
  3. 去除 query 和 fragment。
  4. 去除末尾 /。
  5. 保留协议、hostname、端口和自定义代理路径。
  6. 去除末尾已知 SDK/API Base 后缀,例如:
    • /compatible-mode/v1
    • /apps/anthropic
  7. 不无条件返回 url.origin,避免破坏自定义代理路径。

示例:

用户输入 归一化结果
https://dashscope.aliyuncs.com/ https://dashscope.aliyuncs.com
https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1 https://token-plan.cn-beijing.maas.aliyuncs.com
https://token-plan.cn-beijing.maas.aliyuncs.com/apps/anthropic https://token-plan.cn-beijing.maas.aliyuncs.com
https://proxy.example.com/bailian/ https://proxy.example.com/bailian
https://proxy.example.com/bailian/compatible-mode/v1 https://proxy.example.com/bailian

覆盖入口

所有模型 Base URL 来源都必须经过同一个函数:

  • 模型命令的 --base-url。
  • DASHSCOPE_BASE_URL。
  • config.json 中的 base_url。
  • config set --key base_url。
  • config ui。
  • auth login --base-url。
  • Console 登录回调返回的 base_url。
  • 手工修改的旧配置。
  • 内置默认地址和 Profile 预设地址。

归一化采用双层防线:

  • 写入前归一化,保证磁盘配置整洁。
  • resolveModelBaseUrl() 返回前防御性归一化,兼容旧配置和手工修改。

URL 拼接

归一化后,命令继续拼接已有 endpoint:

text:  <base_url>/compatible-mode/v1/chat/completions
image: <base_url>/api/v1/services/aigc/.../generation

最终 URL 中不得重复出现 /compatible-mode/v1。

API Key 登录与原子保存

当前登录流程可能先写入 base_url,再验证 API Key。该顺序需要独立修复:

解析 Profile 和预设
  -> 归一化 Base URL
  -> 使用最终 Base URL 验证 API Key
  -> 验证成功后一次写入 api_key + base_url + 默认模型

验证失败时,不得产生以下半配置状态:

{
  "token-plan": {
    "base_url": "https://token-plan.cn-beijing.maas.aliyuncs.com"
  }
}

登录验证使用的模型必须在目标 Profile 中可用。基础阶段 Token Plan 预设使用 qwen3.7-max;后续如不同订阅计划的模型集合分化,应将验证模型纳入 Profile 预设,而不是继续在登录函数里硬编码唯一模型。

模型消费范围

基础阶段承诺:

能力 默认模型 调用方式
文本生成和推理 qwen3.7-max OpenAI Compatible Chat Completions
图片生成和编辑 qwen-image-2.0 DashScope 原生图片接口

Token Plan 当前模型快照中还包含其他文本、视觉理解和图片模型,但该列表可能由后端调整。基础接入不维护阻断请求的本地白名单;用户可通过具体模型命令的 --model 临时覆盖本次请求,但再次登录时 Profile 默认模型仍重置为内置版本。

视频、语音和音频不作为本阶段支持承诺。现有命令仍保持通用实现,但 Token Plan Profile 的验收不包含这些模态。

错误处理

CLI 继续遵循“服务端错误消息原样透传”的规则。

例如服务端返回:

{
  "code": "InvalidParameter",
  "message": "Model not exist."
}

CLI 保留 Model not exist.,不改写成“Token Plan 不支持该模态”,因为本地没有权威、实时的模型开放列表。

Commit 拆分

以下 commit 按紧急度和必要依赖提交,每个 commit 都应能独立通过对应测试和静态检查。前三个 commit 组成可优先交付的 Token Plan 模型消费 MVP,后两个 commit 再补齐默认激活体验和通用 URL 输入兼容。

Commit 1:Token Plan 内置 Profile 预设(已实现)

建议提交信息:

feat(core): add token-plan model profile preset

完成内容:

  • 将 token-plan 注册为内置、可选择的 Profile 名。
  • 提供 canonical 默认 Base URL、文本模型和图片模型。
  • Base URL 登录验证遵循 flag > 环境变量 > 已保存 Profile > 预设;环境变量不复制进 Profile。
  • Profile 缺少 Base URL 时物化预设地址;每次 Token Plan 登录都重置并写入内置默认文本和图片模型。
  • 运行时 loader/resolver 不再合并预设。
  • 不新增 AuthRequirement,不修改 Token Plan 管控命令。
  • 补充预设值单元测试;不重复增加 Token Plan 专属消费 E2E。
  • 不依赖通用 Base URL 归一化;预设直接使用规范化后的根地址。

Commit 2:Token Plan API Key 登录(已实现)

建议提交信息:

feat(auth): support token-plan API key login

完成内容:

  • 支持 bl auth login --config token-plan --api-key ...。
  • 未传 --base-url 且没有更高优先级的环境变量或已保存地址时,使用 Token Plan Profile 预设地址。
  • 使用 Token Plan 预设文本模型验证 API Key。
  • 登录验证前不写配置。
  • 验证成功后一次写入 API Key、canonical Base URL 和默认模型。
  • 每次登录都将默认模型重置为 qwen3.7-max 和 qwen-image-2.0。
  • 验证失败不留下半配置。
  • 补充一个最小 Token Plan 登录 E2E,覆盖命名 Profile 落盘、环境变量不复制、预设 Base URL 物化和默认模型重置;通用 API Key 登录 E2E 继续覆盖成功原子保存和失败不写半配置。
  • 该 commit 暂不承诺自动归一化用户显式输入的 SDK Base URL。

Commit 3:Token Plan 文本与图片消费验收(已实现)

建议提交信息:

feat(cli): enable token-plan text and image consumption

完成内容:

  • Token Plan 消费复用现有 API Key、文本和图片调用链,不重复增加专属 E2E。
  • 发布前按需人工验证 auth login --config token-plan --api-key ...、文本和图片调用。
  • 更新 Token Plan 消费方案文档和 Skill reference。
  • 到该 commit 为止即可先交付显式 --config token-plan 的紧急消费能力。

运营文档 TODO

  • 由运营同事补充 README.md 和 README.zh.md 的 Token Plan 模型消费说明。
  • 区分 sk-sp-... 模型消费 API Key 与管控命令使用的 OpenAPI AK/SK。
  • 增加 auth login --config token-plan --api-key ...、文本消费和图片消费示例。
  • 与届时实际上线范围核对模型名称、服务地域、限制条件和用户措辞。

Commit 4:Config 激活状态与切换命令(已实现)

建议提交信息:

feat(config): add active profile selection

完成内容:

  • 增加顶层 active_config 元数据。
  • 实现 --config > active_config > default 的选择顺序。
  • 保证 --config default 能显式覆盖激活项。
  • 新增 bl config list。
  • 新增 bl config use --name <name>。
  • config show、auth status 展示最终选择项,config list 和 config ui 展示激活状态。
  • 删除激活 Profile 时处理状态一致性。
  • 验证激活 token-plan 后不传 --config 的文本和图片请求。
  • 验证临时 --config default 不改变激活状态。
  • 更新命令导出、packages/cli/src/commands.ts、E2E 和生成 reference。

实现选择:删除当前激活的命名 Profile 时,在同一次配置文件写入中将 active_config 重置为 default。auth login --config <name> 和所有显式 --config 仍只作用于本次命令,不修改激活状态。

相关写入交互统一为:auth login、auth logout 和 config set 未传 --config 时作用于当前激活项;显式指定名称时作用于该名称。写命令可在成功落盘时创建不存在的 Profile,读命令不创建。Console access token 自动刷新同样限定在当前选中的 Profile,不得回退读写顶层 default。

激活项选择的是完整 Config,而不是只选择模型消费凭证。激活 token-plan 后,Token Plan 管控命令也会从该 Profile 解析 OpenAPI AK/SK,Console 命令也会从该 Profile 解析 Console 凭证。如果相应凭证仍保存在顶层 default,用户需要为单次命令显式传入 --config default,或将对应凭证域登录到 token-plan;CLI 不为不同鉴权域做隐式跨 Profile 回退。

Commit 5:通用模型 Base URL 归一化(待实现)

建议提交信息:

fix(core): normalize model base URLs across all sources

完成内容:

  • 新增 normalizeModelBaseUrl()。
  • 保留自定义网关路径,去除尾斜杠、query、fragment 和已知 API Base 后缀。
  • resolveModelBaseUrl() 对 flag、env、配置文件和默认值统一归一化。
  • auth login、Console callback、config set、config ui 写入前归一化。
  • 验证 Token Plan 显式输入 /compatible-mode/v1 和 /apps/anthropic 的兼容行为。
  • 补充通用 URL 单元测试和各来源解析测试。
  • 更新 README、中文 README、Skill reference 和本方案状态。

验证清单

Base URL

  • 根地址和自定义路径正确保留。
  • 尾部 / 被移除。
  • /compatible-mode/v1 和 /apps/anthropic 后缀被移除。
  • query 和 fragment 不进入最终请求地址。
  • flag、env、配置文件和所有写入入口结果一致。
  • 最终文本 URL 只包含一次 /compatible-mode/v1。

Config 激活

  • 旧配置缺少 active_config 时继续使用 default。
  • config use 只能激活存在的 Profile。
  • 未传 --config 时使用激活项。
  • 显式 --config 优先且不修改激活项。
  • --config default 能绕过命名激活项。
  • 悬空激活项不会静默回退到其他凭证。
  • 删除激活项后状态保持一致。
  • config list/show/ui 正确标识激活项。

Token Plan

  • token-plan 登录初始化时缺省写入官方根地址。
  • 显式 Base URL 覆盖预设并经过通用归一化。
  • 登录验证失败不写入任何 Token Plan 半配置。
  • 文本默认使用 qwen3.7-max。
  • 图片默认使用 qwen-image-2.0。
  • 文本和图片均复用现有 apiKey Client。
  • 管控命令继续使用 OpenAPI AK/SK,不受模型 Profile 影响。

完成后检查

pnpm run sync:skill-assets
vp check
vp test

“Profile 预设与激活状态”的维护要求已沉淀到 docs/agents/config-profile-change.md。

最终结论

Token Plan 模型消费最终表现为一个可激活的内置 Profile:

通用 Base URL 归一化
  -> Config 选择与激活
  -> 登录时物化 token-plan 预设
  -> 普通 apiKey Client
  -> 文本/图片 endpoint

用户既可以通过 --config token-plan 单次使用,也可以通过 bl config use --name token-plan 将其设为默认激活配置。整个过程不引入 Token Plan 模式,也不复制现有模型调用实现。