Skip to content

feat(dsh): 新增 bailian-cli-dsh(feature catalog + 设置页 + 长期记忆),修复 bl memory 与 v2 API 偏差 - #159

Open
lishengzxc wants to merge 8 commits into
mainfrom
feat/bailian-cli-dsh
Open

feat(dsh): 新增 bailian-cli-dsh(feature catalog + 设置页 + 长期记忆),修复 bl memory 与 v2 API 偏差#159
lishengzxc wants to merge 8 commits into
mainfrom
feat/bailian-cli-dsh

Conversation

@lishengzxc

@lishengzxc lishengzxc commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

背景

DeepSeek Harness(dsh)是「万物皆插件」的 Cordis 架构 agent harness。本 PR 新增 packages/dshbailian-cli-dsh),把百炼能力接入 dsh 的 webui 与插件 seam;并顺带修掉 bl memory 与长期记忆 v2 API 之间的多处偏差。

演进中形态收敛过两次:最初做了 6 个独立模型工具(vision / image / managed-agent / RAG / memory / TokenPlan LLM),实测后砍掉——工具太多会污染 tool 列表,多数百炼能力用 bl 命令行直接调更顺手。最终收敛为 feature catalog + 设置页 + 长期记忆

交付内容

1. Feature catalog:一份声明,两个入口

packages/dsh/src/features.ts 是核心抽象。每个 feature 声明 bl argv、可选参数 flag、summarize 投影、以及一句自然语言 query,然后自动获得两个入口:

  • 自然语言入口 — 每个 feature 注册一个模型工具(bailian_<id>),模型按 intent 判断何时调用
  • 欢迎页卡片 — 点击把 query 填进对话输入框并提交

卡片这条路径值得说明:最初实现是点击后直接 POST 后端路由、把结果渲染在卡片下方。那是个死胡同——用户看到一段摘要但无法追问,agent 也完全不知道这个问题被问过。改成投递自然语言后,由 agent 自己路由到对应工具、缺参数时可以 AskUserQuestion,整个交互留在对话记录里可继续追问。

加能力只需加一条 catalog 条目,不用分别接工具和路由。

2. Bailian 设置页 + 跨会话长期记忆

能力 说明 默认
Bailian 设置页 webui Settings 里的 "Bailian" 页:AK/SK 凭证配置(存入 bldsh 专属 profile)+ TokenPlan 用量展示 + 记忆库参数配置 启用
跨会话长期记忆 自动检索注入 + 自动落库 + 3 个模型工具(search/add/list) 停用(按次计费)

dsh 的 host/client 双半模式:

  • Hostsrc/tokenplan-usage/index.ts):inject: ['subprocess'],通过 bl console call --config dsh 调控制台接口
  • Clientsrc/client.tsclient.bundle.js):声明 dsh.client,注册 settings.sectionconversation.input.dock
  • Memorysrc/memory/index.ts):agent/pre-step 自动检索注入、agent/turn-stopping 自动落库

凭证隔离用 --config dsh 专属 profile,避免和用户主 profile 的 token 互相踩。

用法见 packages/dsh/README.md

3. 客户端 bundle 改为构建产物

dsh 的 web shell 只加载调用 window.__ModuleLoader__.load({ id, factory }) 的客户端插件,externals(react)通过注入的 require 解析。而 vp pack 只产出普通 ESM——格式不对,加载不了

所以客户端单独用 esbuild 构建(CJS + browser platform + react external + ModuleLoader banner/footer),见 scripts/build-client.mjsbuild 脚本是 vp pack && node scripts/build-client.mjs

client.bundle.js 早期手写维护(曾因此引入两处语法错误,会让 webui 直接加载失败),现为构建产物并加入 .gitignore

⚠️ 它仍在 package.jsonfiles——发布前必须先 pnpm build,否则发出去的包会缺这个文件。

4. 新增 CLI 命令

TokenPlan 个人版(支撑设置页用量面板与 feature catalog):

  • bl token-plan personal-usage — 5 小时/1 周用量百分比、套餐状态、额外用量包 credits;负责解开控制台网关嵌套的 data.DataV2.data.data 信封
  • bl token-plan personal-key — 个人版 API key(脱敏)

managed-agent

  • bl managed-agent run — 一步 ensure+run:幂等物化云端 agent + environment,然后开 session 跑任务,无需预先写 agents.yamlapply。照搬 OpenAgentPack webui 后端的配方(resolveProjectConfigFromObjectsyncAgentResourcesWithStateBackendstartSessionRun),state 存在 ~/.bailian/managed-agent/ 而非用户 cwd

均按仓库命令清单完成注册(命令库导出、bl 产品 map、e2e topic routes、生成 reference)。

5. 修复 bl memory(均已线上验证)

两处都是 CLI 的 bug,不是文档过时:

  • profile get 是坏的:走 /profiles 返回 HTTP 500 InternalError,正确路径是 /user_profile
  • add 的返回字段读错:读 response.memory_ids,服务端实际返回 memory_nodes,导致文本模式恒打印 Memory added. IDs: none
  • 附带两个类型错误:MemoryNode.created_at/updated_at 是秒级数字不是字符串;UserProfileResponse.profile 的字段名与实际报文对不上

补齐 v2 API 缺失面:

  • 参数:--meta-data --project-id --project-ids --min-score --enable-rerank --plan-version --enable-judge --enable-rewrite --timestamp
  • 命令:memory profile list|detail|update|delete(v2 的四个 profile-schema 操作原先全缺)

实测得到的几个非显然结论

1. plan_version 是失效的,计费差 50 倍

请求 实际 billing_plan
plan_version: "lite" pro
enable_rerank: false lite
什么都不传 pro

文档说 plan_version 优先级高于 enable_rerank,实际单独传 lite 会被忽略。CLI flag 和 memory 插件现在都下发真正生效的那个参数。

2. 不能挂第二个 pi-ai 实例

最初想新起一个 row id 再挂一个 dsh-llm-pi-ai,理由是 registerAdapter 只在重复 route 时报错。实际启动直接失败:

LlmError: configurable provider "amazon-bedrock" is already declared

pi-ai 每次 apply 都会把内建的整个 provider 目录注册到 ctx.llm.registerConfigurableProviders,而那个目录是全局的。只有 adapter route 按实例隔离。

3. TokenPlan 与按量付费 Key 不可混用

TokenPlan(sk-sp-)和按量付费(sk-ws-)互相 401 对方的端点。所以两者用不同环境变量,不共享 DASHSCOPE_API_KEY

4. agentstudio 只在 workspace 专属域提供

https://{workspace}.cn-beijing.maas.aliyuncs.com——dashscope 主域和 TokenPlan 网关都 404。

工程改动

pnpm-workspace.yaml 关闭 autoInstallPeers@deepseek-ai/dsh-* 的 rc 依赖图 peer 了三个从未发布到 npm 的包(dsh-type-meta / dsh-environment / dsh-tasks),开着的话整个 workspace 装不上。已验证既有包构建不受影响。

依赖统一钉 ^0.1.0-rc.6——npm 的 latest tag 指向残缺的 0.0.1-rc.1 线。

验证情况

已真实验证

  • memory 全链路:profile create/list/detail/get/update/delete + add/search/delete 逐个真实调用并清理干净
  • --enable-rerank false → 响应 billing_plan: "lite"
  • 插件装入 web profile:--dump-config 退出码 0、无 amazon-bedrock 报错、行都在
  • 全仓 vp check 0 error(剩 5 个 warning 均为既有代码)
  • pnpm -F bailian-cli-dsh build 跑通,client.bundle.js(48.6KB)通过 node --check

未验证 — webui 相关部分整体未经真实运行

  • 设置页 UI:AK/SK 保存、用量查询、记忆库配置三个交互只做了类型与打包验证
  • 欢迎页卡片投递 querysendQueryconversation.input 的 shell 获取做了多路兼容(inputHub.for(scope) / inputHub.shell(id))并在失败时静默返回 false——这几条分支哪条真正生效未经验证,若都不匹配则卡片点击无反应
  • feature catalog 的模型工具入口:未实跑
  • bl token-plan personal-usage / personal-key:未用真实 console 凭证调通(信封解包逻辑基于接口结构推导)
  • bl managed-agent run 成功路径:手上账号 agentstudio 返回 404,且现有 managed-agent apply 用相同端点/key 同样 404,说明是账号未开通而非本次改动引入
  • memory 的自动注入/自动落库(agent/pre-step / agent/turn-stopping)未在真实会话中触发

待确认

packages/dsh 尚未纳入 tools/release/lib/packages.mjs 发布清单,目前只能本地 pnpm pack 安装。是否纳入发版流程请评审时定——若纳入,需确保发布流程先跑 pnpm build 以生成 client.bundle.js

🤖 Generated with Claude Code

lishengzxc and others added 5 commits August 15, 2026 01:47
Expose Bailian capabilities to dsh through its service seams as one
package with six subpath plugin entries and a `dsh.bundle` patch:

- TokenPlan as an LLM provider
- bailian_vision_describe / bailian_image_generate tools over `bl`
- knowledge-base retrieval as a WebSearchProvider (`bailian-kb`)
- cross-session memory: tools, pre-step recall, turn-close persist
- managed-agent as a SubagentProvider

TokenPlan configures the base bundle's existing pi-ai row rather than
mounting a second `dsh-llm-pi-ai` instance. A second instance cannot
work: pi-ai re-declares its entire built-in provider catalog to
`registerConfigurableProviders`, and that directory is global, so boot
fails with a duplicate on `amazon-bedrock`.

Routes and vision support were probed against the live gateway.
qwen3.8-max, qwen3.7-plus, qwen3.6-flash and glm-5.2 read images;
qwen3.7-max rejects them with HTTP 400; the DeepSeek routes accept image
content without erroring yet stay blind. The DeepSeek entries therefore
do not declare image input — claiming it would turn a clean refusal into
a silently wrong answer — and `bailian_vision_describe` serves them by
returning text instead.

Also fix `bl memory` against the v2 API, each verified live:

- `profile get` used /profiles, which returns HTTP 500. The documented
  and working endpoint is /user_profile.
- `add` read `response.memory_ids`, which the service never returns. It
  returns `memory_nodes`, so text output always printed "IDs: none".
- `MemoryNode.created_at`/`updated_at` are unix seconds, not strings, and
  `UserProfileResponse.profile` did not match the wire shape.
- Add the missing request parameters: --meta-data, --project-id,
  --project-ids, --min-score, --enable-rerank, --plan-version,
  --enable-judge, --enable-rewrite, --timestamp.
- Add `memory profile list|detail|update|delete`, covering the four v2
  profile-schema operations the CLI was missing.

`plan_version: lite` is ignored by the service and still bills pro;
`enable_rerank: false` is what actually selects lite, which is ~50x
cheaper per search. The CLI flag and the memory plugin both send the
parameter that works.

Disable pnpm's autoInstallPeers: the @deepseek-ai/dsh-* rc line peers on
three packages that were never published to npm, which 404s the whole
workspace install. Verified the existing packages still build.

Co-Authored-By: Claude <noreply@anthropic.com>
Rework the managed-agent integration so a dsh user can, in plain
language, have a Bailian cloud agent created and run a task — no
hand-written agents.yaml, no prior apply.

New `bl managed-agent run --prompt <task> [--instructions] [--model]
[--agent]`: one step that idempotently materializes a cloud agent + its
environment, then opens a session and streams the result. It mirrors the
OpenAgentPack webui backend's ensure+run recipe (resolveProjectConfigFrom
Object → syncAgentResourcesWithStateBackend → readProjectRuntime +
startSessionRun) from an in-memory config, reusing the existing
credential spine in _engine/credentials.ts. State persists under the bl
config dir (~/.bailian/managed-agent/<agent>/), never the user's cwd, so
repeat runs with the same --agent reuse the materialized agent. Unlike
apply it provisions without --yes, since running is the intent.

dsh side: replace the SubagentProvider with a plain tool
`bailian_run_remote_task` (packages/dsh/src/tool-managed-agent). The
subagent seam did not fit: in the web profile every tool-subagent row is
disabled in the host plane (delegation lives in agent presets), a
provider fixes one agent identity in config, and the default numeric
maxDepth would fail-mount a no-depthLimit provider. As a tool the model
calls it directly and fills `instructions` from the user's intent, so the
remote agent's role is defined per task. Enabled by default — it creates
nothing at load, only on invocation.

LLM row: configure the base bundle's existing llm-pi-ai row instead of
mounting a second pi-ai instance (a second instance re-declares pi-ai's
global configurable-provider catalog and fails boot on a duplicate
amazon-bedrock). TokenPlan reads a dedicated BAILIAN_TOKENPLAN_API_KEY,
not DASHSCOPE_API_KEY: TokenPlan (sk-sp-) and pay-as-you-go (sk-ws-) keys
401 each other's endpoints, so sharing one var would silently break
whichever plugin lost.

Note: the ensure+run happy path could not be verified end-to-end on the
available account — agentstudio returns 404 there, and the existing
`managed-agent apply` 404s identically against the same endpoint/key, so
the failure is account/service provisioning, not this change. Command
wiring, dry-run, config assembly, credential injection and URL
construction were all verified.

Co-Authored-By: Claude <noreply@anthropic.com>
- Updated README.md to clarify API key usage and access restrictions for TokenPlan and pay-as-you-go keys.
- Introduced shared credential validation logic to prevent TokenPlan keys from being used in incompatible contexts.
- Enhanced error messaging for credential resolution failures in managed-agent and memory plugins.
- Added tests for credential classification and workspace endpoint composition.
- Updated documentation to reflect changes in credential handling and workspace-scoped agentstudio endpoint requirements.
- Deleted the `tool-image`, `tool-managed-agent`, `tool-vision`, and `web-search-rag` modules from the codebase.
- Updated the Vite configuration to remove entries for the deleted tools and added a new entry for `tokenplan-usage`.
- Adjusted tests to reflect the removal of TokenPlan key handling logic from the now-deleted tools.
@lishengzxc lishengzxc changed the title feat(dsh): 新增 bailian-cli-dsh 插件包,并修复 bl memory 与 v2 API 的偏差 feat(dsh): 新增 bailian-cli-dsh(Bailian 设置页 + 长期记忆),修复 bl memory 与 v2 API 偏差 Aug 16, 2026
lishengzxc and others added 2 commits August 16, 2026 22:07
- Updated build process to include a new script for building the client bundle in ModuleLoader format.
- Introduced `build-client.mjs` to handle client-side bundling with esbuild.
- Added `client.ts` to implement the DSH web UI, including settings and usage pages.
- Registered new settings section for managing credentials and token usage.
- Refactored API routes to remove `/api` prefix for consistency.
- Cleaned up Vite configuration by removing unused client entry.
…n commands

Add a feature catalog (`packages/dsh/src/features.ts`) that drives two entry
points from one declaration: a model tool per feature (natural-language
entry) and a card-click webServer route (UI entry). Each feature declares
its `bl` argv, optional parameter flags, and a `summarize` projection, so
adding a capability means adding one catalog entry rather than wiring a
tool and a route separately.

New CLI commands backing the TokenPlan usage panel:

- `bl token-plan personal-usage` — 5h/1w usage percentage, subscription
  state, and addon credits, unwrapping the console gateway's nested
  `data.DataV2.data.data` envelope.
- `bl token-plan personal-key` — the masked personal-edition API key.

Both are `auth: "console"` and registered per the command checklist
(library export, `bl` product map, e2e topic routes, generated reference).

Two type fixes in the tool registration path:

- The parameter map was typed `Record<string, { type: string; ... }>`,
  which widens `FeatureParam["type"]` to `string` and is then unassignable
  to `ParameterSchemaSpec` (it needs the literal union). Keep the literal.
- `invokeFeature` returned `Promise<unknown>`, so the tool's `{ summary,
  data }` value failed `Record<string, JsonValue>`. It parses
  `bl --output json` output, so its return type is `JsonValue` — narrowing
  the signature is more honest than casting at the call site.

Co-Authored-By: Claude <noreply@anthropic.com>
@lishengzxc lishengzxc changed the title feat(dsh): 新增 bailian-cli-dsh(Bailian 设置页 + 长期记忆),修复 bl memory 与 v2 API 偏差 feat(dsh): 新增 bailian-cli-dsh(feature catalog + 设置页 + 长期记忆),修复 bl memory 与 v2 API 偏差 Aug 16, 2026
Clicking a welcome card used to POST /bailian/console and render the raw
feature result inline — a dead end: the user saw a summary with no way to
follow up, and the agent never learned the question was asked.

Now each feature declares a `query` (natural-language phrasing) and the
card drops it into the conversation input, then submits. The agent routes
it to the matching tool itself, can AskUserQuestion for missing params,
and the whole exchange stays in the transcript where the user can ask
follow-ups. This removes the inline result panel and its loading state.

Drop the `apikey` feature: it only echoed a masked key, which the settings
page already shows. `bl token-plan personal-key` stays as a CLI command.

Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant