Skip to content

feat: pass extra body fields from Lua to HTTP request#262

Merged
kp2pml30 merged 6 commits intomainfrom
feat/llm-extra-body
Feb 12, 2026
Merged

feat: pass extra body fields from Lua to HTTP request#262
kp2pml30 merged 6 commits intomainfrom
feat/llm-extra-body

Conversation

@MuncleUscles
Copy link
Member

@MuncleUscles MuncleUscles commented Feb 8, 2026

Summary

  • Add #[serde(flatten)] to the Args struct in exec_prompt_in_provider so Lua can pass arbitrary extra fields through to the HTTP request body
  • Add ExtraBody type alias and merge_extra helper for merging extra fields into JSON request bodies
  • Thread the extra parameter through the Provider trait methods
  • OpenAICompatible provider merges extra fields into the HTTP body (enables OpenRouter's models array and provider routing options)
  • Other providers (Gemini, OLlama, Anthropic) accept but ignore the parameter

Motivation

OpenRouter supports native fallback via two mechanisms:

  • "models": ["model-a", "model-b"] — cross-model fallback
  • "provider": {"allow_fallbacks": true} — same-model, cross-provider routing

Currently the Lua→Rust FFI boundary (Args struct) only accepts {provider, model, prompt, format}, so Lua can't pass these OpenRouter-specific fields through. This change makes the boundary extensible without requiring Rust changes for each new provider feature.

Usage (Lua side)

After this change, llm.lua can pass extra fields:

request = {
    provider = provider_id,
    model = model,
    prompt = mapped_prompt.prompt,
    format = mapped_prompt.format,
    -- OpenRouter fallback
    models = {"openai/gpt-4o", "anthropic/claude-sonnet-4-5-20250929"},
    provider = { allow_fallbacks = true },
}

Test plan

  • CI passes (existing tests updated with &serde_json::Map::new() for the new parameter)
  • Verify OpenRouter fallback works end-to-end with Studio (follow-up PR in genlayer-studio)

Summary by CodeRabbit

Release Notes

  • New Features

    • OpenAI-compatible providers now support merging extra fields into requests.
    • Prompt structure extended to support configurable extra field merging.
    • Added documentation for floating point behavior (deterministic and non-deterministic modes).
  • Documentation

    • Updated API documentation with versioned changelogs and floating point behavior guide.
  • Bug Fixes

    • Providers now log warnings when extra fields are ignored.
    • Web request method parameter validation improved.
    • Test output now cleaner with ANSI escape sequences removed.
  • Tests

    • Extended test coverage for extra field and merge strategy functionality.

Add serde(flatten) to Args so Lua can pass arbitrary extra fields
(e.g. OpenRouter's `models` array or `provider` routing options)
through to the HTTP request body. OpenAI-compatible providers merge
them; others ignore.
@CLAassistant
Copy link

CLAassistant commented Feb 8, 2026

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ kp2pml30
❌ MuncleUscles
You have signed the CLA already but the status is still pending? Let us recheck it.

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 8, 2026

📝 Walkthrough

Walkthrough

The pull request adds extensible field-merging capabilities to LLM providers via a new configurable merge utility module, extends the Prompt structure with extra fields for provider customization, updates API documentation with changelog reorganization and floating-point behavior guidance, refines logging output formats, and improves type annotations across Lua bindings and test infrastructure.

Changes

Cohort / File(s) Summary
LLM Merge Infrastructure
modules/implementation/src/llm/merge.rs, modules/implementation/src/llm/mod.rs, modules/implementation/src/llm/prompt.rs, modules/implementation/src/llm/providers.rs
Introduces MergeStrategy enum with None, Replace, MergeLeft, MergeRight, and Map variants; implements merge_extra and merge_values functions for flexible JSON field merging. Extends Prompt::Internal with extra and extra_merge_strategy fields. OpenAI-compatible provider now merges extra fields into requests; OLlama, Gemini, Anthropic, and OpenAI providers log warnings when extra fields are present but ignored.
API Documentation
doc/website/src/api/changelog/index.rst, doc/website/src/api/changelog/v0.1.3.rst, doc/website/src/api/changelog/v0.1.8.rst, doc/website/src/api/floating_point.rst, doc/website/src/api/index.rst
Reorganizes changelog structure with versioned index and migration guides. Adds floating-point behavior documentation covering Non-Deterministic and Deterministic modes. Updates toctree to include boot_process, floating_point, and nested changelog entries.
Logging Output Refinement
modules/implementation/src/scripting/ctx/dflt.rs, modules/implementation/src/scripting/mod.rs
Changes logging format from debug-style (?) to serde-based formatting for response and bytes variables in test scenarios.
Type Annotations
modules/install/lib/genvm-lua/lib-llm.lua, modules/install/lib/genvm-lua/lib-web.lua
Extends LLM Prompt type with extra and extra_merge_strategy fields; updates LLMExecPromptTemplatePayload to support dynamic keys. Restricts WebRequestPayload method field from generic string to specific HTTP method union ("GET" | "POST" | "HEAD" | "DELETE" | "OPTIONS" | "PATCH").
Test Output Processing
tools/ya-test-runner/ya_test_runner/exec/command.py
Introduces precompiled regex to strip ANSI escape sequences from captured stdout and stderr before UTF-8 decoding.
Documentation References
doc/website/src/spec/index.rst
Updates documentation link target from api.txt to spec.txt in note reference.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Whiskers twitch with merge delight,
Extra fields now flow just right,
Strategies dance—Left, Right, Map,
No more API gaps to gap!
Docs and types align in grace, 🎯✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: enabling extra body fields from Lua to be passed through to HTTP requests, which aligns with the PR's core objective of making the Lua→Rust boundary extensible for provider-specific fields.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/llm-extra-body

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@modules/implementation/src/llm/ctx.rs`:
- Around line 99-101: The long method call on
`zelf.exec_prompt_in_provider(&args.prompt, &args.model, &args.provider,
args.format, &args.extra).await` exceeds the line-length limit; split the
arguments across multiple lines or assign some arguments to short local
variables before the call so the chain fits formatting. Locate the call in the
`ctx.rs` function where `zelf` invokes `exec_prompt_in_provider` and reformat it
into a multi-line method chain (one argument per line or grouped logically) or
introduce temporaries for `args.prompt`, `args.model`, `args.provider`,
`args.format`, `args.extra` and then call `exec_prompt_in_provider(...) .await`
to satisfy `cargo fmt`.

In `@modules/implementation/src/llm/providers.rs`:
- Around line 106-112: merge_extra currently unconditionally overwrites existing
JSON keys which allows extras to replace core fields like model, messages,
stream, temperature, etc.; change merge_extra (function name: merge_extra) to
only add keys that do not already exist by using the map entry API (e.g.,
obj.entry(k.clone()).or_insert(v.clone())) so extras are purely additive and
cannot overwrite existing request fields or bypass safety controls.
- Around line 134-141: The line calling self.exec_prompt_json_as_text in
function exec_prompt_json exceeds the project's line-length limit; reformat that
call so it wraps arguments across multiple lines (e.g., place each parameter
ctx, prompt, model, extra on its own line and align the .await on the next line)
to satisfy rustfmt—update the expression using the exec_prompt_json_as_text
method and the let res = ... .await assignment so rustfmt no longer flags the
line.
🧹 Nitpick comments (1)
modules/implementation/src/llm/ctx.rs (1)

77-85: #[serde(flatten)] silently swallows typos in known field names.

If Lua sends { provder = "x", ... } (typo), it won't fail deserialization — the misspelled key lands in extra and the actual provider field triggers a missing-field error only if it's required. But for optional-like scenarios or debugging, this can be confusing. Consider adding a log/trace when extra is non-empty so unexpected keys are visible during development.

This is an acceptable trade-off for extensibility, but worth documenting.

@kp2pml30
Copy link
Member

I am taking this one from here, thanks for the PR

@kp2pml30 kp2pml30 enabled auto-merge February 11, 2026 12:19
@kp2pml30 kp2pml30 added this pull request to the merge queue Feb 11, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@modules/install/lib/genvm-lua/lib-web.lua`:
- Line 4: The WebRequestPayload type alias omits the standard "PUT" HTTP method;
update the type alias WebRequestPayload to include "PUT" in the method union
(or, if PUT is intentionally disallowed, add an inline comment on the
WebRequestPayload alias explaining why PUT is excluded) so the method list
correctly reflects allowed methods or documents the intentional restriction.
🧹 Nitpick comments (3)
modules/implementation/src/llm/merge.rs (2)

69-75: merge_extra is a trivial wrapper over merge_values.

Currently these are identical. If the intent is to provide a stable public API for the "merge extra fields into request" use case, consider adding a doc comment clarifying why both exist. Otherwise, callers could just use merge_values directly.


97-104: None strategy silently replaces on type mismatch (e.g., object→scalar or scalar→object).

The catch-all arm on line 102 means that if the source is a different JSON type than the target (e.g., source is an array and target is an object, or vice versa), the target is silently replaced. This is fine for scalar→scalar, but type-changing replacements could mask configuration errors. Consider whether a warning or error for object↔non-object mismatches would be appropriate.

doc/website/src/api/index.rst (1)

14-17: Documentation changes appear unrelated to PR objectives.

The PR objectives describe adding extra body fields support from Lua to HTTP requests (Rust FFI boundary changes). However, these documentation updates add boot_process, floating_point, and reorganize the changelog structure, which don't appear to relate to the core feature described in the PR objectives. Consider moving these documentation changes to a separate PR to maintain focused, single-purpose changes.


---@alias WebRenderPayload { url: string, mode: "text" | "html" | "screenshot", wait_after_loaded: number }
---@alias WebRequestPayload { url: string, method: string, headers: table<string, string>, body: string?, sign: boolean? }
---@alias WebRequestPayload { url: string, method: "GET" | "POST" | "HEAD" | "DELETE" | "OPTIONS" | "PATCH", headers: table<string, string>, body: string?, sign: boolean? }
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

PUT is missing from the HTTP method union.

The type lists "GET" | "POST" | "HEAD" | "DELETE" | "OPTIONS" | "PATCH" but omits "PUT", which is a standard and widely-used HTTP method. If this is intentional (i.e., PUT requests are deliberately disallowed), please add a comment explaining why; otherwise, add it to the union.

Proposed fix
----@alias WebRequestPayload { url: string, method: "GET" | "POST" | "HEAD" | "DELETE" | "OPTIONS" | "PATCH", headers: table<string, string>, body: string?, sign: boolean? }
+---@alias WebRequestPayload { url: string, method: "GET" | "POST" | "PUT" | "HEAD" | "DELETE" | "OPTIONS" | "PATCH", headers: table<string, string>, body: string?, sign: boolean? }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
---@alias WebRequestPayload { url: string, method: "GET" | "POST" | "HEAD" | "DELETE" | "OPTIONS" | "PATCH", headers: table<string, string>, body: string?, sign: boolean? }
---@alias WebRequestPayload { url: string, method: "GET" | "POST" | "PUT" | "HEAD" | "DELETE" | "OPTIONS" | "PATCH", headers: table<string, string>, body: string?, sign: boolean? }
🤖 Prompt for AI Agents
In `@modules/install/lib/genvm-lua/lib-web.lua` at line 4, The WebRequestPayload
type alias omits the standard "PUT" HTTP method; update the type alias
WebRequestPayload to include "PUT" in the method union (or, if PUT is
intentionally disallowed, add an inline comment on the WebRequestPayload alias
explaining why PUT is excluded) so the method list correctly reflects allowed
methods or documents the intentional restriction.

@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Feb 11, 2026
@kp2pml30 kp2pml30 merged commit 7a2dd08 into main Feb 12, 2026
4 of 5 checks passed
@kp2pml30 kp2pml30 deleted the feat/llm-extra-body branch February 12, 2026 09:55
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.

3 participants