Summary
Two related gaps in session handling for the OpenAI-compatible route
(api/openai-router.js, clients/databricks.js — invokeOpenRouter).
Issue 1: sessionId fallback breaks for static-key clients
// api/openai-router.js
const sessionId = req.headers["x-session-id"]
|| req.headers["authorization"]?.split(" ")[1]
|| "openai-session";
Clients that authenticate with a fixed, static API key per config (rather
than a per-user or per-session token) — e.g. a JSON-configured custom model
profile in an IDE agent — send the same Authorization value on every
request, forever. This collapses every real conversation into a single
sessionId, which defeats routing/session-affinity.js's entire purpose:
pins, repin heuristics, and the messageCount <= 2 new-conversation guard
all assume sessionId uniquely identifies one conversation.
Suggested fix: fall back to a content-derived fingerprint (hash of the
first user message, or similar) rather than the raw auth token when no
explicit x-session-id is present.
Issue 2: session_id / plugins never sent to OpenRouter
// clients/databricks.js — invokeOpenRouter()
const openRouterBody = {
model: body._suggestionModeModel || body._tierModel || config.openrouter.model,
messages,
temperature: body.temperature ?? 0.7,
max_tokens: body.max_tokens ?? 16384,
top_p: body.top_p ?? 1.0,
stream: body.stream ?? false
};
Even when a tier resolves to a meta-router alias (openrouter/auto-beta,
openrouter/pareto-code), no session_id or plugins field is ever sent.
This means:
- OpenRouter's own session stickiness
never engages — every call re-ranks fully fresh, even within one Lynkr-pinned session.
cost_tier (Auto Router) and min_coding_score (Pareto Router) can only
be set as account-wide defaults on OpenRouter's Routing page, not per
request/tier, despite Lynkr already having per-tier granularity internally.
Suggested fix: forward body._sessionId as session_id, and add a
plugins block keyed off which meta-router alias is being called.
Impact
A single multi-step agentic task can have its individual tool-calling steps
answered by several different underlying models (observed: 6 distinct
models — glm-5.2, deepseek-v4-pro, gemini-3-flash-preview,
deepseek-v4-flash, grok-4.6, gpt-oss-120b — within one ~5 minute task),
causing redundant/repeated tool calls as continuity is lost between steps.
Environment
- lynkr@9.14.0, Windows 11, client: Junie CLI custom model profile
(apiType: OpenAICompletion), static apiKey per JSON profile
Summary
Two related gaps in session handling for the OpenAI-compatible route
(
api/openai-router.js,clients/databricks.js—invokeOpenRouter).Issue 1: sessionId fallback breaks for static-key clients
Clients that authenticate with a fixed, static API key per config (rather
than a per-user or per-session token) — e.g. a JSON-configured custom model
profile in an IDE agent — send the same Authorization value on every
request, forever. This collapses every real conversation into a single
sessionId, which defeatsrouting/session-affinity.js's entire purpose:pins, repin heuristics, and the
messageCount <= 2new-conversation guardall assume
sessionIduniquely identifies one conversation.Suggested fix: fall back to a content-derived fingerprint (hash of the
first user message, or similar) rather than the raw auth token when no
explicit
x-session-idis present.Issue 2: session_id / plugins never sent to OpenRouter
Even when a tier resolves to a meta-router alias (
openrouter/auto-beta,openrouter/pareto-code), nosession_idorpluginsfield is ever sent.This means:
never engages — every call re-ranks fully fresh, even within one Lynkr-pinned session.
cost_tier(Auto Router) andmin_coding_score(Pareto Router) can onlybe set as account-wide defaults on OpenRouter's Routing page, not per
request/tier, despite Lynkr already having per-tier granularity internally.
Suggested fix: forward
body._sessionIdassession_id, and add apluginsblock keyed off which meta-router alias is being called.Impact
A single multi-step agentic task can have its individual tool-calling steps
answered by several different underlying models (observed: 6 distinct
models — glm-5.2, deepseek-v4-pro, gemini-3-flash-preview,
deepseek-v4-flash, grok-4.6, gpt-oss-120b — within one ~5 minute task),
causing redundant/repeated tool calls as continuity is lost between steps.
Environment
(
apiType: OpenAICompletion), staticapiKeyper JSON profile