Skip to content

test(models): 为 available-models 工具函数添加单元测试#528

Merged
ding113 merged 3 commits intoding113:devfrom
NieiR:test/available-models-utils-tests
Jan 4, 2026
Merged

test(models): 为 available-models 工具函数添加单元测试#528
ding113 merged 3 commits intoding113:devfrom
NieiR:test/available-models-utils-tests

Conversation

@NieiR
Copy link
Contributor

@NieiR NieiR commented Jan 4, 2026

变更摘要

src/app/v1/_lib/models/available-models.ts 中的工具函数添加单元测试覆盖。

变更内容

  • 新增 src/types/models.ts - 提取模型相关类型定义
  • 新增 tests/unit/proxy/available-models.test.ts - 工具函数单元测试
  • 重构 available-models.ts - 导出内部工具函数以便测试

测试覆盖

函数 测试场景
inferOwner 模型所有者推断(Anthropic/OpenAI/Google/DeepSeek/Alibaba/未知)
getProviderTypesForFormat 客户端格式到 Provider 类型映射
formatOpenAIResponse OpenAI 格式响应
formatAnthropicResponse Anthropic 格式响应
formatGeminiResponse Gemini 格式响应

共 23 个测试用例

测试步骤

bun run test tests/unit/proxy/available-models.test.ts

相关 PR/Issue


Description enhanced by Claude AI

导出内部函数(inferOwner、getProviderTypesForFormat、format*Response)以支持单元测试。添加完整的测试覆盖:模型所有者推断、格式到 Provider 类型映射、OpenAI/Anthropic/Gemini 响应格式化。
@coderabbitai
Copy link

coderabbitai bot commented Jan 4, 2026

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

将模型处理模块中若干内部类型与函数改为公共导出,新增 OpenAI/Anthropic/Gemini 的响应类型定义,并为 inferOwner、getProviderTypesForFormat 与 format*Response 系列添加单元测试覆盖。

Changes

Cohort / File(s) 变更摘要
模型处理模块导出
src/app/v1/_lib/models/available-models.ts
将内部声明改为公共导出并收紧签名:export interface FetchedModel、`export type ModelOwner = "anthropic"
供应商模型响应类型
src/types/models.ts
新增并导出响应与模型类型:OpenAIModelsResponse / OpenAIModelAnthropicModelsResponse / AnthropicModelGeminiModelsResponse / GeminiModel,用于强类型描述各供应商的模型列表响应结构。
单元测试
tests/unit/proxy/available-models.test.ts
新增全面单元测试,覆盖 inferOwner 的多供应商识别、getProviderTypesForFormat 映射、以及 formatOpenAIResponse/formatAnthropicResponse/formatGeminiResponse 的字段映射、空列表与回退行为,包含对时间/字段格式的断言与边界情况。

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed PR标题与变更内容高度相关,清晰准确地概括了主要改动:为 available-models 工具函数添加单元测试。
Description check ✅ Passed PR描述完整详细地说明了变更内容、涉及的文件、测试覆盖范围和相关issue,与变更完全相关。
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to Reviews > Disable Cache setting

📥 Commits

Reviewing files that changed from the base of the PR and between eb706e9 and 6a592a1.

📒 Files selected for processing (1)
  • src/app/v1/_lib/models/available-models.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx,js,jsx,json}

📄 CodeRabbit inference engine (CLAUDE.md)

Use 2-space indentation in all code files

Files:

  • src/app/v1/_lib/models/available-models.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Use double quotes for strings instead of single quotes
Use trailing commas in multi-line structures
Enforce maximum line length of 100 characters
Use path alias @/* to reference files from ./src/* directory

**/*.{ts,tsx,js,jsx}: Use Biome for linting and formatting with 2-space indent, double quotes, trailing commas, and 100 character max line length
Use path alias @/* to reference files in ./src/* directory

Files:

  • src/app/v1/_lib/models/available-models.ts
src/app/v1/_lib/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Guard pipeline must execute in order: ProxyAuthenticator, SensitiveWordGuard, VersionGuard, ProxySessionGuard, ProxyRateLimitGuard, ProxyProviderResolver

Files:

  • src/app/v1/_lib/models/available-models.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use TypeScript strict mode for type safety
Use readonly or const assertions for immutable data structures

Files:

  • src/app/v1/_lib/models/available-models.ts
src/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.ts: Hash API keys using SHA-256 before storing in database, never store plaintext keys
Mask API keys and sensitive data in application logs
Validate required environment variables at startup with clear error messages

Files:

  • src/app/v1/_lib/models/available-models.ts
src/app/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Implement Content-Security-Policy headers for XSS prevention

Files:

  • src/app/v1/_lib/models/available-models.ts
src/app/v1/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Use Hono router for ultrafast, lightweight routing in proxy endpoints

Files:

  • src/app/v1/_lib/models/available-models.ts
🧠 Learnings (1)
📚 Learning: 2026-01-03T09:09:37.748Z
Learnt from: NieiR
Repo: ding113/claude-code-hub PR: 517
File: src/app/v1/_lib/models/available-models.ts:45-70
Timestamp: 2026-01-03T09:09:37.748Z
Learning: The `authenticateRequest` function in `src/app/v1/_lib/models/available-models.ts` is intentionally a lightweight version of authentication, specifically designed for the `/v1/models` endpoint. It does not need to check for multi-source conflicts or use the full `ProxyAuthenticator` logic, as the scenario is simpler. The JSON error response format is intentional (more generic than `ProxyResponses.buildError`).

Applied to files:

  • src/app/v1/_lib/models/available-models.ts
🧬 Code graph analysis (1)
src/app/v1/_lib/models/available-models.ts (2)
src/app/v1/_lib/proxy/format-mapper.ts (1)
  • ClientFormat (29-29)
src/types/models.ts (3)
  • OpenAIModelsResponse (7-10)
  • AnthropicModelsResponse (20-23)
  • GeminiModelsResponse (33-35)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: 🌐 API Tests
  • GitHub Check: Docker Build Test
🔇 Additional comments (8)
src/app/v1/_lib/models/available-models.ts (8)

6-10: LGTM!

类型导入正确,使用 type 关键字进行类型导入是 TypeScript 的最佳实践,有助于 tree-shaking 优化。


18-18: LGTM!

将接口导出以支持单元测试是合理的做法,接口定义本身没有改变。


130-133: LGTM!

新增的 ModelOwner 联合类型显著提升了类型安全性,正确实现了先前评审意见中建议的返回类型收窄。这确保了 inferOwner 函数只能返回预期的所有者名称。

根据先前评审意见,此更改已正确实现。


138-138: LGTM!

函数签名改进正确实现了先前评审意见:返回类型从宽泛的 string 收窄为具体的 ModelOwner 联合类型,并导出以支持单元测试。

根据先前评审意见,此更改已正确实现。


272-272: LGTM!

导出函数以支持单元测试,函数实现包含完善的穷举性检查(使用 never 类型),是优秀的 TypeScript 实践。


314-323: LGTM!

返回类型和常量断言的改进非常出色:

  • 返回类型从 object 收窄为具体的 OpenAIModelsResponse
  • 使用 as const 确保字面量类型("model", "list")而非宽泛的 string 类型
  • 完全满足 TypeScript 严格类型检查要求

根据先前评审意见,此更改已正确实现。


329-333: LGTM!

返回类型从 object 收窄为 AnthropicModelsResponse,并为字面量类型添加 as const 断言,确保类型安全性。

根据先前评审意见,此更改已正确实现。


344-344: LGTM!

返回类型从 object 收窄为具体的 GeminiModelsResponse,与其他格式化函数保持一致,提升类型安全性。

根据先前评审意见,此更改已正确实现。


Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @NieiR, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

这个拉取请求旨在通过引入专门的单元测试来提高 available-models 工具函数的代码质量和可靠性。它通过将模型相关的类型定义集中管理,并导出原先内部的函数以方便测试,从而确保了模型信息处理和格式化逻辑的正确性。

Highlights

  • 新增单元测试: 为 available-models.ts 中的 inferOwnergetProviderTypesForFormatformatOpenAIResponseformatAnthropicResponseformatGeminiResponse 等工具函数添加了全面的单元测试。
  • 类型定义提取: 将模型相关的类型定义(如 OpenAI、Anthropic、Gemini 响应结构)提取到新的 src/types/models.ts 文件中,以提高代码组织性和可重用性。
  • 函数导出重构: 重构了 available-models.ts 文件,将 FetchedModel 接口以及多个内部工具函数(如 inferOwnergetProviderTypesForFormatformatOpenAIResponseformatAnthropicResponseformatGeminiResponse)导出,以便进行独立的单元测试。
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

本次 PR 为 available-models.ts 中的工具函数添加了全面的单元测试,并通过导出内部函数和类型的方式使其可测试,这是一个很好的实践。新增的 src/types/models.ts 文件也清晰地定义了模型相关的类型。

我的评审意见主要集中在进一步增强代码的类型安全方面:

  1. 建议将 formatOpenAIResponseformatAnthropicResponseformatGeminiResponse 等函数的返回类型从通用的 object 更改为你在 src/types/models.ts 中定义的更具体的响应类型(例如 OpenAIModelsResponse)。
  2. 建议将 inferOwner 函数的返回类型从 string 收窄为字符串字面量联合类型,以提供更强的类型约束。
  3. 在新增的单元测试中,建议使用这些更具体的类型来进行类型断言,使测试代码更简洁、更健壮。

这些改动将有助于提高代码的可读性和可维护性,并能在编译阶段捕获潜在的错误。

@github-actions github-actions bot added size/S Small PR (< 200 lines) enhancement New feature or request area:core labels Jan 4, 2026
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Additional Comments (2)

  1. tests/unit/proxy/available-models.test.ts, line 4-6 (link)

    syntax: Mock incomplete - missing required exports. When available-models.ts imports, it triggers @/lib/proxy-agent which tries to import fetch-socks. Need to mock all exports or use vi.doMock() before imports.

  2. tests/unit/proxy/available-models.test.ts, line 12-15 (link)

    syntax: Mock incomplete - missing required exports. The provider-selector module exports more than just ProxyProviderResolver.

3 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/app/v1/_lib/models/available-models.ts (1)

304-314: 建议使用强类型返回值替代 object

这三个格式化函数目前返回 object 类型,但 src/types/models.ts 中已定义了对应的强类型接口(OpenAIModelsResponseAnthropicModelsResponseGeminiModelsResponse)。建议更新返回类型以获得更好的类型安全性。

🔎 建议的类型改进

首先在文件顶部导入新类型:

+import type {
+  OpenAIModelsResponse,
+  AnthropicModelsResponse,
+  GeminiModelsResponse,
+} from "@/types/models";

然后更新函数签名:

-export function formatOpenAIResponse(models: FetchedModel[]): object {
+export function formatOpenAIResponse(models: FetchedModel[]): OpenAIModelsResponse {
-export function formatAnthropicResponse(models: FetchedModel[]): object {
+export function formatAnthropicResponse(models: FetchedModel[]): AnthropicModelsResponse {
-export function formatGeminiResponse(models: FetchedModel[]): object {
+export function formatGeminiResponse(models: FetchedModel[]): GeminiModelsResponse {

Also applies to: 319-329, 334-342

🧹 Nitpick comments (1)
tests/unit/proxy/available-models.test.ts (1)

116-146: 建议使用强类型断言提升类型安全性

当前测试中使用了内联类型断言(如 as { object: string; data: unknown[] }),建议导入并使用 src/types/models.ts 中定义的类型接口,以获得更好的类型检查和代码可维护性。

🔎 建议的改进方案

在文件顶部添加类型导入:

 import {
   formatAnthropicResponse,
   formatGeminiResponse,
   formatOpenAIResponse,
   getProviderTypesForFormat,
   inferOwner,
   type FetchedModel,
 } from "@/app/v1/_lib/models/available-models";
+import type {
+  OpenAIModelsResponse,
+  AnthropicModelsResponse,
+  GeminiModelsResponse,
+} from "@/types/models";

然后在测试中使用这些类型:

-const result = formatOpenAIResponse([]) as { object: string; data: unknown[] };
+const result = formatOpenAIResponse([]) as OpenAIModelsResponse;
-const result = formatAnthropicResponse([]) as { data: unknown[]; has_more: boolean };
+const result = formatAnthropicResponse([]) as AnthropicModelsResponse;
-const result = formatGeminiResponse([]) as { models: unknown[] };
+const result = formatGeminiResponse([]) as GeminiModelsResponse;

Also applies to: 162-189, 201-227

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to Reviews > Disable Cache setting

📥 Commits

Reviewing files that changed from the base of the PR and between 83290bc and b41fe6f.

📒 Files selected for processing (3)
  • src/app/v1/_lib/models/available-models.ts
  • src/types/models.ts
  • tests/unit/proxy/available-models.test.ts
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{ts,tsx,js,jsx,json}

📄 CodeRabbit inference engine (CLAUDE.md)

Use 2-space indentation in all code files

Files:

  • src/types/models.ts
  • tests/unit/proxy/available-models.test.ts
  • src/app/v1/_lib/models/available-models.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Use double quotes for strings instead of single quotes
Use trailing commas in multi-line structures
Enforce maximum line length of 100 characters
Use path alias @/* to reference files from ./src/* directory

**/*.{ts,tsx,js,jsx}: Use Biome for linting and formatting with 2-space indent, double quotes, trailing commas, and 100 character max line length
Use path alias @/* to reference files in ./src/* directory

Files:

  • src/types/models.ts
  • tests/unit/proxy/available-models.test.ts
  • src/app/v1/_lib/models/available-models.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use TypeScript strict mode for type safety
Use readonly or const assertions for immutable data structures

Files:

  • src/types/models.ts
  • tests/unit/proxy/available-models.test.ts
  • src/app/v1/_lib/models/available-models.ts
src/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.ts: Hash API keys using SHA-256 before storing in database, never store plaintext keys
Mask API keys and sensitive data in application logs
Validate required environment variables at startup with clear error messages

Files:

  • src/types/models.ts
  • src/app/v1/_lib/models/available-models.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Vitest for unit testing with Node environment, coverage thresholds: 50% lines/functions, 40% branches

Files:

  • tests/unit/proxy/available-models.test.ts
**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

Ensure test database names contain 'test' keyword for safety validation

Files:

  • tests/unit/proxy/available-models.test.ts
src/app/v1/_lib/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Guard pipeline must execute in order: ProxyAuthenticator, SensitiveWordGuard, VersionGuard, ProxySessionGuard, ProxyRateLimitGuard, ProxyProviderResolver

Files:

  • src/app/v1/_lib/models/available-models.ts
src/app/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Implement Content-Security-Policy headers for XSS prevention

Files:

  • src/app/v1/_lib/models/available-models.ts
src/app/v1/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Use Hono router for ultrafast, lightweight routing in proxy endpoints

Files:

  • src/app/v1/_lib/models/available-models.ts
🧠 Learnings (3)
📚 Learning: 2026-01-03T09:08:20.573Z
Learnt from: CR
Repo: ding113/claude-code-hub PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-03T09:08:20.573Z
Learning: Applies to src/app/v1/_lib/converters/**/*.ts : Use Registry pattern in format converters to map conversion pairs between Claude, OpenAI, Codex, and Gemini APIs

Applied to files:

  • src/types/models.ts
  • tests/unit/proxy/available-models.test.ts
📚 Learning: 2026-01-03T09:09:37.748Z
Learnt from: NieiR
Repo: ding113/claude-code-hub PR: 517
File: src/app/v1/_lib/models/available-models.ts:45-70
Timestamp: 2026-01-03T09:09:37.748Z
Learning: The `authenticateRequest` function in `src/app/v1/_lib/models/available-models.ts` is intentionally a lightweight version of authentication, specifically designed for the `/v1/models` endpoint. It does not need to check for multi-source conflicts or use the full `ProxyAuthenticator` logic, as the scenario is simpler. The JSON error response format is intentional (more generic than `ProxyResponses.buildError`).

Applied to files:

  • tests/unit/proxy/available-models.test.ts
📚 Learning: 2026-01-03T09:08:49.019Z
Learnt from: CR
Repo: ding113/claude-code-hub PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-03T09:08:49.019Z
Learning: Applies to tests/integration/**/*.test.ts : Place integration tests requiring database in `tests/integration/` (excluded by default)

Applied to files:

  • tests/unit/proxy/available-models.test.ts
🧬 Code graph analysis (2)
tests/unit/proxy/available-models.test.ts (1)
src/app/v1/_lib/models/available-models.ts (6)
  • inferOwner (128-136)
  • getProviderTypesForFormat (262-279)
  • formatOpenAIResponse (304-314)
  • FetchedModel (13-17)
  • formatAnthropicResponse (319-329)
  • formatGeminiResponse (334-342)
src/app/v1/_lib/models/available-models.ts (2)
src/app/v1/_lib/proxy/format-mapper.ts (1)
  • ClientFormat (29-29)
src/types/provider.ts (1)
  • Provider (20-113)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: pr-review
  • GitHub Check: Greptile Review
  • GitHub Check: 🌐 API Tests
  • GitHub Check: pr-label
  • GitHub Check: pr-description
  • GitHub Check: Docker Build Test
🔇 Additional comments (10)
src/app/v1/_lib/models/available-models.ts (3)

13-17: LGTM - 导出接口以支持测试

导出 FetchedModel 接口是合理的,使得测试代码可以正确引用类型定义。


128-136: LGTM - 导出工具函数以支持单元测试

导出 inferOwner 函数使得可以独立测试模型所有者推断逻辑,这是良好的测试实践。


262-279: LGTM - 导出映射函数以支持单元测试

导出 getProviderTypesForFormat 函数使得可以独立测试客户端格式到 Provider 类型的映射逻辑。

src/types/models.ts (1)

1-41: LGTM - 类型定义准确完整

新增的类型定义准确地描述了三种 AI 提供商的模型响应格式,为代码提供了良好的类型支持。类型结构与 available-models.ts 中的格式化函数输出一致。

建议将这些类型应用到 formatOpenAIResponseformatAnthropicResponseformatGeminiResponse 函数的返回值类型中(已在 available-models.ts 文件中提出)。

tests/unit/proxy/available-models.test.ts (6)

1-26: LGTM - Mock 配置合理

测试文件正确地 mock 了外部依赖(proxy-agent、repository/key、provider-selector),避免了集成测试复杂性,符合单元测试最佳实践。


27-90: LGTM - inferOwner 测试覆盖全面

测试用例全面覆盖了所有支持的模型提供商(Anthropic、OpenAI、Google、DeepSeek、Alibaba)以及未知模型的场景,测试逻辑清晰,分组合理。


92-112: LGTM - getProviderTypesForFormat 测试完整

测试覆盖了所有 5 种客户端格式(claude、openai、gemini、gemini-cli、response)到 Provider 类型的映射,确保了映射逻辑的正确性。


114-158: LGTM - formatOpenAIResponse 测试全面

测试覆盖了空列表、正常格式化、时间戳验证等场景。特别是对 created 时间戳的边界检查(lines 148-157)很好地验证了时间戳的正确性。


160-197: LGTM - formatAnthropicResponse 测试完整

测试覆盖了空列表、完整字段、缺失字段回退等场景。Line 191-196 的测试很好地验证了 displayName 缺失时使用 id 作为 fallback 的逻辑。


199-242: LGTM - formatGeminiResponse 测试完整

测试覆盖了空列表、正常格式化、models/ 前缀添加、displayName fallback 等场景,全面验证了 Gemini 格式的特殊要求。

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Code Review Summary

This PR adds unit tests for utility functions in available-models.ts. The tests are well-structured and provide good coverage of the targeted functions. However, one issue was identified with unused code.

PR Size: S

  • Lines changed: 295 (289 additions, 6 deletions)
  • Files changed: 3

Issues Found

Category Critical High Medium Low
Logic/Bugs 0 0 1 0
Security 0 0 0 0
Error Handling 0 0 0 0
Types 0 0 0 0
Comments/Docs 0 0 0 0
Tests 0 0 0 0
Simplification 0 0 0 0

Medium Priority Issues

1. [MEDIUM] Unused Type Definitions File (src/types/models.ts:1-41)

Problem: The file src/types/models.ts defines 41 lines of type interfaces (OpenAIModelsResponse, AnthropicModelsResponse, GeminiModelsResponse) but is never imported anywhere in the codebase, including the test file created in this PR. This is dead code that adds maintenance burden without providing value.

Evidence:

  • Searched entire codebase: No imports of @/types/models found
  • The test file imports directly from @/app/v1/_lib/models/available-models instead
  • Violates CLAUDE.md principle of avoiding over-engineering

Suggested Fix:

Option 1 - Delete if not needed:

rm src/types/models.ts

Option 2 - Use the types in tests:

// In tests/unit/proxy/available-models.test.ts
import type { 
  OpenAIModelsResponse, 
  AnthropicModelsResponse, 
  GeminiModelsResponse 
} from '@/types/models';

// Use for type-safe validation instead of inline casting
test('should match OpenAI response type', () => {
  const result: OpenAIModelsResponse = formatOpenAIResponse([{ id: 'gpt-4' }]);
  expect(result.object).toBe('list');
  expect(result.data).toBeDefined();
});

Positive Observations

  • Test coverage is comprehensive for all exported utility functions
  • Test cases cover edge cases (empty arrays, missing optional fields, multiple model types)
  • Mock strategy properly isolates units under test
  • Test descriptions are clear and follow good naming conventions
  • Export modifications are minimal and focused on testability

Review Coverage

  • Logic and correctness - Clean
  • Security (OWASP Top 10) - Clean
  • Error handling - Clean
  • Type safety - Clean
  • Documentation accuracy - Clean
  • Test coverage - Good (covers all exported utilities)
  • Code clarity - Good

Recommendation

The PR is approved pending minor cleanup of the unused src/types/models.ts file. The test implementation is solid and adds valuable coverage to critical utility functions.

If the type definitions are intended for future use, please add a comment explaining their purpose or integrate them into the current implementation. Otherwise, removing them will keep the codebase clean.


Automated review by Claude AI

- inferOwner 返回类型收窄为 ModelOwner 联合类型
- format*Response 函数使用强类型返回值
- 测试文件使用已定义类型替代内联断言
- 修复 Biome 格式检查问题
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/app/v1/_lib/models/available-models.ts (2)

314-324: 修复 TypeScript 字面量类型推断问题。

Pipeline 报错:object: "model" 被推断为 string 类型而非字面量类型 "model",导致类型不匹配。需要使用 as const 断言或显式类型标注来保留字面量类型。

🔎 建议的修复方案
 export function formatOpenAIResponse(models: FetchedModel[]): OpenAIModelsResponse {
   const now = Math.floor(Date.now() / 1000);
   const data = models.map((m) => ({
     id: m.id,
-    object: "model",
+    object: "model" as const,
     created: now,
     owned_by: inferOwner(m.id),
   }));
 
   return { object: "list", data };
 }

329-339: 修复 TypeScript 字面量类型推断问题。

Pipeline 报错:type: "model" 被推断为 string 类型而非字面量类型 "model",导致类型不匹配。需要添加 as const 断言。

🔎 建议的修复方案
 export function formatAnthropicResponse(models: FetchedModel[]): AnthropicModelsResponse {
   const now = new Date().toISOString();
   const data = models.map((m) => ({
     id: m.id,
-    type: "model",
+    type: "model" as const,
     display_name: m.displayName || m.id,
     created_at: m.createdAt || now,
   }));
 
   return { data, has_more: false };
 }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to Reviews > Disable Cache setting

📥 Commits

Reviewing files that changed from the base of the PR and between b41fe6f and eb706e9.

📒 Files selected for processing (2)
  • src/app/v1/_lib/models/available-models.ts
  • tests/unit/proxy/available-models.test.ts
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{ts,tsx,js,jsx,json}

📄 CodeRabbit inference engine (CLAUDE.md)

Use 2-space indentation in all code files

Files:

  • src/app/v1/_lib/models/available-models.ts
  • tests/unit/proxy/available-models.test.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Use double quotes for strings instead of single quotes
Use trailing commas in multi-line structures
Enforce maximum line length of 100 characters
Use path alias @/* to reference files from ./src/* directory

**/*.{ts,tsx,js,jsx}: Use Biome for linting and formatting with 2-space indent, double quotes, trailing commas, and 100 character max line length
Use path alias @/* to reference files in ./src/* directory

Files:

  • src/app/v1/_lib/models/available-models.ts
  • tests/unit/proxy/available-models.test.ts
src/app/v1/_lib/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Guard pipeline must execute in order: ProxyAuthenticator, SensitiveWordGuard, VersionGuard, ProxySessionGuard, ProxyRateLimitGuard, ProxyProviderResolver

Files:

  • src/app/v1/_lib/models/available-models.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use TypeScript strict mode for type safety
Use readonly or const assertions for immutable data structures

Files:

  • src/app/v1/_lib/models/available-models.ts
  • tests/unit/proxy/available-models.test.ts
src/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.ts: Hash API keys using SHA-256 before storing in database, never store plaintext keys
Mask API keys and sensitive data in application logs
Validate required environment variables at startup with clear error messages

Files:

  • src/app/v1/_lib/models/available-models.ts
src/app/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Implement Content-Security-Policy headers for XSS prevention

Files:

  • src/app/v1/_lib/models/available-models.ts
src/app/v1/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Use Hono router for ultrafast, lightweight routing in proxy endpoints

Files:

  • src/app/v1/_lib/models/available-models.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Vitest for unit testing with Node environment, coverage thresholds: 50% lines/functions, 40% branches

Files:

  • tests/unit/proxy/available-models.test.ts
**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

Ensure test database names contain 'test' keyword for safety validation

Files:

  • tests/unit/proxy/available-models.test.ts
🧠 Learnings (1)
📚 Learning: 2026-01-03T09:09:37.748Z
Learnt from: NieiR
Repo: ding113/claude-code-hub PR: 517
File: src/app/v1/_lib/models/available-models.ts:45-70
Timestamp: 2026-01-03T09:09:37.748Z
Learning: The `authenticateRequest` function in `src/app/v1/_lib/models/available-models.ts` is intentionally a lightweight version of authentication, specifically designed for the `/v1/models` endpoint. It does not need to check for multi-source conflicts or use the full `ProxyAuthenticator` logic, as the scenario is simpler. The JSON error response format is intentional (more generic than `ProxyResponses.buildError`).

Applied to files:

  • src/app/v1/_lib/models/available-models.ts
  • tests/unit/proxy/available-models.test.ts
🧬 Code graph analysis (2)
src/app/v1/_lib/models/available-models.ts (2)
src/app/v1/_lib/proxy/format-mapper.ts (1)
  • ClientFormat (29-29)
src/types/models.ts (3)
  • OpenAIModelsResponse (7-10)
  • AnthropicModelsResponse (20-23)
  • GeminiModelsResponse (33-35)
tests/unit/proxy/available-models.test.ts (2)
src/app/v1/_lib/models/available-models.ts (6)
  • inferOwner (138-146)
  • getProviderTypesForFormat (272-289)
  • formatOpenAIResponse (314-324)
  • FetchedModel (18-22)
  • formatAnthropicResponse (329-339)
  • formatGeminiResponse (344-352)
src/types/models.ts (3)
  • OpenAIModelsResponse (7-10)
  • AnthropicModelsResponse (20-23)
  • GeminiModelsResponse (33-35)
🪛 GitHub Actions: 🧪 Test Suite
src/app/v1/_lib/models/available-models.ts

[error] 323-323: TS2322: Type '{ id: string; object: string; created: number; owned_by: ModelOwner; }[]' is not assignable to type 'OpenAIModel[]'. Type '{ id: string; object: string; created: number; owned_by: ModelOwner; }' is not assignable to type 'OpenAIModel'. Types of property 'object' are incompatible. Type 'string' is not assignable to type '"model"'.


[error] 338-338: TS2322: Type '{ id: string; type: string; display_name: string; created_at: string; }[]' is not assignable to type 'AnthropicModel[]'. Type '{ id: string; type: string; display_name: string; created_at: string; }' is not assignable to type 'AnthropicModel'. Types of property 'type' are incompatible. Type 'string' is not assignable to type '"model"'.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Docker Build Test
🔇 Additional comments (9)
tests/unit/proxy/available-models.test.ts (6)

1-30: 测试设置正确,依赖模拟合理。

Mock 设置恰当地隔离了被测试的工具函数,避免了导入依赖带来的副作用。导入语句清晰,正确使用了路径别名和类型导入。


32-95: inferOwner 测试覆盖全面。

测试用例涵盖了所有支持的模型所有者(Anthropic、OpenAI、Google、DeepSeek、Alibaba)以及未知模型的降级处理,测试数据真实且具有代表性。


97-117: getProviderTypesForFormat 测试覆盖完整。

测试覆盖了所有客户端格式(claude、openai、gemini、gemini-cli、response)到 Provider 类型的映射,验证逻辑正确。


119-158: formatOpenAIResponse 测试设计良好。

测试用例覆盖了空列表、多模型格式化、时间戳生成等场景,并正确使用了导入的 OpenAIModelsResponse 类型。先前关于类型使用的审查意见已得到妥善处理。


160-196: formatAnthropicResponse 测试覆盖全面。

测试验证了空列表处理、可选字段(displayName、createdAt)的处理以及降级逻辑,类型使用正确。


198-231: formatGeminiResponse 测试逻辑完整。

测试覆盖了 Gemini 格式的特殊要求(models/ 前缀、displayName 降级、supportedGenerationMethods 字段),验证全面。

src/app/v1/_lib/models/available-models.ts (3)

6-10: 类型导入正确,增强类型安全性。

@/types/models 导入响应类型定义,使函数返回值具有明确的类型约束,符合 TypeScript 严格模式要求。


18-22: 导出接口与类型定义合理,支持单元测试。

FetchedModelModelOwner 类型以及 inferOwnergetProviderTypesForFormat 等工具函数导出,既增强了类型安全性(inferOwner 返回类型从 string 收窄为 ModelOwner),又便于编写单元测试。

Also applies to: 130-146, 272-289


344-352: formatGeminiResponse 类型定义正确。

函数返回类型更新为 GeminiModelsResponse,增强了类型安全性,实现逻辑无误。

@ding113 ding113 merged commit 39ec130 into ding113:dev Jan 4, 2026
21 of 22 checks passed
@github-project-automation github-project-automation bot moved this from Backlog to Done in Claude Code Hub Roadmap Jan 4, 2026
@NieiR NieiR deleted the test/available-models-utils-tests branch January 6, 2026 13:21
This was referenced Jan 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core enhancement New feature or request size/S Small PR (< 200 lines)

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants