feat(api): expose the lcm router at POST /v1/classify - #680
Merged
Merged
Conversation
Add lcm.ErrRateLimited and lcm.ErrUnavailable so a caller can back off without knowing a vendor's status codes. TypeSafe's StatusError unwraps to them for 429 and 503/529, and an API that cannot be reached wraps ErrUnavailable.
Put typed questions (noul, choice, score) about a piece of text to a routed classifier and get each answer back with its distribution and the request's usage. Routed like search: classify-fast by default, failover, one stat row per request, server-side only. An unknown target is a 404, a rate-limited provider a 429 and an overloaded or unreachable one a 503, so a caller knows when to retry. Clients are not regenerated yet.
Regenerate the Python, JS, Go, Rust, Ruby, PHP, .NET and Dart clients from the spec. Swift and Kotlin take only client-accessible operations, so they are unchanged. PHP, .NET and Rust also pick up the latency timeline and command_id fields they had not been regenerated for, and the Rust Responses::create now sets command_id to None.
Nash0x7E2
force-pushed
the
nash/lcm-classify
branch
from
September 28, 2026 20:47
f20feff to
2b0153d
Compare
Nash0x7E2
marked this pull request as ready for review
September 28, 2026 20:49
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The lcm router (TypeSafe's Jev behind
classify-fast) could only be reached from inside the router, by guardrails, the prompt-injection screen and sessions./v1/{modality}/streamserves stt, tts, llm and sts only, so the hosted router answers/v1/lcm/streamwith "this deployment does not stream this modality", and a product agent that classifies signal with Jev had to call TypeSafe directly, outside routing, failover and billing.A classifier is one request and one set of answers, so this exposes it the way search is exposed: a plain
POST, not a socket. A caller that retries also has to be able to tell a rate limit from a bad question, which every upstream failure being a 400 made impossible, and the product eval reads input tokens from the response, so the usage comes back with it.Changes
POST /v1/classify: astate(text or a JSON object),questionskeyed by the caller's ids (noul,choice,score), an optionaltarget(defaults toclassify-fast) andtags. Each answer carries only the fields its type uses, alongsideprovider, themodelversion that answered andusage. Server-side only, not client-accessible.lcm.ErrRateLimitedandlcm.ErrUnavailablecarry that without the API layer knowing a vendor's status codes; TypeSafe'sStatusErrorunwraps to them.command_id), and the RustResponses::createnow setscommand_id: None.Tested locally against Jev: a three-question request returns answers with
model: jev-1.13.0andusagein about 0.3 s, an unknown target returns 404, and the call is recorded in/v1/lcm/stats.🤖 Generated with Claude Code