fix(qoder): report usage to all clients and stop inlining large attachments
- Coalesce Qoder's empty finish-in-delta frame with the later choices:[] usage frame so OpenAI and Claude clients receive prompt_tokens, completion_tokens and cache-hit tokens (the dashboard already saw them) - Upload inlined images through /api/v2/image/upload like qodercli, and stub oversized non-image files instead of stuffing 30MB+ data URIs into agent_chat_generation - Emit response.completed -> response.usage for chat-native upstreams so /v1/responses clients (Codex CLI, sub2api) no longer log 0/0/0 - Keep Claude message_delta.usage working when usage arrives without choices[0] - Escalate to the smallest advertised Qoder context tier (200K/400K/1M) when the estimated prompt no longer fits max_input_tokens - Pass apiKey for PAT connections and list hidden enable:false catalog keys from /v1/models
This commit is contained in:
@@ -33,6 +33,39 @@ export const QODER_CHAT_SIG_PATH = "/api/v2/service/pro/sse/agent_chat_generatio
|
||||
export const QODER_CHAT_URL = `${QODER_CHAT_BASE}/algo${QODER_CHAT_SIG_PATH}?FetchKeys=llm_model_result&AgentId=agent_common`;
|
||||
export const QODER_CHAT_URL_ENCODED = `${QODER_CHAT_URL}&Encode=1`;
|
||||
export const QODER_MODEL_LIST_URL = `${QODER_CHAT_BASE}/algo/api/v2/model/list`;
|
||||
// Official qodercli uploads images here (COSY-signed PUT multipart, field "file")
|
||||
// instead of inlining base64 into agent_chat_generation.
|
||||
export const QODER_IMAGE_UPLOAD_SIG_PATH = "/api/v2/image/upload";
|
||||
|
||||
// Drop remaining inlined binaries if the Qoder JSON body would still exceed this.
|
||||
// 30MB+ payloads are what blow past Claude-Code's ~200k context on the wire.
|
||||
export const QODER_MAX_PAYLOAD_BYTES = 6 * 1024 * 1024;
|
||||
// If OSS upload fails, keep tiny data-URIs; anything larger is stubbed.
|
||||
export const QODER_INLINE_FALLBACK_MAX_BYTES = 512 * 1024;
|
||||
|
||||
// Context-window tier selection (see shared/qoder/contextTier.js). The IDE exposes the
|
||||
// model's context_config tiers (200K/400K/1M); we auto-escalate when the estimated prompt
|
||||
// (+ headroom, tokenizer variance) no longer fits the current max_input_tokens.
|
||||
export const QODER_CONTEXT_TIER_HEADROOM = 0.15;
|
||||
export const QODER_CONTEXT_TIER_ENV = "QODER_CONTEXT_TIER";
|
||||
export const QODER_CONTEXT_TIER_MODES = Object.freeze({ AUTO: "auto", MAX: "max", DEFAULT: "default" });
|
||||
|
||||
/**
|
||||
* Job-token (jt-...) traffic must hit api2.qoder.sh — api3 rejects jt- with
|
||||
* "Login expired" (403). Device tokens (dt-...) stay on api3. PATs (pt-...)
|
||||
* are exchanged for jt- before this is consulted.
|
||||
*/
|
||||
export function qoderInferenceBase(credentials) {
|
||||
const raw = credentials?.apiKey || credentials?.accessToken;
|
||||
if (
|
||||
typeof raw === "string" &&
|
||||
!raw.startsWith("pt-") &&
|
||||
(raw.startsWith("jt-") || (credentials?.accessToken || "").startsWith("jt-"))
|
||||
) {
|
||||
return QODER_CHAT_BASE_ALT;
|
||||
}
|
||||
return QODER_CHAT_BASE;
|
||||
}
|
||||
|
||||
// COSY header constants. These are not arbitrary — the upstream signature
|
||||
// validation matches them against the values used at signing time.
|
||||
|
||||
Reference in New Issue
Block a user