feat: add LiteLLM gateway support for chat + embeddings - #44
Conversation
|
@prodmanpd is attempting to deploy a commit to the Together AI Team on Vercel. A member of the Team first needs to authorize it. |
|
I'm concerned about the supply-chain boundary of this LiteLLM integration. The upstream incident report confirms compromised PyPI releases 1.82.7/1.82.8 in March 2026; those releases were removed. This reviewed change uses a proxy-compatible integration; it does not itself add a Python LiteLLM package installation. The deployment questions are who operates the proxy, which verified server version runs there, and whether credentials remain isolated from other providers. Please document those trust boundaries for users. This is one of 49 observed LiteLLM integration PRs from the same account, whose author acknowledged the cross-project effort. The pattern prompted this review; it does not establish malicious intent or connect the author to the incident. The consolidated questions and corrections are in YouDub #130; this PR's review snapshot preserves the revision and scope. |
Summary
Adds optional support for routing notesGPT's LLM calls through a
LiteLLM proxy (or any
OpenAI-compatible gateway), so users can point the chat + embedding calls at
100+ providers (OpenAI, Azure, Anthropic, Bedrock, Gemini, ...) behind a single
URL. Together AI stays the default - existing deployments keep working with
only
TOGETHER_API_KEYset. This is purely additive: no behavior changes unlessyou set the new env vars.
Motivation
Today the provider is hardcoded in
convex/together.ts(
baseURL: 'https://api.together.xyz/v1'+ hardcoded model strings), so there'sno way to run notesGPT against a different LLM without editing source. Routing
through a LiteLLM proxy is the standard way to swap providers, add spend
limits/fallbacks, or use models you already have keys for - without touching app
code.
Changes
convex/llm.ts(new) - central provider config read from env with Together AIdefaults (
LLM_BASE_URL,LLM_API_KEY-> falls back toTOGETHER_API_KEY,LLM_CHAT_MODEL,LLM_EMBEDDING_MODEL,LLM_INSTRUCTOR_MODE) + acreateLLMClient()factory.convex/together.ts- uses the shared client + config instead of the hardcodednew OpenAI({ baseURL: '...together...' })and hardcoded model literals. Theextraction and both embedding call sites now honor the config.
README.md- documents the optional vars and a copy-pasteable LiteLLM proxyexample.
Transcription (
convex/whisper.ts) intentionally stays on Together's Whisperendpoint: it relies on Together's file-URL upload extension (handles >1GB /
30-min audio without chunking), which the generic OpenAI transcription contract
doesn't cover. This PR gateways the chat + embedding inference.
Cross-provider fix caught while testing
Instructor's
mode: 'JSON_SCHEMA'(previously hardcoded) emits Together'sproprietary
response_format.schemafield, which other providers reject(Azure returned
Unknown parameter: 'response_format.schema'). So a naive base-URL swap would 400 on OpenAI/Azure/Anthropic. The fix:
LLM_INSTRUCTOR_MODE(default
JSON_SCHEMAfor Together back-compat) - set it toTOOLSto drivestructured output through cross-provider tool calling. Verified below.
Tests
This repo has no test harness, so here's typecheck + formatter + a real
end-to-end run.
1. Typecheck -
npx tsc --noEmit-> exit 0 (clean).2. Formatting -
npx prettier --check convex/llm.ts convex/together.ts README.md-> all files use Prettier code style.3. Live E2E - configured client -> local LiteLLM proxy -> Azure (gpt via
Azure AI Foundry), structured extraction with
LLM_INSTRUCTOR_MODE=TOOLS:Proxy config used (Azure behind a
chatalias):This proves the full chain:
createLLMClient()-> OpenAI SDK -> LiteLLM proxy ->Azure -> structured JSON matching the existing
NoteSchema. Embeddings runthrough the same configured client (
togetherai.embeddings.create) and the samebase URL; I didn't have an embedding deployment on the test resource, so that
path wasn't exercised live, but it's the identical client + config.
Risk / Compatibility
(Together AI, same models,
JSON_SCHEMAmode).openaiSDK.Example usage
1. Define a LiteLLM proxy config (
litellm.config.yaml) that fronts whateverproviders you want behind one endpoint:
2. Start the proxy (Python) - exposes an OpenAI-compatible API on
:4000:3. Point notesGPT at it - set these Convex env vars (all optional; unset =
Together AI as before):
That's it -
convex/together.tspicks the client/models up automatically: