# Changelog

## 0.2.2

- **The plugin now has its own settings section in the harness UI**, in all
  seven languages it ships. The Models page cannot host it: its provider editor
  picks a layout by namespace (`llm-deepseek`, `llm-pi-ai`, everything else),
  and the fallback branch renders one sentence pointing at settings.yaml with
  Apply disabled — a third-party provider has no editable form there at all.
  This section registers through `settings.section`, the same slot the Models
  page itself uses.

  It covers what the routing table actually needs: the classifier key (stored
  through the credentials service, with a configured/not-configured badge) and
  endpoint, the behaviour fields, the complexity bands with a low-below-medium
  check, the per-tier model chains and the fallback model, and a per-task rule
  editor with add and remove.

  Its copy follows this plugin's `language` setting rather than the harness UI
  language, so the form and the model picker always speak the same language;
  `auto` falls back to the harness language, which offers English and Chinese.
- The browser half is written directly in the module-loader format the host
  serves — no bundler, no JSX — so the published artifact is the file you read.

## 0.2.1

- **`routerUrl` now defaults to `https://router.allaigate.com`.** The previous
  default, `https://api.allaigate.com`, serves the website and answers 404 to
  every API path, so classification never ran: each call degraded to the
  fallback chain, exactly as designed but never as intended. The new host serves
  `/v1/route` under a valid certificate, so Node's fetch reaches it.
- `verifyTls` now says what to do instead of switching it off: a private CA is
  trusted through `NODE_EXTRA_CA_CERTS`, and a self-signed endpoint should be
  given a real certificate. Node's fetch still has no per-request opt-out, so
  the setting continues to only warn.

## 0.2.0

- **The plugin's own copy is translated into 7 languages** (en, ru, zh, de, fr,
  es, tr), selected by the new `language` setting. `auto` — the default —
  follows the harness UI language.

  What that covers is deliberately exact: the entries this provider shows in the
  model picker, and the message a call shows when no candidate could serve it.
  Those are the only strings a third-party provider plugin actually puts in
  front of a person — the harness renders none of a plugin's schema
  descriptions (its provider editor is hand-written React with its own bundled
  copy), and its plugin inventory carries no display metadata at all. Log lines
  stay English on purpose: they are diagnostics for issues and grep.

  The browser client ships two locales (`dsh-client-locale` exposes `en` and
  `zh`), so `auto` can only ever resolve to those two; the other five are
  reachable by naming one in this plugin's settings.
- A catalog entry with an empty `name` now takes this plugin's translated label;
  a name you set still wins.

## 0.1.5

- **A candidate whose provider refuses the call is stepped over.** Whether a
  provider can actually answer is invisible in its catalog — an unconfigured
  key looks exactly like a configured one — so 0.1.4 could route to a
  registered-but-keyless provider and fail the call while the rest of the chain
  sat unused. A first-and-only terminal failure carrying `MISSING_CREDENTIAL`,
  `AUTH`, `NO_ADAPTER`, or `MODEL_NOT_FOUND` now hands the call to the next
  candidate, and the final error names every route that refused.
- Once a provider has emitted a chunk the route is committed: a mid-stream
  failure reaches the caller instead of silently restarting somewhere else.

## 0.1.4

Fixes the boot crash and makes the routing path actually run.

- **Adapter rewritten against the real `@deepseek-ai/dsh-llm` contract.** It now
  extends `LlmAdapter` and implements `stream()`, `providerInfo()`,
  `providerRetryPolicy()`, `listModels()`, and `resolveModel()`. 0.1.3 shipped
  `create()` / `createStream()`, which do not exist in the seam, so
  `registerAdapter()` failed with `adapter.providerInfo is not a function` and
  took the whole profile down with it.
- **Removed the `cortiq-dsh-llm-router/models` bundle entry.** That subpath was
  never exported and never existed; loading the bundle raised
  `ERR_PACKAGE_PATH_NOT_EXPORTED`.
- **Routing works.** Candidate model ids now resolve against the catalogs of
  registered providers (`llm.listProviders()` / `llm.listModels()`), and the call
  is delegated through `ctx.llm.stream()`. 0.1.3 called `llm.getAdapters()` and
  `llm.registerModels()`, neither of which exists.
- **The API key reaches the classifier.** It is resolved through the credentials
  seam per call; 0.1.3 read a field that was never populated, so no prompt was
  ever classified.
- **A candidate may name its route** as `provider:model`; self-routing back into
  `cortiq-router` is refused.
- **Model picker entries are routing entry points**: `auto`, plus
  `auto-cost-saver` / `auto-balanced` / `auto-quality-first`, which pin the
  policy profile for that conversation.
- **Routing decisions are logged** (`echoRouting`) instead of being appended to
  the model's answer as a `<cortiq-routing …/>` tag, which corrupted the reply.
- The router request honors the caller's cancellation and no longer shares one
  `AbortController` across concurrent calls.
- `verifyTls` defaults to `true` and warns that Node's fetch cannot skip
  verification, instead of implying a bypass that never happened.
- Dropped the unused `src/i18n/*.yaml` locale files: nothing loaded them, and the
  harness takes its settings copy from the schema descriptions.
- Added offline contract tests (`npm test`) that run the real `LlmRuntime`.

## 0.1.3

Initial public release.
