Skip to content

fix(api): generateObject forwards serviceTier and customModelParams - #688

Draft
jddunn wants to merge 5 commits into
masterfrom
fix/generate-object-service-tier
Draft

jddunn wants to merge 5 commits into
masterfrom
fix/generate-object-service-tier

Conversation

@jddunn

@jddunn jddunn commented Nov 1, 2026 •

Copy link
Copy Markdown
Member

Summary

generateText() and streamText() take serviceTier and customModelParams and send them to the provider. generateObject() takes neither, so a structured call cannot ask for a service tier or pass a provider field the typed options do not model.

Input: generateObject({ model: 'openai:gpt-6-luna', schema, prompt, serviceTier: 'priority' }). The Chat Completions request OpenAI receives has no service_tier, because generateObject() builds its generateText() call from a fixed list of options and these two are not on it.

Change: GenerateObjectOptions gains serviceTier and customModelParams, and each attempt's generateText() call forwards them, a validation retry included. They reach the provider exactly as they do from generateText() (fallback legs get customModelParams by the same rules). The TSDoc and the options table in docs/orchestration/STRUCTURED_OUTPUT_API.md describe them.

Vendor facts: OpenAI's Chat Completions reference describes service_tier as the processing type for the request, with auto (the project's setting, the default when unset), default, flex and priority, and says the response reports the tier that served it: https://developers.openai.com/api/reference/resources/chat/subresources/completions/methods/create

Type of change

  • Bug fix
  • Tests
  • Documentation

How this was verified

src/api/runtime/__tests__/generateObject.serviceTier.e2e.test.ts drives generateObject() through the real OpenAIProvider with only fetch stubbed and reads the request body OpenAI would receive: service_tier and the customModelParams fields are on the first request and on a validation retry, and no service_tier is sent when the call names none. A generateText() case with the same options is the reference. The first push carries the tests alone and fails at those assertions; the second carries the fix. CI runs the whole suite.

Checklist

  • Tests cover the changed behavior.
  • Docs are updated.
  • The title follows Conventional Commits.
  • No secrets or private data are included.
  • Every automated review thread is settled.
  • I have read this change and can explain every line.

Summary by CodeRabbit

  • New Features
    • generateObject() now accepts serviceTier and provider-specific request parameters, giving you more control over generated responses.
    • These options are included on each generation attempt, including validation retries.
  • Documentation
    • Updated the guides to explain how these options work with generateObject(), retries, and fallback providers.

@coderabbitai

coderabbitai Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 738e571 and dd685a7.

Files selected for processing: 4
  • docs/features/PROMPT_CACHING.md
  • docs/orchestration/STRUCTURED_OUTPUT_API.md
  • src/api/generateObject.ts
  • src/api/runtime/__tests__/generateObject.serviceTier.e2e.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 3 remain after this review.

Walkthrough

generateObject() now accepts serviceTier and customModelParams and forwards defined values to generateText() on each attempt. Documentation and end-to-end tests describe and check the request fields, including behavior during validation retries.

Changes: generateObject Request Options

Layer / File(s) Summary
Option contract, forwarding, and validation
src/api/generateObject.ts, src/api/runtime/__tests__/generateObject.serviceTier.e2e.test.ts, docs/orchestration/STRUCTURED_OUTPUT_API.md, docs/features/PROMPT_CACHING.md
GenerateObjectOptions adds serviceTier and customModelParams. generateObject() forwards defined values on each attempt. Documentation and tests cover request fields, validation retries, and omission of service_tier when no tier is set.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Possibly related PRs

  • framerslab/agentos#568: Changes Anthropic structured-output routing for customModelParams tool settings, which this change exposes through generateObject().
  • framerslab/agentos#563: Changes Anthropic structured-output route selection and handling of passthrough request settings used by generateObject().
  • framerslab/agentos#558: Changes Anthropic structured-output routing and request overrides in the provider pipeline used by generateObject().
Merge Risk: Minimal · previous review dd685

No merge-blocking issue was identified in the new option forwarding.

Pre-merge checks: Passed 5
Check name Status Explanation
Title check Passed The title "fix(api): generateObject forwards serviceTier and customModelParams" names the main change. The changeset adds both options to GenerateObjectOptions and forwards them to generateText() on e…
Description check Passed The description covers the summary, the type of change, verification, and the checklist. It explains the problem, the fix, and the vendor reference. It names the tests and how they were verified, and …
Docstring Coverage Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Title check

Explanation

The title "fix(api): generateObject forwards serviceTier and customModelParams" names the main change. The changeset adds both options to GenerateObjectOptions and forwards them to generateText() on each attempt, including validation retries. The title follows Conventional Commits and is specific. It is 67 characters, within a typical length.

Full details: Description check

Explanation

The description covers the summary, the type of change, verification, and the checklist. It explains the problem, the fix, and the vendor reference. It names the tests and how they were verified, and it states that the first push held failing tests. The Linked issues section is missing, although the template only gives an example there. The Migration notes section is absent, which is acceptable because the change does not break existing users. The unchecked item 'Every automated review thread is settled' is an open checklist item, not a missing section. The author should add a linked issue if one exists.

Resolution

Optional: add a linked issue under the Linked issues heading if one exists (for example, 'Fixes #123'). Otherwise, state that no issue is linked. Settle the automated review threads or leave the checklist item open with a reason.

Full details: Docstring Coverage

Explanation

Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 1 functions across 2 files. (2 skipped: 2 unsupported.)

Finishing Touches
Generate docstrings
  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

@sourcery-ai

sourcery-ai Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

Adds serviceTier and customModelParams to generateObject() and forwards them through every generation attempt to provider request bodies, with documentation and end-to-end coverage for OpenAI, retries, and default omission behavior.

Sequence diagram for generateObject provider option forwarding

sequenceDiagram
    participant Caller
    participant generateObject
    participant generateText
    participant OpenAIProvider

    Caller->>generateObject: generateObject with serviceTier and customModelParams
    generateObject->>generateText: generateText with serviceTier and customModelParams
    generateText->>OpenAIProvider: request with service_tier and customModelParams
    OpenAIProvider-->>generateText: response
    alt validation fails
        generateObject->>generateText: retry generateText with serviceTier and customModelParams
        generateText->>OpenAIProvider: retry request with service_tier and customModelParams
        OpenAIProvider-->>generateText: retry response
    end
    generateText-->>generateObject: generated result
    generateObject-->>Caller: structured result
Loading

File-Level Changes

Change Details Files
Expose structured-output requests to the same provider routing controls as text generation.
  • Add typed serviceTier and provider-specific customModelParams options.
  • Forward both options into the per-attempt generateText() call, including validation retries and existing fallback handling.
  • Document option semantics, supported service tiers, retry behavior, and fallback filtering.
src/api/generateObject.ts
docs/features/PROMPT_CACHING.md
docs/orchestration/STRUCTURED_OUTPUT_API.md
Verify that the new options reach the real OpenAI request payload without changing existing defaults.
  • Exercise generateText() as a reference implementation.
  • Assert service_tier and custom fields on initial structured requests.
  • Assert both fields survive validation retries.
  • Assert service_tier is omitted when unspecified.
src/api/runtime/__tests__/generateObject.serviceTier.e2e.test.ts

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

@jddunn
jddunn marked this pull request as ready for review November 1, 2026 19:07
@jddunn
jddunn requested a review from Victor-Evogor as a code owner November 1, 2026 19:07
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-01T19:08:28.331379Z dd685a7 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

fix(api): forward service tier and custom parameters in generateObject

🐞 Bug fix 🧪 Tests 📝 Documentation 🕐 10-20 Minutes

Grey Divider

AI Description

• Forward serviceTier and customModelParams through every structured-output attempt, including
 validation retries.
• Preserve generateText() provider behavior without introducing a default service tier.
• Verify OpenAI request bodies and document the new options.
Diagram

sequenceDiagram
  actor Caller
  participant Object as generateObject
  participant Text as generateText
  participant Provider as OpenAIProvider
  participant API as OpenAI API
  Caller->>Object: schema and options
  loop Initial attempt and validation retries
    Object->>Text: tier and custom params
    Text->>Provider: completion options
    Provider->>API: service_tier and fields
    API-->>Provider: completion
    Provider-->>Text: provider response
    Text-->>Object: generated text
    Object->>Object: parse and validate
  end
  Object-->>Caller: validated object
Loading
High-Level Assessment

Forwarding the options into the existing generateText() path is the appropriate approach: it preserves provider serialization and fallback rules without duplicating them in generateObject().

Files changed (4) +190 / -2

Bug fix (1) +22 / -1
generateObject.tsForward service tier and custom parameters on every attempt +22/-1

Forward service tier and custom parameters on every attempt

• Adds both options to 'GenerateObjectOptions' and conditionally passes them into each retry-loop call to 'generateText()'. The TSDoc describes provider behavior and the risks of passthrough-field collisions.

src/api/generateObject.ts

Tests (1) +163 / -0
generateObject.serviceTier.e2e.test.tsVerify structured-call options in OpenAI request bodies +163/-0

Verify structured-call options in OpenAI request bodies

• Uses the real OpenAI provider with a stubbed 'fetch' to check initial requests, validation retries, and omission of an unset service tier. A 'generateText()' case establishes the existing behavior for comparison.

src/api/runtime/tests/generateObject.serviceTier.e2e.test.ts

Documentation (2) +5 / -1
PROMPT_CACHING.mdClarify service-tier support for structured calls +3/-1

Clarify service-tier support for structured calls

• Notes that 'generateObject()' accepts 'serviceTier' and sends it on every attempt, including validation retries.

docs/features/PROMPT_CACHING.md

STRUCTURED_OUTPUT_API.mdDocument the new generateObject options +2/-0

Document the new generateObject options

• Adds 'serviceTier' and 'customModelParams' to the options table, including request-body behavior and fallback handling.

docs/orchestration/STRUCTURED_OUTPUT_API.md

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Fallback requests reject foreign fields ✓ Resolved
Description
generateObject forwards customModelParams unchanged into generateText, whose fallback
recursion preserves the record while rebuilding only _responseFormat. If an OpenAI call with a
passthrough response_format falls back to Anthropic, or an Anthropic call with output_config
falls back to OpenAI, the fallback sends a field intended for the other provider and can fail
instead of producing an object.
Code

src/api/generateObject.ts[699]

+      ...(opts.customModelParams !== undefined ? { customModelParams: opts.customModelParams } : {}),
Evidence
The new forwarding activates the existing fallback path for structured calls. That path retains
customModelParams, and the shared filter removes OpenRouter and Gemini keys but not the cited
OpenAI or Anthropic fields; both native providers then merge the surviving fields into their request
payloads.

src/api/generateObject.ts[693-702]
src/api/generateText.ts[3478-3504]
src/core/llm/providers/openrouter-only-params.ts[24-51]
src/core/llm/providers/openrouter-only-params.ts[90-108]
src/core/llm/providers/implementations/AnthropicProvider.ts[1994-2015]
src/core/llm/providers/implementations/OpenAIProvider.ts[1942-1954]
src/core/llm/providers/implementations/OpenAIProvider.ts[2114-2124]

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

## Issue description
`generateObject` now passes provider-specific `customModelParams` into a fallback chain, where fields intended for the primary provider can make another provider reject its request.
## Fix Focus Areas
- src/api/generateObject.ts[696-699]
- src/api/generateText.ts[3478-3504]
- src/core/llm/providers/openrouter-only-params.ts[90-108]
## Recommended Fix
Preserve passthrough fields for the intended provider, but filter provider-specific fields for each fallback leg before constructing its request. Cover OpenAI-to-Anthropic and Anthropic-to-OpenAI structured-output fallbacks with tests.

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


Grey Divider

Tip of the day
💡 Did you know, you can show, collapse, or hide each part of a finding: code, evidence, and all

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread src/api/generateObject.ts Resolved

@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 found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src/api/generateObject.ts" line_range="320-329" />
<code_context>
+   * project's configured tier. `'flex'` bills at about batch rates but can answer 429 under load; `'priority'` is a
+   * paid tier. Other providers ignore it.
+   */
+  serviceTier?: GenerateTextOptions['serviceTier'];
+
+  /**
+   * Provider-specific top-level request fields, forwarded to {@link GenerateTextOptions.customModelParams} and
+   * spread onto every attempt's request body, a validation retry included, with the same rules as there: a fallback
+   * leg gets them minus the fields only another vendor accepts (OpenRouter's routing controls, Gemini's request
+   * fields), and keys collide last-wins with the typed fields at the provider layer. A passthrough `tool_choice`, `tools` or `response_format` here can change the
+   * structured-output route this call takes ({@link generateObject}).
+   */
+  customModelParams?: Record<string, unknown>;
+
   /**
</code_context>
<issue_to_address>
**Streaming structured calls lack options**

When a caller needs incremental structured output and also needs either of these request controls, callers switching from `generateObject()` to `streamObject()` still cannot request a service tier or pass provider-specific fields: `StreamObjectOptions` does not declare them, and its `streamText()` call cannot forward them. The structured-output APIs therefore expose different request controls.

Add both options to `StreamObjectOptions` and forward them to its `streamText()` call.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread src/api/generateObject.ts
Comment on lines +320 to +329
serviceTier?: GenerateTextOptions['serviceTier'];

/**
* Provider-specific top-level request fields, forwarded to {@link GenerateTextOptions.customModelParams} and
* spread onto every attempt's request body, a validation retry included, with the same rules as there: a fallback
* leg gets them minus the fields only another vendor accepts (OpenRouter's routing controls, Gemini's request
* fields), and keys collide last-wins with the typed fields at the provider layer. A passthrough `tool_choice`, `tools` or `response_format` here can change the
* structured-output route this call takes ({@link generateObject}).
*/
customModelParams?: Record<string, unknown>;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Medium · Streaming structured calls lack options

When a caller needs incremental structured output and also needs either of these request controls, callers switching from generateObject() to streamObject() still cannot request a service tier or pass provider-specific fields: StreamObjectOptions does not declare them, and its streamText() call cannot forward them. The structured-output APIs therefore expose different request controls.

Add both options to StreamObjectOptions and forward them to its streamText() call.

Prompt for AI agents
In `src/api/generateObject.ts` at lines 320-329:

**Streaming structured calls lack options**

When a caller needs incremental structured output and also needs either of these request controls, callers switching from `generateObject()` to `streamObject()` still cannot request a service tier or pass provider-specific fields: `StreamObjectOptions` does not declare them, and its `streamText()` call cannot forward them. The structured-output APIs therefore expose different request controls.

Add both options to `StreamObjectOptions` and forward them to its `streamText()` call.

@jddunn
jddunn marked this pull request as draft November 1, 2026 20:12

This branch has not been deployed

No deployments
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