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
+5
View File
@@ -658,6 +658,11 @@ export class GeminiClient {
if (adaptiveConfig) { if (adaptiveConfig) {
modelConfigKey.thinkingBudget = adaptiveConfig.thinkingBudget; modelConfigKey.thinkingBudget = adaptiveConfig.thinkingBudget;
modelConfigKey.thinkingLevel = adaptiveConfig.thinkingLevel; modelConfigKey.thinkingLevel = adaptiveConfig.thinkingLevel;
this.getChat().recordAdaptiveThinking({
complexity: adaptiveConfig.complexity,
thinkingBudget: adaptiveConfig.thinkingBudget,
thinkingLevel: adaptiveConfig.thinkingLevel,
});
} }
} }
} }
+8
View File
@@ -260,6 +260,14 @@ export class GeminiChat {
this.systemInstruction = sysInstr; 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. * Sends a message to the model and returns the response in chunks.
* *
@@ -83,6 +83,11 @@ export type ConversationRecordExtra =
thoughts?: Array<ThoughtSummary & { timestamp: string }>; thoughts?: Array<ThoughtSummary & { timestamp: string }>;
tokens?: TokensSummary | null; tokens?: TokensSummary | null;
model?: string; model?: string;
adaptiveThinking?: {
complexity: number;
thinkingBudget?: number;
thinkingLevel?: string;
};
}; };
/** /**
@@ -130,6 +135,11 @@ export class ChatRecordingService {
private projectHash: string; private projectHash: string;
private queuedThoughts: Array<ThoughtSummary & { timestamp: string }> = []; private queuedThoughts: Array<ThoughtSummary & { timestamp: string }> = [];
private queuedTokens: TokensSummary | null = null; private queuedTokens: TokensSummary | null = null;
private queuedAdaptiveThinking?: {
complexity: number;
thinkingBudget?: number;
thinkingLevel?: string;
};
private config: Config; private config: Config;
constructor(config: Config) { constructor(config: Config) {
@@ -186,6 +196,7 @@ export class ChatRecordingService {
// Clear any queued data since this is a fresh start // Clear any queued data since this is a fresh start
this.queuedThoughts = []; this.queuedThoughts = [];
this.queuedTokens = null; this.queuedTokens = null;
this.queuedAdaptiveThinking = undefined;
} catch (error) { } catch (error) {
// Handle disk full (ENOSPC) gracefully - disable recording but allow CLI to continue // Handle disk full (ENOSPC) gracefully - disable recording but allow CLI to continue
if ( if (
@@ -230,6 +241,11 @@ export class ChatRecordingService {
type: ConversationRecordExtra['type']; type: ConversationRecordExtra['type'];
content: PartListUnion; content: PartListUnion;
displayContent?: PartListUnion; displayContent?: PartListUnion;
adaptiveThinking?: {
complexity: number;
thinkingBudget?: number;
thinkingLevel?: string;
};
}): void { }): void {
if (!this.conversationFile) return; if (!this.conversationFile) return;
@@ -247,9 +263,12 @@ export class ChatRecordingService {
thoughts: this.queuedThoughts, thoughts: this.queuedThoughts,
tokens: this.queuedTokens, tokens: this.queuedTokens,
model: message.model, model: message.model,
adaptiveThinking:
message.adaptiveThinking || this.queuedAdaptiveThinking,
}); });
this.queuedThoughts = []; this.queuedThoughts = [];
this.queuedTokens = null; this.queuedTokens = null;
this.queuedAdaptiveThinking = undefined;
} else { } else {
// Or else just add it. // Or else just add it.
conversation.messages.push(msg); 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. * Records a thought from the assistant's reasoning process.
*/ */
+26 -1
View File
@@ -553,7 +553,7 @@ function toGenerateContentConfigAttributes(
if (!config) { if (!config) {
return {}; return {};
} }
return { const attributes: LogAttributes = {
'gen_ai.request.temperature': config.temperature, 'gen_ai.request.temperature': config.temperature,
'gen_ai.request.top_p': config.topP, 'gen_ai.request.top_p': config.topP,
'gen_ai.request.top_k': config.topK, 'gen_ai.request.top_k': config.topK,
@@ -568,6 +568,20 @@ function toGenerateContentConfigAttributes(
toSystemInstruction(config.systemInstruction), 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 { export class ApiResponseEvent implements BaseTelemetryEvent {
@@ -632,6 +646,17 @@ export class ApiResponseEvent implements BaseTelemetryEvent {
status_code: this.status_code, status_code: this.status_code,
finish_reasons: this.finish_reasons, 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) { if (this.response_text) {
attributes['response_text'] = this.response_text; attributes['response_text'] = this.response_text;
} }