From d497e92626a4c78a4ae755cd8e5cadb4a1e671b4 Mon Sep 17 00:00:00 2001 From: ywkj Date: Sun, 26 Apr 2026 19:45:08 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=94=A8=20fetch=20wrapper=20=E6=B3=A8?= =?UTF-8?q?=E5=85=A5=20metadata.session=5Fid=20=E6=9B=BF=E4=BB=A3=20HTTP?= =?UTF-8?q?=20header?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LiteLLM 不处理 x-langfuse-session-id header。改用 fetch 拦截器在请求体 metadata 里注入 session_id,LiteLLM 直接透传给 Langfuse 创建 session。 Co-Authored-By: Claude Opus 4.7 --- src/index.ts | 24 ++++++++++++++++++------ src/post-filter.ts | 23 +++++++++++++++++------ src/product-detector.ts | 23 +++++++++++++++++------ 3 files changed, 52 insertions(+), 18 deletions(-) diff --git a/src/index.ts b/src/index.ts index 2a92092..86bfa81 100644 --- a/src/index.ts +++ b/src/index.ts @@ -417,13 +417,25 @@ function getFlag(args: string[], flag: string): string | undefined { } function createVisionModel(config: VisionConfig) { - const headers: Record = { - 'x-langfuse-tags': 'skill:video-product-snapshot', + const sessionId = config.sessionId || ''; + const originFetch = globalThis.fetch; + // Inject metadata.session_id into request body so LiteLLM → Langfuse creates sessions + const wrapped = async (input: RequestInfo | URL, init?: RequestInit) => { + if (init?.body && typeof init.body === 'string') { + try { + const body = JSON.parse(init.body); + if (!body.metadata) body.metadata = {}; + if (!body.metadata.session_id) body.metadata.session_id = sessionId; + body.metadata.tags = ['skill:video-product-snapshot']; + init = { ...init, body: JSON.stringify(body) }; + } catch {} + } + return originFetch(input, init); }; - if (config.sessionId) { - headers['x-langfuse-session-id'] = config.sessionId; - } - const openai = createOpenAI({ apiKey: config.apiKey, baseURL: config.baseURL, headers }); + const openai = createOpenAI({ + apiKey: config.apiKey, baseURL: config.baseURL, + fetch: wrapped as typeof globalThis.fetch, + }); return openai(config.model); } diff --git a/src/post-filter.ts b/src/post-filter.ts index b87e8b0..f667fab 100644 --- a/src/post-filter.ts +++ b/src/post-filter.ts @@ -34,13 +34,24 @@ const FILTER_PROMPT = (count: number, description?: string) => { }; function createModel(config: VisionConfig) { - const headers: Record = { - 'x-langfuse-tags': 'skill:video-product-snapshot', + const sessionId = config.sessionId || ''; + const originFetch = globalThis.fetch; + const wrapped = async (input: RequestInfo | URL, init?: RequestInit) => { + if (init?.body && typeof init.body === 'string') { + try { + const body = JSON.parse(init.body); + if (!body.metadata) body.metadata = {}; + if (!body.metadata.session_id) body.metadata.session_id = sessionId; + body.metadata.tags = ['skill:video-product-snapshot']; + init = { ...init, body: JSON.stringify(body) }; + } catch {} + } + return originFetch(input, init); }; - if (config.sessionId) { - headers['x-langfuse-session-id'] = config.sessionId; - } - const provider = createOpenAI({ apiKey: config.apiKey, baseURL: config.baseURL, headers }); + const provider = createOpenAI({ + apiKey: config.apiKey, baseURL: config.baseURL, + fetch: wrapped as typeof globalThis.fetch, + }); return provider(config.model); } diff --git a/src/product-detector.ts b/src/product-detector.ts index 1e971aa..68d3eeb 100644 --- a/src/product-detector.ts +++ b/src/product-detector.ts @@ -78,13 +78,24 @@ Return: - boundingBox: tight box of the PRODUCT ONLY as [x1, y1, x2, y2] normalized 0.0–1.0, top-left origin. Exclude hands, background, and unrelated objects. The product is near the center of the frame.`; function createVisionModel(config: VisionConfig) { - const headers: Record = { - 'x-langfuse-tags': 'skill:video-product-snapshot', + const sessionId = config.sessionId || ''; + const originFetch = globalThis.fetch; + const wrapped = async (input: RequestInfo | URL, init?: RequestInit) => { + if (init?.body && typeof init.body === 'string') { + try { + const body = JSON.parse(init.body); + if (!body.metadata) body.metadata = {}; + if (!body.metadata.session_id) body.metadata.session_id = sessionId; + body.metadata.tags = ['skill:video-product-snapshot']; + init = { ...init, body: JSON.stringify(body) }; + } catch {} + } + return originFetch(input, init); }; - if (config.sessionId) { - headers['x-langfuse-session-id'] = config.sessionId; - } - const provider = createOpenAI({ apiKey: config.apiKey, baseURL: config.baseURL, headers }); + const provider = createOpenAI({ + apiKey: config.apiKey, baseURL: config.baseURL, + fetch: wrapped as typeof globalThis.fetch, + }); return provider(config.model); }