diff --git a/.github/workflows/gemini-automated-issue-triage.yml b/.github/workflows/gemini-automated-issue-triage.yml index 7dbc0a56..bfd6c624 100644 --- a/.github/workflows/gemini-automated-issue-triage.yml +++ b/.github/workflows/gemini-automated-issue-triage.yml @@ -24,7 +24,7 @@ jobs: ISSUE_TITLE: ${{ github.event.issue.title }} ISSUE_BODY: ${{ github.event.issue.body }} with: - version: 0.0.4 + version: 0.0.6 OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} settings_json: | { diff --git a/.github/workflows/gemini-scheduled-issue-triage.yml b/.github/workflows/gemini-scheduled-issue-triage.yml index 10a1ab97..9fa9ddc0 100644 --- a/.github/workflows/gemini-scheduled-issue-triage.yml +++ b/.github/workflows/gemini-scheduled-issue-triage.yml @@ -42,7 +42,7 @@ jobs: ISSUES_TO_TRIAGE: ${{ steps.find_issues.outputs.issues_to_triage }} REPOSITORY: ${{ github.repository }} with: - version: 0.0.4 + version: 0.0.6 OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }} OPENAI_MODEL: ${{ secrets.OPENAI_MODEL }} diff --git a/package-lock.json b/package-lock.json index 5fafdc03..87b50ec7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@qwen-code/qwen-code", - "version": "0.0.4", + "version": "0.0.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@qwen-code/qwen-code", - "version": "0.0.4", + "version": "0.0.6", "workspaces": [ "packages/*" ], @@ -11817,7 +11817,7 @@ }, "packages/cli": { "name": "@qwen-code/qwen-code", - "version": "0.0.4", + "version": "0.0.6", "dependencies": { "@google/genai": "1.9.0", "@iarna/toml": "^2.2.5", @@ -11894,7 +11894,7 @@ }, "packages/core": { "name": "@qwen-code/qwen-code-core", - "version": "0.0.4", + "version": "0.0.6", "dependencies": { "@google/genai": "1.9.0", "@modelcontextprotocol/sdk": "^1.11.0", @@ -11962,7 +11962,7 @@ }, "packages/vscode-ide-companion": { "name": "qwen-code-vscode-ide-companion", - "version": "0.0.4", + "version": "0.0.6", "license": "LICENSE", "dependencies": { "@modelcontextprotocol/sdk": "^1.15.1", diff --git a/package.json b/package.json index 25b104e2..e73eb562 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@qwen-code/qwen-code", - "version": "0.0.4", + "version": "0.0.6", "engines": { "node": ">=20.0.0" }, @@ -13,7 +13,7 @@ "url": "git+https://github.com/QwenLM/qwen-code.git" }, "config": { - "sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.0.4" + "sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.0.6" }, "scripts": { "start": "node scripts/start.js", diff --git a/packages/cli/package.json b/packages/cli/package.json index c4b1092b..3b02043b 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@qwen-code/qwen-code", - "version": "0.0.4", + "version": "0.0.6", "description": "Qwen Code", "repository": { "type": "git", @@ -25,7 +25,7 @@ "dist" ], "config": { - "sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.0.4" + "sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.0.6" }, "dependencies": { "@google/genai": "1.9.0", diff --git a/packages/cli/src/config/config.ts b/packages/cli/src/config/config.ts index 9dc66b1f..77095633 100644 --- a/packages/cli/src/config/config.ts +++ b/packages/cli/src/config/config.ts @@ -412,6 +412,7 @@ export async function loadCliConfig( } const sandboxConfig = await loadSandboxConfig(settings, argv); + const cliVersion = await getCliVersion(); return new Config({ sessionId, @@ -497,6 +498,7 @@ export async function loadCliConfig( }, ], contentGenerator: settings.contentGenerator, + cliVersion, }); } diff --git a/packages/core/package.json b/packages/core/package.json index a3a1e7dc..b4350897 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@qwen-code/qwen-code-core", - "version": "0.0.4", + "version": "0.0.6", "description": "Qwen Code Core", "repository": { "type": "git", diff --git a/packages/core/src/config/config.ts b/packages/core/src/config/config.ts index e854de31..af6b070a 100644 --- a/packages/core/src/config/config.ts +++ b/packages/core/src/config/config.ts @@ -208,6 +208,7 @@ export interface ConfigParameters { timeout?: number; maxRetries?: number; }; + cliVersion?: string; } export class Config { @@ -281,6 +282,7 @@ export class Config { timeout?: number; maxRetries?: number; }; + private readonly cliVersion?: string; constructor(params: ConfigParameters) { this.sessionId = params.sessionId; this.embeddingModel = @@ -350,6 +352,7 @@ export class Config { this.enableOpenAILogging = params.enableOpenAILogging ?? false; this.sampling_params = params.sampling_params; this.contentGenerator = params.contentGenerator; + this.cliVersion = params.cliVersion; if (params.contextFileName) { setGeminiMdFilename(params.contextFileName); @@ -719,6 +722,10 @@ export class Config { return this.contentGenerator?.maxRetries; } + getCliVersion(): string | undefined { + return this.cliVersion; + } + getSystemPromptMappings(): | Array<{ baseUrls?: string[]; diff --git a/packages/core/src/core/__tests__/openaiTimeoutHandling.test.ts b/packages/core/src/core/__tests__/openaiTimeoutHandling.test.ts index 158b0c33..c743c9b5 100644 --- a/packages/core/src/core/__tests__/openaiTimeoutHandling.test.ts +++ b/packages/core/src/core/__tests__/openaiTimeoutHandling.test.ts @@ -45,6 +45,7 @@ describe('OpenAIContentGenerator Timeout Handling', () => { timeout: 120000, maxRetries: 3, }), + getCliVersion: vi.fn().mockReturnValue('1.0.0'), } as unknown as Config; // Mock OpenAI client @@ -256,6 +257,7 @@ describe('OpenAIContentGenerator Timeout Handling', () => { timeout: 300000, // 5 minutes maxRetries: 5, }), + getCliVersion: vi.fn().mockReturnValue('1.0.0'), } as unknown as Config; new OpenAIContentGenerator('test-key', 'gpt-4', customConfig); @@ -274,6 +276,7 @@ describe('OpenAIContentGenerator Timeout Handling', () => { it('should handle missing timeout config gracefully', () => { const noTimeoutConfig = { getContentGeneratorConfig: vi.fn().mockReturnValue({}), + getCliVersion: vi.fn().mockReturnValue('1.0.0'), } as unknown as Config; new OpenAIContentGenerator('test-key', 'gpt-4', noTimeoutConfig); diff --git a/packages/core/src/core/client.test.ts b/packages/core/src/core/client.test.ts index 98c4965c..b4d2c08b 100644 --- a/packages/core/src/core/client.test.ts +++ b/packages/core/src/core/client.test.ts @@ -228,6 +228,7 @@ describe('Gemini Client (client.ts)', () => { getGeminiClient: vi.fn(), setFallbackMode: vi.fn(), getDebugMode: vi.fn().mockReturnValue(false), + getCliVersion: vi.fn().mockReturnValue('1.0.0'), }; const MockedConfig = vi.mocked(Config, true); MockedConfig.mockImplementation( diff --git a/packages/core/src/core/contentGenerator.test.ts b/packages/core/src/core/contentGenerator.test.ts index cb117df2..df90f988 100644 --- a/packages/core/src/core/contentGenerator.test.ts +++ b/packages/core/src/core/contentGenerator.test.ts @@ -17,7 +17,9 @@ import { Config } from '../config/config.js'; vi.mock('../code_assist/codeAssist.js'); vi.mock('@google/genai'); -const mockConfig = {} as unknown as Config; +const mockConfig = { + getCliVersion: vi.fn().mockReturnValue('1.0.0'), +} as unknown as Config; describe('createContentGenerator', () => { it('should create a CodeAssistContentGenerator', async () => { @@ -73,6 +75,7 @@ describe('createContentGeneratorConfig', () => { getSamplingParams: vi.fn().mockReturnValue(undefined), getContentGeneratorTimeout: vi.fn().mockReturnValue(undefined), getContentGeneratorMaxRetries: vi.fn().mockReturnValue(undefined), + getCliVersion: vi.fn().mockReturnValue('1.0.0'), } as unknown as Config; beforeEach(() => { diff --git a/packages/core/src/core/contentGenerator.ts b/packages/core/src/core/contentGenerator.ts index b04ae36d..76c09ad3 100644 --- a/packages/core/src/core/contentGenerator.ts +++ b/packages/core/src/core/contentGenerator.ts @@ -151,7 +151,7 @@ export async function createContentGenerator( gcConfig: Config, sessionId?: string, ): Promise { - const version = process.env.CLI_VERSION || process.version; + const version = gcConfig.getCliVersion() || 'unknown'; const httpOptions = { headers: { 'User-Agent': `GeminiCLI/${version} (${process.platform}; ${process.arch})`, diff --git a/packages/core/src/core/openaiContentGenerator.test.ts b/packages/core/src/core/openaiContentGenerator.test.ts index 51939b1e..637c6135 100644 --- a/packages/core/src/core/openaiContentGenerator.test.ts +++ b/packages/core/src/core/openaiContentGenerator.test.ts @@ -66,6 +66,7 @@ describe('OpenAIContentGenerator', () => { top_p: 0.9, }, }), + getCliVersion: vi.fn().mockReturnValue('1.0.0'), } as unknown as Config; // Mock OpenAI client @@ -143,6 +144,7 @@ describe('OpenAIContentGenerator', () => { timeout: 300000, maxRetries: 5, }), + getCliVersion: vi.fn().mockReturnValue('1.0.0'), } as unknown as Config; new OpenAIContentGenerator('test-key', 'gpt-4', customConfig); @@ -901,6 +903,7 @@ describe('OpenAIContentGenerator', () => { getContentGeneratorConfig: vi.fn().mockReturnValue({ enableOpenAILogging: true, }), + getCliVersion: vi.fn().mockReturnValue('1.0.0'), } as unknown as Config; const loggingGenerator = new OpenAIContentGenerator( @@ -1023,6 +1026,7 @@ describe('OpenAIContentGenerator', () => { getContentGeneratorConfig: vi.fn().mockReturnValue({ enableOpenAILogging: true, }), + getCliVersion: vi.fn().mockReturnValue('1.0.0'), } as unknown as Config; const loggingGenerator = new OpenAIContentGenerator( @@ -1817,6 +1821,7 @@ describe('OpenAIContentGenerator', () => { max_tokens: 500, }, }), + getCliVersion: vi.fn().mockReturnValue('1.0.0'), } as unknown as Config; const loggingGenerator = new OpenAIContentGenerator( @@ -2001,6 +2006,7 @@ describe('OpenAIContentGenerator', () => { getContentGeneratorConfig: vi.fn().mockReturnValue({ enableOpenAILogging: true, }), + getCliVersion: vi.fn().mockReturnValue('1.0.0'), } as unknown as Config; const loggingGenerator = new OpenAIContentGenerator( @@ -2257,6 +2263,7 @@ describe('OpenAIContentGenerator', () => { top_p: undefined, }, }), + getCliVersion: vi.fn().mockReturnValue('1.0.0'), } as unknown as Config; const testGenerator = new OpenAIContentGenerator( @@ -2314,6 +2321,7 @@ describe('OpenAIContentGenerator', () => { frequency_penalty: 0.3, }, }), + getCliVersion: vi.fn().mockReturnValue('1.0.0'), } as unknown as Config; const testGenerator = new OpenAIContentGenerator( @@ -2394,6 +2402,7 @@ describe('OpenAIContentGenerator', () => { enableOpenAILogging: false, }), getSessionId: vi.fn().mockReturnValue('test-session-id'), + getCliVersion: vi.fn().mockReturnValue('1.0.0'), } as unknown as Config; const qwenGenerator = new OpenAIContentGenerator( @@ -2447,6 +2456,7 @@ describe('OpenAIContentGenerator', () => { enableOpenAILogging: false, }), getSessionId: vi.fn().mockReturnValue('dashscope-session-id'), + getCliVersion: vi.fn().mockReturnValue('1.0.0'), } as unknown as Config; const dashscopeGenerator = new OpenAIContentGenerator( @@ -2507,6 +2517,7 @@ describe('OpenAIContentGenerator', () => { enableOpenAILogging: false, }), getSessionId: vi.fn().mockReturnValue('regular-session-id'), + getCliVersion: vi.fn().mockReturnValue('1.0.0'), } as unknown as Config; const regularGenerator = new OpenAIContentGenerator( @@ -2552,6 +2563,7 @@ describe('OpenAIContentGenerator', () => { enableOpenAILogging: false, }), getSessionId: vi.fn().mockReturnValue('other-session-id'), + getCliVersion: vi.fn().mockReturnValue('1.0.0'), } as unknown as Config; const otherGenerator = new OpenAIContentGenerator( @@ -2600,6 +2612,7 @@ describe('OpenAIContentGenerator', () => { enableOpenAILogging: false, }), getSessionId: vi.fn().mockReturnValue('other-base-url-session-id'), + getCliVersion: vi.fn().mockReturnValue('1.0.0'), } as unknown as Config; const otherBaseUrlGenerator = new OpenAIContentGenerator( @@ -2648,6 +2661,7 @@ describe('OpenAIContentGenerator', () => { enableOpenAILogging: false, }), getSessionId: vi.fn().mockReturnValue('streaming-session-id'), + getCliVersion: vi.fn().mockReturnValue('1.0.0'), } as unknown as Config; const qwenGenerator = new OpenAIContentGenerator( @@ -2726,6 +2740,7 @@ describe('OpenAIContentGenerator', () => { enableOpenAILogging: false, }), getSessionId: vi.fn().mockReturnValue('regular-streaming-session-id'), + getCliVersion: vi.fn().mockReturnValue('1.0.0'), } as unknown as Config; const regularGenerator = new OpenAIContentGenerator( @@ -2799,6 +2814,7 @@ describe('OpenAIContentGenerator', () => { enableOpenAILogging: false, }), getSessionId: vi.fn().mockReturnValue(undefined), // Undefined session ID + getCliVersion: vi.fn().mockReturnValue('1.0.0'), } as unknown as Config; const qwenGenerator = new OpenAIContentGenerator( @@ -2852,6 +2868,7 @@ describe('OpenAIContentGenerator', () => { enableOpenAILogging: false, }), getSessionId: vi.fn().mockReturnValue('no-base-url-session-id'), + getCliVersion: vi.fn().mockReturnValue('1.0.0'), } as unknown as Config; const noBaseUrlGenerator = new OpenAIContentGenerator( @@ -2900,6 +2917,7 @@ describe('OpenAIContentGenerator', () => { enableOpenAILogging: false, }), getSessionId: vi.fn().mockReturnValue('undefined-auth-session-id'), + getCliVersion: vi.fn().mockReturnValue('1.0.0'), } as unknown as Config; const undefinedAuthGenerator = new OpenAIContentGenerator( @@ -2945,6 +2963,7 @@ describe('OpenAIContentGenerator', () => { const undefinedConfig = { getContentGeneratorConfig: vi.fn().mockReturnValue(undefined), // Undefined config getSessionId: vi.fn().mockReturnValue('undefined-config-session-id'), + getCliVersion: vi.fn().mockReturnValue('1.0.0'), } as unknown as Config; const undefinedConfigGenerator = new OpenAIContentGenerator( diff --git a/packages/core/src/core/openaiContentGenerator.ts b/packages/core/src/core/openaiContentGenerator.ts index 505f3dc6..16404d30 100644 --- a/packages/core/src/core/openaiContentGenerator.ts +++ b/packages/core/src/core/openaiContentGenerator.ts @@ -114,8 +114,7 @@ export class OpenAIContentGenerator implements ContentGenerator { timeoutConfig.maxRetries = contentGeneratorConfig.maxRetries; } - // Set up User-Agent header (same format as contentGenerator.ts) - const version = process.env.CLI_VERSION || process.version; + const version = config.getCliVersion() || 'unknown'; const userAgent = `QwenCode/${version} (${process.platform}; ${process.arch})`; // Check if using OpenRouter and add required headers diff --git a/packages/core/src/telemetry/qwen-logger/qwen-logger.ts b/packages/core/src/telemetry/qwen-logger/qwen-logger.ts index e3ec55d8..803d19ca 100644 --- a/packages/core/src/telemetry/qwen-logger/qwen-logger.ts +++ b/packages/core/src/telemetry/qwen-logger/qwen-logger.ts @@ -140,14 +140,14 @@ export class QwenLogger { return this.createRumEvent('exception', type, name, properties); } - createRumPayload(): RumPayload { - const version = process.env.CLI_VERSION || process.version; + async createRumPayload(): Promise { + const version = this.config?.getCliVersion() || 'unknown'; return { app: { id: RUN_APP_ID, env: process.env.DEBUG ? 'dev' : 'prod', - version, + version: version || 'unknown', type: 'cli', }, user: { @@ -190,7 +190,7 @@ export class QwenLogger { this.isFlushInProgress = true; - const rumPayload = this.createRumPayload(); + const rumPayload = await this.createRumPayload(); const flushFn = () => new Promise((resolve, reject) => { const body = safeJsonStringify(rumPayload); diff --git a/packages/vscode-ide-companion/package.json b/packages/vscode-ide-companion/package.json index 471e7296..cb55827a 100644 --- a/packages/vscode-ide-companion/package.json +++ b/packages/vscode-ide-companion/package.json @@ -2,7 +2,7 @@ "name": "qwen-code-vscode-ide-companion", "displayName": "Qwen Code Companion", "description": "Enable Qwen Code with direct access to your VS Code workspace.", - "version": "0.0.4", + "version": "0.0.6", "publisher": "qwenlm", "icon": "assets/icon.png", "repository": {