Skip to content

Config Driven Classification Adapters - #16208

Closed
aligulzar729 wants to merge 2 commits into
LibreChat-AI:devfrom
aligulzar729:feat/classification-adapters
Closed

aligulzar729 wants to merge 2 commits into
LibreChat-AI:devfrom
aligulzar729:feat/classification-adapters

Conversation

@aligulzar729

Copy link
Copy Markdown

Summary

Depends on #16180.

I run a self-hosted instance with local models. While wiring a second classification host I noticed the three I care about differ only in data, not behaviour: same question shapes, same answer fields, same usage block. Only the URL, the model name and the body wrapping change.

URL model body response
TypeSafe /v1/systemone jev-latest flat bare
Cloudflare /accounts/{id}/ai/run typesafe/jev {input: {...}} {result: {...}}
OpenRouter /api/alpha/decisions ~typesafe/jev-latest flat bare

An adapter file per host would mean a merged PR and a release before an operator can point at a gateway that already works. So this makes those differences configuration instead.

Three optional fields on a provider: dialect picks the wire vocabulary, requestKey nests state and questions under a key, responseKey unwraps an envelope. A host nobody has heard of then needs no code at all:

classification:
  enabled: true
  provider: inhouse
  providers:
    inhouse:
      baseURL: https://classify.internal/v1/run
      model: your-model
      dialect: systemone
      requestKey: input
      responseKey: result
      apiKeyEnv: INHOUSE_CLASSIFIER_KEY

Known hosts ship as presets, so naming one is usually enough, and any field can be overridden:

classification:
  provider: cloudflare
  providers:
    cloudflare:
      baseURL: https://api.cloudflare.com/client/v4/accounts/<account-id>/ai/run
      apiKeyEnv: CLOUDFLARE_API_TOKEN

How it works

resolve.ts     preset for the name, merged under the operator's settings
registry.ts    presets as data: http, typesafe, openrouter, cloudflare
providers/
  dialect.ts   port <-> systemone question and answer mapping
  http.ts      one HTTP classifier, wraps and unwraps per config
  transport.ts unchanged: timeout, retry, typed failures

dialect exists because the only vocabulary difference between the two families is the word for a yes/no question. Everything else on the wire is already identical, so one mapping file covers both.

ClassificationRequest also gains an optional timeoutMs, because one ceiling does not fit every question. On my instance a ranking request over a 202-tool catalog is about 9,600 input tokens and takes roughly 4s, while a yes/no gate answers in under a second.

Cloudflare has no default URL, since the account id is part of it. It stays off with a warning rather than guessing one.

Type of change

  • Feature

Testing

dialect.spec.ts (10), presets.spec.ts (10) and config.spec.ts (8), 59 across the classification module.

The ones worth reading: a provider the code has never heard of, built from config alone and asserted on the wire; the Cloudflare envelope handled both wrapped and bare, because their model page shows a bare body and their platform docs show {result}; an override beating the preset it sits on; and a misspelled key rejected rather than silently dropped.

cd packages/api && npx jest src/classification passes 59. npx tsc --noEmit clean for all workspaces.

Risk / compatibility

No behaviour change when classification is off, which is the default. An existing http provider config keeps working: dialect defaults to the port vocabulary and both wrapping fields default to none.

classificationProviderSchema is now .strict(), matching the twelve other strict schemas in this file. A misspelled key that used to be dropped silently now fails at config load, which is the point, but it is worth calling out.

Checklist

@aligulzar729

Copy link
Copy Markdown
Author

Folded into #16180. With #16182 closed there is no reason to land the interface and then immediately rewrite it: #16180 now ships config-driven from the start, so no file is reviewed twice.

@aligulzar729
aligulzar729 deleted the feat/classification-adapters branch September 22, 2026 12:27
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