feat: publish typed JSON Schemas for llm-router + provider iii functions - #270
feat: publish typed JSON Schemas for llm-router + provider iii functions#270ytallo wants to merge 1 commit into
Conversation
…JSON Schemas for the iii function surface
Every iii function in these workers was registered with a
`Fn(Value) -> Value` handler, so the SDK auto-extracted the permissive
`AnyValue` schema and the workers.iii.dev API reference rendered
request/response as "unknown".
Attach precise request/response JSON Schemas at registration via
`request_format`/`response_format`, without changing any handler:
- llm-router: derive `JsonSchema` across the wire type graph
(events/messages/content/model/credential/router), add a `wire_schema`
helper (`schema_of` + `with_schemas`), and wrap all 14 `router::*`
registrations. `router::models::get` publishes its `{model}|null`
union; the trigger handlers publish a null response.
- provider-anthropic / provider-openai: wrap the 3 `provider::*`
registrations, reusing the shared protocol types and helper from
llm-router (no direct schemars dep needed).
Handlers stay on `Value`, so tolerant parsing, streaming sinks, and the
`router/invalid_request` + `provider/invalid_request` error contracts are
unchanged. `schemars` is pinned to the same major as iii-sdk so the
emitted schemas match the SDK's own draft-07 settings. Golden tests in
each crate lock the published surface.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
skill-check — worker0 verified, 22 skipped (no docs/).
Four for four. Nicely done. |
📝 WalkthroughWalkthroughAdds Draft-07 JSON schema publishing to the ChangesWire Schema Publishing for llm-router
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@provider-anthropic/tests/schemas.rs`:
- Around line 32-34: The `on_router_ready` handler test currently only asserts
the response schema (ProviderAck) but is missing the request schema assertion
(NoParams). Add an assertion for the request schema before the existing response
assertion in both affected files. In `provider-anthropic/tests/schemas.rs` at
lines 32-34, insert `assert_structured(&schema_of::<NoParams>(),
"on_router_ready req");` before the existing
`assert_structured(&schema_of::<ProviderAck>(), "on_router_ready resp");` line.
Apply the identical change in `provider-openai/tests/schemas.rs` at lines 32-34
to ensure both provider test suites consistently validate both request and
response schemas for the `on_router_ready` registration contract.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: b415feaa-3bf9-4803-aa18-8b826aa04862
⛔ Files ignored due to path filters (3)
llm-router/Cargo.lockis excluded by!**/*.lockprovider-anthropic/Cargo.lockis excluded by!**/*.lockprovider-openai/Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (16)
llm-router/Cargo.tomlllm-router/src/lib.rsllm-router/src/register.rsllm-router/src/registry/register.rsllm-router/src/types/content.rsllm-router/src/types/credential.rsllm-router/src/types/events.rsllm-router/src/types/messages.rsllm-router/src/types/model.rsllm-router/src/types/router.rsllm-router/src/wire_schema.rsllm-router/tests/schemas.rsprovider-anthropic/src/register.rsprovider-anthropic/tests/schemas.rsprovider-openai/src/register.rsprovider-openai/tests/schemas.rs
| // provider::anthropic::on_router_ready | ||
| assert_structured(&schema_of::<ProviderAck>(), "on_router_ready resp"); | ||
| } |
There was a problem hiding this comment.
Add request-schema assertions for on_router_ready in both provider test suites.
At Line 33 in each file, only the response (ProviderAck) is asserted. The registration contract for on_router_ready is request+response (NoParams/ProviderAck), so request-side regressions would currently pass unnoticed.
provider-anthropic/tests/schemas.rs#L32-L34: addassert_structured(&schema_of::<NoParams>(), "on_router_ready req");before the response assertion.provider-openai/tests/schemas.rs#L32-L34: addassert_structured(&schema_of::<NoParams>(), "on_router_ready req");before the response assertion.
Suggested patch
--- a/provider-anthropic/tests/schemas.rs
+++ b/provider-anthropic/tests/schemas.rs
@@
// provider::anthropic::on_router_ready
+ assert_structured(&schema_of::<NoParams>(), "on_router_ready req");
assert_structured(&schema_of::<ProviderAck>(), "on_router_ready resp");--- a/provider-openai/tests/schemas.rs
+++ b/provider-openai/tests/schemas.rs
@@
// provider::openai::on_router_ready
+ assert_structured(&schema_of::<NoParams>(), "on_router_ready req");
assert_structured(&schema_of::<ProviderAck>(), "on_router_ready resp");📝 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.
| // provider::anthropic::on_router_ready | |
| assert_structured(&schema_of::<ProviderAck>(), "on_router_ready resp"); | |
| } | |
| // provider::anthropic::on_router_ready | |
| assert_structured(&schema_of::<NoParams>(), "on_router_ready req"); | |
| assert_structured(&schema_of::<ProviderAck>(), "on_router_ready resp"); | |
| } |
📍 Affects 2 files
provider-anthropic/tests/schemas.rs#L32-L34(this comment)provider-openai/tests/schemas.rs#L32-L34
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@provider-anthropic/tests/schemas.rs` around lines 32 - 34, The
`on_router_ready` handler test currently only asserts the response schema
(ProviderAck) but is missing the request schema assertion (NoParams). Add an
assertion for the request schema before the existing response assertion in both
affected files. In `provider-anthropic/tests/schemas.rs` at lines 32-34, insert
`assert_structured(&schema_of::<NoParams>(), "on_router_ready req");` before the
existing `assert_structured(&schema_of::<ProviderAck>(), "on_router_ready
resp");` line. Apply the identical change in `provider-openai/tests/schemas.rs`
at lines 32-34 to ensure both provider test suites consistently validate both
request and response schemas for the `on_router_ready` registration contract.
|
|
||
| /// Content blocks — the atomic units of message content (README § Content blocks). | ||
| #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] | ||
| #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)] |
There was a problem hiding this comment.
can we remove the schemars:: and add it to the import?
Why
The API reference at
workers.iii.dev/workers/<worker>?tab=apirenders "unknown" forllm-router,provider-anthropic, andprovider-openai.Root cause: every iii function in these workers is registered with a
Fn(Value) -> Valuehandler. The SDK auto-extracts request/response schemas from the handler's argument/return types, butserde_json::Valueproduces the permissiveAnyValueschema (no structure), so the registry has nothing concrete to render. (approval-gate renders fine because it uses typedFn(Req) -> Resphandlers — this brings the router family to parity.)What
Attach precise request/response JSON Schemas at registration time via the SDK's
request_format/response_format, without changing any handler dispatch. The handlers stay onValue, so every tolerant parse, streaming sink, bare-nullanswer, and error contract is byte-for-byte preserved.JsonSchemaacross the wire type graph (events/messages/content/model/credential/router).wire_schemamodule:schema_of::<T>()(mirrors the SDK's draft-07 generator) +with_schemas::<Req, Resp>(reg).router::*registrations.router::models::getpublishes its real{ model } | nullunion; the engine-trigger handlers (on_worker_available,on_config_changed) publish anullresponse.ChatRequest,ChatResponse,CompleteResponse, …); added small schema-only types for the previously-inline shapes (RouteRequest/Response,ModelsListRequest, etc.) and the shared provider-protocol acks.provider::*registrations each, reusingllm_router's helper and the sharedProviderStreamInput/ProviderAck/RefreshModelsAck/NoParamstypes. No directschemarsdep needed (the lockfile change is the transitive pickup via the path-dep).schemarsis pinned to0.8— the same major asiii-sdk0.19.2 — so the emitted schemas are byte-identical to what a typed SDK handler would auto-extract, and there's a singleJsonSchematrait across the graph.Behavior / risk
Schema-metadata only.
request_format/response_formatare descriptive registry metadata; the engine never validates payloads against them at invoke time, and the handler closures are untouched. An adversarial review confirmed dispatch is unchanged (handlers still takeValue; no serde attribute changed).Tests
Golden
tests/schemas.rsin each crate asserts every published request/response type renders a structured schema (never theAnyValuetrue), pins key fields (ChatRequestcarrieswriter_ref;CompleteRequestdoes not), and checks the{model}|nulland null-response shapes. All suites green: llm-router 61, provider-anthropic 78, provider-openai 65 (incl. the existing engine-backed integration tests).cargo fmt+clippy -D warningsclean on all three.Release note for the operator
No
Cargo.tomlversions are bumped here (thecreate-tagworkflow does that). Published schemas are collected by booting the worker at release time, andrelease.ymlpublishes one worker per tag — so after merge, run Create Tag → bumppatchfor all three workers (llm-router, thenprovider-anthropic,provider-openai) or the providers will keep serving their previously-registered (stale) schemas.Summary by CodeRabbit
New Features
Tests