feat: instrument adaptive thinking metrics in telemetry and chat logs

This commit is contained in:
Adam Weidman
2026-02-09 14:49:40 -05:00
parent 1de614f38e
commit 5eeddaef52
4 changed files with 70 additions and 1 deletions

View File

@@ -658,6 +658,11 @@ export class GeminiClient {
if (adaptiveConfig) {
modelConfigKey.thinkingBudget = adaptiveConfig.thinkingBudget;
modelConfigKey.thinkingLevel = adaptiveConfig.thinkingLevel;
this.getChat().recordAdaptiveThinking({
complexity: adaptiveConfig.complexity,
thinkingBudget: adaptiveConfig.thinkingBudget,
thinkingLevel: adaptiveConfig.thinkingLevel,
});
}
}
}

View File

@@ -260,6 +260,14 @@ export class GeminiChat {
this.systemInstruction = sysInstr;
}
recordAdaptiveThinking(info: {
complexity: number;
thinkingBudget?: number;
thinkingLevel?: string;
}) {
this.chatRecordingService.recordAdaptiveThinking(info);
}
/**
* Sends a message to the model and returns the response in chunks.
*

View File

@@ -83,6 +83,11 @@ export type ConversationRecordExtra =
thoughts?: Array<ThoughtSummary & { timestamp: string }>;
tokens?: TokensSummary | null;
model?: string;
adaptiveThinking?: {
complexity: number;
thinkingBudget?: number;
thinkingLevel?: string;
};
};
/**
@@ -130,6 +135,11 @@ export class ChatRecordingService {
private projectHash: string;
private queuedThoughts: Array<ThoughtSummary & { timestamp: string }> = [];
private queuedTokens: TokensSummary | null = null;
private queuedAdaptiveThinking?: {
complexity: number;
thinkingBudget?: number;
thinkingLevel?: string;
};
private config: Config;
constructor(config: Config) {
@@ -186,6 +196,7 @@ export class ChatRecordingService {
// Clear any queued data since this is a fresh start
this.queuedThoughts = [];
this.queuedTokens = null;
this.queuedAdaptiveThinking = undefined;
} catch (error) {
// Handle disk full (ENOSPC) gracefully - disable recording but allow CLI to continue
if (
@@ -230,6 +241,11 @@ export class ChatRecordingService {
type: ConversationRecordExtra['type'];
content: PartListUnion;
displayContent?: PartListUnion;
adaptiveThinking?: {
complexity: number;
thinkingBudget?: number;
thinkingLevel?: string;
};
}): void {
if (!this.conversationFile) return;
@@ -247,9 +263,12 @@ export class ChatRecordingService {
thoughts: this.queuedThoughts,
tokens: this.queuedTokens,
model: message.model,
adaptiveThinking:
message.adaptiveThinking || this.queuedAdaptiveThinking,
});
this.queuedThoughts = [];
this.queuedTokens = null;
this.queuedAdaptiveThinking = undefined;
} else {
// Or else just add it.
conversation.messages.push(msg);
@@ -261,6 +280,18 @@ export class ChatRecordingService {
}
}
/**
* Queues adaptive thinking info to be recorded with the next Gemini message.
*/
recordAdaptiveThinking(info: {
complexity: number;
thinkingBudget?: number;
thinkingLevel?: string;
}): void {
if (!this.conversationFile) return;
this.queuedAdaptiveThinking = info;
}
/**
* Records a thought from the assistant's reasoning process.
*/

View File

@@ -553,7 +553,7 @@ function toGenerateContentConfigAttributes(
if (!config) {
return {};
}
return {
const attributes: LogAttributes = {
'gen_ai.request.temperature': config.temperature,
'gen_ai.request.top_p': config.topP,
'gen_ai.request.top_k': config.topK,
@@ -568,6 +568,20 @@ function toGenerateContentConfigAttributes(
toSystemInstruction(config.systemInstruction),
),
};
if (config.thinkingConfig) {
const thinkingConfig = config.thinkingConfig;
if (thinkingConfig.thinkingBudget !== undefined) {
attributes['gen_ai.request.thinking_budget'] =
thinkingConfig.thinkingBudget;
}
if (thinkingConfig.thinkingLevel !== undefined) {
attributes['gen_ai.request.thinking_level'] =
thinkingConfig.thinkingLevel;
}
}
return attributes;
}
export class ApiResponseEvent implements BaseTelemetryEvent {
@@ -632,6 +646,17 @@ export class ApiResponseEvent implements BaseTelemetryEvent {
status_code: this.status_code,
finish_reasons: this.finish_reasons,
};
if (this.prompt.generate_content_config?.thinkingConfig) {
const thinkingConfig = this.prompt.generate_content_config.thinkingConfig;
if (thinkingConfig.thinkingBudget !== undefined) {
attributes['thinking_budget'] = thinkingConfig.thinkingBudget;
}
if (thinkingConfig.thinkingLevel !== undefined) {
attributes['thinking_level'] = thinkingConfig.thinkingLevel;
}
}
if (this.response_text) {
attributes['response_text'] = this.response_text;
}