Skip to content

feat: 支持自定义 JSON 请求体#218

Open
ZRHann wants to merge 1 commit into
Bistutu:mainfrom
ZRHann:feature/custom-request-body
Open

feat: 支持自定义 JSON 请求体#218
ZRHann wants to merge 1 commit into
Bistutu:mainfrom
ZRHann:feature/custom-request-body

Conversation

@ZRHann

@ZRHann ZRHann commented Jun 4, 2026

Copy link
Copy Markdown

背景

实现 #213:当前各 AI 服务的请求体是写死的(如 commonMsgTemplate 固定输出 {model, temperature, messages}),无法追加服务商特定的字段。典型场景是 Kimi(K2.5 / K2.6)的「思考开关」——思考与非思考模式共用同一个模型名,靠请求体顶层的 thinking 字段控制({"type":"enabled"} / {"type":"disabled"}),现有自定义接口无法设置它。

改动

新增按服务保存的「自定义请求体」配置,会以顶层浅合并、用户字段优先的方式合并进请求体:

  • Config.customBodyentrypoints/utils/model.ts):按服务存储的 JSON 字符串。
  • mergeCustomBody()entrypoints/utils/template.ts):纯函数,解析用户 JSON 并合并进 payload;空字符串 / 非法 JSON 自动忽略,绝不影响正常翻译。已接入全部消息模板(common / deepseek / gemini / claude / tongyi / yiyan / minimax / coze),因此对所有 AI 服务生效(含「自定义接口」)。
  • 设置 UIcomponents/Main.vue):在「自定义模型」下方新增「自定义请求体」输入框,带 JSON 合法性校验(非法时红框提示并被忽略),并在配置导出时清理空值。

用法示例(Kimi 关闭思考)

「自定义请求体」填:

{"thinking": {"type": "disabled"}}

最终发出的请求体:

{"model":"kimi-k2.6","temperature":1,"messages":[...],"thinking":{"type":"disabled"}}

测试

引入 Vitest(项目此前无测试框架),新增 tests/template.test.ts,共 18 个用例,覆盖:

  • mergeCustomBody 的合并 / 覆盖 / 嵌套对象 / 空值 / 非法 JSON / 数组与基本类型拒绝等边界;
  • commonMsgTemplate 在有 / 无自定义请求体下的输出,以及 thinking 字段注入。
pnpm test   # 18 passed
pnpm build  # 构建通过

说明

  • 引入 vitest 会带入第二份 vite,导致 vue-tscwxt.config.ts 上出现类型冲突;故在 package.json 加了 pnpm.overrides.vite,固定为项目原本的 5.4.11 做去重,对运行时构建无影响。

Closes #213

Summary by Sourcery

Add per-service configurable JSON request body that is shallow-merged into all AI service payloads, expose it in the UI, and introduce a Vitest test setup to cover the new merging logic and templates.

New Features:

  • Allow configuring a per-service custom JSON request body that is shallow-merged into AI request payloads with user fields taking precedence.
  • Expose a "自定义请求体" input in the main UI for custom models, with inline JSON validation and omission of empty values from exported config.

Enhancements:

  • Wire the custom request body merging into all existing message templates so it applies uniformly across all AI services, including custom endpoints.

Build:

  • Add Vitest configuration and npm scripts for running tests, along with a pnpm vite override to avoid version conflicts.

Tests:

  • Introduce a Vitest-based test suite for the template utilities, covering custom body merging behavior and common message template outputs.

新增按服务保存的「自定义请求体」配置,以顶层浅合并(用户字段优先)的方式追加到各 AI 服务的请求体中,可用于补充服务商需要的额外参数(如 thinking 等控制字段)。

- model: Config 新增 customBody 字段
- template: 新增 mergeCustomBody 辅助函数,接入全部消息模板(覆盖所有 AI 服务);空/非法 JSON 自动忽略,不影响翻译
- ui: 设置页「自定义模型」下方新增「自定义请求体」输入框,含 JSON 校验与导出清理
- test: 引入 Vitest,覆盖 mergeCustomBody 与 commonMsgTemplate

相关 issue: Bistutu#213

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@sourcery-ai

sourcery-ai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds per-service configurable custom JSON request bodies that are shallow-merged into all AI service payloads, wires this into the UI and config model, and introduces Vitest-based tests (plus tooling tweaks) to verify the merge logic and templates.

Sequence diagram for applying custom JSON body to AI request

sequenceDiagram
    actor User
    participant MainVue as Main_vue
    participant Config as Config
    participant Template as commonMsgTemplate
    participant Merge as mergeCustomBody
    participant Service as AI_service

    User->>MainVue: Edit config.customBody[config.service]
    MainVue->>Config: Persist customBody per service

    User->>Template: commonMsgTemplate(origin)
    Template->>Config: Read config.service
    Template->>Config: Read config.customBody[config.service]
    Template->>Merge: mergeCustomBody(payload, currentCustomBody())
    Merge-->>Template: merged payload
    Template->>Service: JSON.stringify(merged payload)
Loading

File-Level Changes

Change Details Files
Introduce mergeCustomBody helper and apply it across all message templates to support per-service custom request body fields.
  • Add mergeCustomBody(payload, raw) to parse a JSON string, validate it is a plain object, and shallow-merge it into the base payload with user fields taking precedence.
  • Add currentCustomBody() to read the active service’s customBody JSON from config and return it for use in templates.
  • Refactor all message template builders to create a payload object, then JSON.stringify(mergeCustomBody(payload, currentCustomBody())).
entrypoints/utils/template.ts
Extend configuration model to store custom JSON bodies per service and initialize defaults.
  • Add customBody mapping field to Config class to hold per-service JSON strings for extra request payload fields.
  • Initialize Config.customBody to an empty object in the constructor so it is always defined.
entrypoints/utils/model.ts
Add UI for editing per-service custom request body JSON with validation and export-time cleanup.
  • Insert a new UI row under custom model settings to input a JSON object string that will be merged into the request body for the current service.
  • Implement isValidCustomBody to treat empty strings as valid and otherwise ensure the value parses to a non-array object, driving error styling and helper text.
  • Update handleExport to strip empty customBody entries and remove the customBody object entirely if it becomes empty before exporting config.
components/Main.vue
Introduce Vitest test setup and add tests for mergeCustomBody and templates, plus align Vite versions to avoid type conflicts.
  • Add vitest and related scripts (test, test:watch) plus a pnpm.vite override in package.json to dedupe Vite to 5.4.11.
  • Create vitest.config.ts with alias configuration matching wxt ("@" → project root) and Node test environment, scoping tests to tests/**/*.test.ts.
  • Add tests/template.test.ts to cover mergeCustomBody behaviors and ensure commonMsgTemplate (and related scenarios like thinking field injection) work with and without custom request bodies.
  • Update pnpm-lock.yaml to reflect new dev dependency graph.
package.json
vitest.config.ts
tests/template.test.ts
pnpm-lock.yaml

Assessment against linked issues

Issue Objective Addressed Explanation
#213 Support specifying a per-service custom JSON request body that is merged into the AI request payload so that additional top-level fields (e.g., thinking) can be sent.
#213 Expose configuration for this custom JSON request body in the UI / config so users can set it for services like Kimi and have it persist in imports/exports.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot 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.

Hey - I've left some high level feedback:

  • In mergeCustomBody, consider avoiding mutation of the payload argument (e.g., return a new merged object) so callers don’t need to reason about in-place side effects and it’s easier to reuse in different contexts.
  • The JSON-object validation logic for customBody is duplicated between isValidCustomBody and mergeCustomBody; you could extract a shared helper (e.g., parseCustomBody) to keep the rules consistent and reduce maintenance overhead.
  • In Main.vue, the v-model="config.customBody[config.service]" will throw if config.customBody is undefined; it might be safer to ensure customBody is always initialized in the reactive config or to guard this access in the template/computed.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `mergeCustomBody`, consider avoiding mutation of the `payload` argument (e.g., return a new merged object) so callers don’t need to reason about in-place side effects and it’s easier to reuse in different contexts.
- The JSON-object validation logic for customBody is duplicated between `isValidCustomBody` and `mergeCustomBody`; you could extract a shared helper (e.g., `parseCustomBody`) to keep the rules consistent and reduce maintenance overhead.
- In `Main.vue`, the `v-model="config.customBody[config.service]"` will throw if `config.customBody` is undefined; it might be safer to ensure `customBody` is always initialized in the reactive config or to guard this access in the template/computed.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

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.

[功能请求] 自定义json请求体

1 participant