Skip to content

CL-6204: Ollama adapter overrides via the inference adapter manifest - #236

Merged
TheGreatAxios merged 8 commits into
mainfrom
cl-6204-inference-adapter
Aug 21, 2026
Merged

TheGreatAxios merged 8 commits into
mainfrom
cl-6204-inference-adapter

Conversation

@TheGreatAxios

Copy link
Copy Markdown
Contributor

Summary

The owner asked for maximum flexibility on context window, max output tokens, and reasoning options for local inference — without vendoring @intx/inference (OpenAIQuirks is closed, no body passthrough). Interchange already ships the supported extension point for exactly this: loadAdapterRegistry(manifest) merges an operator-configured custom adapter over a built-in sharing its provider key, and buildRequest returns the body as a string, so a custom adapter has total control over it.

  • packages/ollama-adapter — new @corbits/ollama-adapter package. createOllamaAdapter wraps the built-in OpenAI adapter (SSE parsing, retry/pacing headers, message marshaling all reused unchanged) and adds one buildRequest pass applying typed, arktype-validated overrides — numCtx (Ollama's openai-compatible endpoint has no OpenAI-shaped context-window field; it only takes num_ctx through the endpoint's options passthrough object, same as native /api/chat), maxOutputTokens, and reasoningEffort ("low"|"medium"|"high", the field Ollama already recognizes for gpt-oss models on this endpoint) — general (default) or per model (perModel), per-model winning field-by-field.
  • Closed a real gap in the manifest wiring. The child-side path (apps/sidecar/src/workflow-substrate-factory) already parsed SIDECAR_ADAPTER_MANIFEST and fed it to loadAdapterRegistry correctly. But the boot edge (apps/sidecar/src/index.ts) hardcoded loadAdapterRegistry([]) for its own registry and SIDECAR_ADAPTER_MANIFEST: JSON.stringify([]) in every child's substrate env — there was no env var an operator could actually set. Added SIDECAR_ADAPTER_MANIFEST as an optional, arktype-validated env var in apps/sidecar/src/config.ts, threaded to both call sites.
  • Documented activation in the new package's README and in .env.example.

What actually works end-to-end

All three override classes verified via the built request body (package tests): numCtx -> options.num_ctx, maxOutputTokens -> overrides whichever max-tokens field the built-in adapter set, reasoningEffort -> reasoning_effort. Per-model beats general default; no override configured leaves the body byte-equivalent to the built-in adapter's.

Checks run (memory-constrained machine — see note below)

Per the owner's active memory constraint, bun run check / repo-root lint / repo-root typecheck were not run. Ran only, one at a time:

  • bun install (once, cache-backed, ~12s) to resolve the new package
  • packages/ollama-adapter: bun test (14 pass), bun run typecheck (clean)
  • apps/sidecar: bun run typecheck (clean), bun test (full suite, 164 pass — confirms the config.ts/index.ts wiring change didn't regress anything)

Not run: repo-root lint/prettier, check:packages, check:licenses, check:tool-package-pins — CI should run these. check:tool-package-pins shouldn't apply here: nothing pins @corbits/ollama-adapter via a { name, version } tool-package literal (it's an npm-style workspace dependency, not a tool package).

Test plan

  • CI: bun run check (lint/typecheck/test across the workspace)
  • CI: check:packages (packed-consumption check for the new package's exports)
  • CI: check:licenses (LGPL-2.1-or-later + canonical LICENSE text)

Red tests for a custom Interchange inference adapter package: typed
context-window/max-output-token/reasoning-effort override resolution
(per-model beats general default, unset stays unset), and the built
request body actually carrying configured num_ctx/max-tokens/
reasoning_effort while staying byte-equivalent to the built-in OpenAI
adapter's output when unconfigured.
Interchange's loadAdapterRegistry manifest is the supported extension
point for per-provider request overrides (buildRequest returns the
body as a string, so a custom adapter has full control over it) — no
vendoring needed. This wraps the built-in OpenAI adapter unchanged
(SSE parsing, retry/pacing headers, message marshaling) and adds one
buildRequest pass applying operator-configured overrides: num_ctx
(Ollama's openai-compatible endpoint has no OpenAI-shaped field for
context window; it only takes it through the options passthrough
object), max output tokens, and reasoning_effort, general or per model.
Documents the SIDECAR_ADAPTER_MANIFEST entry that activates the
adapter for the ollama provider key and the quirks (InferenceSource
overrides) shape: default/perModel numCtx, maxOutputTokens, and
reasoningEffort.
readSidecarConfig hardcoded SIDECAR_ADAPTER_MANIFEST to "[]" for every
workflow-process child and passed loadAdapterRegistry([]) for its own
adapters — the child-side parsing/wiring (parseAdapterManifest,
workflow-substrate-factory) already reached loadAdapterRegistry, but no
operator-facing env var ever fed it anything but empty. These tests
cover the new optional SIDECAR_ADAPTER_MANIFEST env var: a valid
manifest parses through, a malformed one or one missing a required
field fails boot naming the variable.
Closes the gap between the child-side manifest wiring (already
correct: parseAdapterManifest -> loadAdapterRegistry in
workflow-substrate-factory) and the boot edge, which never read an
env var and always threaded an empty manifest to both its own
loadAdapterRegistry call and every child's substrate env. The
manifest is now parsed and validated once at boot (failing loud on a
malformed value, matching every other substrate-config knob) and
threaded verbatim to both.
Names the contract and shows activating @corbits/ollama-adapter for
the ollama provider key.
@TheGreatAxios
TheGreatAxios merged commit b63e325 into main Aug 21, 2026
2 checks passed
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