Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[codex] feat(ai plugin): support custom request options#534

Open
jn12-29 wants to merge 2 commits into
ZToolsCenter:main from
jn12-29:codex/ai-request-options
Open

[codex] feat(ai plugin): support custom request options #534
jn12-29 wants to merge 2 commits into
ZToolsCenter:main from
jn12-29:codex/ai-request-options

Conversation

@jn12-29

@jn12-29 jn12-29 commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds per-request AI options for plugin calls:

  • passes custom headers through to the OpenAI SDK request options
  • passes extraBody fields into chat completion request bodies
  • keeps runtime-owned fields (model, messages, tools, stream) protected from extraBody overrides

Validation

  • pnpm run typecheck:node
  • pnpm build:unpack
  • node _work/2026-06-08-ai-extra-body/verify-ai-extra-body-dev.js
  • git -C _work/pr-ai-extra-body-submit diff --check upstream/main..HEAD

gemini-code-assist[bot] reacted with eyes emoji
Add new fields `headers` and `extraBody` to AiOption interface to allow passing custom request headers and additional OpenAI-compatible request body parameters. Implement normalization logic for headers and extra body, filter out reserved keys from extra body, and apply them to both streaming and non-streaming AI API calls.
@jn12-29 jn12-29 marked this pull request as ready for review June 7, 2026 17:18
Copilot AI review requested due to automatic review settings June 7, 2026 17:18

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for custom headers and extra OpenAI-compatible request body fields (extraBody) in the AI plugin API. It adds validation and normalization helpers (isPlainObject, normalizeHeaders, and normalizeExtraBody) to process these inputs before passing them to the OpenAI client. The review feedback suggests improving the robustness of these helpers by implementing stricter plain object validation, handling null values safely, and preventing the stringification of null or undefined header values.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/main/api/plugin/ai.ts
Comment on lines +234 to +261
private isPlainObject(value: unknown): value is Record<string, unknown> {
return Boolean(value && typeof value === 'object' && !Array.isArray(value))
}

private normalizeHeaders(headers: unknown): Record<string, string> | undefined {
if (headers === undefined) return undefined
if (!this.isPlainObject(headers)) {
throw new Error('headers 必须是对象')
}

const normalized = Object.fromEntries(
Object.entries(headers).map(([key, value]) => [key, String(value)])
)
return Object.keys(normalized).length > 0 ? normalized : undefined
}

private normalizeExtraBody(extraBody: unknown): Record<string, unknown> | undefined {
if (extraBody === undefined) return undefined
if (!this.isPlainObject(extraBody)) {
throw new Error('extraBody 必须是对象')
}

const normalized = { ...extraBody }
for (const key of RESERVED_EXTRA_BODY_KEYS) {
delete normalized[key]
}
return Object.keys(normalized).length > 0 ? normalized : undefined
}

@gemini-code-assist gemini-code-assist Bot Jun 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

There are a few areas where robustness and correctness can be improved:

  1. Stricter Plain Object Validation: The current isPlainObject implementation returns true for instances of Date, RegExp, Map, Set, etc. Checking the prototype using Object.getPrototypeOf ensures only plain objects are accepted.
  2. Defensive Programming (Null Safety): The current checks only handle undefined. If null is passed (which is common in JSON/IPC payloads), it will fail the isPlainObject check and throw an error. Using == null safely handles both null and undefined.
  3. Header Stringification Pitfall: Using String(value) directly on object entries can convert null or undefined values to "null" or "undefined" strings, which will be sent as actual header values. It is safer to filter out null and undefined values before stringifying.
 private isPlainObject(value: unknown): value is Record<string, unknown> {
 if (typeof value !== 'object' || value === null) return false
 const proto = Object.getPrototypeOf(value)
 return proto === null || proto === Object.prototype
 }
 private normalizeHeaders(headers: unknown): Record<string, string> | undefined {
 if (headers == null) return undefined
 if (!this.isPlainObject(headers)) {
 throw new Error('headers 必须是对象')
 }
 const normalized: Record<string, string> = {}
 for (const [key, value] of Object.entries(headers)) {
 if (value !== null && value !== undefined) {
 normalized[key] = String(value)
 }
 }
 return Object.keys(normalized).length > 0 ? normalized : undefined
 }
 private normalizeExtraBody(extraBody: unknown): Record<string, unknown> | undefined {
 if (extraBody == null) return undefined
 if (!this.isPlainObject(extraBody)) {
 throw new Error('extraBody 必须是对象')
 }
 const normalized = { ...extraBody }
 for (const key of RESERVED_EXTRA_BODY_KEYS) {
 delete normalized[key]
 }
 return Object.keys(normalized).length > 0 ? normalized : undefined
 }

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

Note

Copilot was unable to run its full agentic suite in this review.

This PR extends the plugin AI API to allow callers to pass additional HTTP headers and OpenAI-compatible extra request body fields, forwarding them through the OpenAI SDK request.

Changes:

  • Added headers and extraBody to AiOption.
  • Added normalization helpers to validate/normalize headers and extra body fields.
  • Wired headers and extraBody into both non-streaming and streaming chat completion requests.

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

Comment thread src/main/api/plugin/ai.ts Outdated
Comment on lines +234 to +246
private isPlainObject(value: unknown): value is Record<string, unknown> {
return Boolean(value && typeof value === 'object' && !Array.isArray(value))
}

private normalizeHeaders(headers: unknown): Record<string, string> | undefined {
if (headers === undefined) return undefined
if (!this.isPlainObject(headers)) {
throw new Error('headers 必须是对象')
}

const normalized = Object.fromEntries(
Object.entries(headers).map(([key, value]) => [key, String(value)])
)
Comment thread src/main/api/plugin/ai.ts
const client = this.createClient(modelConfig)
const openaiTools = option.tools?.length ? this.convertTools(option.tools) : undefined
const messages = [...option.messages]
const requestHeaders = this.normalizeHeaders(option.headers)
Comment thread src/main/api/plugin/ai.ts
Comment on lines 367 to +377
const response = await client.chat.completions.create(
{
...extraBody,
model: modelConfig.id,
messages: this.convertMessages(messages),
...(openaiTools?.length ? { tools: openaiTools } : {})
},
{ signal: abortController.signal }
{
signal: abortController.signal,
...(requestHeaders ? { headers: requestHeaders } : {})
}
Comment thread src/main/api/plugin/ai.ts
Comment on lines +250 to +261
private normalizeExtraBody(extraBody: unknown): Record<string, unknown> | undefined {
if (extraBody === undefined) return undefined
if (!this.isPlainObject(extraBody)) {
throw new Error('extraBody 必须是对象')
}

const normalized = { ...extraBody }
for (const key of RESERVED_EXTRA_BODY_KEYS) {
delete normalized[key]
}
return Object.keys(normalized).length > 0 ? normalized : undefined
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

Copilot code review Copilot Copilot left review comments

+1 more reviewer

@gemini-code-assist gemini-code-assist[bot] gemini-code-assist[bot] left review comments

Reviewers whose approvals may not affect merge requirements

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

2 participants

AltStyle によって変換されたページ (->オリジナル) /