From 23f6ae8513b68b9f0c8b4d49254914f7d261312f Mon Sep 17 00:00:00 2001 From: "koalazf.99" Date: Sat, 2 Aug 2025 14:47:37 +0800 Subject: [PATCH] merge main branch functionalities --- .gitignore | 3 +- packages/cli/src/config/config.test.ts | 64 +- packages/cli/src/config/config.ts | 3 + packages/cli/src/config/settings.ts | 10 + .../cli/src/test-utils/mockCommandContext.ts | 2 + .../cli/src/ui/commands/clearCommand.test.ts | 6 + packages/cli/src/ui/commands/clearCommand.ts | 1 + packages/cli/src/ui/commands/docsCommand.ts | 4 +- packages/cli/src/ui/commands/toolsCommand.ts | 4 +- packages/cli/src/ui/commands/types.ts | 1 + .../cli/src/ui/contexts/SessionContext.tsx | 13 +- .../cli/src/ui/hooks/slashCommandProcessor.ts | 2 + packages/cli/src/ui/hooks/useGeminiStream.ts | 21 + packages/cli/src/ui/utils/updateCheck.ts | 2 +- packages/cli/src/utils/userStartupWarnings.ts | 2 +- packages/core/src/code_assist/server.ts | 2 +- packages/core/src/config/config.ts | 60 +- .../core/__snapshots__/prompts.test.ts.snap | 1107 ++++++++++++----- packages/core/src/core/client.test.ts | 3 + packages/core/src/core/client.ts | 81 +- .../core/src/core/contentGenerator.test.ts | 4 + packages/core/src/core/contentGenerator.ts | 4 + packages/core/src/core/modelCheck.ts | 62 +- .../core/src/core/openaiContentGenerator.ts | 8 +- packages/core/src/core/prompts.test.ts | 93 ++ packages/core/src/core/prompts.ts | 207 ++- packages/core/src/core/turn.ts | 13 + packages/core/src/mcp/oauth-provider.ts | 2 +- .../core/src/utils/getFolderStructure.test.ts | 10 +- packages/core/src/utils/getFolderStructure.ts | 4 +- 30 files changed, 1378 insertions(+), 420 deletions(-) diff --git a/.gitignore b/.gitignore index 2a3d9076..fb9ccaa5 100644 --- a/.gitignore +++ b/.gitignore @@ -41,4 +41,5 @@ packages/cli/src/generated/ packages/vscode-ide-companion/*.vsix # Qwen Code Configs -.qwen/ \ No newline at end of file +.qwen/ +logs/ \ No newline at end of file diff --git a/packages/cli/src/config/config.test.ts b/packages/cli/src/config/config.test.ts index b1f13fd0..c8e2bd71 100644 --- a/packages/cli/src/config/config.test.ts +++ b/packages/cli/src/config/config.test.ts @@ -6,7 +6,7 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import * as os from 'os'; -import { loadCliConfig, parseArguments } from './config.js'; +import { loadCliConfig, parseArguments, CliArgs } from './config.js'; import { Settings } from './settings.js'; import { Extension } from './extension.js'; import * as ServerConfig from '@qwen-code/qwen-code-core'; @@ -561,6 +561,68 @@ describe('mergeMcpServers', () => { }); }); +describe('loadCliConfig systemPromptMappings', () => { + it('should use default systemPromptMappings when not provided in settings', async () => { + const mockSettings: Settings = { + theme: 'dark', + }; + const mockExtensions: Extension[] = []; + const mockSessionId = 'test-session'; + const mockArgv: CliArgs = { + model: 'test-model', + } as CliArgs; + + const config = await loadCliConfig( + mockSettings, + mockExtensions, + mockSessionId, + mockArgv, + ); + + expect(config.getSystemPromptMappings()).toEqual([ + { + baseUrls: [ + 'https://dashscope.aliyuncs.com/compatible-mode/v1/', + 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1/', + ], + modelNames: ['qwen3-coder-plus'], + template: + 'SYSTEM_TEMPLATE:{"name":"qwen3_coder","params":{"is_git_repository":{RUNTIME_VARS_IS_GIT_REPO},"sandbox":"{RUNTIME_VARS_SANDBOX}"}}', + }, + ]); + }); + + it('should use custom systemPromptMappings when provided in settings', async () => { + const customSystemPromptMappings = [ + { + baseUrls: ['https://custom-api.com'], + modelNames: ['custom-model'], + template: 'Custom template', + }, + ]; + const mockSettings: Settings = { + theme: 'dark', + systemPromptMappings: customSystemPromptMappings, + }; + const mockExtensions: Extension[] = []; + const mockSessionId = 'test-session'; + const mockArgv: CliArgs = { + model: 'test-model', + } as CliArgs; + + const config = await loadCliConfig( + mockSettings, + mockExtensions, + mockSessionId, + mockArgv, + ); + + expect(config.getSystemPromptMappings()).toEqual( + customSystemPromptMappings, + ); + }); +}); + describe('mergeExcludeTools', () => { it('should merge excludeTools from settings and extensions', async () => { const settings: Settings = { excludeTools: ['tool1', 'tool2'] }; diff --git a/packages/cli/src/config/config.ts b/packages/cli/src/config/config.ts index a8271e26..5e6652e8 100644 --- a/packages/cli/src/config/config.ts +++ b/packages/cli/src/config/config.ts @@ -441,6 +441,8 @@ export async function loadCliConfig( model: argv.model!, extensionContextFilePaths, maxSessionTurns: settings.maxSessionTurns ?? -1, + sessionTokenLimit: settings.sessionTokenLimit ?? 32000, + maxFolderItems: settings.maxFolderItems ?? 20, experimentalAcp: argv.experimentalAcp || false, listExtensions: argv.listExtensions || false, extensions: allExtensions, @@ -465,6 +467,7 @@ export async function loadCliConfig( 'SYSTEM_TEMPLATE:{"name":"qwen3_coder","params":{"is_git_repository":{RUNTIME_VARS_IS_GIT_REPO},"sandbox":"{RUNTIME_VARS_SANDBOX}"}}', }, ], + contentGenerator: settings.contentGenerator, }); } diff --git a/packages/cli/src/config/settings.ts b/packages/cli/src/config/settings.ts index 13528df4..31de5004 100644 --- a/packages/cli/src/config/settings.ts +++ b/packages/cli/src/config/settings.ts @@ -95,6 +95,12 @@ export interface Settings { // Setting for setting maximum number of user/model/tool turns in a session. maxSessionTurns?: number; + // Setting for maximum token limit for conversation history before blocking requests + sessionTokenLimit?: number; + + // Setting for maximum number of files and folders to show in folder structure + maxFolderItems?: number; + // A map of tool names to their summarization settings. summarizeToolOutput?: Record; @@ -109,6 +115,10 @@ export interface Settings { modelNames: string[]; template: string; }>; + contentGenerator?: { + timeout?: number; + maxRetries?: number; + }; } export interface SettingsError { diff --git a/packages/cli/src/test-utils/mockCommandContext.ts b/packages/cli/src/test-utils/mockCommandContext.ts index 7d38b213..029d0350 100644 --- a/packages/cli/src/test-utils/mockCommandContext.ts +++ b/packages/cli/src/test-utils/mockCommandContext.ts @@ -69,7 +69,9 @@ export const createMockCommandContext = ( byName: {}, }, }, + promptCount: 0, } as SessionStatsState, + resetSession: vi.fn(), }, }; diff --git a/packages/cli/src/ui/commands/clearCommand.test.ts b/packages/cli/src/ui/commands/clearCommand.test.ts index d34b3d59..492196a2 100644 --- a/packages/cli/src/ui/commands/clearCommand.test.ts +++ b/packages/cli/src/ui/commands/clearCommand.test.ts @@ -55,6 +55,7 @@ describe('clearCommand', () => { expect(mockContext.ui.setDebugMessage).toHaveBeenCalledTimes(1); expect(mockResetChat).toHaveBeenCalledTimes(1); + expect(mockContext.session.resetSession).toHaveBeenCalledTimes(1); expect(uiTelemetryService.resetLastPromptTokenCount).toHaveBeenCalledTimes( 1, ); @@ -64,6 +65,8 @@ describe('clearCommand', () => { const setDebugMessageOrder = (mockContext.ui.setDebugMessage as Mock).mock .invocationCallOrder[0]; const resetChatOrder = mockResetChat.mock.invocationCallOrder[0]; + const resetSessionOrder = (mockContext.session.resetSession as Mock).mock + .invocationCallOrder[0]; const resetTelemetryOrder = ( uiTelemetryService.resetLastPromptTokenCount as Mock ).mock.invocationCallOrder[0]; @@ -73,6 +76,8 @@ describe('clearCommand', () => { expect(setDebugMessageOrder).toBeLessThan(resetChatOrder); expect(resetChatOrder).toBeLessThan(resetTelemetryOrder); expect(resetTelemetryOrder).toBeLessThan(clearOrder); + expect(resetChatOrder).toBeLessThan(resetSessionOrder); + expect(resetSessionOrder).toBeLessThan(clearOrder); }); it('should not attempt to reset chat if config service is not available', async () => { @@ -92,6 +97,7 @@ describe('clearCommand', () => { 'Clearing terminal.', ); expect(mockResetChat).not.toHaveBeenCalled(); + expect(nullConfigContext.session.resetSession).toHaveBeenCalledTimes(1); expect(uiTelemetryService.resetLastPromptTokenCount).toHaveBeenCalledTimes( 1, ); diff --git a/packages/cli/src/ui/commands/clearCommand.ts b/packages/cli/src/ui/commands/clearCommand.ts index 0bf46af1..78d4012d 100644 --- a/packages/cli/src/ui/commands/clearCommand.ts +++ b/packages/cli/src/ui/commands/clearCommand.ts @@ -24,6 +24,7 @@ export const clearCommand: SlashCommand = { } uiTelemetryService.resetLastPromptTokenCount(); + context.session.resetSession(); context.ui.clear(); }, }; diff --git a/packages/cli/src/ui/commands/docsCommand.ts b/packages/cli/src/ui/commands/docsCommand.ts index 922b236a..72d988d5 100644 --- a/packages/cli/src/ui/commands/docsCommand.ts +++ b/packages/cli/src/ui/commands/docsCommand.ts @@ -15,10 +15,10 @@ import { MessageType } from '../types.js'; export const docsCommand: SlashCommand = { name: 'docs', - description: 'open full Gemini CLI documentation in your browser', + description: 'open full Qwen Code documentation in your browser', kind: CommandKind.BUILT_IN, action: async (context: CommandContext): Promise => { - const docsUrl = 'https://goo.gle/gemini-cli-docs'; + const docsUrl = 'https://github.com/QwenLM/qwen-code'; if (process.env.SANDBOX && process.env.SANDBOX !== 'sandbox-exec') { context.ui.addItem( diff --git a/packages/cli/src/ui/commands/toolsCommand.ts b/packages/cli/src/ui/commands/toolsCommand.ts index e993bab3..984d3cf5 100644 --- a/packages/cli/src/ui/commands/toolsCommand.ts +++ b/packages/cli/src/ui/commands/toolsCommand.ts @@ -13,7 +13,7 @@ import { MessageType } from '../types.js'; export const toolsCommand: SlashCommand = { name: 'tools', - description: 'list available Gemini CLI tools', + description: 'list available Qwen Codetools', kind: CommandKind.BUILT_IN, action: async (context: CommandContext, args?: string): Promise => { const subCommand = args?.trim(); @@ -40,7 +40,7 @@ export const toolsCommand: SlashCommand = { // Filter out MCP tools by checking for the absence of a serverName property const geminiTools = tools.filter((tool) => !('serverName' in tool)); - let message = 'Available Gemini CLI tools:\n\n'; + let message = 'Available Qwen Code tools:\n\n'; if (geminiTools.length > 0) { geminiTools.forEach((tool) => { diff --git a/packages/cli/src/ui/commands/types.ts b/packages/cli/src/ui/commands/types.ts index f36aff3a..21ab7828 100644 --- a/packages/cli/src/ui/commands/types.ts +++ b/packages/cli/src/ui/commands/types.ts @@ -63,6 +63,7 @@ export interface CommandContext { // Session-specific data session: { stats: SessionStatsState; + resetSession: () => void; /** A transient list of shell commands the user has approved for this session. */ sessionShellAllowlist: Set; }; diff --git a/packages/cli/src/ui/contexts/SessionContext.tsx b/packages/cli/src/ui/contexts/SessionContext.tsx index 0a588c0b..001badf7 100644 --- a/packages/cli/src/ui/contexts/SessionContext.tsx +++ b/packages/cli/src/ui/contexts/SessionContext.tsx @@ -50,6 +50,7 @@ interface SessionStatsContextValue { stats: SessionStatsState; startNewPrompt: () => void; getPromptCount: () => number; + resetSession: () => void; } // --- Context Definition --- @@ -109,13 +110,23 @@ export const SessionStatsProvider: React.FC<{ children: React.ReactNode }> = ({ [stats.promptCount], ); + const resetSession = useCallback(() => { + setStats({ + sessionStartTime: new Date(), + metrics: uiTelemetryService.getMetrics(), + lastPromptTokenCount: uiTelemetryService.getLastPromptTokenCount(), + promptCount: 0, + }); + }, []); + const value = useMemo( () => ({ stats, startNewPrompt, getPromptCount, + resetSession, }), - [stats, startNewPrompt, getPromptCount], + [stats, startNewPrompt, getPromptCount, resetSession], ); return ( diff --git a/packages/cli/src/ui/hooks/slashCommandProcessor.ts b/packages/cli/src/ui/hooks/slashCommandProcessor.ts index 16c25635..8500728e 100644 --- a/packages/cli/src/ui/hooks/slashCommandProcessor.ts +++ b/packages/cli/src/ui/hooks/slashCommandProcessor.ts @@ -162,6 +162,7 @@ export const useSlashCommandProcessor = ( session: { stats: session.stats, sessionShellAllowlist, + resetSession: session.resetSession, }, }), [ @@ -174,6 +175,7 @@ export const useSlashCommandProcessor = ( clearItems, refreshStatic, session.stats, + session.resetSession, onDebugMessage, pendingCompressionItemRef, setPendingCompressionItem, diff --git a/packages/cli/src/ui/hooks/useGeminiStream.ts b/packages/cli/src/ui/hooks/useGeminiStream.ts index a5e3f4f6..7ff3515b 100644 --- a/packages/cli/src/ui/hooks/useGeminiStream.ts +++ b/packages/cli/src/ui/hooks/useGeminiStream.ts @@ -511,6 +511,23 @@ export const useGeminiStream = ( [addItem, config], ); + const handleSessionTokenLimitExceededEvent = useCallback( + (value: { currentTokens: number; limit: number; message: string }) => + addItem( + { + type: 'error', + text: + `🚫 Session token limit exceeded: ${value.currentTokens.toLocaleString()} tokens > ${value.limit.toLocaleString()} limit.\n\n` + + `πŸ’‘ Solutions:\n` + + ` β€’ Start a new session: Use /clear command\n` + + ` β€’ Increase limit: Add "sessionTokenLimit": (e.g., 128000) to your settings.json\n` + + ` β€’ Compress history: Use /compress command to compress history`, + }, + Date.now(), + ), + [addItem], + ); + const handleLoopDetectedEvent = useCallback(() => { addItem( { @@ -560,6 +577,9 @@ export const useGeminiStream = ( case ServerGeminiEventType.MaxSessionTurns: handleMaxSessionTurnsEvent(); break; + case ServerGeminiEventType.SessionTokenLimitExceeded: + handleSessionTokenLimitExceededEvent(event.value); + break; case ServerGeminiEventType.Finished: handleFinishedEvent( event as ServerGeminiFinishedEvent, @@ -591,6 +611,7 @@ export const useGeminiStream = ( handleChatCompressionEvent, handleFinishedEvent, handleMaxSessionTurnsEvent, + handleSessionTokenLimitExceededEvent, ], ); diff --git a/packages/cli/src/ui/utils/updateCheck.ts b/packages/cli/src/ui/utils/updateCheck.ts index 904a9890..f02c95ca 100644 --- a/packages/cli/src/ui/utils/updateCheck.ts +++ b/packages/cli/src/ui/utils/updateCheck.ts @@ -34,7 +34,7 @@ export async function checkForUpdates(): Promise { notifier.update && semver.gt(notifier.update.latest, notifier.update.current) ) { - return `Gemini CLI update available! ${notifier.update.current} β†’ ${notifier.update.latest}\nRun npm install -g ${packageJson.name} to update`; + return `Qwen Code update available! ${notifier.update.current} β†’ ${notifier.update.latest}\nRun npm install -g ${packageJson.name} to update`; } return null; diff --git a/packages/cli/src/utils/userStartupWarnings.ts b/packages/cli/src/utils/userStartupWarnings.ts index edb5e92d..20a3534b 100644 --- a/packages/cli/src/utils/userStartupWarnings.ts +++ b/packages/cli/src/utils/userStartupWarnings.ts @@ -24,7 +24,7 @@ const homeDirectoryCheck: WarningCheck = { ]); if (workspaceRealPath === homeRealPath) { - return 'You are running Gemini CLI in your home directory. It is recommended to run in a project-specific directory.'; + return 'You are running Qwen Code in your home directory. It is recommended to run in a project-specific directory.'; } return null; } catch (_err: unknown) { diff --git a/packages/core/src/code_assist/server.ts b/packages/core/src/code_assist/server.ts index 7af643f7..0bbab1f5 100644 --- a/packages/core/src/code_assist/server.ts +++ b/packages/core/src/code_assist/server.ts @@ -39,7 +39,7 @@ export interface HttpOptions { headers?: Record; } -export const CODE_ASSIST_ENDPOINT = 'https://cloudcode-pa.googleapis.com'; +export const CODE_ASSIST_ENDPOINT = 'https://localhost:0'; // Disable Google Code Assist API Request export const CODE_ASSIST_API_VERSION = 'v1internal'; export class CodeAssistServer implements ContentGenerator { diff --git a/packages/core/src/config/config.ts b/packages/core/src/config/config.ts index e7555477..feb67a92 100644 --- a/packages/core/src/config/config.ts +++ b/packages/core/src/config/config.ts @@ -175,6 +175,8 @@ export interface ConfigParameters { model: string; extensionContextFilePaths?: string[]; maxSessionTurns?: number; + sessionTokenLimit?: number; + maxFolderItems?: number; experimentalAcp?: boolean; listExtensions?: boolean; extensions?: GeminiCLIExtension[]; @@ -190,6 +192,10 @@ export interface ConfigParameters { modelNames: string[]; template: string; }>; + contentGenerator?: { + timeout?: number; + maxRetries?: number; + }; } export class Config { @@ -233,8 +239,15 @@ export class Config { private readonly noBrowser: boolean; private readonly ideMode: boolean; private readonly ideClient: IdeClient | undefined; + private readonly systemPromptMappings?: Array<{ + baseUrls?: string[]; + modelNames?: string[]; + template?: string; + }>; private modelSwitchedDuringSession: boolean = false; private readonly maxSessionTurns: number; + private readonly sessionTokenLimit: number; + private readonly maxFolderItems: number; private readonly listExtensions: boolean; private readonly _extensions: GeminiCLIExtension[]; private readonly _blockedMcpServers: Array<{ @@ -247,7 +260,12 @@ export class Config { | Record | undefined; private readonly experimentalAcp: boolean = false; - + private readonly enableOpenAILogging: boolean; + private readonly sampling_params?: Record; + private readonly contentGenerator?: { + timeout?: number; + maxRetries?: number; + }; constructor(params: ConfigParameters) { this.sessionId = params.sessionId; this.embeddingModel = @@ -291,6 +309,8 @@ export class Config { this.model = params.model; this.extensionContextFilePaths = params.extensionContextFilePaths ?? []; this.maxSessionTurns = params.maxSessionTurns ?? -1; + this.sessionTokenLimit = params.sessionTokenLimit ?? 32000; + this.maxFolderItems = params.maxFolderItems ?? 20; this.experimentalAcp = params.experimentalAcp ?? false; this.listExtensions = params.listExtensions ?? false; this._extensions = params.extensions ?? []; @@ -299,6 +319,10 @@ export class Config { this.summarizeToolOutput = params.summarizeToolOutput; this.ideMode = params.ideMode ?? false; this.ideClient = params.ideClient; + this.systemPromptMappings = params.systemPromptMappings; + this.enableOpenAILogging = params.enableOpenAILogging ?? false; + this.sampling_params = params.sampling_params; + this.contentGenerator = params.contentGenerator; if (params.contextFileName) { setGeminiMdFilename(params.contextFileName); @@ -378,6 +402,14 @@ export class Config { return this.maxSessionTurns; } + getSessionTokenLimit(): number { + return this.sessionTokenLimit; + } + + getMaxFolderItems(): number { + return this.maxFolderItems; + } + setQuotaErrorOccurred(value: boolean): void { this.quotaErrorOccurred = value; } @@ -596,6 +628,32 @@ export class Config { return this.ideClient; } + getEnableOpenAILogging(): boolean { + return this.enableOpenAILogging; + } + + getSamplingParams(): Record | undefined { + return this.sampling_params; + } + + getContentGeneratorTimeout(): number | undefined { + return this.contentGenerator?.timeout; + } + + getContentGeneratorMaxRetries(): number | undefined { + return this.contentGenerator?.maxRetries; + } + + getSystemPromptMappings(): + | Array<{ + baseUrls?: string[]; + modelNames?: string[]; + template?: string; + }> + | undefined { + return this.systemPromptMappings; + } + async getGitService(): Promise { if (!this.gitService) { this.gitService = new GitService(this.targetDir); diff --git a/packages/core/src/core/__snapshots__/prompts.test.ts.snap b/packages/core/src/core/__snapshots__/prompts.test.ts.snap index 56d231f4..774bf9c7 100644 --- a/packages/core/src/core/__snapshots__/prompts.test.ts.snap +++ b/packages/core/src/core/__snapshots__/prompts.test.ts.snap @@ -91,26 +91,52 @@ user: is 13 a prime number? model: true - -user: list files here. -model: [tool_call: list_directory for path '/path/to/project'] - - user: start the server implemented in server.js -model: [tool_call: run_shell_command for 'node server.js &' because it must run in the background] +model: + + + +node server.js & + + + user: Refactor the auth logic in src/auth.py to use the requests library instead of urllib. model: Okay, I can refactor 'src/auth.py'. First, I'll analyze the code and check for a test safety net before planning any changes. -[tool_call: glob for path 'tests/test_auth.py'] -[tool_call: read_file for absolute_path '/path/to/tests/test_auth.py'] + + + +tests/test_auth.py + + + + + + +/path/to/tests/test_auth.py + + +0 + + +10 + + + (After analysis) Great, 'tests/test_auth.py' exists and covers the core authentication logic. With this safety net in place, I can safely plan the refactoring. I'll also confirm 'requests' is a dependency. -[tool_call: read_file for absolute_path '/path/to/requirements.txt'] + + + +/path/to/requirements.txt + + + (After analysis) Looks good, 'requests' is available. @@ -120,15 +146,30 @@ Here's the plan: 3. Remove the old 'urllib' import. 4. Run the project's linter and tests to verify the changes. -Should I proceed? -user: Yes -model: -[tool_call: write_file or replace to apply the refactoring to 'src/auth.py'] + + + +src/auth.py + + +(old code content) + + +(new code content) + + + Refactoring complete. Running verification... -[tool_call: run_shell_command for 'ruff check src/auth.py && pytest'] + + +ruff check src/auth.py && pytest + + + (After verification passes) All checks passed. This is a stable checkpoint. - +Would you like me to write a commit message and commit these changes? @@ -139,32 +180,48 @@ model: I can run \`rm -rf /path/to/project/temp\`. This will permanently delete user: Write tests for someFile.ts model: -Okay, I can write those tests. First, I'll read \`someFile.ts\` to understand its functionality. -[tool_call: read_file for absolute_path '/path/to/someFile.ts' or use glob to find \`someFile.ts\` if its location is unknown] +Okay, I can write those tests. First, I'll read someFile.ts to understand its functionality. + + + +/path/to/someFile.ts + + + Now I'll look for existing or related test files to understand current testing conventions and dependencies. -[tool_call: read_many_files for paths ['**/*.test.ts', 'src/**/*.spec.ts'] assuming someFile.ts is in the src directory] + +read_many_files for paths ['**/*.test.ts', 'src/**/*.spec.ts'] assuming someFile.ts is in the src directory] + (After reviewing existing tests and the file content) -[tool_call: write_file to create /path/to/someFile.test.ts with the test code] + + + +/path/to/someFile.test.ts + + + I've written the tests. Now I'll run the project's test command to verify them. -[tool_call: run_shell_command for 'npm run test'] - - - -user: How do I update the user's profile information in this system? -model: -I'm not immediately sure how user profile information is updated. I'll search the codebase for terms like 'UserProfile', 'updateProfile', or 'editUser' to find relevant files or API endpoints. -[tool_call: search_file_content for pattern 'UserProfile|updateProfile|editUser'] -(After reviewing search results, assuming a relevant file like '/path/to/UserProfileService.java' was found) -Okay, \`/path/to/UserProfileService.java\` seems like the most relevant file. I'll read its content to understand how updates are handled. -[tool_call: read_file for absolute_path '/path/to/UserProfileService.java'] -(After reading the file) -It appears the \`updateUserProfile\` method in \`UserProfileService.java\` is responsible for this. It expects a user ID and a \`UserProfileDTO\` object... + + + +npm run test + + + +(After verification passes) +All checks passed. This is a stable checkpoint. user: Where are all the 'app.config' files in this project? I need to check their settings. model: -[tool_call: glob for pattern '**/app.config'] + + + +./**/app.config + + + (Assuming GlobTool returns a list of paths like ['/path/to/moduleA/app.config', '/path/to/moduleB/app.config']) I found the following 'app.config' files: - /path/to/moduleA/app.config @@ -287,26 +344,52 @@ user: is 13 a prime number? model: true - -user: list files here. -model: [tool_call: list_directory for path '/path/to/project'] - - user: start the server implemented in server.js -model: [tool_call: run_shell_command for 'node server.js &' because it must run in the background] +model: + + + +node server.js & + + + user: Refactor the auth logic in src/auth.py to use the requests library instead of urllib. model: Okay, I can refactor 'src/auth.py'. First, I'll analyze the code and check for a test safety net before planning any changes. -[tool_call: glob for path 'tests/test_auth.py'] -[tool_call: read_file for absolute_path '/path/to/tests/test_auth.py'] + + + +tests/test_auth.py + + + + + + +/path/to/tests/test_auth.py + + +0 + + +10 + + + (After analysis) Great, 'tests/test_auth.py' exists and covers the core authentication logic. With this safety net in place, I can safely plan the refactoring. I'll also confirm 'requests' is a dependency. -[tool_call: read_file for absolute_path '/path/to/requirements.txt'] + + + +/path/to/requirements.txt + + + (After analysis) Looks good, 'requests' is available. @@ -316,12 +399,27 @@ Here's the plan: 3. Remove the old 'urllib' import. 4. Run the project's linter and tests to verify the changes. -Should I proceed? -user: Yes -model: -[tool_call: write_file or replace to apply the refactoring to 'src/auth.py'] + + + +src/auth.py + + +(old code content) + + +(new code content) + + + Refactoring complete. Running verification... -[tool_call: run_shell_command for 'ruff check src/auth.py && pytest'] + + +ruff check src/auth.py && pytest + + + (After verification passes) All checks passed. This is a stable checkpoint. Would you like me to write a commit message and commit these changes? @@ -335,32 +433,48 @@ model: I can run \`rm -rf /path/to/project/temp\`. This will permanently delete user: Write tests for someFile.ts model: -Okay, I can write those tests. First, I'll read \`someFile.ts\` to understand its functionality. -[tool_call: read_file for absolute_path '/path/to/someFile.ts' or use glob to find \`someFile.ts\` if its location is unknown] +Okay, I can write those tests. First, I'll read someFile.ts to understand its functionality. + + + +/path/to/someFile.ts + + + Now I'll look for existing or related test files to understand current testing conventions and dependencies. -[tool_call: read_many_files for paths ['**/*.test.ts', 'src/**/*.spec.ts'] assuming someFile.ts is in the src directory] + +read_many_files for paths ['**/*.test.ts', 'src/**/*.spec.ts'] assuming someFile.ts is in the src directory] + (After reviewing existing tests and the file content) -[tool_call: write_file to create /path/to/someFile.test.ts with the test code] + + + +/path/to/someFile.test.ts + + + I've written the tests. Now I'll run the project's test command to verify them. -[tool_call: run_shell_command for 'npm run test'] - - - -user: How do I update the user's profile information in this system? -model: -I'm not immediately sure how user profile information is updated. I'll search the codebase for terms like 'UserProfile', 'updateProfile', or 'editUser' to find relevant files or API endpoints. -[tool_call: search_file_content for pattern 'UserProfile|updateProfile|editUser'] -(After reviewing search results, assuming a relevant file like '/path/to/UserProfileService.java' was found) -Okay, \`/path/to/UserProfileService.java\` seems like the most relevant file. I'll read its content to understand how updates are handled. -[tool_call: read_file for absolute_path '/path/to/UserProfileService.java'] -(After reading the file) -It appears the \`updateUserProfile\` method in \`UserProfileService.java\` is responsible for this. It expects a user ID and a \`UserProfileDTO\` object... + + + +npm run test + + + +(After verification passes) +All checks passed. This is a stable checkpoint. user: Where are all the 'app.config' files in this project? I need to check their settings. model: -[tool_call: glob for pattern '**/app.config'] + + + +./**/app.config + + + (Assuming GlobTool returns a list of paths like ['/path/to/moduleA/app.config', '/path/to/moduleB/app.config']) I found the following 'app.config' files: - /path/to/moduleA/app.config @@ -463,26 +577,52 @@ user: is 13 a prime number? model: true - -user: list files here. -model: [tool_call: list_directory for path '/path/to/project'] - - user: start the server implemented in server.js -model: [tool_call: run_shell_command for 'node server.js &' because it must run in the background] +model: + + + +node server.js & + + + user: Refactor the auth logic in src/auth.py to use the requests library instead of urllib. model: Okay, I can refactor 'src/auth.py'. First, I'll analyze the code and check for a test safety net before planning any changes. -[tool_call: glob for path 'tests/test_auth.py'] -[tool_call: read_file for absolute_path '/path/to/tests/test_auth.py'] + + + +tests/test_auth.py + + + + + + +/path/to/tests/test_auth.py + + +0 + + +10 + + + (After analysis) Great, 'tests/test_auth.py' exists and covers the core authentication logic. With this safety net in place, I can safely plan the refactoring. I'll also confirm 'requests' is a dependency. -[tool_call: read_file for absolute_path '/path/to/requirements.txt'] + + + +/path/to/requirements.txt + + + (After analysis) Looks good, 'requests' is available. @@ -492,15 +632,30 @@ Here's the plan: 3. Remove the old 'urllib' import. 4. Run the project's linter and tests to verify the changes. -Should I proceed? -user: Yes -model: -[tool_call: write_file or replace to apply the refactoring to 'src/auth.py'] + + + +src/auth.py + + +(old code content) + + +(new code content) + + + Refactoring complete. Running verification... -[tool_call: run_shell_command for 'ruff check src/auth.py && pytest'] + + +ruff check src/auth.py && pytest + + + (After verification passes) All checks passed. This is a stable checkpoint. - +Would you like me to write a commit message and commit these changes? @@ -511,32 +666,48 @@ model: I can run \`rm -rf /path/to/project/temp\`. This will permanently delete user: Write tests for someFile.ts model: -Okay, I can write those tests. First, I'll read \`someFile.ts\` to understand its functionality. -[tool_call: read_file for absolute_path '/path/to/someFile.ts' or use glob to find \`someFile.ts\` if its location is unknown] +Okay, I can write those tests. First, I'll read someFile.ts to understand its functionality. + + + +/path/to/someFile.ts + + + Now I'll look for existing or related test files to understand current testing conventions and dependencies. -[tool_call: read_many_files for paths ['**/*.test.ts', 'src/**/*.spec.ts'] assuming someFile.ts is in the src directory] + +read_many_files for paths ['**/*.test.ts', 'src/**/*.spec.ts'] assuming someFile.ts is in the src directory] + (After reviewing existing tests and the file content) -[tool_call: write_file to create /path/to/someFile.test.ts with the test code] + + + +/path/to/someFile.test.ts + + + I've written the tests. Now I'll run the project's test command to verify them. -[tool_call: run_shell_command for 'npm run test'] - - - -user: How do I update the user's profile information in this system? -model: -I'm not immediately sure how user profile information is updated. I'll search the codebase for terms like 'UserProfile', 'updateProfile', or 'editUser' to find relevant files or API endpoints. -[tool_call: search_file_content for pattern 'UserProfile|updateProfile|editUser'] -(After reviewing search results, assuming a relevant file like '/path/to/UserProfileService.java' was found) -Okay, \`/path/to/UserProfileService.java\` seems like the most relevant file. I'll read its content to understand how updates are handled. -[tool_call: read_file for absolute_path '/path/to/UserProfileService.java'] -(After reading the file) -It appears the \`updateUserProfile\` method in \`UserProfileService.java\` is responsible for this. It expects a user ID and a \`UserProfileDTO\` object... + + + +npm run test + + + +(After verification passes) +All checks passed. This is a stable checkpoint. user: Where are all the 'app.config' files in this project? I need to check their settings. model: -[tool_call: glob for pattern '**/app.config'] + + + +./**/app.config + + + (Assuming GlobTool returns a list of paths like ['/path/to/moduleA/app.config', '/path/to/moduleB/app.config']) I found the following 'app.config' files: - /path/to/moduleA/app.config @@ -639,26 +810,52 @@ user: is 13 a prime number? model: true - -user: list files here. -model: [tool_call: list_directory for path '/path/to/project'] - - user: start the server implemented in server.js -model: [tool_call: run_shell_command for 'node server.js &' because it must run in the background] +model: + + + +node server.js & + + + user: Refactor the auth logic in src/auth.py to use the requests library instead of urllib. model: Okay, I can refactor 'src/auth.py'. First, I'll analyze the code and check for a test safety net before planning any changes. -[tool_call: glob for path 'tests/test_auth.py'] -[tool_call: read_file for absolute_path '/path/to/tests/test_auth.py'] + + + +tests/test_auth.py + + + + + + +/path/to/tests/test_auth.py + + +0 + + +10 + + + (After analysis) Great, 'tests/test_auth.py' exists and covers the core authentication logic. With this safety net in place, I can safely plan the refactoring. I'll also confirm 'requests' is a dependency. -[tool_call: read_file for absolute_path '/path/to/requirements.txt'] + + + +/path/to/requirements.txt + + + (After analysis) Looks good, 'requests' is available. @@ -668,15 +865,30 @@ Here's the plan: 3. Remove the old 'urllib' import. 4. Run the project's linter and tests to verify the changes. -Should I proceed? -user: Yes -model: -[tool_call: write_file or replace to apply the refactoring to 'src/auth.py'] + + + +src/auth.py + + +(old code content) + + +(new code content) + + + Refactoring complete. Running verification... -[tool_call: run_shell_command for 'ruff check src/auth.py && pytest'] + + +ruff check src/auth.py && pytest + + + (After verification passes) All checks passed. This is a stable checkpoint. - +Would you like me to write a commit message and commit these changes? @@ -687,32 +899,48 @@ model: I can run \`rm -rf /path/to/project/temp\`. This will permanently delete user: Write tests for someFile.ts model: -Okay, I can write those tests. First, I'll read \`someFile.ts\` to understand its functionality. -[tool_call: read_file for absolute_path '/path/to/someFile.ts' or use glob to find \`someFile.ts\` if its location is unknown] +Okay, I can write those tests. First, I'll read someFile.ts to understand its functionality. + + + +/path/to/someFile.ts + + + Now I'll look for existing or related test files to understand current testing conventions and dependencies. -[tool_call: read_many_files for paths ['**/*.test.ts', 'src/**/*.spec.ts'] assuming someFile.ts is in the src directory] + +read_many_files for paths ['**/*.test.ts', 'src/**/*.spec.ts'] assuming someFile.ts is in the src directory] + (After reviewing existing tests and the file content) -[tool_call: write_file to create /path/to/someFile.test.ts with the test code] + + + +/path/to/someFile.test.ts + + + I've written the tests. Now I'll run the project's test command to verify them. -[tool_call: run_shell_command for 'npm run test'] - - - -user: How do I update the user's profile information in this system? -model: -I'm not immediately sure how user profile information is updated. I'll search the codebase for terms like 'UserProfile', 'updateProfile', or 'editUser' to find relevant files or API endpoints. -[tool_call: search_file_content for pattern 'UserProfile|updateProfile|editUser'] -(After reviewing search results, assuming a relevant file like '/path/to/UserProfileService.java' was found) -Okay, \`/path/to/UserProfileService.java\` seems like the most relevant file. I'll read its content to understand how updates are handled. -[tool_call: read_file for absolute_path '/path/to/UserProfileService.java'] -(After reading the file) -It appears the \`updateUserProfile\` method in \`UserProfileService.java\` is responsible for this. It expects a user ID and a \`UserProfileDTO\` object... + + + +npm run test + + + +(After verification passes) +All checks passed. This is a stable checkpoint. user: Where are all the 'app.config' files in this project? I need to check their settings. model: -[tool_call: glob for pattern '**/app.config'] + + + +./**/app.config + + + (Assuming GlobTool returns a list of paths like ['/path/to/moduleA/app.config', '/path/to/moduleB/app.config']) I found the following 'app.config' files: - /path/to/moduleA/app.config @@ -799,7 +1027,7 @@ When requested to perform tasks like fixing bugs, adding features, refactoring, # macOS Seatbelt -You are running under macos seatbelt with limited access to files outside the project directory or system temp directory, and with limited access to host system resources such as ports. If you encounter failures that could be due to macOS Seatbelt (e.g. if a command fails with 'Operation not permitted' or similar error), as you report the error to the user, also explain why you think it could be due to macOS Seatbelt, and how the user may need to adjust their Seatbelt profile. +You are running under macos seatbelt with limited access to files outside the project directory or system temp directory, and with limited access to host system resources such as ports. If you encounter failures that could be due to MacOS Seatbelt (e.g. if a command fails with 'Operation not permitted' or similar error), as you report the error to the user, also explain why you think it could be due to MacOS Seatbelt, and how the user may need to adjust their Seatbelt profile. @@ -815,26 +1043,52 @@ user: is 13 a prime number? model: true - -user: list files here. -model: [tool_call: list_directory for path '/path/to/project'] - - user: start the server implemented in server.js -model: [tool_call: run_shell_command for 'node server.js &' because it must run in the background] +model: + + + +node server.js & + + + user: Refactor the auth logic in src/auth.py to use the requests library instead of urllib. model: Okay, I can refactor 'src/auth.py'. First, I'll analyze the code and check for a test safety net before planning any changes. -[tool_call: glob for path 'tests/test_auth.py'] -[tool_call: read_file for absolute_path '/path/to/tests/test_auth.py'] + + + +tests/test_auth.py + + + + + + +/path/to/tests/test_auth.py + + +0 + + +10 + + + (After analysis) Great, 'tests/test_auth.py' exists and covers the core authentication logic. With this safety net in place, I can safely plan the refactoring. I'll also confirm 'requests' is a dependency. -[tool_call: read_file for absolute_path '/path/to/requirements.txt'] + + + +/path/to/requirements.txt + + + (After analysis) Looks good, 'requests' is available. @@ -844,15 +1098,30 @@ Here's the plan: 3. Remove the old 'urllib' import. 4. Run the project's linter and tests to verify the changes. -Should I proceed? -user: Yes -model: -[tool_call: write_file or replace to apply the refactoring to 'src/auth.py'] + + + +src/auth.py + + +(old code content) + + +(new code content) + + + Refactoring complete. Running verification... -[tool_call: run_shell_command for 'ruff check src/auth.py && pytest'] + + +ruff check src/auth.py && pytest + + + (After verification passes) All checks passed. This is a stable checkpoint. - +Would you like me to write a commit message and commit these changes? @@ -863,32 +1132,48 @@ model: I can run \`rm -rf /path/to/project/temp\`. This will permanently delete user: Write tests for someFile.ts model: -Okay, I can write those tests. First, I'll read \`someFile.ts\` to understand its functionality. -[tool_call: read_file for absolute_path '/path/to/someFile.ts' or use glob to find \`someFile.ts\` if its location is unknown] +Okay, I can write those tests. First, I'll read someFile.ts to understand its functionality. + + + +/path/to/someFile.ts + + + Now I'll look for existing or related test files to understand current testing conventions and dependencies. -[tool_call: read_many_files for paths ['**/*.test.ts', 'src/**/*.spec.ts'] assuming someFile.ts is in the src directory] + +read_many_files for paths ['**/*.test.ts', 'src/**/*.spec.ts'] assuming someFile.ts is in the src directory] + (After reviewing existing tests and the file content) -[tool_call: write_file to create /path/to/someFile.test.ts with the test code] + + + +/path/to/someFile.test.ts + + + I've written the tests. Now I'll run the project's test command to verify them. -[tool_call: run_shell_command for 'npm run test'] - - - -user: How do I update the user's profile information in this system? -model: -I'm not immediately sure how user profile information is updated. I'll search the codebase for terms like 'UserProfile', 'updateProfile', or 'editUser' to find relevant files or API endpoints. -[tool_call: search_file_content for pattern 'UserProfile|updateProfile|editUser'] -(After reviewing search results, assuming a relevant file like '/path/to/UserProfileService.java' was found) -Okay, \`/path/to/UserProfileService.java\` seems like the most relevant file. I'll read its content to understand how updates are handled. -[tool_call: read_file for absolute_path '/path/to/UserProfileService.java'] -(After reading the file) -It appears the \`updateUserProfile\` method in \`UserProfileService.java\` is responsible for this. It expects a user ID and a \`UserProfileDTO\` object... + + + +npm run test + + + +(After verification passes) +All checks passed. This is a stable checkpoint. user: Where are all the 'app.config' files in this project? I need to check their settings. model: -[tool_call: glob for pattern '**/app.config'] + + + +./**/app.config + + + (Assuming GlobTool returns a list of paths like ['/path/to/moduleA/app.config', '/path/to/moduleB/app.config']) I found the following 'app.config' files: - /path/to/moduleA/app.config @@ -991,26 +1276,52 @@ user: is 13 a prime number? model: true - -user: list files here. -model: [tool_call: list_directory for path '/path/to/project'] - - user: start the server implemented in server.js -model: [tool_call: run_shell_command for 'node server.js &' because it must run in the background] +model: + + + +node server.js & + + + user: Refactor the auth logic in src/auth.py to use the requests library instead of urllib. model: Okay, I can refactor 'src/auth.py'. First, I'll analyze the code and check for a test safety net before planning any changes. -[tool_call: glob for path 'tests/test_auth.py'] -[tool_call: read_file for absolute_path '/path/to/tests/test_auth.py'] + + + +tests/test_auth.py + + + + + + +/path/to/tests/test_auth.py + + +0 + + +10 + + + (After analysis) Great, 'tests/test_auth.py' exists and covers the core authentication logic. With this safety net in place, I can safely plan the refactoring. I'll also confirm 'requests' is a dependency. -[tool_call: read_file for absolute_path '/path/to/requirements.txt'] + + + +/path/to/requirements.txt + + + (After analysis) Looks good, 'requests' is available. @@ -1020,15 +1331,30 @@ Here's the plan: 3. Remove the old 'urllib' import. 4. Run the project's linter and tests to verify the changes. -Should I proceed? -user: Yes -model: -[tool_call: write_file or replace to apply the refactoring to 'src/auth.py'] + + + +src/auth.py + + +(old code content) + + +(new code content) + + + Refactoring complete. Running verification... -[tool_call: run_shell_command for 'ruff check src/auth.py && pytest'] + + +ruff check src/auth.py && pytest + + + (After verification passes) All checks passed. This is a stable checkpoint. - +Would you like me to write a commit message and commit these changes? @@ -1039,32 +1365,48 @@ model: I can run \`rm -rf /path/to/project/temp\`. This will permanently delete user: Write tests for someFile.ts model: -Okay, I can write those tests. First, I'll read \`someFile.ts\` to understand its functionality. -[tool_call: read_file for absolute_path '/path/to/someFile.ts' or use glob to find \`someFile.ts\` if its location is unknown] +Okay, I can write those tests. First, I'll read someFile.ts to understand its functionality. + + + +/path/to/someFile.ts + + + Now I'll look for existing or related test files to understand current testing conventions and dependencies. -[tool_call: read_many_files for paths ['**/*.test.ts', 'src/**/*.spec.ts'] assuming someFile.ts is in the src directory] + +read_many_files for paths ['**/*.test.ts', 'src/**/*.spec.ts'] assuming someFile.ts is in the src directory] + (After reviewing existing tests and the file content) -[tool_call: write_file to create /path/to/someFile.test.ts with the test code] + + + +/path/to/someFile.test.ts + + + I've written the tests. Now I'll run the project's test command to verify them. -[tool_call: run_shell_command for 'npm run test'] - - - -user: How do I update the user's profile information in this system? -model: -I'm not immediately sure how user profile information is updated. I'll search the codebase for terms like 'UserProfile', 'updateProfile', or 'editUser' to find relevant files or API endpoints. -[tool_call: search_file_content for pattern 'UserProfile|updateProfile|editUser'] -(After reviewing search results, assuming a relevant file like '/path/to/UserProfileService.java' was found) -Okay, \`/path/to/UserProfileService.java\` seems like the most relevant file. I'll read its content to understand how updates are handled. -[tool_call: read_file for absolute_path '/path/to/UserProfileService.java'] -(After reading the file) -It appears the \`updateUserProfile\` method in \`UserProfileService.java\` is responsible for this. It expects a user ID and a \`UserProfileDTO\` object... + + + +npm run test + + + +(After verification passes) +All checks passed. This is a stable checkpoint. user: Where are all the 'app.config' files in this project? I need to check their settings. model: -[tool_call: glob for pattern '**/app.config'] + + + +./**/app.config + + + (Assuming GlobTool returns a list of paths like ['/path/to/moduleA/app.config', '/path/to/moduleB/app.config']) I found the following 'app.config' files: - /path/to/moduleA/app.config @@ -1167,26 +1509,52 @@ user: is 13 a prime number? model: true - -user: list files here. -model: [tool_call: list_directory for path '/path/to/project'] - - user: start the server implemented in server.js -model: [tool_call: run_shell_command for 'node server.js &' because it must run in the background] +model: + + + +node server.js & + + + user: Refactor the auth logic in src/auth.py to use the requests library instead of urllib. model: Okay, I can refactor 'src/auth.py'. First, I'll analyze the code and check for a test safety net before planning any changes. -[tool_call: glob for path 'tests/test_auth.py'] -[tool_call: read_file for absolute_path '/path/to/tests/test_auth.py'] + + + +tests/test_auth.py + + + + + + +/path/to/tests/test_auth.py + + +0 + + +10 + + + (After analysis) Great, 'tests/test_auth.py' exists and covers the core authentication logic. With this safety net in place, I can safely plan the refactoring. I'll also confirm 'requests' is a dependency. -[tool_call: read_file for absolute_path '/path/to/requirements.txt'] + + + +/path/to/requirements.txt + + + (After analysis) Looks good, 'requests' is available. @@ -1196,15 +1564,30 @@ Here's the plan: 3. Remove the old 'urllib' import. 4. Run the project's linter and tests to verify the changes. -Should I proceed? -user: Yes -model: -[tool_call: write_file or replace to apply the refactoring to 'src/auth.py'] + + + +src/auth.py + + +(old code content) + + +(new code content) + + + Refactoring complete. Running verification... -[tool_call: run_shell_command for 'ruff check src/auth.py && pytest'] + + +ruff check src/auth.py && pytest + + + (After verification passes) All checks passed. This is a stable checkpoint. - +Would you like me to write a commit message and commit these changes? @@ -1215,32 +1598,48 @@ model: I can run \`rm -rf /path/to/project/temp\`. This will permanently delete user: Write tests for someFile.ts model: -Okay, I can write those tests. First, I'll read \`someFile.ts\` to understand its functionality. -[tool_call: read_file for absolute_path '/path/to/someFile.ts' or use glob to find \`someFile.ts\` if its location is unknown] +Okay, I can write those tests. First, I'll read someFile.ts to understand its functionality. + + + +/path/to/someFile.ts + + + Now I'll look for existing or related test files to understand current testing conventions and dependencies. -[tool_call: read_many_files for paths ['**/*.test.ts', 'src/**/*.spec.ts'] assuming someFile.ts is in the src directory] + +read_many_files for paths ['**/*.test.ts', 'src/**/*.spec.ts'] assuming someFile.ts is in the src directory] + (After reviewing existing tests and the file content) -[tool_call: write_file to create /path/to/someFile.test.ts with the test code] + + + +/path/to/someFile.test.ts + + + I've written the tests. Now I'll run the project's test command to verify them. -[tool_call: run_shell_command for 'npm run test'] - - - -user: How do I update the user's profile information in this system? -model: -I'm not immediately sure how user profile information is updated. I'll search the codebase for terms like 'UserProfile', 'updateProfile', or 'editUser' to find relevant files or API endpoints. -[tool_call: search_file_content for pattern 'UserProfile|updateProfile|editUser'] -(After reviewing search results, assuming a relevant file like '/path/to/UserProfileService.java' was found) -Okay, \`/path/to/UserProfileService.java\` seems like the most relevant file. I'll read its content to understand how updates are handled. -[tool_call: read_file for absolute_path '/path/to/UserProfileService.java'] -(After reading the file) -It appears the \`updateUserProfile\` method in \`UserProfileService.java\` is responsible for this. It expects a user ID and a \`UserProfileDTO\` object... + + + +npm run test + + + +(After verification passes) +All checks passed. This is a stable checkpoint. user: Where are all the 'app.config' files in this project? I need to check their settings. model: -[tool_call: glob for pattern '**/app.config'] + + + +./**/app.config + + + (Assuming GlobTool returns a list of paths like ['/path/to/moduleA/app.config', '/path/to/moduleB/app.config']) I found the following 'app.config' files: - /path/to/moduleA/app.config @@ -1343,26 +1742,52 @@ user: is 13 a prime number? model: true - -user: list files here. -model: [tool_call: list_directory for path '/path/to/project'] - - user: start the server implemented in server.js -model: [tool_call: run_shell_command for 'node server.js &' because it must run in the background] +model: + + + +node server.js & + + + user: Refactor the auth logic in src/auth.py to use the requests library instead of urllib. model: Okay, I can refactor 'src/auth.py'. First, I'll analyze the code and check for a test safety net before planning any changes. -[tool_call: glob for path 'tests/test_auth.py'] -[tool_call: read_file for absolute_path '/path/to/tests/test_auth.py'] + + + +tests/test_auth.py + + + + + + +/path/to/tests/test_auth.py + + +0 + + +10 + + + (After analysis) Great, 'tests/test_auth.py' exists and covers the core authentication logic. With this safety net in place, I can safely plan the refactoring. I'll also confirm 'requests' is a dependency. -[tool_call: read_file for absolute_path '/path/to/requirements.txt'] + + + +/path/to/requirements.txt + + + (After analysis) Looks good, 'requests' is available. @@ -1372,15 +1797,30 @@ Here's the plan: 3. Remove the old 'urllib' import. 4. Run the project's linter and tests to verify the changes. -Should I proceed? -user: Yes -model: -[tool_call: write_file or replace to apply the refactoring to 'src/auth.py'] + + + +src/auth.py + + +(old code content) + + +(new code content) + + + Refactoring complete. Running verification... -[tool_call: run_shell_command for 'ruff check src/auth.py && pytest'] + + +ruff check src/auth.py && pytest + + + (After verification passes) All checks passed. This is a stable checkpoint. - +Would you like me to write a commit message and commit these changes? @@ -1391,32 +1831,48 @@ model: I can run \`rm -rf /path/to/project/temp\`. This will permanently delete user: Write tests for someFile.ts model: -Okay, I can write those tests. First, I'll read \`someFile.ts\` to understand its functionality. -[tool_call: read_file for absolute_path '/path/to/someFile.ts' or use glob to find \`someFile.ts\` if its location is unknown] +Okay, I can write those tests. First, I'll read someFile.ts to understand its functionality. + + + +/path/to/someFile.ts + + + Now I'll look for existing or related test files to understand current testing conventions and dependencies. -[tool_call: read_many_files for paths ['**/*.test.ts', 'src/**/*.spec.ts'] assuming someFile.ts is in the src directory] + +read_many_files for paths ['**/*.test.ts', 'src/**/*.spec.ts'] assuming someFile.ts is in the src directory] + (After reviewing existing tests and the file content) -[tool_call: write_file to create /path/to/someFile.test.ts with the test code] + + + +/path/to/someFile.test.ts + + + I've written the tests. Now I'll run the project's test command to verify them. -[tool_call: run_shell_command for 'npm run test'] - - - -user: How do I update the user's profile information in this system? -model: -I'm not immediately sure how user profile information is updated. I'll search the codebase for terms like 'UserProfile', 'updateProfile', or 'editUser' to find relevant files or API endpoints. -[tool_call: search_file_content for pattern 'UserProfile|updateProfile|editUser'] -(After reviewing search results, assuming a relevant file like '/path/to/UserProfileService.java' was found) -Okay, \`/path/to/UserProfileService.java\` seems like the most relevant file. I'll read its content to understand how updates are handled. -[tool_call: read_file for absolute_path '/path/to/UserProfileService.java'] -(After reading the file) -It appears the \`updateUserProfile\` method in \`UserProfileService.java\` is responsible for this. It expects a user ID and a \`UserProfileDTO\` object... + + + +npm run test + + + +(After verification passes) +All checks passed. This is a stable checkpoint. user: Where are all the 'app.config' files in this project? I need to check their settings. model: -[tool_call: glob for pattern '**/app.config'] + + + +./**/app.config + + + (Assuming GlobTool returns a list of paths like ['/path/to/moduleA/app.config', '/path/to/moduleB/app.config']) I found the following 'app.config' files: - /path/to/moduleA/app.config @@ -1519,26 +1975,52 @@ user: is 13 a prime number? model: true - -user: list files here. -model: [tool_call: list_directory for path '/path/to/project'] - - user: start the server implemented in server.js -model: [tool_call: run_shell_command for 'node server.js &' because it must run in the background] +model: + + + +node server.js & + + + user: Refactor the auth logic in src/auth.py to use the requests library instead of urllib. model: Okay, I can refactor 'src/auth.py'. First, I'll analyze the code and check for a test safety net before planning any changes. -[tool_call: glob for path 'tests/test_auth.py'] -[tool_call: read_file for absolute_path '/path/to/tests/test_auth.py'] + + + +tests/test_auth.py + + + + + + +/path/to/tests/test_auth.py + + +0 + + +10 + + + (After analysis) Great, 'tests/test_auth.py' exists and covers the core authentication logic. With this safety net in place, I can safely plan the refactoring. I'll also confirm 'requests' is a dependency. -[tool_call: read_file for absolute_path '/path/to/requirements.txt'] + + + +/path/to/requirements.txt + + + (After analysis) Looks good, 'requests' is available. @@ -1548,15 +2030,30 @@ Here's the plan: 3. Remove the old 'urllib' import. 4. Run the project's linter and tests to verify the changes. -Should I proceed? -user: Yes -model: -[tool_call: write_file or replace to apply the refactoring to 'src/auth.py'] + + + +src/auth.py + + +(old code content) + + +(new code content) + + + Refactoring complete. Running verification... -[tool_call: run_shell_command for 'ruff check src/auth.py && pytest'] + + +ruff check src/auth.py && pytest + + + (After verification passes) All checks passed. This is a stable checkpoint. - +Would you like me to write a commit message and commit these changes? @@ -1567,32 +2064,48 @@ model: I can run \`rm -rf /path/to/project/temp\`. This will permanently delete user: Write tests for someFile.ts model: -Okay, I can write those tests. First, I'll read \`someFile.ts\` to understand its functionality. -[tool_call: read_file for absolute_path '/path/to/someFile.ts' or use glob to find \`someFile.ts\` if its location is unknown] +Okay, I can write those tests. First, I'll read someFile.ts to understand its functionality. + + + +/path/to/someFile.ts + + + Now I'll look for existing or related test files to understand current testing conventions and dependencies. -[tool_call: read_many_files for paths ['**/*.test.ts', 'src/**/*.spec.ts'] assuming someFile.ts is in the src directory] + +read_many_files for paths ['**/*.test.ts', 'src/**/*.spec.ts'] assuming someFile.ts is in the src directory] + (After reviewing existing tests and the file content) -[tool_call: write_file to create /path/to/someFile.test.ts with the test code] + + + +/path/to/someFile.test.ts + + + I've written the tests. Now I'll run the project's test command to verify them. -[tool_call: run_shell_command for 'npm run test'] - - - -user: How do I update the user's profile information in this system? -model: -I'm not immediately sure how user profile information is updated. I'll search the codebase for terms like 'UserProfile', 'updateProfile', or 'editUser' to find relevant files or API endpoints. -[tool_call: search_file_content for pattern 'UserProfile|updateProfile|editUser'] -(After reviewing search results, assuming a relevant file like '/path/to/UserProfileService.java' was found) -Okay, \`/path/to/UserProfileService.java\` seems like the most relevant file. I'll read its content to understand how updates are handled. -[tool_call: read_file for absolute_path '/path/to/UserProfileService.java'] -(After reading the file) -It appears the \`updateUserProfile\` method in \`UserProfileService.java\` is responsible for this. It expects a user ID and a \`UserProfileDTO\` object... + + + +npm run test + + + +(After verification passes) +All checks passed. This is a stable checkpoint. user: Where are all the 'app.config' files in this project? I need to check their settings. model: -[tool_call: glob for pattern '**/app.config'] + + + +./**/app.config + + + (Assuming GlobTool returns a list of paths like ['/path/to/moduleA/app.config', '/path/to/moduleB/app.config']) I found the following 'app.config' files: - /path/to/moduleA/app.config diff --git a/packages/core/src/core/client.test.ts b/packages/core/src/core/client.test.ts index 25ea9bc1..f091a8cd 100644 --- a/packages/core/src/core/client.test.ts +++ b/packages/core/src/core/client.test.ts @@ -195,9 +195,12 @@ describe('Gemini Client (client.ts)', () => { getWorkingDir: vi.fn().mockReturnValue('/test/dir'), getFileService: vi.fn().mockReturnValue(fileService), getMaxSessionTurns: vi.fn().mockReturnValue(0), + getSessionTokenLimit: vi.fn().mockReturnValue(32000), + getMaxFolderItems: vi.fn().mockReturnValue(20), getQuotaErrorOccurred: vi.fn().mockReturnValue(false), setQuotaErrorOccurred: vi.fn(), getNoBrowser: vi.fn().mockReturnValue(false), + getSystemPromptMappings: vi.fn().mockReturnValue(undefined), getUsageStatisticsEnabled: vi.fn().mockReturnValue(true), getIdeMode: vi.fn().mockReturnValue(false), getGeminiClient: vi.fn(), diff --git a/packages/core/src/core/client.ts b/packages/core/src/core/client.ts index 77683a45..f762f7f9 100644 --- a/packages/core/src/core/client.ts +++ b/packages/core/src/core/client.ts @@ -182,9 +182,10 @@ export class GeminiClient { const platform = process.platform; const folderStructure = await getFolderStructure(cwd, { fileService: this.config.getFileService(), + maxItems: this.config.getMaxFolderItems(), }); const context = ` - This is the Gemini CLI. We are setting up the context for our chat. + This is the Qwen Code. We are setting up the context for our chat. Today's date is ${today}. My operating system is: ${platform} I'm currently working in the directory: ${cwd} @@ -319,6 +320,49 @@ export class GeminiClient { yield { type: GeminiEventType.ChatCompressed, value: compressed }; } + // Check session token limit after compression using accurate token counting + const sessionTokenLimit = this.config.getSessionTokenLimit(); + if (sessionTokenLimit > 0) { + // Get all the content that would be sent in an API call + const currentHistory = this.getChat().getHistory(true); + const userMemory = this.config.getUserMemory(); + const systemPrompt = getCoreSystemPrompt(userMemory); + const environment = await this.getEnvironment(); + + // Create a mock request content to count total tokens + const mockRequestContent = [ + { + role: 'system' as const, + parts: [{ text: systemPrompt }, ...environment], + }, + ...currentHistory, + ]; + + // Use the improved countTokens method for accurate counting + const { totalTokens: totalRequestTokens } = + await this.getContentGenerator().countTokens({ + model: this.config.getModel(), + contents: mockRequestContent, + }); + + if ( + totalRequestTokens !== undefined && + totalRequestTokens > sessionTokenLimit + ) { + yield { + type: GeminiEventType.SessionTokenLimitExceeded, + value: { + currentTokens: totalRequestTokens, + limit: sessionTokenLimit, + message: + `Session token limit exceeded: ${totalRequestTokens} tokens > ${sessionTokenLimit} limit. ` + + 'Please start a new session or increase the sessionTokenLimit in your settings.json.', + }, + }; + return new Turn(this.getChat(), prompt_id); + } + } + if (this.config.getIdeMode()) { const openFiles = ideContext.getOpenFilesContext(); if (openFiles) { @@ -419,7 +463,10 @@ export class GeminiClient { model || this.config.getModel() || DEFAULT_GEMINI_FLASH_MODEL; try { const userMemory = this.config.getUserMemory(); - const systemInstruction = getCoreSystemPrompt(userMemory); + const systemPromptMappings = this.config.getSystemPromptMappings(); + const systemInstruction = getCoreSystemPrompt(userMemory, { + systemPromptMappings, + }); const requestConfig = { abortSignal, ...this.generateContentConfig, @@ -458,7 +505,30 @@ export class GeminiClient { throw error; } try { - return JSON.parse(text); + // Try to extract JSON from various formats + const extractors = [ + // Match ```json ... ``` or ``` ... ``` blocks + /```(?:json)?\s*\n?([\s\S]*?)\n?```/, + // Match inline code blocks `{...}` + /`(\{[\s\S]*?\})`/, + // Match raw JSON objects or arrays + /(\{[\s\S]*\}|\[[\s\S]*\])/, + ]; + + for (const regex of extractors) { + const match = text.match(regex); + if (match && match[1]) { + try { + return JSON.parse(match[1].trim()); + } catch { + // Continue to next pattern if parsing fails + continue; + } + } + } + + // If no patterns matched, try parsing the entire text + return JSON.parse(text.trim()); } catch (parseError) { await reportError( parseError, @@ -512,7 +582,10 @@ export class GeminiClient { try { const userMemory = this.config.getUserMemory(); - const systemInstruction = getCoreSystemPrompt(userMemory); + const systemPromptMappings = this.config.getSystemPromptMappings(); + const systemInstruction = getCoreSystemPrompt(userMemory, { + systemPromptMappings, + }); const requestConfig = { abortSignal, diff --git a/packages/core/src/core/contentGenerator.test.ts b/packages/core/src/core/contentGenerator.test.ts index 78eee386..cb117df2 100644 --- a/packages/core/src/core/contentGenerator.test.ts +++ b/packages/core/src/core/contentGenerator.test.ts @@ -69,6 +69,10 @@ describe('createContentGeneratorConfig', () => { setModel: vi.fn(), flashFallbackHandler: vi.fn(), getProxy: vi.fn(), + getEnableOpenAILogging: vi.fn().mockReturnValue(false), + getSamplingParams: vi.fn().mockReturnValue(undefined), + getContentGeneratorTimeout: vi.fn().mockReturnValue(undefined), + getContentGeneratorMaxRetries: vi.fn().mockReturnValue(undefined), } as unknown as Config; beforeEach(() => { diff --git a/packages/core/src/core/contentGenerator.ts b/packages/core/src/core/contentGenerator.ts index 548eb162..3f6e74b0 100644 --- a/packages/core/src/core/contentGenerator.ts +++ b/packages/core/src/core/contentGenerator.ts @@ -85,6 +85,10 @@ export function createContentGeneratorConfig( model: effectiveModel, authType, proxy: config?.getProxy(), + enableOpenAILogging: config.getEnableOpenAILogging(), + timeout: config.getContentGeneratorTimeout(), + maxRetries: config.getContentGeneratorMaxRetries(), + samplingParams: config.getSamplingParams(), }; // If we are using Google auth or we are in Cloud Shell, there is nothing else to validate for now diff --git a/packages/core/src/core/modelCheck.ts b/packages/core/src/core/modelCheck.ts index 25d86993..78530232 100644 --- a/packages/core/src/core/modelCheck.ts +++ b/packages/core/src/core/modelCheck.ts @@ -4,11 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { setGlobalDispatcher, ProxyAgent } from 'undici'; -import { - DEFAULT_GEMINI_MODEL, - DEFAULT_GEMINI_FLASH_MODEL, -} from '../config/models.js'; +// 移陀ζœͺδ½Ώη”¨ηš„ε―Όε…₯ /** * Checks if the default "pro" model is rate-limited and returns a fallback "flash" @@ -19,58 +15,10 @@ import { * and the original model if a switch happened. */ export async function getEffectiveModel( - apiKey: string, + _apiKey: string, currentConfiguredModel: string, - proxy?: string, + _proxy: string | undefined, ): Promise { - if (currentConfiguredModel !== DEFAULT_GEMINI_MODEL) { - // Only check if the user is trying to use the specific pro model we want to fallback from. - return currentConfiguredModel; - } - - const modelToTest = DEFAULT_GEMINI_MODEL; - const fallbackModel = DEFAULT_GEMINI_FLASH_MODEL; - const endpoint = `https://generativelanguage.googleapis.com/v1beta/models/${modelToTest}:generateContent`; - const body = JSON.stringify({ - contents: [{ parts: [{ text: 'test' }] }], - generationConfig: { - maxOutputTokens: 1, - temperature: 0, - topK: 1, - thinkingConfig: { thinkingBudget: 128, includeThoughts: false }, - }, - }); - - const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), 2000); // 500ms timeout for the request - - try { - if (proxy) { - setGlobalDispatcher(new ProxyAgent(proxy)); - } - const response = await fetch(endpoint, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'x-goog-api-key': apiKey, - }, - body, - signal: controller.signal, - }); - - clearTimeout(timeoutId); - - if (response.status === 429) { - console.log( - `[INFO] Your configured model (${modelToTest}) was temporarily unavailable. Switched to ${fallbackModel} for this session.`, - ); - return fallbackModel; - } - // For any other case (success, other error codes), we stick to the original model. - return currentConfiguredModel; - } catch (_error) { - clearTimeout(timeoutId); - // On timeout or any other fetch error, stick to the original model. - return currentConfiguredModel; - } + // Disable Google API Model Check + return currentConfiguredModel; } diff --git a/packages/core/src/core/openaiContentGenerator.ts b/packages/core/src/core/openaiContentGenerator.ts index 91d798c1..34066a69 100644 --- a/packages/core/src/core/openaiContentGenerator.ts +++ b/packages/core/src/core/openaiContentGenerator.ts @@ -1154,7 +1154,9 @@ export class OpenAIContentGenerator implements ContentGenerator { } response.responseId = openaiResponse.id; - response.createTime = openaiResponse.created.toString(); + response.createTime = openaiResponse.created + ? openaiResponse.created.toString() + : new Date().getTime().toString(); response.candidates = [ { @@ -1290,7 +1292,9 @@ export class OpenAIContentGenerator implements ContentGenerator { } response.responseId = chunk.id; - response.createTime = chunk.created.toString(); + response.createTime = chunk.created + ? chunk.created.toString() + : new Date().getTime().toString(); response.modelVersion = this.model; response.promptFeedback = { safetyRatings: [] }; diff --git a/packages/core/src/core/prompts.test.ts b/packages/core/src/core/prompts.test.ts index 06260186..837ec062 100644 --- a/packages/core/src/core/prompts.test.ts +++ b/packages/core/src/core/prompts.test.ts @@ -270,3 +270,96 @@ describe('Core System Prompt (prompts.ts)', () => { }); }); }); + +describe('URL matching with trailing slash compatibility', () => { + it('should match URLs with and without trailing slash', () => { + const config = { + systemPromptMappings: [ + { + baseUrls: ['https://api.example.com'], + modelNames: ['gpt-4'], + template: 'Custom template for example.com', + }, + { + baseUrls: ['https://api.openai.com/'], + modelNames: ['gpt-3.5-turbo'], + template: 'Custom template for openai.com', + }, + ], + }; + + // Simulate environment variables + const originalEnv = process.env; + + // Test case 1: No trailing slash in config, actual URL has trailing slash + process.env = { + ...originalEnv, + OPENAI_BASE_URL: 'https://api.example.com/', + OPENAI_MODEL: 'gpt-4', + }; + + const result1 = getCoreSystemPrompt(undefined, config); + expect(result1).toContain('Custom template for example.com'); + + // Test case 2: Config has trailing slash, actual URL has no trailing slash + process.env = { + ...originalEnv, + OPENAI_BASE_URL: 'https://api.openai.com', + OPENAI_MODEL: 'gpt-3.5-turbo', + }; + + const result2 = getCoreSystemPrompt(undefined, config); + expect(result2).toContain('Custom template for openai.com'); + + // Test case 3: No trailing slash in config, actual URL has no trailing slash + process.env = { + ...originalEnv, + OPENAI_BASE_URL: 'https://api.example.com', + OPENAI_MODEL: 'gpt-4', + }; + + const result3 = getCoreSystemPrompt(undefined, config); + expect(result3).toContain('Custom template for example.com'); + + // Test case 4: Config has trailing slash, actual URL has trailing slash + process.env = { + ...originalEnv, + OPENAI_BASE_URL: 'https://api.openai.com/', + OPENAI_MODEL: 'gpt-3.5-turbo', + }; + + const result4 = getCoreSystemPrompt(undefined, config); + expect(result4).toContain('Custom template for openai.com'); + + // Restore original environment variables + process.env = originalEnv; + }); + + it('should not match when URLs are different', () => { + const config = { + systemPromptMappings: [ + { + baseUrls: ['https://api.example.com'], + modelNames: ['gpt-4'], + template: 'Custom template for example.com', + }, + ], + }; + + const originalEnv = process.env; + + // Test case: URLs do not match + process.env = { + ...originalEnv, + OPENAI_BASE_URL: 'https://api.different.com', + OPENAI_MODEL: 'gpt-4', + }; + + const result = getCoreSystemPrompt(undefined, config); + // Should return default template, not contain custom template + expect(result).not.toContain('Custom template for example.com'); + + // Restore original environment variables + process.env = originalEnv; + }); +}); diff --git a/packages/core/src/core/prompts.ts b/packages/core/src/core/prompts.ts index b130dbb1..f40fc0b6 100644 --- a/packages/core/src/core/prompts.ts +++ b/packages/core/src/core/prompts.ts @@ -7,7 +7,6 @@ import path from 'node:path'; import fs from 'node:fs'; import os from 'node:os'; -import { LSTool } from '../tools/ls.js'; import { EditTool } from '../tools/edit.js'; import { GlobTool } from '../tools/glob.js'; import { GrepTool } from '../tools/grep.js'; @@ -19,7 +18,35 @@ import process from 'node:process'; import { isGitRepository } from '../utils/gitUtils.js'; import { MemoryTool, GEMINI_CONFIG_DIR } from '../tools/memoryTool.js'; -export function getCoreSystemPrompt(userMemory?: string): string { +export interface ModelTemplateMapping { + baseUrls?: string[]; + modelNames?: string[]; + template?: string; +} + +export interface SystemPromptConfig { + systemPromptMappings?: ModelTemplateMapping[]; +} + +/** + * Normalizes a URL by removing trailing slash for consistent comparison + */ +function normalizeUrl(url: string): string { + return url.endsWith('/') ? url.slice(0, -1) : url; +} + +/** + * Checks if a URL matches any URL in the array, ignoring trailing slashes + */ +function urlMatches(urlArray: string[], targetUrl: string): boolean { + const normalizedTarget = normalizeUrl(targetUrl); + return urlArray.some((url) => normalizeUrl(url) === normalizedTarget); +} + +export function getCoreSystemPrompt( + userMemory?: string, + config?: SystemPromptConfig, +): string { // if GEMINI_SYSTEM_MD is set (and not 0|false), override system prompt from file // default path is .gemini/system.md but can be modified via custom path in GEMINI_SYSTEM_MD let systemMdEnabled = false; @@ -44,6 +71,52 @@ export function getCoreSystemPrompt(userMemory?: string): string { } } } + + // Check for system prompt mappings from global config + if (config?.systemPromptMappings) { + const currentModel = process.env.OPENAI_MODEL || ''; + const currentBaseUrl = process.env.OPENAI_BASE_URL || ''; + + const matchedMapping = config.systemPromptMappings.find((mapping) => { + const { baseUrls, modelNames } = mapping; + // Check if baseUrl matches (when specified) + if ( + baseUrls && + modelNames && + urlMatches(baseUrls, currentBaseUrl) && + modelNames.includes(currentModel) + ) { + return true; + } + + if (baseUrls && urlMatches(baseUrls, currentBaseUrl) && !modelNames) { + return true; + } + if (modelNames && modelNames.includes(currentModel) && !baseUrls) { + return true; + } + + return false; + }); + + if (matchedMapping?.template) { + const isGitRepo = isGitRepository(process.cwd()); + + // Replace placeholders in template + let template = matchedMapping.template; + template = template.replace( + '{RUNTIME_VARS_IS_GIT_REPO}', + String(isGitRepo), + ); + template = template.replace( + '{RUNTIME_VARS_SANDBOX}', + process.env.SANDBOX || '', + ); + + return template; + } + } + const basePrompt = systemMdEnabled ? fs.readFileSync(systemMdPath, 'utf8') : ` @@ -127,7 +200,7 @@ ${(function () { if (isSandboxExec) { return ` # macOS Seatbelt -You are running under macos seatbelt with limited access to files outside the project directory or system temp directory, and with limited access to host system resources such as ports. If you encounter failures that could be due to macOS Seatbelt (e.g. if a command fails with 'Operation not permitted' or similar error), as you report the error to the user, also explain why you think it could be due to macOS Seatbelt, and how the user may need to adjust their Seatbelt profile. +You are running under macos seatbelt with limited access to files outside the project directory or system temp directory, and with limited access to host system resources such as ports. If you encounter failures that could be due to MacOS Seatbelt (e.g. if a command fails with 'Operation not permitted' or similar error), as you report the error to the user, also explain why you think it could be due to MacOS Seatbelt, and how the user may need to adjust their Seatbelt profile. `; } else if (isGenericSandbox) { return ` @@ -175,26 +248,52 @@ user: is 13 a prime number? model: true - -user: list files here. -model: [tool_call: ${LSTool.Name} for path '/path/to/project'] - - user: start the server implemented in server.js -model: [tool_call: ${ShellTool.Name} for 'node server.js &' because it must run in the background] +model: + + + +node server.js & + + + user: Refactor the auth logic in src/auth.py to use the requests library instead of urllib. model: Okay, I can refactor 'src/auth.py'. First, I'll analyze the code and check for a test safety net before planning any changes. -[tool_call: ${GlobTool.Name} for path 'tests/test_auth.py'] -[tool_call: ${ReadFileTool.Name} for absolute_path '/path/to/tests/test_auth.py'] + + + +tests/test_auth.py + + + + + + +/path/to/tests/test_auth.py + + +0 + + +10 + + + (After analysis) Great, 'tests/test_auth.py' exists and covers the core authentication logic. With this safety net in place, I can safely plan the refactoring. I'll also confirm 'requests' is a dependency. -[tool_call: ${ReadFileTool.Name} for absolute_path '/path/to/requirements.txt'] + + + +/path/to/requirements.txt + + + (After analysis) Looks good, 'requests' is available. @@ -204,20 +303,30 @@ Here's the plan: 3. Remove the old 'urllib' import. 4. Run the project's linter and tests to verify the changes. -Should I proceed? -user: Yes -model: -[tool_call: ${WriteFileTool.Name} or ${EditTool.Name} to apply the refactoring to 'src/auth.py'] + + + +src/auth.py + + +(old code content) + + +(new code content) + + + Refactoring complete. Running verification... -[tool_call: ${ShellTool.Name} for 'ruff check src/auth.py && pytest'] + + +ruff check src/auth.py && pytest + + + (After verification passes) All checks passed. This is a stable checkpoint. -${(function () { - if (isGitRepository(process.cwd())) { - return `Would you like me to write a commit message and commit these changes?`; - } - return ''; -})()} +Would you like me to write a commit message and commit these changes? @@ -228,32 +337,48 @@ model: I can run \`rm -rf /path/to/project/temp\`. This will permanently delete user: Write tests for someFile.ts model: -Okay, I can write those tests. First, I'll read \`someFile.ts\` to understand its functionality. -[tool_call: ${ReadFileTool.Name} for absolute_path '/path/to/someFile.ts' or use ${GlobTool.Name} to find \`someFile.ts\` if its location is unknown] +Okay, I can write those tests. First, I'll read someFile.ts to understand its functionality. + + + +/path/to/someFile.ts + + + Now I'll look for existing or related test files to understand current testing conventions and dependencies. -[tool_call: ${ReadManyFilesTool.Name} for paths ['**/*.test.ts', 'src/**/*.spec.ts'] assuming someFile.ts is in the src directory] + +read_many_files for paths ['**/*.test.ts', 'src/**/*.spec.ts'] assuming someFile.ts is in the src directory] + (After reviewing existing tests and the file content) -[tool_call: ${WriteFileTool.Name} to create /path/to/someFile.test.ts with the test code] + + + +/path/to/someFile.test.ts + + + I've written the tests. Now I'll run the project's test command to verify them. -[tool_call: ${ShellTool.Name} for 'npm run test'] - - - -user: How do I update the user's profile information in this system? -model: -I'm not immediately sure how user profile information is updated. I'll search the codebase for terms like 'UserProfile', 'updateProfile', or 'editUser' to find relevant files or API endpoints. -[tool_call: ${GrepTool.Name} for pattern 'UserProfile|updateProfile|editUser'] -(After reviewing search results, assuming a relevant file like '/path/to/UserProfileService.java' was found) -Okay, \`/path/to/UserProfileService.java\` seems like the most relevant file. I'll read its content to understand how updates are handled. -[tool_call: ${ReadFileTool.Name} for absolute_path '/path/to/UserProfileService.java'] -(After reading the file) -It appears the \`updateUserProfile\` method in \`UserProfileService.java\` is responsible for this. It expects a user ID and a \`UserProfileDTO\` object... + + + +npm run test + + + +(After verification passes) +All checks passed. This is a stable checkpoint. user: Where are all the 'app.config' files in this project? I need to check their settings. model: -[tool_call: ${GlobTool.Name} for pattern '**/app.config'] + + + +./**/app.config + + + (Assuming GlobTool returns a list of paths like ['/path/to/moduleA/app.config', '/path/to/moduleB/app.config']) I found the following 'app.config' files: - /path/to/moduleA/app.config diff --git a/packages/core/src/core/turn.ts b/packages/core/src/core/turn.ts index bea29b66..6feb75b7 100644 --- a/packages/core/src/core/turn.ts +++ b/packages/core/src/core/turn.ts @@ -50,6 +50,7 @@ export enum GeminiEventType { ChatCompressed = 'chat_compressed', Thought = 'thought', MaxSessionTurns = 'max_session_turns', + SessionTokenLimitExceeded = 'session_token_limit_exceeded', Finished = 'finished', LoopDetected = 'loop_detected', } @@ -63,6 +64,12 @@ export interface GeminiErrorEventValue { error: StructuredError; } +export interface SessionTokenLimitExceededValue { + currentTokens: number; + limit: number; + message: string; +} + export interface ToolCallRequestInfo { callId: string; name: string; @@ -136,6 +143,11 @@ export type ServerGeminiMaxSessionTurnsEvent = { type: GeminiEventType.MaxSessionTurns; }; +export type ServerGeminiSessionTokenLimitExceededEvent = { + type: GeminiEventType.SessionTokenLimitExceeded; + value: SessionTokenLimitExceededValue; +}; + export type ServerGeminiFinishedEvent = { type: GeminiEventType.Finished; value: FinishReason; @@ -156,6 +168,7 @@ export type ServerGeminiStreamEvent = | ServerGeminiChatCompressedEvent | ServerGeminiThoughtEvent | ServerGeminiMaxSessionTurnsEvent + | ServerGeminiSessionTokenLimitExceededEvent | ServerGeminiFinishedEvent | ServerGeminiLoopDetectedEvent; diff --git a/packages/core/src/mcp/oauth-provider.ts b/packages/core/src/mcp/oauth-provider.ts index 2f65f051..03401a4c 100644 --- a/packages/core/src/mcp/oauth-provider.ts +++ b/packages/core/src/mcp/oauth-provider.ts @@ -108,7 +108,7 @@ export class MCPOAuthProvider { `http://localhost:${this.REDIRECT_PORT}${this.REDIRECT_PATH}`; const registrationRequest: OAuthClientRegistrationRequest = { - client_name: 'Gemini CLI MCP Client', + client_name: 'Gemini CLI (Google ADC)', redirect_uris: [redirectUri], grant_types: ['authorization_code', 'refresh_token'], response_types: ['code'], diff --git a/packages/core/src/utils/getFolderStructure.test.ts b/packages/core/src/utils/getFolderStructure.test.ts index f7b67ae4..8786c099 100644 --- a/packages/core/src/utils/getFolderStructure.test.ts +++ b/packages/core/src/utils/getFolderStructure.test.ts @@ -45,7 +45,7 @@ describe('getFolderStructure', () => { const structure = await getFolderStructure(testRootDir); expect(structure.trim()).toBe( ` -Showing up to 200 items (files + folders). +Showing up to 20 items (files + folders). ${testRootDir}${path.sep} β”œβ”€β”€β”€fileA1.ts @@ -60,7 +60,7 @@ ${testRootDir}${path.sep} const structure = await getFolderStructure(testRootDir); expect(structure.trim()).toBe( ` -Showing up to 200 items (files + folders). +Showing up to 20 items (files + folders). ${testRootDir}${path.sep} ` @@ -81,7 +81,7 @@ ${testRootDir}${path.sep} const structure = await getFolderStructure(testRootDir); expect(structure.trim()).toBe( ` -Showing up to 200 items (files + folders). Folders or files indicated with ... contain more items not shown, were ignored, or the display limit (200 items) was reached. +Showing up to 20 items (files + folders). Folders or files indicated with ... contain more items not shown, were ignored, or the display limit (20 items) was reached. ${testRootDir}${path.sep} β”œβ”€β”€β”€.hiddenfile @@ -108,7 +108,7 @@ ${testRootDir}${path.sep} ignoredFolders: new Set(['subfolderA', 'node_modules']), }); const expected = ` -Showing up to 200 items (files + folders). Folders or files indicated with ... contain more items not shown, were ignored, or the display limit (200 items) was reached. +Showing up to 20 items (files + folders). Folders or files indicated with ... contain more items not shown, were ignored, or the display limit (20 items) was reached. ${testRootDir}${path.sep} β”œβ”€β”€β”€.hiddenfile @@ -129,7 +129,7 @@ ${testRootDir}${path.sep} fileIncludePattern: /\.ts$/, }); const expected = ` -Showing up to 200 items (files + folders). +Showing up to 20 items (files + folders). ${testRootDir}${path.sep} β”œβ”€β”€β”€fileA1.ts diff --git a/packages/core/src/utils/getFolderStructure.ts b/packages/core/src/utils/getFolderStructure.ts index 60c539b5..e682375e 100644 --- a/packages/core/src/utils/getFolderStructure.ts +++ b/packages/core/src/utils/getFolderStructure.ts @@ -12,7 +12,7 @@ import { FileDiscoveryService } from '../services/fileDiscoveryService.js'; import { FileFilteringOptions } from '../config/config.js'; import { DEFAULT_FILE_FILTERING_OPTIONS } from '../config/config.js'; -const MAX_ITEMS = 200; +const MAX_ITEMS = 20; const TRUNCATION_INDICATOR = '...'; const DEFAULT_IGNORED_FOLDERS = new Set(['node_modules', '.git', 'dist']); @@ -20,7 +20,7 @@ const DEFAULT_IGNORED_FOLDERS = new Set(['node_modules', '.git', 'dist']); /** Options for customizing folder structure retrieval. */ interface FolderStructureOptions { - /** Maximum number of files and folders combined to display. Defaults to 200. */ + /** Maximum number of files and folders combined to display. Defaults to 20. */ maxItems?: number; /** Set of folder names to ignore completely. Case-sensitive. */ ignoredFolders?: Set;