mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-25 20:44:46 -07:00
perf: optimize chat recording and add universal tool output truncation
This commit is contained in:
@@ -17,7 +17,6 @@ import {
|
|||||||
logToolOutputTruncated,
|
logToolOutputTruncated,
|
||||||
runInDevTraceSpan,
|
runInDevTraceSpan,
|
||||||
} from '../index.js';
|
} from '../index.js';
|
||||||
import { SHELL_TOOL_NAME } from '../tools/tool-names.js';
|
|
||||||
import { ShellToolInvocation } from '../tools/shell.js';
|
import { ShellToolInvocation } from '../tools/shell.js';
|
||||||
import { executeToolWithHooks } from '../core/coreToolHookTriggers.js';
|
import { executeToolWithHooks } from '../core/coreToolHookTriggers.js';
|
||||||
import {
|
import {
|
||||||
@@ -204,7 +203,7 @@ export class ToolExecutor {
|
|||||||
const toolName = call.request.name;
|
const toolName = call.request.name;
|
||||||
const callId = call.request.callId;
|
const callId = call.request.callId;
|
||||||
|
|
||||||
if (typeof content === 'string' && toolName === SHELL_TOOL_NAME) {
|
if (typeof content === 'string') {
|
||||||
const threshold = this.config.getTruncateToolOutputThreshold();
|
const threshold = this.config.getTruncateToolOutputThreshold();
|
||||||
|
|
||||||
if (threshold > 0 && content.length > threshold) {
|
if (threshold > 0 && content.length > threshold) {
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ export interface ResumedSessionData {
|
|||||||
*/
|
*/
|
||||||
export class ChatRecordingService {
|
export class ChatRecordingService {
|
||||||
private conversationFile: string | null = null;
|
private conversationFile: string | null = null;
|
||||||
|
private conversation: ConversationRecord | null = null;
|
||||||
private cachedLastConvData: string | null = null;
|
private cachedLastConvData: string | null = null;
|
||||||
private sessionId: string;
|
private sessionId: string;
|
||||||
private projectHash: string;
|
private projectHash: string;
|
||||||
@@ -148,6 +149,7 @@ export class ChatRecordingService {
|
|||||||
// Resume from existing session
|
// Resume from existing session
|
||||||
this.conversationFile = resumedSessionData.filePath;
|
this.conversationFile = resumedSessionData.filePath;
|
||||||
this.sessionId = resumedSessionData.conversation.sessionId;
|
this.sessionId = resumedSessionData.conversation.sessionId;
|
||||||
|
this.conversation = resumedSessionData.conversation;
|
||||||
|
|
||||||
// Update the session ID in the existing file
|
// Update the session ID in the existing file
|
||||||
this.updateConversation((conversation) => {
|
this.updateConversation((conversation) => {
|
||||||
@@ -174,13 +176,15 @@ export class ChatRecordingService {
|
|||||||
)}.json`;
|
)}.json`;
|
||||||
this.conversationFile = path.join(chatsDir, filename);
|
this.conversationFile = path.join(chatsDir, filename);
|
||||||
|
|
||||||
this.writeConversation({
|
const initialConversation: ConversationRecord = {
|
||||||
sessionId: this.sessionId,
|
sessionId: this.sessionId,
|
||||||
projectHash: this.projectHash,
|
projectHash: this.projectHash,
|
||||||
startTime: new Date().toISOString(),
|
startTime: new Date().toISOString(),
|
||||||
lastUpdated: new Date().toISOString(),
|
lastUpdated: new Date().toISOString(),
|
||||||
messages: [],
|
messages: [],
|
||||||
});
|
};
|
||||||
|
this.conversation = initialConversation;
|
||||||
|
this.writeConversation(initialConversation, { allowEmpty: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear any queued data since this is a fresh start
|
// Clear any queued data since this is a fresh start
|
||||||
@@ -416,9 +420,12 @@ export class ChatRecordingService {
|
|||||||
* Loads up the conversation record from disk.
|
* Loads up the conversation record from disk.
|
||||||
*/
|
*/
|
||||||
private readConversation(): ConversationRecord {
|
private readConversation(): ConversationRecord {
|
||||||
|
if (this.conversation) return this.conversation;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.cachedLastConvData = fs.readFileSync(this.conversationFile!, 'utf8');
|
this.cachedLastConvData = fs.readFileSync(this.conversationFile!, 'utf8');
|
||||||
return JSON.parse(this.cachedLastConvData);
|
this.conversation = JSON.parse(this.cachedLastConvData);
|
||||||
|
return this.conversation!;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
|
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
|
||||||
debugLogger.error('Error reading conversation file.', error);
|
debugLogger.error('Error reading conversation file.', error);
|
||||||
@@ -426,13 +433,14 @@ export class ChatRecordingService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Placeholder empty conversation if file doesn't exist.
|
// Placeholder empty conversation if file doesn't exist.
|
||||||
return {
|
this.conversation = {
|
||||||
sessionId: this.sessionId,
|
sessionId: this.sessionId,
|
||||||
projectHash: this.projectHash,
|
projectHash: this.projectHash,
|
||||||
startTime: new Date().toISOString(),
|
startTime: new Date().toISOString(),
|
||||||
lastUpdated: new Date().toISOString(),
|
lastUpdated: new Date().toISOString(),
|
||||||
messages: [],
|
messages: [],
|
||||||
};
|
};
|
||||||
|
return this.conversation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -446,14 +454,18 @@ export class ChatRecordingService {
|
|||||||
try {
|
try {
|
||||||
if (!this.conversationFile) return;
|
if (!this.conversationFile) return;
|
||||||
// Don't write the file yet until there's at least one message.
|
// Don't write the file yet until there's at least one message.
|
||||||
if (conversation.messages.length === 0 && !allowEmpty) return;
|
if ((conversation.messages?.length ?? 0) === 0 && !allowEmpty) return;
|
||||||
|
|
||||||
// Only write the file if this change would change the file.
|
// Avoid redundant stringification by checking if the content changed first.
|
||||||
if (this.cachedLastConvData !== JSON.stringify(conversation, null, 2)) {
|
// We use the cached string for comparison to avoid a new stringification
|
||||||
|
// when nothing has changed.
|
||||||
|
const currentContent = JSON.stringify(conversation, null, 2);
|
||||||
|
if (this.cachedLastConvData !== currentContent) {
|
||||||
|
// Only update the timestamp and re-stringify if something actually changed.
|
||||||
conversation.lastUpdated = new Date().toISOString();
|
conversation.lastUpdated = new Date().toISOString();
|
||||||
const newContent = JSON.stringify(conversation, null, 2);
|
const finalContent = JSON.stringify(conversation, null, 2);
|
||||||
this.cachedLastConvData = newContent;
|
this.cachedLastConvData = finalContent;
|
||||||
fs.writeFileSync(this.conversationFile, newContent);
|
fs.writeFileSync(this.conversationFile, finalContent);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Handle disk full (ENOSPC) gracefully - disable recording but allow conversation to continue
|
// Handle disk full (ENOSPC) gracefully - disable recording but allow conversation to continue
|
||||||
|
|||||||
Reference in New Issue
Block a user