Skip to content

sessionId falls back to static Authorization token; session_id/plugins never forwarded to OpenRouter #95

Description

@bsperduto

Summary

Two related gaps in session handling for the OpenAI-compatible route
(api/openai-router.js, clients/databricks.jsinvokeOpenRouter).

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions