Skip to content

feat(sdk): NanobotAdapter 校验与错误区分 + CLI 联邦搜索 - #12

Merged
chenchenchenchencj merged 1 commit into
masterfrom
cccc
Mar 6, 2026
Merged

chenchenchenchencj merged 1 commit into
masterfrom
cccc

Conversation

@chenchenchenchencj

Copy link
Copy Markdown
Contributor
  • NanobotAdapter: JSON 解析后校验为非空对象,否则 warn 并 return
  • NanobotAdapter: catch 区分配置不存在(ENOENT)/JSON 格式错误(SyntaxError)/其他
  • types: 导出 FederatedSearchResult
  • SDK: 新增 federatedSearch(),请求 /api/v1/genes/search
  • CLI search: 默认联邦搜索,表格展示来源(local/clawhub),--local 仅本地
  • 单测: federatedSearch 两例 + nanobot 内容非对象/格式错误两例 + mcp_servers transport
  • docs: 里程碑与 CLI 说明更新

Made-with: Cursor

- NanobotAdapter: JSON 解析后校验为非空对象,否则 warn 并 return
- NanobotAdapter: catch 区分配置不存在(ENOENT)/JSON 格式错误(SyntaxError)/其他
- types: 导出 FederatedSearchResult
- SDK: 新增 federatedSearch(),请求 /api/v1/genes/search
- CLI search: 默认联邦搜索,表格展示来源(local/clawhub),--local 仅本地
- 单测: federatedSearch 两例 + nanobot 内容非对象/格式错误两例 + mcp_servers transport
- docs: 里程碑与 CLI 说明更新

Made-with: Cursor
Copilot AI review requested due to automatic review settings March 6, 2026 12:59
@chenchenchenchencj
chenchenchenchencj merged commit b347f43 into master Mar 6, 2026
6 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the TypeScript SDK and CLI to support federated gene search (local DB + external sources like ClawHub), while improving NanobotAdapter’s config parsing validation and error differentiation.

Changes:

  • Export FederatedSearchResult from types and add SDK federatedSearch() calling /api/v1/genes/search.
  • Update CLI search to default to federated search with source-aware table output; add --local to keep the previous local-only search behavior.
  • Harden NanobotAdapter MCP config merge: validate parsed JSON is a non-empty object and distinguish ENOENT vs JSON syntax errors; add tests.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/types/src/api.ts Introduces/export FederatedSearchResult and reuses it in FederatedSearchResponse.
packages/sdk/typescript/src/client.ts Adds federatedSearch() to SDK client and builds query params.
packages/sdk/typescript/src/adapters/nanobot.ts Adds config JSON object-shape validation and more granular warning branches.
packages/sdk/typescript/src/tests/nanobot-adapter.test.ts Adds transport field and new tests for invalid config content / bad JSON.
packages/sdk/typescript/src/tests/client.test.ts Adds federatedSearch request/param coverage tests.
packages/cli/src/commands/search.ts Defaults search to federated search, adds --local and --limit, changes table output.
packages/cli/README.md Documents default federated search and --local.
docs/architecture.md Updates CLI command description and milestone checkboxes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +58 to +59
const result = await client.federatedSearch({
q: keyword ?? '',

Copilot AI Mar 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

当前在非 --local 模式下把 q 设置为 keyword ?? '',而后端 /api/v1/genes/search 对空/空白 query 会直接返回空结果(见 packages/registry/src/api/genes.ts)。由于 commander 这里把 keyword 定义为可选参数([keyword]),这会导致 genehub search(不带 keyword)从原先的“列出本地最新”退化为永远“未找到”。建议:非 --local 且 keyword 为空时要么提示用户必须提供 keyword(并退出非 0),要么自动回退到本地 searchGenes 行为。

Suggested change
const result = await client.federatedSearch({
q: keyword ?? '',
const trimmedKeyword = keyword?.trim();
// 当未提供 keyword 且未指定 --local 时,回退到本地 searchGenes 行为
if (!trimmedKeyword) {
const result = await client.searchGenes({
q: undefined,
category: opts.category,
tags: opts.tags?.split(','),
compatibility: opts.compat,
sort: opts.sort,
page: Number(opts.page),
});
if (opts.json) {
console.log(JSON.stringify(result, null, 2));
return;
}
if (result.items.length === 0) {
output.info('未找到匹配的基因');
return;
}
output.table(
['slug', '名称', '版本', '分类', '兼容', '安装数'],
result.items.map((g) => [
g.slug,
g.name,
g.version,
g.category,
(g.compatibility as string[]).join(', '),
String(g.install_count),
]),
);
output.info(`共 ${result.total} 条结果,第 ${result.page}/${result.total_pages} 页`);
return;
}
const result = await client.federatedSearch({
q: trimmedKeyword,

Copilot uses AI. Check for mistakes.
Comment on lines +76 to +80
async federatedSearch(params: {
q: string;
category?: string;
limit?: number;
}): Promise<FederatedSearchResult> {

Copilot AI Mar 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

federatedSearch 的参数类型这里是内联定义的,但 types 包里已经有 FederatedSearchParams(packages/types/src/api.ts)。建议直接复用该类型,避免 SDK 与 API 类型定义漂移(尤其是后续参数扩展时)。

Copilot uses AI. Check for mistakes.
const qs = new URLSearchParams();
qs.set('q', params.q);
if (params.category) qs.set('category', params.category);
if (params.limit != null) qs.set('limit', String(params.limit));

Copilot AI Mar 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里对 limit 的判断使用了 params.limit != null,会把 0 / NaN / 非有限值也序列化进查询串(例如 limit=NaN),而后端又会把 limit=0 视为默认值。建议在客户端侧做一次校验/归一化(例如仅当 Number.isFinite(limit) && limit > 0 时才 set;或直接按后端规则 clamp 到 1..50),并与 web client 的行为保持一致。

Suggested change
if (params.limit != null) qs.set('limit', String(params.limit));
if (Number.isFinite(params.limit) && (params.limit as number) > 0) {
qs.set('limit', String(params.limit));
}

Copilot uses AI. Check for mistakes.
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.

2 participants