diff --git a/src/services/api/claude.ts b/src/services/api/claude.ts index 720370db6..af310af8f 100644 --- a/src/services/api/claude.ts +++ b/src/services/api/claude.ts @@ -1776,6 +1776,8 @@ async function* queryModel( // captures only primitives instead of paramsFromContext's full closure scope // (messagesForAPI, system, allTools, betas — the entire request-building // context), which would otherwise be pinned until the promise resolves. + // Also capture thinking params for Langfuse observability. + let langfuseThinking: { type: string; budgetTokens?: number } | undefined { const queryParams = paramsFromContext({ model: options.model, @@ -1785,6 +1787,15 @@ async function* queryModel( const logBetas = useBetas ? (queryParams.betas ?? []) : [] const logThinkingType = queryParams.thinking?.type ?? 'disabled' const logEffortValue = queryParams.output_config?.effort + if (queryParams.thinking && queryParams.thinking.type !== 'disabled') { + langfuseThinking = { + type: queryParams.thinking.type, + ...('budget_tokens' in queryParams.thinking && + typeof queryParams.thinking.budget_tokens === 'number' && { + budgetTokens: queryParams.thinking.budget_tokens, + }), + } + } void options.getToolPermissionContext().then(permissionContext => { logAPIQuery({ model: options.model, @@ -2925,6 +2936,7 @@ async function* queryModel( endTime: new Date(), completionStartTime: ttftMs > 0 ? new Date(start + ttftMs) : undefined, tools: convertToolsToLangfuse(toolSchemas as unknown[]), + thinking: langfuseThinking, }) void options.getToolPermissionContext().then(permissionContext => { diff --git a/src/services/api/gemini/index.ts b/src/services/api/gemini/index.ts index bf9058b6e..af9a0debb 100644 --- a/src/services/api/gemini/index.ts +++ b/src/services/api/gemini/index.ts @@ -193,6 +193,15 @@ export async function* queryModelGemini( endTime: new Date(), completionStartTime: ttftMs > 0 ? new Date(start + ttftMs) : undefined, tools: convertToolsToLangfuse(toolSchemas as unknown[]), + thinking: + thinkingConfig.type !== 'disabled' + ? { + type: thinkingConfig.type, + ...(thinkingConfig.type === 'enabled' && { + budgetTokens: thinkingConfig.budgetTokens, + }), + } + : undefined, }) } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error) diff --git a/src/services/api/openai/index.ts b/src/services/api/openai/index.ts index 248c2dac3..f161cb602 100644 --- a/src/services/api/openai/index.ts +++ b/src/services/api/openai/index.ts @@ -418,6 +418,7 @@ export async function* queryModelOpenAI( endTime: new Date(), completionStartTime: ttftMs > 0 ? new Date(start + ttftMs) : undefined, tools: convertToolsToLangfuse(toolSchemas as unknown[]), + ...(enableThinking && { thinking: { type: 'enabled' } }), }) // Safety: if stream ended without message_stop, assemble and yield whatever we have diff --git a/src/services/langfuse/tracing.ts b/src/services/langfuse/tracing.ts index da6ed00d1..ff57b334e 100644 --- a/src/services/langfuse/tracing.ts +++ b/src/services/langfuse/tracing.ts @@ -78,6 +78,11 @@ export function recordLLMObservation( endTime?: Date completionStartTime?: Date tools?: unknown + /** Thinking depth configuration used for this request */ + thinking?: { + type: string + budgetTokens?: number + } }, ): void { if (!rootSpan || !isLangfuseEnabled()) return @@ -97,6 +102,10 @@ export function recordLLMObservation( metadata: { provider: params.provider, model: params.model, + ...(params.thinking && { thinkingType: params.thinking.type }), + ...(params.thinking?.budgetTokens !== undefined && { + thinkingBudgetTokens: params.thinking.budgetTokens, + }), }, ...(params.completionStartTime && { completionStartTime: params.completionStartTime }), }, diff --git a/src/services/tokenEstimation.ts b/src/services/tokenEstimation.ts index 07a7eb59b..32388fca7 100644 --- a/src/services/tokenEstimation.ts +++ b/src/services/tokenEstimation.ts @@ -354,6 +354,7 @@ export async function countTokensViaHaikuFallback( }, startTime: new Date(apiStart), endTime: new Date(), + ...(containsThinking && { thinking: { type: 'enabled', budgetTokens: TOKEN_COUNT_THINKING_BUDGET } }), }) endTrace(langfuseTrace) diff --git a/src/utils/sideQuery.ts b/src/utils/sideQuery.ts index 6aa66aad3..c1f5bc3c6 100644 --- a/src/utils/sideQuery.ts +++ b/src/utils/sideQuery.ts @@ -294,6 +294,12 @@ export async function sideQuery(opts: SideQueryOptions): Promise { startTime: new Date(start), endTime: new Date(), ...(tools && { tools: convertToolsToLangfuse(tools as unknown[]) }), + ...(thinkingConfig && thinkingConfig.type !== 'disabled' && { + thinking: { + type: thinkingConfig.type, + ...(thinkingConfig.type === 'enabled' && { budgetTokens: thinkingConfig.budget_tokens }), + }, + }), }) endTrace(langfuseTrace)