Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,30 @@ describe('QwenAgentManager.setModelFromUi', () => {
expect(onModelChanged).toHaveBeenCalledWith(selectedModel);
});
});

describe('QwenAgentManager.createNewSession', () => {
it('creates a fresh ACP session when explicitly requested even if one is already active', async () => {
const manager = new QwenAgentManager();
const connection = {
currentSessionId: 'session-1',
newSession: vi.fn().mockImplementation(async () => {
connection.currentSessionId = 'session-2';
return { sessionId: 'session-2' };
}),
authenticate: vi.fn(),
};

(
manager as unknown as {
connection: typeof connection;
}
).connection = connection;

const newSessionId = await manager.createNewSession('/workspace', {
forceNew: true,
} as never);

expect(connection.newSession).toHaveBeenCalledWith('/workspace');
expect(newSessionId).toBe('session-2');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ interface AgentConnectOptions {
}
interface AgentSessionOptions {
autoAuthenticate?: boolean;
forceNew?: boolean;
}

export class QwenAgentManager {
Expand Down Expand Up @@ -1163,8 +1164,10 @@ export class QwenAgentManager {
options?: AgentSessionOptions,
): Promise<string | null> {
const autoAuthenticate = options?.autoAuthenticate ?? true;
// Reuse existing session if present
if (this.connection.currentSessionId) {
const forceNew = options?.forceNew ?? false;
// Reuse the current session for implicit session bootstrap paths.
// Explicit "new session" actions must bypass this and call session/new.
if (!forceNew && this.connection.currentSessionId) {
console.log(
'[QwenAgentManager] createNewSession: reusing existing session',
this.connection.currentSessionId,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* @license
* Copyright 2025 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/

import esbuild from 'esbuild';
import { fileURLToPath } from 'node:url';
import { describe, expect, it } from 'vitest';

describe('imageSupport browser bundling', () => {
it('does not leave qwen-code-core runtime imports in the webview bundle', async () => {
const result = await esbuild.build({
entryPoints: [
fileURLToPath(new URL('./imageSupport.ts', import.meta.url)),
],
bundle: true,
format: 'iife',
platform: 'browser',
write: false,
logLevel: 'silent',
external: ['@qwen-code/qwen-code-core'],
});

const output = result.outputFiles[0]?.text ?? '';

expect(output).not.toContain('@qwen-code/qwen-code-core');
expect(output).not.toContain('supportedImageFormats.js');
});

it('does not leave qwen-code-core runtime imports in the App webview bundle', async () => {
const result = await esbuild.build({
entryPoints: [
fileURLToPath(new URL('../webview/App.tsx', import.meta.url)),
],
bundle: true,
format: 'iife',
platform: 'browser',
write: false,
logLevel: 'silent',
external: ['@qwen-code/qwen-code-core'],
});

const output = result.outputFiles[0]?.text ?? '';

expect(output).not.toContain('@qwen-code/qwen-code-core');

Check failure on line 46 in packages/vscode-ide-companion/src/utils/imageSupport.bundle.test.ts

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 20.x)

src/utils/imageSupport.bundle.test.ts > imageSupport browser bundling > does not leave qwen-code-core runtime imports in the App webview bundle

AssertionError: expected '"use strict";\n(() => {\n var __crea…' not to contain '@qwen-code/qwen-code-core' - Expected + Received - @qwen-code/qwen-code-core + "use strict"; + (() => { + var __create = Object.create; + var __defProp = Object.defineProperty; + var __getOwnPropDesc = Object.getOwnPropertyDescriptor; + var __getOwnPropNames = Object.getOwnPropertyNames; + var __getProtoOf = Object.getPrototypeOf; + var __hasOwnProp = Object.prototype.hasOwnProperty; + var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { + get: (a, b) => (typeof require !== "undefined" ? require : a)[b] + }) : x)(function(x) { + if (typeof require !== "undefined") return require.apply(this, arguments); + throw Error('Dynamic require of "' + x + '" is not supported'); + }); + var __commonJS = (cb, mod) => function __require2() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + }; + var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; + }; + var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod + )); + + // ../../node_modules/react/cjs/react.development.js + var require_react_development = __commonJS({ + "../../node_modules/react/cjs/react.development.js"(exports, module) { + "use strict"; + (function() { + function defineDeprecationWarning(methodName, info) { + Object.defineProperty(Component.prototype, methodName, { + get: function() { + console.warn( + "%s(...) is deprecated in plain JavaScript React classes. %s", + info[0], + info[1] + ); + } + }); + } + function getIteratorFn(maybeIterable) { + if (null === maybeIterable || "object" !== typeof maybeIterable) + return null; + maybeIterable = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable["@@iterator"]; + return "function" === typeof maybeIterable ? maybeIterable : null; + } + function warnNoop(publicInstance, callerName) { + publicInstance = (publicInstance = publicInstance.constructor) && (publicInstance.displayName || publicInstance.name) || "ReactClass"; + var warningKey = publicInstance + "." + callerName; + didWarnStateUpdateForUnmountedComponent[warningKey] || (console.error( + "Can't call %s on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to `this.state` directly or define a `state = {};` class property with the desired state in the %s component.", + callerName, + publicInstance + ), didWarnStateUpdateForUnmountedComponent[warningKey] = true); + } + function Component(props, context, updater) { + this.props = props; + this.context = context; + this.refs = emptyObject; + this.updater = updater || ReactNoopUpdateQueue; + } + function ComponentDummy() { + } + function PureComponent(props, context, updater) { +

Check failure on line 46 in packages/vscode-ide-companion/src/utils/imageSupport.bundle.test.ts

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 20.x)

src/utils/imageSupport.bundle.test.ts > imageSupport browser bundling > does not leave qwen-code-core runtime imports in the App webview bundle

AssertionError: expected '"use strict";\n(() => {\n var __crea…' not to contain '@qwen-code/qwen-code-core' - Expected + Received - @qwen-code/qwen-code-core + "use strict"; + (() => { + var __create = Object.create; + var __defProp = Object.defineProperty; + var __getOwnPropDesc = Object.getOwnPropertyDescriptor; + var __getOwnPropNames = Object.getOwnPropertyNames; + var __getProtoOf = Object.getPrototypeOf; + var __hasOwnProp = Object.prototype.hasOwnProperty; + var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { + get: (a, b) => (typeof require !== "undefined" ? require : a)[b] + }) : x)(function(x) { + if (typeof require !== "undefined") return require.apply(this, arguments); + throw Error('Dynamic require of "' + x + '" is not supported'); + }); + var __commonJS = (cb, mod) => function __require2() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + }; + var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; + }; + var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod + )); + + // ../../node_modules/react/cjs/react.development.js + var require_react_development = __commonJS({ + "../../node_modules/react/cjs/react.development.js"(exports, module) { + "use strict"; + (function() { + function defineDeprecationWarning(methodName, info) { + Object.defineProperty(Component.prototype, methodName, { + get: function() { + console.warn( + "%s(...) is deprecated in plain JavaScript React classes. %s", + info[0], + info[1] + ); + } + }); + } + function getIteratorFn(maybeIterable) { + if (null === maybeIterable || "object" !== typeof maybeIterable) + return null; + maybeIterable = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable["@@iterator"]; + return "function" === typeof maybeIterable ? maybeIterable : null; + } + function warnNoop(publicInstance, callerName) { + publicInstance = (publicInstance = publicInstance.constructor) && (publicInstance.displayName || publicInstance.name) || "ReactClass"; + var warningKey = publicInstance + "." + callerName; + didWarnStateUpdateForUnmountedComponent[warningKey] || (console.error( + "Can't call %s on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to `this.state` directly or define a `state = {};` class property with the desired state in the %s component.", + callerName, + publicInstance + ), didWarnStateUpdateForUnmountedComponent[warningKey] = true); + } + function Component(props, context, updater) { + this.props = props; + this.context = context; + this.refs = emptyObject; + this.updater = updater || ReactNoopUpdateQueue; + } + function ComponentDummy() { + } + function PureComponent(props, context, updater) { +

Check failure on line 46 in packages/vscode-ide-companion/src/utils/imageSupport.bundle.test.ts

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 24.x)

src/utils/imageSupport.bundle.test.ts > imageSupport browser bundling > does not leave qwen-code-core runtime imports in the App webview bundle

AssertionError: expected '"use strict";\n(() => {\n var __crea…' not to contain '@qwen-code/qwen-code-core' - Expected + Received - @qwen-code/qwen-code-core + "use strict"; + (() => { + var __create = Object.create; + var __defProp = Object.defineProperty; + var __getOwnPropDesc = Object.getOwnPropertyDescriptor; + var __getOwnPropNames = Object.getOwnPropertyNames; + var __getProtoOf = Object.getPrototypeOf; + var __hasOwnProp = Object.prototype.hasOwnProperty; + var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { + get: (a, b) => (typeof require !== "undefined" ? require : a)[b] + }) : x)(function(x) { + if (typeof require !== "undefined") return require.apply(this, arguments); + throw Error('Dynamic require of "' + x + '" is not supported'); + }); + var __commonJS = (cb, mod) => function __require2() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + }; + var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; + }; + var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod + )); + + // ../../node_modules/react/cjs/react.development.js + var require_react_development = __commonJS({ + "../../node_modules/react/cjs/react.development.js"(exports, module) { + "use strict"; + (function() { + function defineDeprecationWarning(methodName, info) { + Object.defineProperty(Component.prototype, methodName, { + get: function() { + console.warn( + "%s(...) is deprecated in plain JavaScript React classes. %s", + info[0], + info[1] + ); + } + }); + } + function getIteratorFn(maybeIterable) { + if (null === maybeIterable || "object" !== typeof maybeIterable) + return null; + maybeIterable = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable["@@iterator"]; + return "function" === typeof maybeIterable ? maybeIterable : null; + } + function warnNoop(publicInstance, callerName) { + publicInstance = (publicInstance = publicInstance.constructor) && (publicInstance.displayName || publicInstance.name) || "ReactClass"; + var warningKey = publicInstance + "." + callerName; + didWarnStateUpdateForUnmountedComponent[warningKey] || (console.error( + "Can't call %s on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to `this.state` directly or define a `state = {};` class property with the desired state in the %s component.", + callerName, + publicInstance + ), didWarnStateUpdateForUnmountedComponent[warningKey] = true); + } + function Component(props, context, updater) { + this.props = props; + this.context = context; + this.refs = emptyObject; + this.updater = updater || ReactNoopUpdateQueue; + } + function ComponentDummy() { + } + function PureComponent(props, context, updater) { +

Check failure on line 46 in packages/vscode-ide-companion/src/utils/imageSupport.bundle.test.ts

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 24.x)

src/utils/imageSupport.bundle.test.ts > imageSupport browser bundling > does not leave qwen-code-core runtime imports in the App webview bundle

AssertionError: expected '"use strict";\n(() => {\n var __crea…' not to contain '@qwen-code/qwen-code-core' - Expected + Received - @qwen-code/qwen-code-core + "use strict"; + (() => { + var __create = Object.create; + var __defProp = Object.defineProperty; + var __getOwnPropDesc = Object.getOwnPropertyDescriptor; + var __getOwnPropNames = Object.getOwnPropertyNames; + var __getProtoOf = Object.getPrototypeOf; + var __hasOwnProp = Object.prototype.hasOwnProperty; + var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { + get: (a, b) => (typeof require !== "undefined" ? require : a)[b] + }) : x)(function(x) { + if (typeof require !== "undefined") return require.apply(this, arguments); + throw Error('Dynamic require of "' + x + '" is not supported'); + }); + var __commonJS = (cb, mod) => function __require2() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + }; + var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; + }; + var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod + )); + + // ../../node_modules/react/cjs/react.development.js + var require_react_development = __commonJS({ + "../../node_modules/react/cjs/react.development.js"(exports, module) { + "use strict"; + (function() { + function defineDeprecationWarning(methodName, info) { + Object.defineProperty(Component.prototype, methodName, { + get: function() { + console.warn( + "%s(...) is deprecated in plain JavaScript React classes. %s", + info[0], + info[1] + ); + } + }); + } + function getIteratorFn(maybeIterable) { + if (null === maybeIterable || "object" !== typeof maybeIterable) + return null; + maybeIterable = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable["@@iterator"]; + return "function" === typeof maybeIterable ? maybeIterable : null; + } + function warnNoop(publicInstance, callerName) { + publicInstance = (publicInstance = publicInstance.constructor) && (publicInstance.displayName || publicInstance.name) || "ReactClass"; + var warningKey = publicInstance + "." + callerName; + didWarnStateUpdateForUnmountedComponent[warningKey] || (console.error( + "Can't call %s on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to `this.state` directly or define a `state = {};` class property with the desired state in the %s component.", + callerName, + publicInstance + ), didWarnStateUpdateForUnmountedComponent[warningKey] = true); + } + function Component(props, context, updater) { + this.props = props; + this.context = context; + this.refs = emptyObject; + this.updater = updater || ReactNoopUpdateQueue; + } + function ComponentDummy() { + } + function PureComponent(props, context, updater) { +

Check failure on line 46 in packages/vscode-ide-companion/src/utils/imageSupport.bundle.test.ts

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 22.x)

src/utils/imageSupport.bundle.test.ts > imageSupport browser bundling > does not leave qwen-code-core runtime imports in the App webview bundle

AssertionError: expected '"use strict";\n(() => {\n var __crea…' not to contain '@qwen-code/qwen-code-core' - Expected + Received - @qwen-code/qwen-code-core + "use strict"; + (() => { + var __create = Object.create; + var __defProp = Object.defineProperty; + var __getOwnPropDesc = Object.getOwnPropertyDescriptor; + var __getOwnPropNames = Object.getOwnPropertyNames; + var __getProtoOf = Object.getPrototypeOf; + var __hasOwnProp = Object.prototype.hasOwnProperty; + var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { + get: (a, b) => (typeof require !== "undefined" ? require : a)[b] + }) : x)(function(x) { + if (typeof require !== "undefined") return require.apply(this, arguments); + throw Error('Dynamic require of "' + x + '" is not supported'); + }); + var __commonJS = (cb, mod) => function __require2() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + }; + var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; + }; + var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod + )); + + // ../../node_modules/react/cjs/react.development.js + var require_react_development = __commonJS({ + "../../node_modules/react/cjs/react.development.js"(exports, module) { + "use strict"; + (function() { + function defineDeprecationWarning(methodName, info) { + Object.defineProperty(Component.prototype, methodName, { + get: function() { + console.warn( + "%s(...) is deprecated in plain JavaScript React classes. %s", + info[0], + info[1] + ); + } + }); + } + function getIteratorFn(maybeIterable) { + if (null === maybeIterable || "object" !== typeof maybeIterable) + return null; + maybeIterable = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable["@@iterator"]; + return "function" === typeof maybeIterable ? maybeIterable : null; + } + function warnNoop(publicInstance, callerName) { + publicInstance = (publicInstance = publicInstance.constructor) && (publicInstance.displayName || publicInstance.name) || "ReactClass"; + var warningKey = publicInstance + "." + callerName; + didWarnStateUpdateForUnmountedComponent[warningKey] || (console.error( + "Can't call %s on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to `this.state` directly or define a `state = {};` class property with the desired state in the %s component.", + callerName, + publicInstance + ), didWarnStateUpdateForUnmountedComponent[warningKey] = true); + } + function Component(props, context, updater) { + this.props = props; + this.context = context; + this.refs = emptyObject; + this.updater = updater || ReactNoopUpdateQueue; + } + function ComponentDummy() { + } + function PureComponent(props, context, updater) { +

Check failure on line 46 in packages/vscode-ide-companion/src/utils/imageSupport.bundle.test.ts

View workflow job for this annotation

GitHub Actions / Test (macos-latest, 22.x)

src/utils/imageSupport.bundle.test.ts > imageSupport browser bundling > does not leave qwen-code-core runtime imports in the App webview bundle

AssertionError: expected '"use strict";\n(() => {\n var __crea…' not to contain '@qwen-code/qwen-code-core' - Expected + Received - @qwen-code/qwen-code-core + "use strict"; + (() => { + var __create = Object.create; + var __defProp = Object.defineProperty; + var __getOwnPropDesc = Object.getOwnPropertyDescriptor; + var __getOwnPropNames = Object.getOwnPropertyNames; + var __getProtoOf = Object.getPrototypeOf; + var __hasOwnProp = Object.prototype.hasOwnProperty; + var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { + get: (a, b) => (typeof require !== "undefined" ? require : a)[b] + }) : x)(function(x) { + if (typeof require !== "undefined") return require.apply(this, arguments); + throw Error('Dynamic require of "' + x + '" is not supported'); + }); + var __commonJS = (cb, mod) => function __require2() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + }; + var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; + }; + var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod + )); + + // ../../node_modules/react/cjs/react.development.js + var require_react_development = __commonJS({ + "../../node_modules/react/cjs/react.development.js"(exports, module) { + "use strict"; + (function() { + function defineDeprecationWarning(methodName, info) { + Object.defineProperty(Component.prototype, methodName, { + get: function() { + console.warn( + "%s(...) is deprecated in plain JavaScript React classes. %s", + info[0], + info[1] + ); + } + }); + } + function getIteratorFn(maybeIterable) { + if (null === maybeIterable || "object" !== typeof maybeIterable) + return null; + maybeIterable = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable["@@iterator"]; + return "function" === typeof maybeIterable ? maybeIterable : null; + } + function warnNoop(publicInstance, callerName) { + publicInstance = (publicInstance = publicInstance.constructor) && (publicInstance.displayName || publicInstance.name) || "ReactClass"; + var warningKey = publicInstance + "." + callerName; + didWarnStateUpdateForUnmountedComponent[warningKey] || (console.error( + "Can't call %s on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to `this.state` directly or define a `state = {};` class property with the desired state in the %s component.", + callerName, + publicInstance + ), didWarnStateUpdateForUnmountedComponent[warningKey] = true); + } + function Component(props, context, updater) { + this.props = props; + this.context = context; + this.refs = emptyObject; + this.updater = updater || ReactNoopUpdateQueue; + } + function ComponentDummy() { + } + function PureComponent(props, context, updater) { +

Check failure on line 46 in packages/vscode-ide-companion/src/utils/imageSupport.bundle.test.ts

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 24.x)

src/utils/imageSupport.bundle.test.ts > imageSupport browser bundling > does not leave qwen-code-core runtime imports in the App webview bundle

AssertionError: expected '"use strict";\n(() => {\n var __crea…' not to contain '@qwen-code/qwen-code-core' - Expected + Received - @qwen-code/qwen-code-core + "use strict"; + (() => { + var __create = Object.create; + var __defProp = Object.defineProperty; + var __getOwnPropDesc = Object.getOwnPropertyDescriptor; + var __getOwnPropNames = Object.getOwnPropertyNames; + var __getProtoOf = Object.getPrototypeOf; + var __hasOwnProp = Object.prototype.hasOwnProperty; + var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { + get: (a, b) => (typeof require !== "undefined" ? require : a)[b] + }) : x)(function(x) { + if (typeof require !== "undefined") return require.apply(this, arguments); + throw Error('Dynamic require of "' + x + '" is not supported'); + }); + var __commonJS = (cb, mod) => function __require2() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + }; + var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; + }; + var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod + )); + + // ../../node_modules/react/cjs/react.development.js + var require_react_development = __commonJS({ + "../../node_modules/react/cjs/react.development.js"(exports, module) { + "use strict"; + (function() { + function defineDeprecationWarning(methodName, info) { + Object.defineProperty(Component.prototype, methodName, { + get: function() { + console.warn( + "%s(...) is deprecated in plain JavaScript React classes. %s", + info[0], + info[1] + ); + } + }); + } + function getIteratorFn(maybeIterable) { + if (null === maybeIterable || "object" !== typeof maybeIterable) + return null; + maybeIterable = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable["@@iterator"]; + return "function" === typeof maybeIterable ? maybeIterable : null; + } + function warnNoop(publicInstance, callerName) { + publicInstance = (publicInstance = publicInstance.constructor) && (publicInstance.displayName || publicInstance.name) || "ReactClass"; + var warningKey = publicInstance + "." + callerName; + didWarnStateUpdateForUnmountedComponent[warningKey] || (console.error( + "Can't call %s on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to `this.state` directly or define a `state = {};` class property with the desired state in the %s component.", + callerName, + publicInstance + ), didWarnStateUpdateForUnmountedComponent[warningKey] = true); + } + function Component(props, context, updater) { + this.props = props; + this.context = context; + this.refs = emptyObject; + this.updater = updater || ReactNoopUpdateQueue; + } + function ComponentDummy() { + } + function PureComponent(props, context, updater) { +

Check failure on line 46 in packages/vscode-ide-companion/src/utils/imageSupport.bundle.test.ts

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 22.x)

src/utils/imageSupport.bundle.test.ts > imageSupport browser bundling > does not leave qwen-code-core runtime imports in the App webview bundle

AssertionError: expected '"use strict";\n(() => {\n var __crea…' not to contain '@qwen-code/qwen-code-core' - Expected + Received - @qwen-code/qwen-code-core + "use strict"; + (() => { + var __create = Object.create; + var __defProp = Object.defineProperty; + var __getOwnPropDesc = Object.getOwnPropertyDescriptor; + var __getOwnPropNames = Object.getOwnPropertyNames; + var __getProtoOf = Object.getPrototypeOf; + var __hasOwnProp = Object.prototype.hasOwnProperty; + var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { + get: (a, b) => (typeof require !== "undefined" ? require : a)[b] + }) : x)(function(x) { + if (typeof require !== "undefined") return require.apply(this, arguments); + throw Error('Dynamic require of "' + x + '" is not supported'); + }); + var __commonJS = (cb, mod) => function __require2() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + }; + var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; + }; + var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod + )); + + // ../../node_modules/react/cjs/react.development.js + var require_react_development = __commonJS({ + "../../node_modules/react/cjs/react.development.js"(exports, module) { + "use strict"; + (function() { + function defineDeprecationWarning(methodName, info) { + Object.defineProperty(Component.prototype, methodName, { + get: function() { + console.warn( + "%s(...) is deprecated in plain JavaScript React classes. %s", + info[0], + info[1] + ); + } + }); + } + function getIteratorFn(maybeIterable) { + if (null === maybeIterable || "object" !== typeof maybeIterable) + return null; + maybeIterable = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable["@@iterator"]; + return "function" === typeof maybeIterable ? maybeIterable : null; + } + function warnNoop(publicInstance, callerName) { + publicInstance = (publicInstance = publicInstance.constructor) && (publicInstance.displayName || publicInstance.name) || "ReactClass"; + var warningKey = publicInstance + "." + callerName; + didWarnStateUpdateForUnmountedComponent[warningKey] || (console.error( + "Can't call %s on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to `this.state` directly or define a `state = {};` class property with the desired state in the %s component.", + callerName, + publicInstance + ), didWarnStateUpdateForUnmountedComponent[warningKey] = true); + } + function Component(props, context, updater) { + this.props = props; + this.context = context; + this.refs = emptyObject; + this.updater = updater || ReactNoopUpdateQueue; + } + function ComponentDummy() { + } + function PureComponent(props, context, updater) { +

Check failure on line 46 in packages/vscode-ide-companion/src/utils/imageSupport.bundle.test.ts

View workflow job for this annotation

GitHub Actions / Test (windows-latest, 20.x)

src/utils/imageSupport.bundle.test.ts > imageSupport browser bundling > does not leave qwen-code-core runtime imports in the App webview bundle

AssertionError: expected '"use strict";\n(() => {\n var __crea…' not to contain '@qwen-code/qwen-code-core' - Expected + Received - @qwen-code/qwen-code-core + "use strict"; + (() => { + var __create = Object.create; + var __defProp = Object.defineProperty; + var __getOwnPropDesc = Object.getOwnPropertyDescriptor; + var __getOwnPropNames = Object.getOwnPropertyNames; + var __getProtoOf = Object.getPrototypeOf; + var __hasOwnProp = Object.prototype.hasOwnProperty; + var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { + get: (a, b) => (typeof require !== "undefined" ? require : a)[b] + }) : x)(function(x) { + if (typeof require !== "undefined") return require.apply(this, arguments); + throw Error('Dynamic require of "' + x + '" is not supported'); + }); + var __commonJS = (cb, mod) => function __require2() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + }; + var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; + }; + var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod + )); + + // ../../node_modules/react/cjs/react.development.js + var require_react_development = __commonJS({ + "../../node_modules/react/cjs/react.development.js"(exports, module) { + "use strict"; + (function() { + function defineDeprecationWarning(methodName, info) { + Object.defineProperty(Component.prototype, methodName, { + get: function() { + console.warn( + "%s(...) is deprecated in plain JavaScript React classes. %s", + info[0], + info[1] + ); + } + }); + } + function getIteratorFn(maybeIterable) { + if (null === maybeIterable || "object" !== typeof maybeIterable) + return null; + maybeIterable = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable["@@iterator"]; + return "function" === typeof maybeIterable ? maybeIterable : null; + } + function warnNoop(publicInstance, callerName) { + publicInstance = (publicInstance = publicInstance.constructor) && (publicInstance.displayName || publicInstance.name) || "ReactClass"; + var warningKey = publicInstance + "." + callerName; + didWarnStateUpdateForUnmountedComponent[warningKey] || (console.error( + "Can't call %s on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to `this.state` directly or define a `state = {};` class property with the desired state in the %s component.", + callerName, + publicInstance + ), didWarnStateUpdateForUnmountedComponent[warningKey] = true); + } + function Component(props, context, updater) { + this.props = props; + this.context = context; + this.refs = emptyObject; + this.updater = updater || ReactNoopUpdateQueue; + } + function ComponentDummy() { + } + function PureComponent(props, context, updater) { +
expect(output).not.toContain('tokenLimits.js');
});
});
17 changes: 17 additions & 0 deletions packages/vscode-ide-companion/src/utils/imageSupport.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* @license
* Copyright 2025 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/

import { describe, expect, it } from 'vitest';
import { SUPPORTED_IMAGE_MIME_TYPES } from '@qwen-code/qwen-code-core/src/utils/request-tokenizer/supportedImageFormats.js';
import { SUPPORTED_PASTED_IMAGE_MIME_TYPES } from './imageSupport.js';

describe('imageSupport constants', () => {
it('keeps the browser-safe pasted image list aligned with core-supported formats', () => {
expect(SUPPORTED_PASTED_IMAGE_MIME_TYPES).toEqual(
new Set(SUPPORTED_IMAGE_MIME_TYPES),
);
});
});
9 changes: 6 additions & 3 deletions packages/vscode-ide-companion/src/utils/imageSupport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { isSupportedImageMimeType } from '@qwen-code/qwen-code-core/src/utils/request-tokenizer/supportedImageFormats.js';

// ---------- Types ----------

export interface ImageAttachment {
Expand Down Expand Up @@ -73,6 +71,11 @@ const PASTED_IMAGE_MIME_TO_EXTENSION: Record<string, string> = {
'image/webp': '.webp',
};

// Keep this list aligned with packages/core/src/utils/request-tokenizer/supportedImageFormats.ts.
export const SUPPORTED_PASTED_IMAGE_MIME_TYPES = new Set(
Object.keys(PASTED_IMAGE_MIME_TO_EXTENSION),
);

const DISPLAYABLE_IMAGE_EXTENSION_TO_MIME: Record<string, string> = {
'.bmp': 'image/bmp',
'.gif': 'image/gif',
Expand All @@ -86,7 +89,7 @@ const DISPLAYABLE_IMAGE_EXTENSION_TO_MIME: Record<string, string> = {
};

export function isSupportedPastedImageMimeType(mimeType: string): boolean {
return isSupportedImageMimeType(mimeType);
return SUPPORTED_PASTED_IMAGE_MIME_TYPES.has(mimeType);
}

export function getImageExtensionForMimeType(mimeType: string): string {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,33 @@ describe('SessionMessageHandler', () => {
},
]);
});

it('forces a fresh ACP session when the webview requests a new session', async () => {
const agentManager = {
isConnected: true,
currentSessionId: 'session-1',
createNewSession: vi.fn().mockResolvedValue('session-2'),
};
const conversationStore = {
createConversation: vi.fn(),
getConversation: vi.fn(),
addMessage: vi.fn(),
};
const sendToWebView = vi.fn();

const handler = new SessionMessageHandler(
agentManager as never,
conversationStore as never,
null,
sendToWebView,
);

await handler.handle({
type: 'newQwenSession',
});

expect(agentManager.createNewSession).toHaveBeenCalledWith('/workspace', {
forceNew: true,
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,7 @@ export class SessionMessageHandler extends BaseMessageHandler {
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
const workingDir = workspaceFolder?.uri.fsPath || process.cwd();

await this.agentManager.createNewSession(workingDir);
await this.agentManager.createNewSession(workingDir, { forceNew: true });

this.sendToWebView({
type: 'conversationCleared',
Expand Down Expand Up @@ -726,8 +726,12 @@ export class SessionMessageHandler extends BaseMessageHandler {
// If we are connected, try to create a fresh ACP session so user can interact
if (this.agentManager.isConnected) {
try {
const newAcpSessionId =
await this.agentManager.createNewSession(workingDir);
const newAcpSessionId = await this.agentManager.createNewSession(
workingDir,
{
forceNew: true,
},
);

this.currentConversationId = newAcpSessionId;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ vi.mock('../../services/qwenAgentManager.js', () => ({
onPermissionRequest = vi.fn();
onAskUserQuestion = vi.fn();
disconnect = vi.fn();
createNewSession = vi.fn();
},
}));

Expand Down Expand Up @@ -288,3 +289,26 @@ describe('WebViewProvider.attachToView', () => {
expect(panelPostMessage).not.toHaveBeenCalled();
});
});

describe('WebViewProvider.createNewSession', () => {
it('forces a fresh ACP session for the sidebar new-session action', async () => {
const provider = new WebViewProvider(
{ subscriptions: [] } as never,
{ fsPath: '/extension-root' } as never,
);
const agentManager = (
provider as unknown as {
agentManager: {
createNewSession: ReturnType<typeof vi.fn>;
};
}
).agentManager;

await provider.createNewSession();

expect(agentManager.createNewSession).toHaveBeenCalledWith(
'/workspace-root',
{ forceNew: true },
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -1614,7 +1614,7 @@ export class WebViewProvider {
const workingDir = workspaceFolder?.uri.fsPath || process.cwd();

// Create new Qwen session via agent manager
await this.agentManager.createNewSession(workingDir);
await this.agentManager.createNewSession(workingDir, { forceNew: true });

// Clear current conversation UI
this.sendMessageToWebView({
Expand Down
Loading