code-yeongyu / code-yeongyu/senpi

OpenAI-completions tools lose root type object when parameters use oneOf/anyOf (Console Go 400)

Open
#710 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
429
Forks
98
Avg merge
5h 3m
Merged PRs (30d)
526

Description

### Summary

Function tools whose `parameters` schema uses a combiner (`anyOf` / `oneOf` / `allOf`) are sent to OpenAI-compatible backends without the root `type: "object"` marker. `normalizeToolParametersForOpenAICompat` moves the root `type` into combiner branches and then deletes it (`moveTypeIntoCombinerBranches` in `packages/ai/src/utils/tool-schema-compat.ts`).

Gateways backed by Gemini-style validation (e.g. OpenCode Go / Zen proxying to Console) reject the first request:

```text
Error: 400: {"param":null,"type":"invalid_request_error","code":"invalid_request_error","message":"Error from provider (Console Go): Upstream request failed: [invalid_request_error] Invalid schema for function 'mcp__ast_grep_scan': schema must be a JSON Schema of 'type: \"object\"', got 'type: null'."}
```

### Reproduction

1. Use the ast-grep MCP `scan` tool, whose parameters schema is `type: "object"` plus a `oneOf` (ruleFile XOR inlineRules) contract.
2. Start a chat with any `opencode-go` model (for example `deepseek-v4-flash`).
3. The first request fails with the 400 above.

Verified locally: `normalizeToolParametersForOpenAICompat(scanSchema)` drops the top-level `type`, while `search` / `rewrite` (no combiner) keep it.

### Root cause

`moveTypeIntoCombinerBranches` deletes the parent `type` for every combiner schema. That behavior exists for Moonshot-flavored backends (Apitopia → Kimi / Moonshot), but OpenAI Chat Completions requires every function's `parameters` root to be a JSON Schema of `type: "object"`, and the Gemini-backed Console gateways enforce the same.

### Suggested fix

Restore the root `type: "object"` marker at the OpenAI-completions wire boundary (`convertTools` and `normalizeRequestToolSchemas`) instead of changing the Moonshot-flavored normalizer behavior. A PR with tests for both conversion paths is attached.

Contributor guide

Open the contributing guide

Research direction

Start in packages/ai/src/utils/tool-schema-compat.ts, especially moveTypeIntoCombinerBranches, then trace the OpenAI-completions wire paths through convertTools and normalizeRequestToolSchemas. Add tests covering both conversion paths, confirming combiner schemas retain the root type: "object" while the existing Moonshot-flavored normalization behavior remains unchanged.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.