DeepSeek request isolation — user_id
Every DeepSeek-direct dispatch now carries DeepSeek's userid isolation field, which buys content-safety, KVCache, and scheduling isolation for sub-identities under one API account. On an account...
Every DeepSeek-direct dispatch now carries DeepSeek's user_id isolation field, which buys
content-safety, KVCache, and scheduling isolation for sub-identities under one API account. On an
account with increased quota it also buys PER-user_id concurrency at the full limits (500 pro /
2500 flash / 2500 vision), so one id exhausting its limit 429s only that id instead of the whole
account. Nothing to configure — it is derived automatically:
| Call site | Id | Why that key |
|---|---|---|
LoopAgentAdapter (only when deepSeekDirect) | buildRunUserId(task.id) — one id per RUN | KVCache isolation pays off when fan-out workers share a long prompt prefix, so one dispatch's workers reuse each other's cached prefix; a per-worker id would fragment it. Scheduling isolation still holds: one run cannot starve another. |
makeOpenAICompletion (judges, gated on an api.deepseek.com baseURL) | buildJudgeUserId() — per-call nonce | Judge calls are single-turn with no shared prefix, so there is no cache to preserve; the value is only the separate scheduling bucket. |
Helpers live in src/core/userId.ts; the id is a UUID behind a cyberine- prefix, sanitized to
DeepSeek's [a-zA-Z0-9\-_]+ / max-512 contract, so it carries nothing user-identifying by
construction. Non-DeepSeek providers (OpenRouter, the LiteLLM gateway) never receive the field.
The field is emitted as a TOP-LEVEL body key, never wrapped in extra_body — that envelope is a
Python-SDK concept and openai-node 4.x has no equivalent, so nesting it there would put a literal
extra_body object on the wire and DeepSeek would never see the id. Verify with:
npm run selftest:user-id-wire # offline; no key, no networkKnown limitation / deferred work: the isolation is real but its BENEFIT is unmeasured — nothing
here proves a KVCache hit-rate or a concurrency improvement, and on a regular (non-increased-quota)
account every id still pools into one concurrency count, so the scheduling half is inert until the
account is upgraded. The 10-minute no-inference server disconnect DeepSeek documents alongside this
field is written down in docs/providers/deepseek.md next to the IdleStreamWatchdog
(CYBERINE_STREAM_WATCHDOG_MS, default 5 minutes) but has never been exercised against a live
10-minute stall, and whether an SSE : keep-alive comment resets that watchdog is untested. The
Anthropic-SDK transport for the same field (metadata: {"user_id": ...}) is not wired.
Vision / multimodal tasks
Loop workers can forward image attachments to vision-capable models. Images are read from disk and sent as OpenAI-style imageurl content parts (base64 data URLs). The router automatically excludes...
The opencode2 worker (OpenCode 2.0 preview)
opencode2-deepseek is a build-fleet worker driving the OpenCode 2.0 preview binary. It is a SIBLING of opencode-deepseek, not a replacement — v1 and v2 are separate binaries, and the v1 one is...