Skip to content

正确转发 Usage 数据#2

Open
kazaff wants to merge 3 commits into
xiaoshaoning:mainfrom
kazaff:main
Open

正确转发 Usage 数据#2
kazaff wants to merge 3 commits into
xiaoshaoning:mainfrom
kazaff:main

Conversation

@kazaff
Copy link
Copy Markdown

@kazaff kazaff commented May 27, 2026

用于让 CC-Switch 类的下游应用可以拿到完整正确的响应结果。

kazaff added 2 commits May 27, 2026 11:09
feat(proxy): add TypeScript implementation of DeepSeek proxy server

Add a complete TypeScript proxy server that converts OpenAI Responses API
requests to DeepSeek Chat Completions API. This includes support for
streaming/non-streaming responses, tool/function call conversions, and
XML function call parsing.

- Convert OpenAI Responses API requests to DeepSeek Chat Completions format
- Support both streaming and non-streaming responses
- Handle tool/function call conversions
- Parse XML function calls from DeepSeek responses
- Map model names between OpenAI and DeepSeek
- Provide health check endpoint
- Implement graceful shutdown with signal handling

Add AGENTS.md documentation covering project overview, features,
API endpoints, environment variables, and development instructions.

chore(converter): add usage conversion function for DeepSeek responses

Add convert_deepseek_usage_to_responses function to properly map
DeepSeek usage metrics (prompt_tokens, completion_tokens, total_tokens)
to the expected response format. Apply this conversion across all
response types including tool calls and regular responses.
```
@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Fix usage data conversion and forwarding in DeepSeek proxy

🐞 Bug fix ✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add convert_deepseek_usage_to_responses() function to properly map DeepSeek usage metrics to
  OpenAI Responses API format
• Apply usage conversion across all response types (tool calls, regular, XML-based)
• Pass usage data from DeepSeek stream chunks to StreamChunk output
• Add comprehensive AGENTS.md documentation for TypeScript proxy server
Diagram
flowchart LR
  A["DeepSeek Response<br/>with usage"] -->|convert_deepseek_usage_to_responses| B["Mapped Usage<br/>prompt_tokens → input_tokens"]
  B -->|apply to all responses| C["Tool Calls Response"]
  B -->|apply to all responses| D["Regular Response"]
  B -->|apply to all responses| E["XML Tool Calls"]
  B -->|apply to stream chunks| F["Stream Chunk Output"]
  C -->|OpenAI Responses API| G["Downstream Apps"]
  D -->|OpenAI Responses API| G
  E -->|OpenAI Responses API| G
  F -->|OpenAI Responses API| G

Loading

Grey Divider

File Changes

1. src/converter.ts 🐞 Bug fix +20/-6

Implement proper usage data conversion and forwarding

• Add new convert_deepseek_usage_to_responses() function to map DeepSeek usage metrics
 (prompt_tokens, completion_tokens, total_tokens) to OpenAI format (input_tokens, output_tokens,
 total_tokens)
• Apply usage conversion in convert_tool_calls_response() for both empty and non-empty tool calls
 cases
• Apply usage conversion in convert_regular_response() for standard responses
• Apply usage conversion in convert_tool_calls_from_xml() for XML-parsed tool calls
• Pass usage field from stream chunks to convert_stream_chunk() output in both response paths

src/converter.ts


2. AGENTS.md 📝 Documentation +56/-0

Add comprehensive proxy server documentation

• Create new documentation file for the TypeScript DeepSeek proxy server
• Document project overview, key features, and API endpoints
• List environment variables (DEEPSEEK_API_KEY, OPENAI_API_KEY, SHUTDOWN_SECRET)
• Provide development setup and code style guidelines
• Include instructions for running the server in production and development modes

AGENTS.md


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented May 27, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (1)

Grey Divider


Action required

1. convert_deepseek_usage_to_responses uses any 📘 Rule violation ⚙ Maintainability
Description
The newly added convert_deepseek_usage_to_responses(usage: any): any bypasses strict TypeScript
typing by introducing any in both parameter and return types. This weakens type safety and can
mask schema/field mismatches at compile time.
Code

src/converter.ts[R727-736]

Evidence
PR Compliance ID 1 requires strict typing and disallows weakening type checks via any. The added
helper function explicitly declares both its input and output as any, directly bypassing strict
typing.

CLAUDE.md: Use TypeScript strict typing
src/converter.ts[727-736]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
New code introduces `any` types (`usage: any` and return `any`) in `convert_deepseek_usage_to_responses`, which weakens strict typing guarantees.

## Issue Context
The project compliance requires strict TypeScript typing; this helper can be typed with a small interface/type describing DeepSeek usage input and the normalized Responses usage output.

## Fix Focus Areas
- src/converter.ts[727-736]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. SSE usage变成0 🐞 Bug ≡ Correctness
Description
convert_deepseek_usage_to_responses 将 usage 字段从 DeepSeek 的 prompt_tokens/completion_tokens 改为
input_tokens/output_tokens,但 streaming.ts 的 build_completed_event 仍只读取
prompt_tokens/completion_tokens。结果是在“非流式响应被包装成模拟 SSE”时,response.completed 会输出全 0 的 usage。
Code

src/converter.ts[R727-735]

Evidence
converter.ts 已把 usage 键名转换为 input_tokens/output_tokens;但 streaming.ts 的 build_completed_event 仍只从
prompt_tokens/completion_tokens 读取,并且 generate_simulated_sse 将 responses_response.usage 直接传入该函数,因此模拟
SSE 完成事件会拿不到 token 数。

src/converter.ts[727-736]
src/converter.ts[904-920]
src/streaming.ts[560-575]
src/streaming.ts[596-612]
src/streaming.ts[614-708]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
非流式转换后的 `responses_response.usage` 现在是 `{input_tokens, output_tokens, total_tokens}`,但 `streaming.ts` 的 `build_completed_event()` 仍按 `{prompt_tokens, completion_tokens, total_tokens}` 映射,导致模拟 SSE 的 `response.completed` usage 归零。

## Issue Context
- `convert_deepseek_usage_to_responses()` 将 DeepSeek usage 键名改成 Responses usage。
- `handle_non_streaming_response()` 在 `original_request.stream=true` 时会调用 `generate_simulated_sse(responses_response, ...)`。
- `generate_simulated_sse()` 把 `responses_response.usage` 传给 `build_completed_event()`,但后者只读取 `prompt_tokens/completion_tokens`。

## Fix Focus Areas
- src/streaming.ts[596-612]
- src/streaming.ts[614-708]

## Suggested fix
在 `build_completed_event(response_id, usage)` 中同时兼容两套字段:
- 若存在 `usage.input_tokens`/`usage.output_tokens`,直接使用它们
- 否则回退到 `usage.prompt_tokens`/`usage.completion_tokens`
并保证 `total_tokens` 也按同样逻辑取值。这样模拟 SSE 与真实 streaming 两条路径都能得到正确 usage。

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Advisory comments

3. 缺少文件末尾换行 🐞 Bug ⚙ Maintainability
Description
新增的 AGENTS.md 文件末尾缺少换行符,会导致后续编辑产生噪声 diff,并可能触发部分格式化/检查工具告警。
Code

AGENTS.md[R49-56]

Evidence
PR diff 明确标注了该文件“末尾无换行”。

AGENTS.md[49-56]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
AGENTS.md 末尾没有以换行符结尾(git diff 已提示)。

## Fix Focus Areas
- AGENTS.md[49-56]

## Suggested fix
在文件最后一行后补充一个换行符并重新提交。

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread src/converter.ts
Comment on lines +727 to +736
export function convert_deepseek_usage_to_responses(usage: any): any {
if (!usage || typeof usage !== 'object') {
return { input_tokens: 0, output_tokens: 0, total_tokens: 0 };
}
return {
input_tokens: usage.prompt_tokens ?? 0,
output_tokens: usage.completion_tokens ?? 0,
total_tokens: usage.total_tokens ?? 0
};
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. convert_deepseek_usage_to_responses uses any 📘 Rule violation ⚙ Maintainability

The newly added convert_deepseek_usage_to_responses(usage: any): any bypasses strict TypeScript
typing by introducing any in both parameter and return types. This weakens type safety and can
mask schema/field mismatches at compile time.
Agent Prompt
## Issue description
New code introduces `any` types (`usage: any` and return `any`) in `convert_deepseek_usage_to_responses`, which weakens strict typing guarantees.

## Issue Context
The project compliance requires strict TypeScript typing; this helper can be typed with a small interface/type describing DeepSeek usage input and the normalized Responses usage output.

## Fix Focus Areas
- src/converter.ts[727-736]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread src/converter.ts
Comment on lines +727 to +735
export function convert_deepseek_usage_to_responses(usage: any): any {
if (!usage || typeof usage !== 'object') {
return { input_tokens: 0, output_tokens: 0, total_tokens: 0 };
}
return {
input_tokens: usage.prompt_tokens ?? 0,
output_tokens: usage.completion_tokens ?? 0,
total_tokens: usage.total_tokens ?? 0
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

2. Sse usage变成0 🐞 Bug ≡ Correctness

convert_deepseek_usage_to_responses 将 usage 字段从 DeepSeek 的 prompt_tokens/completion_tokens 改为
input_tokens/output_tokens,但 streaming.ts 的 build_completed_event 仍只读取
prompt_tokens/completion_tokens。结果是在“非流式响应被包装成模拟 SSE”时,response.completed 会输出全 0 的 usage。
Agent Prompt
## Issue description
非流式转换后的 `responses_response.usage` 现在是 `{input_tokens, output_tokens, total_tokens}`,但 `streaming.ts` 的 `build_completed_event()` 仍按 `{prompt_tokens, completion_tokens, total_tokens}` 映射,导致模拟 SSE 的 `response.completed` usage 归零。

## Issue Context
- `convert_deepseek_usage_to_responses()` 将 DeepSeek usage 键名改成 Responses usage。
- `handle_non_streaming_response()` 在 `original_request.stream=true` 时会调用 `generate_simulated_sse(responses_response, ...)`。
- `generate_simulated_sse()` 把 `responses_response.usage` 传给 `build_completed_event()`,但后者只读取 `prompt_tokens/completion_tokens`。

## Fix Focus Areas
- src/streaming.ts[596-612]
- src/streaming.ts[614-708]

## Suggested fix
在 `build_completed_event(response_id, usage)` 中同时兼容两套字段:
- 若存在 `usage.input_tokens`/`usage.output_tokens`,直接使用它们
- 否则回退到 `usage.prompt_tokens`/`usage.completion_tokens`
并保证 `total_tokens` 也按同样逻辑取值。这样模拟 SSE 与真实 streaming 两条路径都能得到正确 usage。

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

feat(security): sanitize sensitive data from logs

- Disable full request logging in converter.ts that could contain sensitive data
- Implement header sanitization in server.ts to redact authorization,
  x-api-key, and shutdown secrets with truncated values
- Remove debug file writing functionality that could leak sensitive data
- Disable message logging in streaming.ts that could expose sensitive information
```
@xiaoshaoning xiaoshaoning force-pushed the main branch 2 times, most recently from 9a8b70b to 7738511 Compare May 29, 2026 15:14
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