@defai.digital/automatosx 12.6.1 → 12.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.js +2001 -1392
- package/dist/mcp/index.js +1277 -371
- package/package.json +1 -1
package/dist/mcp/index.js
CHANGED
|
@@ -22,7 +22,6 @@ import { EventEmitter } from 'events';
|
|
|
22
22
|
import { findUp } from 'find-up';
|
|
23
23
|
import * as sqliteVec from 'sqlite-vec';
|
|
24
24
|
import { randomUUID, randomBytes, createHash } from 'crypto';
|
|
25
|
-
import yaml from 'yaml';
|
|
26
25
|
import { gzipSync, gunzipSync } from 'zlib';
|
|
27
26
|
|
|
28
27
|
var __defProp = Object.defineProperty;
|
|
@@ -772,6 +771,119 @@ var init_errors = __esm({
|
|
|
772
771
|
}
|
|
773
772
|
});
|
|
774
773
|
|
|
774
|
+
// src/shared/utils/safe-timers.ts
|
|
775
|
+
function createSafeInterval(callback, intervalMs, options = {}) {
|
|
776
|
+
const { ref = false, name, signal, immediate = false } = options;
|
|
777
|
+
if (signal?.aborted) {
|
|
778
|
+
logger.debug("createSafeInterval: already aborted", { name });
|
|
779
|
+
return () => {
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
let cleared = false;
|
|
783
|
+
let intervalId = null;
|
|
784
|
+
const safeCallback = async () => {
|
|
785
|
+
if (cleared) return;
|
|
786
|
+
try {
|
|
787
|
+
await callback();
|
|
788
|
+
} catch (error) {
|
|
789
|
+
logger.error("Safe interval callback error", {
|
|
790
|
+
name,
|
|
791
|
+
error: error.message
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
};
|
|
795
|
+
if (immediate) {
|
|
796
|
+
setImmediate(() => {
|
|
797
|
+
if (!cleared) {
|
|
798
|
+
safeCallback();
|
|
799
|
+
}
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
intervalId = setInterval(safeCallback, intervalMs);
|
|
803
|
+
if (!ref && intervalId.unref) {
|
|
804
|
+
intervalId.unref();
|
|
805
|
+
}
|
|
806
|
+
const cleanup = () => {
|
|
807
|
+
if (cleared) return;
|
|
808
|
+
cleared = true;
|
|
809
|
+
if (intervalId !== null) {
|
|
810
|
+
clearInterval(intervalId);
|
|
811
|
+
intervalId = null;
|
|
812
|
+
logger.debug("Safe interval cleared", { name });
|
|
813
|
+
}
|
|
814
|
+
};
|
|
815
|
+
if (signal) {
|
|
816
|
+
signal.addEventListener("abort", cleanup, { once: true });
|
|
817
|
+
}
|
|
818
|
+
logger.debug("Safe interval created", {
|
|
819
|
+
name,
|
|
820
|
+
intervalMs,
|
|
821
|
+
ref,
|
|
822
|
+
immediate
|
|
823
|
+
});
|
|
824
|
+
return cleanup;
|
|
825
|
+
}
|
|
826
|
+
function createSafeTimeout(callback, delayMs, options = {}) {
|
|
827
|
+
const { ref = false, name, signal } = options;
|
|
828
|
+
if (signal?.aborted) {
|
|
829
|
+
logger.debug("createSafeTimeout: already aborted", { name });
|
|
830
|
+
return () => {
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
let cleared = false;
|
|
834
|
+
let timeoutId = null;
|
|
835
|
+
const safeCallback = async () => {
|
|
836
|
+
if (cleared) return;
|
|
837
|
+
cleared = true;
|
|
838
|
+
try {
|
|
839
|
+
await callback();
|
|
840
|
+
} catch (error) {
|
|
841
|
+
logger.error("Safe timeout callback error", {
|
|
842
|
+
name,
|
|
843
|
+
error: error.message
|
|
844
|
+
});
|
|
845
|
+
}
|
|
846
|
+
};
|
|
847
|
+
timeoutId = setTimeout(safeCallback, delayMs);
|
|
848
|
+
if (!ref && timeoutId.unref) {
|
|
849
|
+
timeoutId.unref();
|
|
850
|
+
}
|
|
851
|
+
const cleanup = () => {
|
|
852
|
+
if (cleared) return;
|
|
853
|
+
cleared = true;
|
|
854
|
+
if (timeoutId !== null) {
|
|
855
|
+
clearTimeout(timeoutId);
|
|
856
|
+
timeoutId = null;
|
|
857
|
+
logger.debug("Safe timeout cleared", { name });
|
|
858
|
+
}
|
|
859
|
+
};
|
|
860
|
+
if (signal) {
|
|
861
|
+
signal.addEventListener("abort", cleanup, { once: true });
|
|
862
|
+
}
|
|
863
|
+
logger.debug("Safe timeout created", {
|
|
864
|
+
name,
|
|
865
|
+
delayMs,
|
|
866
|
+
ref
|
|
867
|
+
});
|
|
868
|
+
return cleanup;
|
|
869
|
+
}
|
|
870
|
+
async function sleep(ms, signal) {
|
|
871
|
+
return new Promise((resolve5, reject) => {
|
|
872
|
+
const timeoutId = setTimeout(() => {
|
|
873
|
+
resolve5();
|
|
874
|
+
}, ms);
|
|
875
|
+
if (timeoutId.unref) {
|
|
876
|
+
timeoutId.unref();
|
|
877
|
+
}
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
var init_safe_timers = __esm({
|
|
881
|
+
"src/shared/utils/safe-timers.ts"() {
|
|
882
|
+
init_esm_shims();
|
|
883
|
+
init_logger();
|
|
884
|
+
}
|
|
885
|
+
});
|
|
886
|
+
|
|
775
887
|
// src/shared/process/process-manager.ts
|
|
776
888
|
var process_manager_exports = {};
|
|
777
889
|
__export(process_manager_exports, {
|
|
@@ -2379,6 +2491,7 @@ function getRetryableErrors(provider) {
|
|
|
2379
2491
|
return [...baseErrors, ...CODEX_RETRYABLE_ERRORS];
|
|
2380
2492
|
case "glm":
|
|
2381
2493
|
case "grok":
|
|
2494
|
+
case "qwen":
|
|
2382
2495
|
return [...baseErrors, ...OPENAI_RETRYABLE_ERRORS];
|
|
2383
2496
|
case "base":
|
|
2384
2497
|
default:
|
|
@@ -2481,6 +2594,10 @@ var init_base_provider = __esm({
|
|
|
2481
2594
|
// v12.0.0: Native Grok provider (xAI)
|
|
2482
2595
|
"ax-grok",
|
|
2483
2596
|
// v12.0.0: Alias for grok
|
|
2597
|
+
"qwen",
|
|
2598
|
+
// v12.7.0: Qwen Code provider (Alibaba Cloud)
|
|
2599
|
+
"qwen-code",
|
|
2600
|
+
// v12.7.0: Alias for qwen
|
|
2484
2601
|
"test-provider"
|
|
2485
2602
|
// For unit tests
|
|
2486
2603
|
];
|
|
@@ -2843,7 +2960,7 @@ var init_base_provider = __esm({
|
|
|
2843
2960
|
if (readlineInterface) {
|
|
2844
2961
|
try {
|
|
2845
2962
|
readlineInterface.close();
|
|
2846
|
-
} catch
|
|
2963
|
+
} catch {
|
|
2847
2964
|
} finally {
|
|
2848
2965
|
readlineInterface = null;
|
|
2849
2966
|
}
|
|
@@ -2851,7 +2968,7 @@ var init_base_provider = __esm({
|
|
|
2851
2968
|
if (stderrInterface) {
|
|
2852
2969
|
try {
|
|
2853
2970
|
stderrInterface.close();
|
|
2854
|
-
} catch
|
|
2971
|
+
} catch {
|
|
2855
2972
|
} finally {
|
|
2856
2973
|
stderrInterface = null;
|
|
2857
2974
|
}
|
|
@@ -3045,7 +3162,7 @@ ${fullPrompt}
|
|
|
3045
3162
|
this.health.consecutiveSuccesses = 0;
|
|
3046
3163
|
}
|
|
3047
3164
|
return available;
|
|
3048
|
-
} catch
|
|
3165
|
+
} catch {
|
|
3049
3166
|
this.health.available = false;
|
|
3050
3167
|
this.health.errorRate = 1;
|
|
3051
3168
|
this.health.lastCheck = Date.now();
|
|
@@ -3221,6 +3338,8 @@ ${fullPrompt}
|
|
|
3221
3338
|
retryableProvider = "glm";
|
|
3222
3339
|
} else if (providerName === "grok" || providerName === "ax-grok") {
|
|
3223
3340
|
retryableProvider = "grok";
|
|
3341
|
+
} else if (providerName === "qwen" || providerName === "qwen-code") {
|
|
3342
|
+
retryableProvider = "qwen";
|
|
3224
3343
|
}
|
|
3225
3344
|
return shouldRetryError(error, retryableProvider);
|
|
3226
3345
|
}
|
|
@@ -5295,6 +5414,7 @@ var init_hybrid_adapter_base = __esm({
|
|
|
5295
5414
|
init_flags();
|
|
5296
5415
|
init_fallback_decision();
|
|
5297
5416
|
init_provider_metrics();
|
|
5417
|
+
init_safe_timers();
|
|
5298
5418
|
DEFAULT_CIRCUIT_BREAKER_CONFIG = {
|
|
5299
5419
|
failureThreshold: 3,
|
|
5300
5420
|
resetTimeout: 6e4,
|
|
@@ -5449,7 +5569,7 @@ var init_hybrid_adapter_base = __esm({
|
|
|
5449
5569
|
});
|
|
5450
5570
|
if (classification.decision === "retry_sdk" /* RETRY_SDK */ && attempt < this.maxRetries) {
|
|
5451
5571
|
const delay = classification.retryDelayMs || 1e3;
|
|
5452
|
-
await
|
|
5572
|
+
await sleep(delay);
|
|
5453
5573
|
continue;
|
|
5454
5574
|
}
|
|
5455
5575
|
if (classification.decision === "use_cli" /* USE_CLI */ || classification.decision === "retry_sdk" /* RETRY_SDK */ && attempt >= this.maxRetries) {
|
|
@@ -5624,12 +5744,6 @@ var init_hybrid_adapter_base = __esm({
|
|
|
5624
5744
|
} catch {
|
|
5625
5745
|
}
|
|
5626
5746
|
}
|
|
5627
|
-
/**
|
|
5628
|
-
* Sleep utility
|
|
5629
|
-
*/
|
|
5630
|
-
sleep(ms) {
|
|
5631
|
-
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
5632
|
-
}
|
|
5633
5747
|
/**
|
|
5634
5748
|
* Get current active mode
|
|
5635
5749
|
*/
|
|
@@ -5680,13 +5794,21 @@ var init_types2 = __esm({
|
|
|
5680
5794
|
"src/integrations/ax-glm/types.ts"() {
|
|
5681
5795
|
init_esm_shims();
|
|
5682
5796
|
GLM_MODEL_MAPPING = {
|
|
5797
|
+
// Convenience aliases (ax-cli v4.3.15)
|
|
5798
|
+
"glm-latest": "glm-4.6",
|
|
5799
|
+
"glm-vision": "glm-4.6v",
|
|
5800
|
+
"glm-fast": "glm-4-flash",
|
|
5801
|
+
"glm-image": "cogview-4",
|
|
5802
|
+
// Legacy aliases (deprecated)
|
|
5683
5803
|
"glm-4-plus": "glm-4.6",
|
|
5684
|
-
"glm-
|
|
5804
|
+
"glm-4.5v": "glm-4.6v",
|
|
5805
|
+
"glm-4v": "glm-4.6v",
|
|
5806
|
+
"glm-4": "glm-4.6",
|
|
5685
5807
|
"glm-4-air": "glm-4-flash",
|
|
5686
5808
|
"glm-4-airx": "glm-4-flash"
|
|
5687
5809
|
};
|
|
5688
5810
|
GLM_DEFAULT_BASE_URL = "https://open.bigmodel.cn/api/paas/v4";
|
|
5689
|
-
GLM_DEFAULT_MODEL = "glm-4";
|
|
5811
|
+
GLM_DEFAULT_MODEL = "glm-4.6";
|
|
5690
5812
|
GLM_DEFAULT_COMMAND = "ax-glm";
|
|
5691
5813
|
}
|
|
5692
5814
|
});
|
|
@@ -6225,6 +6347,7 @@ var init_sdk_only_adapter = __esm({
|
|
|
6225
6347
|
"src/integrations/ax-glm/sdk-only-adapter.ts"() {
|
|
6226
6348
|
init_esm_shims();
|
|
6227
6349
|
init_logger();
|
|
6350
|
+
init_safe_timers();
|
|
6228
6351
|
init_sdk_adapter2();
|
|
6229
6352
|
init_types2();
|
|
6230
6353
|
GLMSdkOnlyAdapter = class {
|
|
@@ -6304,7 +6427,7 @@ var init_sdk_only_adapter = __esm({
|
|
|
6304
6427
|
attempt: attempt + 1,
|
|
6305
6428
|
delayMs: delay
|
|
6306
6429
|
});
|
|
6307
|
-
await
|
|
6430
|
+
await sleep(delay);
|
|
6308
6431
|
continue;
|
|
6309
6432
|
}
|
|
6310
6433
|
break;
|
|
@@ -6340,12 +6463,6 @@ var init_sdk_only_adapter = __esm({
|
|
|
6340
6463
|
}
|
|
6341
6464
|
return false;
|
|
6342
6465
|
}
|
|
6343
|
-
/**
|
|
6344
|
-
* Sleep utility
|
|
6345
|
-
*/
|
|
6346
|
-
sleep(ms) {
|
|
6347
|
-
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
6348
|
-
}
|
|
6349
6466
|
/**
|
|
6350
6467
|
* Get the configured model
|
|
6351
6468
|
*/
|
|
@@ -6640,10 +6757,18 @@ var init_types3 = __esm({
|
|
|
6640
6757
|
"src/integrations/ax-grok/types.ts"() {
|
|
6641
6758
|
init_esm_shims();
|
|
6642
6759
|
GROK_MODEL_MAPPING = {
|
|
6643
|
-
|
|
6760
|
+
// Convenience aliases (ax-cli v4.3.15)
|
|
6761
|
+
"grok-latest": "grok-4-0709",
|
|
6762
|
+
"grok-fast": "grok-4.1-fast",
|
|
6763
|
+
"grok-mini": "grok-3-mini",
|
|
6764
|
+
"grok-vision": "grok-2-vision-1212",
|
|
6765
|
+
"grok-image": "grok-2-image-1212",
|
|
6766
|
+
// Legacy aliases (deprecated)
|
|
6767
|
+
"grok-beta": "grok-3",
|
|
6768
|
+
"grok-2-vision": "grok-2-vision-1212"
|
|
6644
6769
|
};
|
|
6645
6770
|
GROK_DEFAULT_BASE_URL = "https://api.x.ai/v1";
|
|
6646
|
-
GROK_DEFAULT_MODEL = "grok-
|
|
6771
|
+
GROK_DEFAULT_MODEL = "grok-4-0709";
|
|
6647
6772
|
GROK_DEFAULT_COMMAND = "ax-grok";
|
|
6648
6773
|
}
|
|
6649
6774
|
});
|
|
@@ -7182,6 +7307,7 @@ var init_sdk_only_adapter2 = __esm({
|
|
|
7182
7307
|
"src/integrations/ax-grok/sdk-only-adapter.ts"() {
|
|
7183
7308
|
init_esm_shims();
|
|
7184
7309
|
init_logger();
|
|
7310
|
+
init_safe_timers();
|
|
7185
7311
|
init_sdk_adapter3();
|
|
7186
7312
|
init_types3();
|
|
7187
7313
|
GrokSdkOnlyAdapter = class {
|
|
@@ -7261,7 +7387,7 @@ var init_sdk_only_adapter2 = __esm({
|
|
|
7261
7387
|
attempt: attempt + 1,
|
|
7262
7388
|
delayMs: delay
|
|
7263
7389
|
});
|
|
7264
|
-
await
|
|
7390
|
+
await sleep(delay);
|
|
7265
7391
|
continue;
|
|
7266
7392
|
}
|
|
7267
7393
|
break;
|
|
@@ -7297,12 +7423,6 @@ var init_sdk_only_adapter2 = __esm({
|
|
|
7297
7423
|
}
|
|
7298
7424
|
return false;
|
|
7299
7425
|
}
|
|
7300
|
-
/**
|
|
7301
|
-
* Sleep utility
|
|
7302
|
-
*/
|
|
7303
|
-
sleep(ms) {
|
|
7304
|
-
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
7305
|
-
}
|
|
7306
7426
|
/**
|
|
7307
7427
|
* Get the configured model
|
|
7308
7428
|
*/
|
|
@@ -7580,6 +7700,902 @@ Mode: ${this.grokConfig.mode || "auto"}`;
|
|
|
7580
7700
|
}
|
|
7581
7701
|
});
|
|
7582
7702
|
|
|
7703
|
+
// src/integrations/qwen-code/types.ts
|
|
7704
|
+
function normalizeQwenModel(model) {
|
|
7705
|
+
return QWEN_MODEL_MAPPING[model] || model;
|
|
7706
|
+
}
|
|
7707
|
+
function isVisionModel(model) {
|
|
7708
|
+
return model.includes("qwen3-coder") || model.includes("qwen-max");
|
|
7709
|
+
}
|
|
7710
|
+
function getModelContextWindow(model) {
|
|
7711
|
+
const normalizedModel = normalizeQwenModel(model);
|
|
7712
|
+
if (normalizedModel.includes("480b")) return 128e3;
|
|
7713
|
+
if (normalizedModel.includes("30b")) return 64e3;
|
|
7714
|
+
if (normalizedModel.includes("qwen-max")) return 128e3;
|
|
7715
|
+
if (normalizedModel.includes("qwen-plus")) return 128e3;
|
|
7716
|
+
if (normalizedModel.includes("qwen-turbo")) return 128e3;
|
|
7717
|
+
return 64e3;
|
|
7718
|
+
}
|
|
7719
|
+
var QWEN_DEFAULT_BASE_URL, QWEN_DEFAULT_MODEL, QWEN_DEFAULT_COMMAND, QWEN_MODEL_MAPPING;
|
|
7720
|
+
var init_types4 = __esm({
|
|
7721
|
+
"src/integrations/qwen-code/types.ts"() {
|
|
7722
|
+
init_esm_shims();
|
|
7723
|
+
QWEN_DEFAULT_BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1";
|
|
7724
|
+
QWEN_DEFAULT_MODEL = "qwen-turbo";
|
|
7725
|
+
QWEN_DEFAULT_COMMAND = "qwen";
|
|
7726
|
+
QWEN_MODEL_MAPPING = {
|
|
7727
|
+
// Normalize common aliases
|
|
7728
|
+
"qwen-coder": "qwen3-coder-480b-a35b-instruct",
|
|
7729
|
+
"qwen-coder-480b": "qwen3-coder-480b-a35b-instruct",
|
|
7730
|
+
"qwen-coder-30b": "qwen3-coder-30b-a3b-instruct",
|
|
7731
|
+
"qwen2.5-coder": "qwen2.5-coder-32b-instruct"
|
|
7732
|
+
};
|
|
7733
|
+
}
|
|
7734
|
+
});
|
|
7735
|
+
|
|
7736
|
+
// src/integrations/qwen-code/sdk-adapter.ts
|
|
7737
|
+
var QwenSdkAdapter;
|
|
7738
|
+
var init_sdk_adapter4 = __esm({
|
|
7739
|
+
"src/integrations/qwen-code/sdk-adapter.ts"() {
|
|
7740
|
+
init_esm_shims();
|
|
7741
|
+
init_logger();
|
|
7742
|
+
init_validation_limits();
|
|
7743
|
+
init_types4();
|
|
7744
|
+
QwenSdkAdapter = class {
|
|
7745
|
+
client = null;
|
|
7746
|
+
config;
|
|
7747
|
+
initialized = false;
|
|
7748
|
+
constructor(config = {}) {
|
|
7749
|
+
const apiKey = config.apiKey || process.env.DASHSCOPE_API_KEY || process.env.QWEN_API_KEY || "";
|
|
7750
|
+
this.config = {
|
|
7751
|
+
apiKey,
|
|
7752
|
+
baseUrl: config.baseUrl || QWEN_DEFAULT_BASE_URL,
|
|
7753
|
+
model: config.model || QWEN_DEFAULT_MODEL,
|
|
7754
|
+
timeout: config.timeout || TIMEOUTS.PROVIDER_DEFAULT
|
|
7755
|
+
};
|
|
7756
|
+
logger.debug("[Qwen SDK] Adapter created", {
|
|
7757
|
+
model: this.config.model,
|
|
7758
|
+
baseUrl: this.config.baseUrl,
|
|
7759
|
+
hasApiKey: !!this.config.apiKey
|
|
7760
|
+
});
|
|
7761
|
+
}
|
|
7762
|
+
/**
|
|
7763
|
+
* Check if SDK is available (OpenAI package installed and API key configured)
|
|
7764
|
+
*/
|
|
7765
|
+
async isAvailable() {
|
|
7766
|
+
try {
|
|
7767
|
+
if (!this.config.apiKey) {
|
|
7768
|
+
logger.debug("[Qwen SDK] No API key configured (set DASHSCOPE_API_KEY or QWEN_API_KEY)");
|
|
7769
|
+
return false;
|
|
7770
|
+
}
|
|
7771
|
+
await import('openai');
|
|
7772
|
+
return true;
|
|
7773
|
+
} catch (error) {
|
|
7774
|
+
logger.debug("[Qwen SDK] OpenAI SDK not available", {
|
|
7775
|
+
error: error instanceof Error ? error.message : String(error)
|
|
7776
|
+
});
|
|
7777
|
+
return false;
|
|
7778
|
+
}
|
|
7779
|
+
}
|
|
7780
|
+
/**
|
|
7781
|
+
* Initialize the SDK client
|
|
7782
|
+
*/
|
|
7783
|
+
async initialize() {
|
|
7784
|
+
if (this.initialized) {
|
|
7785
|
+
return;
|
|
7786
|
+
}
|
|
7787
|
+
try {
|
|
7788
|
+
const OpenAI = (await import('openai')).default;
|
|
7789
|
+
this.client = new OpenAI({
|
|
7790
|
+
apiKey: this.config.apiKey,
|
|
7791
|
+
baseURL: this.config.baseUrl,
|
|
7792
|
+
timeout: this.config.timeout
|
|
7793
|
+
});
|
|
7794
|
+
this.initialized = true;
|
|
7795
|
+
logger.debug("[Qwen SDK] Client initialized", {
|
|
7796
|
+
model: this.config.model
|
|
7797
|
+
});
|
|
7798
|
+
} catch (error) {
|
|
7799
|
+
throw new Error(
|
|
7800
|
+
`Failed to initialize Qwen SDK: ${error instanceof Error ? error.message : String(error)}`
|
|
7801
|
+
);
|
|
7802
|
+
}
|
|
7803
|
+
}
|
|
7804
|
+
/**
|
|
7805
|
+
* Execute a request using the Qwen SDK
|
|
7806
|
+
*/
|
|
7807
|
+
async execute(request) {
|
|
7808
|
+
if (!this.initialized) {
|
|
7809
|
+
await this.initialize();
|
|
7810
|
+
}
|
|
7811
|
+
const startTime = Date.now();
|
|
7812
|
+
try {
|
|
7813
|
+
const messages = [];
|
|
7814
|
+
if (request.systemPrompt) {
|
|
7815
|
+
messages.push({
|
|
7816
|
+
role: "system",
|
|
7817
|
+
content: request.systemPrompt
|
|
7818
|
+
});
|
|
7819
|
+
}
|
|
7820
|
+
messages.push({
|
|
7821
|
+
role: "user",
|
|
7822
|
+
content: request.prompt
|
|
7823
|
+
});
|
|
7824
|
+
const model = normalizeQwenModel(request.model || this.config.model);
|
|
7825
|
+
logger.debug("[Qwen SDK] Executing request", {
|
|
7826
|
+
model,
|
|
7827
|
+
messageCount: messages.length,
|
|
7828
|
+
promptLength: request.prompt.length
|
|
7829
|
+
});
|
|
7830
|
+
const openaiClient = this.client;
|
|
7831
|
+
const response = await openaiClient.chat.completions.create({
|
|
7832
|
+
model,
|
|
7833
|
+
messages,
|
|
7834
|
+
max_tokens: request.maxTokens,
|
|
7835
|
+
temperature: request.temperature,
|
|
7836
|
+
stream: false
|
|
7837
|
+
});
|
|
7838
|
+
const latencyMs = Date.now() - startTime;
|
|
7839
|
+
if (!response.choices || response.choices.length === 0) {
|
|
7840
|
+
throw new Error("Qwen API returned empty choices array");
|
|
7841
|
+
}
|
|
7842
|
+
const choice = response.choices[0];
|
|
7843
|
+
const content = choice?.message?.content || "";
|
|
7844
|
+
const finishReason = choice?.finish_reason || "unknown";
|
|
7845
|
+
logger.debug("[Qwen SDK] Request completed", {
|
|
7846
|
+
model: response.model,
|
|
7847
|
+
latencyMs,
|
|
7848
|
+
tokensUsed: response.usage?.total_tokens
|
|
7849
|
+
});
|
|
7850
|
+
return {
|
|
7851
|
+
content,
|
|
7852
|
+
model: response.model,
|
|
7853
|
+
tokensUsed: response.usage ? {
|
|
7854
|
+
prompt: response.usage.prompt_tokens,
|
|
7855
|
+
completion: response.usage.completion_tokens,
|
|
7856
|
+
total: response.usage.total_tokens
|
|
7857
|
+
} : { prompt: 0, completion: 0, total: 0 },
|
|
7858
|
+
latencyMs,
|
|
7859
|
+
finishReason,
|
|
7860
|
+
cached: false
|
|
7861
|
+
};
|
|
7862
|
+
} catch (error) {
|
|
7863
|
+
const latencyMs = Date.now() - startTime;
|
|
7864
|
+
logger.error("[Qwen SDK] Request failed", {
|
|
7865
|
+
error: error instanceof Error ? error.message : String(error),
|
|
7866
|
+
latencyMs
|
|
7867
|
+
});
|
|
7868
|
+
throw error;
|
|
7869
|
+
}
|
|
7870
|
+
}
|
|
7871
|
+
/**
|
|
7872
|
+
* Get the configured model
|
|
7873
|
+
*/
|
|
7874
|
+
getModel() {
|
|
7875
|
+
return this.config.model;
|
|
7876
|
+
}
|
|
7877
|
+
/**
|
|
7878
|
+
* Clean up resources
|
|
7879
|
+
*/
|
|
7880
|
+
async destroy() {
|
|
7881
|
+
this.client = null;
|
|
7882
|
+
this.initialized = false;
|
|
7883
|
+
logger.debug("[Qwen SDK] Adapter destroyed");
|
|
7884
|
+
}
|
|
7885
|
+
};
|
|
7886
|
+
}
|
|
7887
|
+
});
|
|
7888
|
+
var NON_INTERACTIVE_ENV, SIGKILL_ESCALATION_MS, QwenCliWrapper;
|
|
7889
|
+
var init_cli_wrapper4 = __esm({
|
|
7890
|
+
"src/integrations/qwen-code/cli-wrapper.ts"() {
|
|
7891
|
+
init_esm_shims();
|
|
7892
|
+
init_logger();
|
|
7893
|
+
init_validation_limits();
|
|
7894
|
+
init_cli_provider_detector();
|
|
7895
|
+
init_types4();
|
|
7896
|
+
NON_INTERACTIVE_ENV = {
|
|
7897
|
+
TERM: "dumb",
|
|
7898
|
+
NO_COLOR: "1",
|
|
7899
|
+
FORCE_COLOR: "0",
|
|
7900
|
+
CI: "true",
|
|
7901
|
+
NO_UPDATE_NOTIFIER: "1",
|
|
7902
|
+
DEBIAN_FRONTEND: "noninteractive"
|
|
7903
|
+
};
|
|
7904
|
+
SIGKILL_ESCALATION_MS = 5e3;
|
|
7905
|
+
QwenCliWrapper = class {
|
|
7906
|
+
config;
|
|
7907
|
+
constructor(config = {}) {
|
|
7908
|
+
this.config = {
|
|
7909
|
+
command: config.command || QWEN_DEFAULT_COMMAND,
|
|
7910
|
+
vlmSwitchMode: config.vlmSwitchMode || "once",
|
|
7911
|
+
yolo: config.yolo || false,
|
|
7912
|
+
timeout: config.timeout || TIMEOUTS.PROVIDER_DEFAULT
|
|
7913
|
+
};
|
|
7914
|
+
logger.debug("[Qwen CLI] Wrapper created", {
|
|
7915
|
+
command: this.config.command,
|
|
7916
|
+
timeout: this.config.timeout
|
|
7917
|
+
});
|
|
7918
|
+
}
|
|
7919
|
+
/**
|
|
7920
|
+
* Check if Qwen CLI is available on PATH
|
|
7921
|
+
*/
|
|
7922
|
+
async isAvailable() {
|
|
7923
|
+
if (process.env.AX_MOCK_PROVIDERS === "true") {
|
|
7924
|
+
return true;
|
|
7925
|
+
}
|
|
7926
|
+
try {
|
|
7927
|
+
const result = findOnPath(this.config.command);
|
|
7928
|
+
logger.debug("[Qwen CLI] Availability check", {
|
|
7929
|
+
available: result.found,
|
|
7930
|
+
path: result.path
|
|
7931
|
+
});
|
|
7932
|
+
return result.found;
|
|
7933
|
+
} catch (error) {
|
|
7934
|
+
logger.debug("[Qwen CLI] Availability check failed", {
|
|
7935
|
+
error: error instanceof Error ? error.message : String(error)
|
|
7936
|
+
});
|
|
7937
|
+
return false;
|
|
7938
|
+
}
|
|
7939
|
+
}
|
|
7940
|
+
/**
|
|
7941
|
+
* Execute a prompt using the Qwen CLI
|
|
7942
|
+
*
|
|
7943
|
+
* Since Qwen CLI is interactive, we:
|
|
7944
|
+
* 1. Spawn the process
|
|
7945
|
+
* 2. Send the prompt via stdin
|
|
7946
|
+
* 3. Capture output until we detect completion
|
|
7947
|
+
* 4. Return the response
|
|
7948
|
+
*/
|
|
7949
|
+
async execute(request) {
|
|
7950
|
+
if (process.env.AX_MOCK_PROVIDERS === "true") {
|
|
7951
|
+
return this.createMockResponse(request.prompt);
|
|
7952
|
+
}
|
|
7953
|
+
const startTime = Date.now();
|
|
7954
|
+
return new Promise((resolve5, reject) => {
|
|
7955
|
+
const args2 = [];
|
|
7956
|
+
if (this.config.vlmSwitchMode !== "once") {
|
|
7957
|
+
args2.push("--vlm-switch-mode", this.config.vlmSwitchMode);
|
|
7958
|
+
}
|
|
7959
|
+
if (this.config.yolo) {
|
|
7960
|
+
args2.push("--yolo");
|
|
7961
|
+
}
|
|
7962
|
+
logger.debug("[Qwen CLI] Spawning process", {
|
|
7963
|
+
command: this.config.command,
|
|
7964
|
+
args: args2,
|
|
7965
|
+
promptLength: request.prompt.length
|
|
7966
|
+
});
|
|
7967
|
+
const child = spawn(this.config.command, args2, {
|
|
7968
|
+
env: { ...process.env, ...NON_INTERACTIVE_ENV }
|
|
7969
|
+
});
|
|
7970
|
+
let stdout = "";
|
|
7971
|
+
let stderr = "";
|
|
7972
|
+
let timeoutId = null;
|
|
7973
|
+
let forceKillTimer = null;
|
|
7974
|
+
let readlineInterface = null;
|
|
7975
|
+
let responseStarted = false;
|
|
7976
|
+
const cleanup = () => {
|
|
7977
|
+
if (timeoutId) {
|
|
7978
|
+
clearTimeout(timeoutId);
|
|
7979
|
+
timeoutId = null;
|
|
7980
|
+
}
|
|
7981
|
+
if (forceKillTimer) {
|
|
7982
|
+
clearTimeout(forceKillTimer);
|
|
7983
|
+
forceKillTimer = null;
|
|
7984
|
+
}
|
|
7985
|
+
if (readlineInterface) {
|
|
7986
|
+
try {
|
|
7987
|
+
readlineInterface.close();
|
|
7988
|
+
} catch {
|
|
7989
|
+
}
|
|
7990
|
+
readlineInterface = null;
|
|
7991
|
+
}
|
|
7992
|
+
};
|
|
7993
|
+
if (child.stdout) {
|
|
7994
|
+
readlineInterface = readline.createInterface({
|
|
7995
|
+
input: child.stdout,
|
|
7996
|
+
crlfDelay: Infinity
|
|
7997
|
+
});
|
|
7998
|
+
readlineInterface.on("line", (line) => {
|
|
7999
|
+
if (line.startsWith(">") && !responseStarted) {
|
|
8000
|
+
responseStarted = true;
|
|
8001
|
+
return;
|
|
8002
|
+
}
|
|
8003
|
+
if (responseStarted) {
|
|
8004
|
+
stdout += line + "\n";
|
|
8005
|
+
}
|
|
8006
|
+
});
|
|
8007
|
+
readlineInterface.on("error", (error) => {
|
|
8008
|
+
logger.debug("[Qwen CLI] Readline error", {
|
|
8009
|
+
error: error.message
|
|
8010
|
+
});
|
|
8011
|
+
});
|
|
8012
|
+
}
|
|
8013
|
+
if (child.stderr) {
|
|
8014
|
+
child.stderr.on("data", (data) => {
|
|
8015
|
+
stderr += data.toString();
|
|
8016
|
+
});
|
|
8017
|
+
}
|
|
8018
|
+
if (child.stdin) {
|
|
8019
|
+
try {
|
|
8020
|
+
let fullPrompt = request.prompt;
|
|
8021
|
+
if (request.systemPrompt) {
|
|
8022
|
+
fullPrompt = `${request.systemPrompt}
|
|
8023
|
+
|
|
8024
|
+
${request.prompt}`;
|
|
8025
|
+
}
|
|
8026
|
+
child.stdin.write(fullPrompt);
|
|
8027
|
+
child.stdin.write("\n");
|
|
8028
|
+
child.stdin.end();
|
|
8029
|
+
} catch (error) {
|
|
8030
|
+
cleanup();
|
|
8031
|
+
child.kill("SIGTERM");
|
|
8032
|
+
reject(new Error(`Failed to write to Qwen stdin: ${error instanceof Error ? error.message : String(error)}`));
|
|
8033
|
+
return;
|
|
8034
|
+
}
|
|
8035
|
+
} else {
|
|
8036
|
+
cleanup();
|
|
8037
|
+
reject(new Error("Qwen CLI stdin not available"));
|
|
8038
|
+
return;
|
|
8039
|
+
}
|
|
8040
|
+
child.on("close", (code, signal) => {
|
|
8041
|
+
cleanup();
|
|
8042
|
+
const latencyMs = Date.now() - startTime;
|
|
8043
|
+
if (stderr) {
|
|
8044
|
+
logger.debug("[Qwen CLI] stderr output", { stderr: stderr.trim() });
|
|
8045
|
+
}
|
|
8046
|
+
if ((code === 0 || code === null) && !signal) {
|
|
8047
|
+
const content = this.parseResponse(stdout);
|
|
8048
|
+
resolve5({
|
|
8049
|
+
content: content.trim(),
|
|
8050
|
+
model: "qwen-code-cli",
|
|
8051
|
+
tokensUsed: {
|
|
8052
|
+
prompt: this.estimateTokens(request.prompt),
|
|
8053
|
+
completion: this.estimateTokens(content),
|
|
8054
|
+
total: this.estimateTokens(request.prompt) + this.estimateTokens(content)
|
|
8055
|
+
},
|
|
8056
|
+
latencyMs,
|
|
8057
|
+
finishReason: "stop",
|
|
8058
|
+
cached: false
|
|
8059
|
+
});
|
|
8060
|
+
} else if (signal) {
|
|
8061
|
+
reject(new Error(`Qwen CLI killed by signal ${signal}. stderr: ${stderr || "none"}`));
|
|
8062
|
+
} else {
|
|
8063
|
+
reject(new Error(`Qwen CLI exited with code ${code}. stderr: ${stderr || "none"}`));
|
|
8064
|
+
}
|
|
8065
|
+
});
|
|
8066
|
+
child.on("error", (error) => {
|
|
8067
|
+
cleanup();
|
|
8068
|
+
logger.error("[Qwen CLI] Process error", {
|
|
8069
|
+
error: error.message
|
|
8070
|
+
});
|
|
8071
|
+
reject(new Error(`Failed to spawn Qwen CLI: ${error.message}`));
|
|
8072
|
+
});
|
|
8073
|
+
timeoutId = setTimeout(() => {
|
|
8074
|
+
if (child.pid && !child.killed) {
|
|
8075
|
+
logger.warn("[Qwen CLI] Killing process due to timeout", {
|
|
8076
|
+
pid: child.pid,
|
|
8077
|
+
timeout: this.config.timeout
|
|
8078
|
+
});
|
|
8079
|
+
child.kill("SIGTERM");
|
|
8080
|
+
forceKillTimer = setTimeout(() => {
|
|
8081
|
+
if (child.pid) {
|
|
8082
|
+
try {
|
|
8083
|
+
process.kill(child.pid, 0);
|
|
8084
|
+
logger.warn("[Qwen CLI] Force killing process", { pid: child.pid });
|
|
8085
|
+
child.kill("SIGKILL");
|
|
8086
|
+
} catch {
|
|
8087
|
+
}
|
|
8088
|
+
}
|
|
8089
|
+
}, SIGKILL_ESCALATION_MS);
|
|
8090
|
+
}
|
|
8091
|
+
}, this.config.timeout);
|
|
8092
|
+
});
|
|
8093
|
+
}
|
|
8094
|
+
/**
|
|
8095
|
+
* Parse response from CLI output
|
|
8096
|
+
*
|
|
8097
|
+
* Qwen CLI outputs include prompts and formatting that we need to strip.
|
|
8098
|
+
*/
|
|
8099
|
+
parseResponse(output) {
|
|
8100
|
+
let content = output.trim();
|
|
8101
|
+
content = content.replace(/\x1B\[[0-9;]*[mGKH]/g, "");
|
|
8102
|
+
content = content.replace(/^>\s*/gm, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
8103
|
+
return content;
|
|
8104
|
+
}
|
|
8105
|
+
/**
|
|
8106
|
+
* Estimate token count
|
|
8107
|
+
*/
|
|
8108
|
+
estimateTokens(text) {
|
|
8109
|
+
return Math.ceil(text.length / 4);
|
|
8110
|
+
}
|
|
8111
|
+
/**
|
|
8112
|
+
* Create mock response for testing
|
|
8113
|
+
*/
|
|
8114
|
+
createMockResponse(prompt) {
|
|
8115
|
+
return {
|
|
8116
|
+
content: `[Mock Qwen Response]
|
|
8117
|
+
|
|
8118
|
+
This is a mock response from Qwen Code CLI.
|
|
8119
|
+
Prompt length: ${prompt.length} characters.`,
|
|
8120
|
+
model: "qwen-code-cli-mock",
|
|
8121
|
+
tokensUsed: {
|
|
8122
|
+
prompt: this.estimateTokens(prompt),
|
|
8123
|
+
completion: 50,
|
|
8124
|
+
total: this.estimateTokens(prompt) + 50
|
|
8125
|
+
},
|
|
8126
|
+
latencyMs: 10,
|
|
8127
|
+
finishReason: "stop",
|
|
8128
|
+
cached: false
|
|
8129
|
+
};
|
|
8130
|
+
}
|
|
8131
|
+
/**
|
|
8132
|
+
* Get CLI command
|
|
8133
|
+
*/
|
|
8134
|
+
getCommand() {
|
|
8135
|
+
return this.config.command;
|
|
8136
|
+
}
|
|
8137
|
+
};
|
|
8138
|
+
}
|
|
8139
|
+
});
|
|
8140
|
+
|
|
8141
|
+
// src/integrations/qwen-code/hybrid-adapter.ts
|
|
8142
|
+
var QwenHybridAdapter;
|
|
8143
|
+
var init_hybrid_adapter4 = __esm({
|
|
8144
|
+
"src/integrations/qwen-code/hybrid-adapter.ts"() {
|
|
8145
|
+
init_esm_shims();
|
|
8146
|
+
init_logger();
|
|
8147
|
+
init_sdk_adapter4();
|
|
8148
|
+
init_cli_wrapper4();
|
|
8149
|
+
QwenHybridAdapter = class {
|
|
8150
|
+
sdkAdapter = null;
|
|
8151
|
+
cliWrapper = null;
|
|
8152
|
+
options;
|
|
8153
|
+
activeMode = null;
|
|
8154
|
+
// Circuit breakers for each mode
|
|
8155
|
+
sdkCircuitBreaker = {
|
|
8156
|
+
failures: 0,
|
|
8157
|
+
lastFailure: 0,
|
|
8158
|
+
isOpen: false
|
|
8159
|
+
};
|
|
8160
|
+
cliCircuitBreaker = {
|
|
8161
|
+
failures: 0,
|
|
8162
|
+
lastFailure: 0,
|
|
8163
|
+
isOpen: false
|
|
8164
|
+
};
|
|
8165
|
+
// Circuit breaker configuration
|
|
8166
|
+
FAILURE_THRESHOLD = 3;
|
|
8167
|
+
RECOVERY_TIMEOUT_MS = 6e4;
|
|
8168
|
+
// 1 minute
|
|
8169
|
+
constructor(options = {}) {
|
|
8170
|
+
this.options = {
|
|
8171
|
+
mode: options.mode || "auto",
|
|
8172
|
+
model: options.model || "qwen-turbo",
|
|
8173
|
+
apiKey: options.apiKey,
|
|
8174
|
+
baseUrl: options.baseUrl,
|
|
8175
|
+
command: options.command || "qwen",
|
|
8176
|
+
timeout: options.timeout
|
|
8177
|
+
};
|
|
8178
|
+
logger.debug("[Qwen Hybrid] Adapter created", {
|
|
8179
|
+
mode: this.options.mode,
|
|
8180
|
+
model: this.options.model
|
|
8181
|
+
});
|
|
8182
|
+
}
|
|
8183
|
+
/**
|
|
8184
|
+
* Get or create SDK adapter
|
|
8185
|
+
*/
|
|
8186
|
+
getSdkAdapter() {
|
|
8187
|
+
if (!this.sdkAdapter) {
|
|
8188
|
+
const config = {
|
|
8189
|
+
apiKey: this.options.apiKey,
|
|
8190
|
+
baseUrl: this.options.baseUrl,
|
|
8191
|
+
model: this.options.model,
|
|
8192
|
+
timeout: this.options.timeout
|
|
8193
|
+
};
|
|
8194
|
+
this.sdkAdapter = new QwenSdkAdapter(config);
|
|
8195
|
+
}
|
|
8196
|
+
return this.sdkAdapter;
|
|
8197
|
+
}
|
|
8198
|
+
/**
|
|
8199
|
+
* Get or create CLI wrapper
|
|
8200
|
+
*/
|
|
8201
|
+
getCliWrapper() {
|
|
8202
|
+
if (!this.cliWrapper) {
|
|
8203
|
+
const config = {
|
|
8204
|
+
command: this.options.command,
|
|
8205
|
+
timeout: this.options.timeout
|
|
8206
|
+
};
|
|
8207
|
+
this.cliWrapper = new QwenCliWrapper(config);
|
|
8208
|
+
}
|
|
8209
|
+
return this.cliWrapper;
|
|
8210
|
+
}
|
|
8211
|
+
/**
|
|
8212
|
+
* Check if a circuit breaker should allow requests
|
|
8213
|
+
*/
|
|
8214
|
+
isCircuitClosed(breaker) {
|
|
8215
|
+
if (!breaker.isOpen) {
|
|
8216
|
+
return true;
|
|
8217
|
+
}
|
|
8218
|
+
if (Date.now() - breaker.lastFailure > this.RECOVERY_TIMEOUT_MS) {
|
|
8219
|
+
breaker.isOpen = false;
|
|
8220
|
+
breaker.failures = 0;
|
|
8221
|
+
return true;
|
|
8222
|
+
}
|
|
8223
|
+
return false;
|
|
8224
|
+
}
|
|
8225
|
+
/**
|
|
8226
|
+
* Record a failure on a circuit breaker
|
|
8227
|
+
*/
|
|
8228
|
+
recordFailure(breaker) {
|
|
8229
|
+
breaker.failures++;
|
|
8230
|
+
breaker.lastFailure = Date.now();
|
|
8231
|
+
if (breaker.failures >= this.FAILURE_THRESHOLD) {
|
|
8232
|
+
breaker.isOpen = true;
|
|
8233
|
+
logger.warn("[Qwen Hybrid] Circuit breaker opened", {
|
|
8234
|
+
failures: breaker.failures
|
|
8235
|
+
});
|
|
8236
|
+
}
|
|
8237
|
+
}
|
|
8238
|
+
/**
|
|
8239
|
+
* Record a success on a circuit breaker
|
|
8240
|
+
*/
|
|
8241
|
+
recordSuccess(breaker) {
|
|
8242
|
+
breaker.failures = 0;
|
|
8243
|
+
breaker.isOpen = false;
|
|
8244
|
+
}
|
|
8245
|
+
/**
|
|
8246
|
+
* Execute a request using the appropriate mode
|
|
8247
|
+
*/
|
|
8248
|
+
async execute(request) {
|
|
8249
|
+
const mode = this.options.mode;
|
|
8250
|
+
if (mode === "sdk") {
|
|
8251
|
+
return this.executeWithSdk(request);
|
|
8252
|
+
}
|
|
8253
|
+
if (mode === "cli") {
|
|
8254
|
+
return this.executeWithCli(request);
|
|
8255
|
+
}
|
|
8256
|
+
return this.executeWithAuto(request);
|
|
8257
|
+
}
|
|
8258
|
+
/**
|
|
8259
|
+
* Execute with SDK only
|
|
8260
|
+
*/
|
|
8261
|
+
async executeWithSdk(request) {
|
|
8262
|
+
const adapter = this.getSdkAdapter();
|
|
8263
|
+
if (!await adapter.isAvailable()) {
|
|
8264
|
+
throw new Error("Qwen SDK is not available. Check DASHSCOPE_API_KEY or QWEN_API_KEY.");
|
|
8265
|
+
}
|
|
8266
|
+
this.activeMode = "sdk";
|
|
8267
|
+
return adapter.execute(request);
|
|
8268
|
+
}
|
|
8269
|
+
/**
|
|
8270
|
+
* Execute with CLI only
|
|
8271
|
+
*/
|
|
8272
|
+
async executeWithCli(request) {
|
|
8273
|
+
const wrapper = this.getCliWrapper();
|
|
8274
|
+
if (!await wrapper.isAvailable()) {
|
|
8275
|
+
throw new Error("Qwen CLI is not available. Run: npm install -g @qwen-code/qwen-code@latest");
|
|
8276
|
+
}
|
|
8277
|
+
this.activeMode = "cli";
|
|
8278
|
+
return wrapper.execute(request);
|
|
8279
|
+
}
|
|
8280
|
+
/**
|
|
8281
|
+
* Execute with automatic mode selection
|
|
8282
|
+
*/
|
|
8283
|
+
async executeWithAuto(request) {
|
|
8284
|
+
if (this.isCircuitClosed(this.sdkCircuitBreaker)) {
|
|
8285
|
+
const adapter = this.getSdkAdapter();
|
|
8286
|
+
try {
|
|
8287
|
+
if (await adapter.isAvailable()) {
|
|
8288
|
+
logger.debug("[Qwen Hybrid] Using SDK mode");
|
|
8289
|
+
this.activeMode = "sdk";
|
|
8290
|
+
const response = await adapter.execute(request);
|
|
8291
|
+
this.recordSuccess(this.sdkCircuitBreaker);
|
|
8292
|
+
return response;
|
|
8293
|
+
}
|
|
8294
|
+
} catch (error) {
|
|
8295
|
+
logger.warn("[Qwen Hybrid] SDK execution failed, trying CLI", {
|
|
8296
|
+
error: error instanceof Error ? error.message : String(error)
|
|
8297
|
+
});
|
|
8298
|
+
this.recordFailure(this.sdkCircuitBreaker);
|
|
8299
|
+
}
|
|
8300
|
+
}
|
|
8301
|
+
if (this.isCircuitClosed(this.cliCircuitBreaker)) {
|
|
8302
|
+
const wrapper = this.getCliWrapper();
|
|
8303
|
+
try {
|
|
8304
|
+
if (await wrapper.isAvailable()) {
|
|
8305
|
+
logger.debug("[Qwen Hybrid] Using CLI mode (fallback)");
|
|
8306
|
+
this.activeMode = "cli";
|
|
8307
|
+
const response = await wrapper.execute(request);
|
|
8308
|
+
this.recordSuccess(this.cliCircuitBreaker);
|
|
8309
|
+
return response;
|
|
8310
|
+
}
|
|
8311
|
+
} catch (error) {
|
|
8312
|
+
logger.error("[Qwen Hybrid] CLI execution also failed", {
|
|
8313
|
+
error: error instanceof Error ? error.message : String(error)
|
|
8314
|
+
});
|
|
8315
|
+
this.recordFailure(this.cliCircuitBreaker);
|
|
8316
|
+
throw error;
|
|
8317
|
+
}
|
|
8318
|
+
}
|
|
8319
|
+
throw new Error(
|
|
8320
|
+
"Qwen execution failed: Both SDK and CLI modes are unavailable or have failed too many times. Ensure DASHSCOPE_API_KEY is set or Qwen CLI is installed."
|
|
8321
|
+
);
|
|
8322
|
+
}
|
|
8323
|
+
/**
|
|
8324
|
+
* Get the currently active execution mode
|
|
8325
|
+
*/
|
|
8326
|
+
getActiveMode() {
|
|
8327
|
+
return this.activeMode;
|
|
8328
|
+
}
|
|
8329
|
+
/**
|
|
8330
|
+
* Reset circuit breakers
|
|
8331
|
+
*/
|
|
8332
|
+
resetCircuitBreakers() {
|
|
8333
|
+
this.sdkCircuitBreaker = { failures: 0, lastFailure: 0, isOpen: false };
|
|
8334
|
+
this.cliCircuitBreaker = { failures: 0, lastFailure: 0, isOpen: false };
|
|
8335
|
+
logger.debug("[Qwen Hybrid] Circuit breakers reset");
|
|
8336
|
+
}
|
|
8337
|
+
/**
|
|
8338
|
+
* Clean up resources
|
|
8339
|
+
*/
|
|
8340
|
+
async destroy() {
|
|
8341
|
+
if (this.sdkAdapter) {
|
|
8342
|
+
await this.sdkAdapter.destroy();
|
|
8343
|
+
this.sdkAdapter = null;
|
|
8344
|
+
}
|
|
8345
|
+
this.cliWrapper = null;
|
|
8346
|
+
this.activeMode = null;
|
|
8347
|
+
logger.debug("[Qwen Hybrid] Adapter destroyed");
|
|
8348
|
+
}
|
|
8349
|
+
};
|
|
8350
|
+
}
|
|
8351
|
+
});
|
|
8352
|
+
|
|
8353
|
+
// src/integrations/qwen-code/index.ts
|
|
8354
|
+
var init_qwen_code = __esm({
|
|
8355
|
+
"src/integrations/qwen-code/index.ts"() {
|
|
8356
|
+
init_esm_shims();
|
|
8357
|
+
init_hybrid_adapter4();
|
|
8358
|
+
init_sdk_adapter4();
|
|
8359
|
+
init_cli_wrapper4();
|
|
8360
|
+
init_types4();
|
|
8361
|
+
}
|
|
8362
|
+
});
|
|
8363
|
+
|
|
8364
|
+
// src/providers/qwen-provider.ts
|
|
8365
|
+
var qwen_provider_exports = {};
|
|
8366
|
+
__export(qwen_provider_exports, {
|
|
8367
|
+
QwenProvider: () => QwenProvider,
|
|
8368
|
+
default: () => QwenProvider
|
|
8369
|
+
});
|
|
8370
|
+
var SUPPORTED_MODELS, QwenProvider;
|
|
8371
|
+
var init_qwen_provider = __esm({
|
|
8372
|
+
"src/providers/qwen-provider.ts"() {
|
|
8373
|
+
init_esm_shims();
|
|
8374
|
+
init_base_provider();
|
|
8375
|
+
init_logger();
|
|
8376
|
+
init_qwen_code();
|
|
8377
|
+
SUPPORTED_MODELS = [
|
|
8378
|
+
"qwen3-coder-480b-a35b-instruct",
|
|
8379
|
+
"qwen3-coder-30b-a3b-instruct",
|
|
8380
|
+
"qwen2.5-coder-32b-instruct",
|
|
8381
|
+
"qwen-max",
|
|
8382
|
+
"qwen-plus",
|
|
8383
|
+
"qwen-turbo"
|
|
8384
|
+
];
|
|
8385
|
+
QwenProvider = class extends BaseProvider {
|
|
8386
|
+
/** Selected model */
|
|
8387
|
+
model;
|
|
8388
|
+
/** SDK adapter for direct execution */
|
|
8389
|
+
sdkAdapter = null;
|
|
8390
|
+
/** Hybrid adapter for 'auto' mode */
|
|
8391
|
+
hybridAdapter = null;
|
|
8392
|
+
/** Provider configuration */
|
|
8393
|
+
qwenConfig;
|
|
8394
|
+
/** Supported models */
|
|
8395
|
+
static SUPPORTED_MODELS = SUPPORTED_MODELS;
|
|
8396
|
+
constructor(config) {
|
|
8397
|
+
super({
|
|
8398
|
+
...config,
|
|
8399
|
+
command: "qwen"
|
|
8400
|
+
});
|
|
8401
|
+
this.qwenConfig = config;
|
|
8402
|
+
const requestedModel = config.model || QWEN_DEFAULT_MODEL;
|
|
8403
|
+
if (!SUPPORTED_MODELS.includes(requestedModel)) {
|
|
8404
|
+
logger.warn(`[Qwen] Unknown model: ${requestedModel}. Using ${QWEN_DEFAULT_MODEL}.`);
|
|
8405
|
+
this.model = QWEN_DEFAULT_MODEL;
|
|
8406
|
+
} else {
|
|
8407
|
+
this.model = requestedModel;
|
|
8408
|
+
}
|
|
8409
|
+
logger.debug("[Qwen Provider] Initialized", {
|
|
8410
|
+
model: this.model,
|
|
8411
|
+
mode: config.mode || "sdk"
|
|
8412
|
+
});
|
|
8413
|
+
}
|
|
8414
|
+
/**
|
|
8415
|
+
* Get the normalized model name
|
|
8416
|
+
*/
|
|
8417
|
+
getNormalizedModel() {
|
|
8418
|
+
return normalizeQwenModel(this.model);
|
|
8419
|
+
}
|
|
8420
|
+
/**
|
|
8421
|
+
* Get or create SDK adapter
|
|
8422
|
+
*/
|
|
8423
|
+
getSdkAdapter() {
|
|
8424
|
+
if (!this.sdkAdapter) {
|
|
8425
|
+
this.sdkAdapter = new QwenSdkAdapter({
|
|
8426
|
+
model: this.model,
|
|
8427
|
+
apiKey: this.qwenConfig.apiKey,
|
|
8428
|
+
baseUrl: this.qwenConfig.baseUrl,
|
|
8429
|
+
timeout: this.qwenConfig.timeout
|
|
8430
|
+
});
|
|
8431
|
+
}
|
|
8432
|
+
return this.sdkAdapter;
|
|
8433
|
+
}
|
|
8434
|
+
/**
|
|
8435
|
+
* Get or create hybrid adapter
|
|
8436
|
+
*/
|
|
8437
|
+
getHybridAdapter() {
|
|
8438
|
+
if (!this.hybridAdapter) {
|
|
8439
|
+
const options = {
|
|
8440
|
+
mode: this.qwenConfig.mode || "auto",
|
|
8441
|
+
model: this.model,
|
|
8442
|
+
apiKey: this.qwenConfig.apiKey,
|
|
8443
|
+
baseUrl: this.qwenConfig.baseUrl,
|
|
8444
|
+
command: "qwen",
|
|
8445
|
+
timeout: this.qwenConfig.timeout
|
|
8446
|
+
};
|
|
8447
|
+
this.hybridAdapter = new QwenHybridAdapter(options);
|
|
8448
|
+
}
|
|
8449
|
+
return this.hybridAdapter;
|
|
8450
|
+
}
|
|
8451
|
+
/**
|
|
8452
|
+
* Execute a task using Qwen
|
|
8453
|
+
*
|
|
8454
|
+
* Execution flow:
|
|
8455
|
+
* 1. Mock mode → return mock response
|
|
8456
|
+
* 2. mode='sdk' (default) → use SDK adapter
|
|
8457
|
+
* 3. mode='auto' → use hybrid adapter (SDK with CLI fallback)
|
|
8458
|
+
* 4. mode='cli' → use CLI via BaseProvider
|
|
8459
|
+
*/
|
|
8460
|
+
async execute(request) {
|
|
8461
|
+
if (process.env.AX_MOCK_PROVIDERS === "true") {
|
|
8462
|
+
return this.createMockResponse(request.prompt);
|
|
8463
|
+
}
|
|
8464
|
+
const effectiveMode = this.qwenConfig.mode || "sdk";
|
|
8465
|
+
if (effectiveMode === "cli") {
|
|
8466
|
+
logger.debug("[Qwen Provider] Executing via CLI", {
|
|
8467
|
+
model: this.model
|
|
8468
|
+
});
|
|
8469
|
+
return super.execute(request);
|
|
8470
|
+
}
|
|
8471
|
+
if (effectiveMode === "auto") {
|
|
8472
|
+
logger.debug("[Qwen Provider] Executing via hybrid adapter", {
|
|
8473
|
+
promptLength: request.prompt.length,
|
|
8474
|
+
model: this.model
|
|
8475
|
+
});
|
|
8476
|
+
const adapter2 = this.getHybridAdapter();
|
|
8477
|
+
return adapter2.execute(request);
|
|
8478
|
+
}
|
|
8479
|
+
logger.debug("[Qwen Provider] Executing via SDK adapter", {
|
|
8480
|
+
promptLength: request.prompt.length,
|
|
8481
|
+
model: this.model
|
|
8482
|
+
});
|
|
8483
|
+
const adapter = this.getSdkAdapter();
|
|
8484
|
+
if (!await adapter.isAvailable()) {
|
|
8485
|
+
throw new Error(
|
|
8486
|
+
'Qwen SDK is not available. Set DASHSCOPE_API_KEY or QWEN_API_KEY environment variable, or use mode: "cli" to use Qwen Code CLI.'
|
|
8487
|
+
);
|
|
8488
|
+
}
|
|
8489
|
+
return adapter.execute(request);
|
|
8490
|
+
}
|
|
8491
|
+
/**
|
|
8492
|
+
* Get CLI command
|
|
8493
|
+
*/
|
|
8494
|
+
getCLICommand() {
|
|
8495
|
+
const activeMode = this.hybridAdapter?.getActiveMode();
|
|
8496
|
+
if (activeMode === "sdk") {
|
|
8497
|
+
return "qwen-sdk";
|
|
8498
|
+
}
|
|
8499
|
+
return "qwen";
|
|
8500
|
+
}
|
|
8501
|
+
/**
|
|
8502
|
+
* Get CLI arguments for Qwen Code CLI
|
|
8503
|
+
*
|
|
8504
|
+
* Note: Qwen Code CLI is interactive by default.
|
|
8505
|
+
* We pass the prompt via stdin instead of command-line args.
|
|
8506
|
+
*/
|
|
8507
|
+
getCLIArgs() {
|
|
8508
|
+
return [];
|
|
8509
|
+
}
|
|
8510
|
+
/**
|
|
8511
|
+
* Create mock response for testing
|
|
8512
|
+
*/
|
|
8513
|
+
createMockResponse(prompt) {
|
|
8514
|
+
return {
|
|
8515
|
+
content: this.getMockResponse(),
|
|
8516
|
+
model: this.getNormalizedModel(),
|
|
8517
|
+
tokensUsed: {
|
|
8518
|
+
prompt: this.estimateTokens(prompt),
|
|
8519
|
+
completion: 50,
|
|
8520
|
+
total: this.estimateTokens(prompt) + 50
|
|
8521
|
+
},
|
|
8522
|
+
latencyMs: 10,
|
|
8523
|
+
finishReason: "stop",
|
|
8524
|
+
cached: false
|
|
8525
|
+
};
|
|
8526
|
+
}
|
|
8527
|
+
/**
|
|
8528
|
+
* Estimate token count
|
|
8529
|
+
*/
|
|
8530
|
+
estimateTokens(text) {
|
|
8531
|
+
return Math.ceil(text.length / 4);
|
|
8532
|
+
}
|
|
8533
|
+
/**
|
|
8534
|
+
* Get mock response for testing
|
|
8535
|
+
*/
|
|
8536
|
+
getMockResponse() {
|
|
8537
|
+
return `[Mock Qwen Response]
|
|
8538
|
+
|
|
8539
|
+
This is a mock response from the Qwen provider (${this.getNormalizedModel()}).
|
|
8540
|
+
In production, this would be a response from ${this.qwenConfig.mode === "sdk" ? "Qwen SDK" : "Qwen Code CLI"}.
|
|
8541
|
+
|
|
8542
|
+
Model: ${this.getNormalizedModel()}
|
|
8543
|
+
Provider: Qwen (Alibaba Cloud)
|
|
8544
|
+
Mode: ${this.qwenConfig.mode || "sdk"}`;
|
|
8545
|
+
}
|
|
8546
|
+
/**
|
|
8547
|
+
* Get provider capabilities
|
|
8548
|
+
*/
|
|
8549
|
+
get capabilities() {
|
|
8550
|
+
const model = this.getNormalizedModel();
|
|
8551
|
+
const hasVision = isVisionModel(model);
|
|
8552
|
+
const maxContextTokens = getModelContextWindow(model);
|
|
8553
|
+
const activeMode = this.hybridAdapter?.getActiveMode();
|
|
8554
|
+
const integrationMode = activeMode === "sdk" ? "sdk" : "cli";
|
|
8555
|
+
return {
|
|
8556
|
+
...super.capabilities,
|
|
8557
|
+
supportsStreaming: true,
|
|
8558
|
+
supportsVision: hasVision,
|
|
8559
|
+
maxContextTokens,
|
|
8560
|
+
supportedModels: SUPPORTED_MODELS,
|
|
8561
|
+
integrationMode
|
|
8562
|
+
};
|
|
8563
|
+
}
|
|
8564
|
+
/**
|
|
8565
|
+
* Get the active execution mode
|
|
8566
|
+
*/
|
|
8567
|
+
getActiveMode() {
|
|
8568
|
+
return this.hybridAdapter?.getActiveMode() || null;
|
|
8569
|
+
}
|
|
8570
|
+
/**
|
|
8571
|
+
* Reset circuit breakers
|
|
8572
|
+
*/
|
|
8573
|
+
resetCircuitBreakers() {
|
|
8574
|
+
this.hybridAdapter?.resetCircuitBreakers();
|
|
8575
|
+
}
|
|
8576
|
+
/**
|
|
8577
|
+
* Clean up resources
|
|
8578
|
+
*/
|
|
8579
|
+
async destroy() {
|
|
8580
|
+
if (this.sdkAdapter) {
|
|
8581
|
+
await this.sdkAdapter.destroy();
|
|
8582
|
+
this.sdkAdapter = null;
|
|
8583
|
+
}
|
|
8584
|
+
if (this.hybridAdapter) {
|
|
8585
|
+
await this.hybridAdapter.destroy();
|
|
8586
|
+
this.hybridAdapter = null;
|
|
8587
|
+
}
|
|
8588
|
+
}
|
|
8589
|
+
/**
|
|
8590
|
+
* Get the list of supported models
|
|
8591
|
+
*/
|
|
8592
|
+
static getSupportedModels() {
|
|
8593
|
+
return [...SUPPORTED_MODELS];
|
|
8594
|
+
}
|
|
8595
|
+
};
|
|
8596
|
+
}
|
|
8597
|
+
});
|
|
8598
|
+
|
|
7583
8599
|
// src/mcp/index.ts
|
|
7584
8600
|
init_esm_shims();
|
|
7585
8601
|
|
|
@@ -8032,12 +9048,16 @@ init_logger();
|
|
|
8032
9048
|
|
|
8033
9049
|
// src/shared/helpers/deep-merge.ts
|
|
8034
9050
|
init_esm_shims();
|
|
9051
|
+
function isPlainObject(value) {
|
|
9052
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && Object.prototype.toString.call(value) === "[object Object]";
|
|
9053
|
+
}
|
|
8035
9054
|
function deepMerge(defaults, user) {
|
|
8036
9055
|
if (user === null || user === void 0) {
|
|
8037
|
-
return defaults;
|
|
9056
|
+
return { ...defaults };
|
|
8038
9057
|
}
|
|
8039
|
-
const result = {
|
|
8040
|
-
|
|
9058
|
+
const result = Object.assign({}, defaults);
|
|
9059
|
+
const userKeys = Object.keys(user);
|
|
9060
|
+
for (const key of userKeys) {
|
|
8041
9061
|
const userValue = user[key];
|
|
8042
9062
|
if (userValue === null) {
|
|
8043
9063
|
result[key] = void 0;
|
|
@@ -8047,8 +9067,11 @@ function deepMerge(defaults, user) {
|
|
|
8047
9067
|
continue;
|
|
8048
9068
|
}
|
|
8049
9069
|
const defaultValue = defaults[key];
|
|
8050
|
-
if (
|
|
8051
|
-
result[key] = deepMerge(
|
|
9070
|
+
if (isPlainObject(userValue) && isPlainObject(defaultValue)) {
|
|
9071
|
+
result[key] = deepMerge(
|
|
9072
|
+
defaultValue,
|
|
9073
|
+
userValue
|
|
9074
|
+
);
|
|
8052
9075
|
} else {
|
|
8053
9076
|
result[key] = userValue;
|
|
8054
9077
|
}
|
|
@@ -8690,7 +9713,7 @@ var PRECOMPILED_CONFIG = {
|
|
|
8690
9713
|
"enableFreeTierPrioritization": true,
|
|
8691
9714
|
"enableWorkloadAwareRouting": true
|
|
8692
9715
|
},
|
|
8693
|
-
"version": "12.6.
|
|
9716
|
+
"version": "12.6.3"
|
|
8694
9717
|
};
|
|
8695
9718
|
|
|
8696
9719
|
// src/core/config/schemas.ts
|
|
@@ -9565,107 +10588,7 @@ init_logger();
|
|
|
9565
10588
|
// src/shared/utils/disposable.ts
|
|
9566
10589
|
init_esm_shims();
|
|
9567
10590
|
init_logger();
|
|
9568
|
-
|
|
9569
|
-
// src/shared/utils/safe-timers.ts
|
|
9570
|
-
init_esm_shims();
|
|
9571
|
-
init_logger();
|
|
9572
|
-
function createSafeInterval(callback, intervalMs, options = {}) {
|
|
9573
|
-
const { ref = false, name, signal, immediate = false } = options;
|
|
9574
|
-
if (signal?.aborted) {
|
|
9575
|
-
logger.debug("createSafeInterval: already aborted", { name });
|
|
9576
|
-
return () => {
|
|
9577
|
-
};
|
|
9578
|
-
}
|
|
9579
|
-
let cleared = false;
|
|
9580
|
-
let intervalId = null;
|
|
9581
|
-
const safeCallback = async () => {
|
|
9582
|
-
if (cleared) return;
|
|
9583
|
-
try {
|
|
9584
|
-
await callback();
|
|
9585
|
-
} catch (error) {
|
|
9586
|
-
logger.error("Safe interval callback error", {
|
|
9587
|
-
name,
|
|
9588
|
-
error: error.message
|
|
9589
|
-
});
|
|
9590
|
-
}
|
|
9591
|
-
};
|
|
9592
|
-
if (immediate) {
|
|
9593
|
-
setImmediate(() => {
|
|
9594
|
-
if (!cleared) {
|
|
9595
|
-
safeCallback();
|
|
9596
|
-
}
|
|
9597
|
-
});
|
|
9598
|
-
}
|
|
9599
|
-
intervalId = setInterval(safeCallback, intervalMs);
|
|
9600
|
-
if (!ref && intervalId.unref) {
|
|
9601
|
-
intervalId.unref();
|
|
9602
|
-
}
|
|
9603
|
-
const cleanup = () => {
|
|
9604
|
-
if (cleared) return;
|
|
9605
|
-
cleared = true;
|
|
9606
|
-
if (intervalId !== null) {
|
|
9607
|
-
clearInterval(intervalId);
|
|
9608
|
-
intervalId = null;
|
|
9609
|
-
logger.debug("Safe interval cleared", { name });
|
|
9610
|
-
}
|
|
9611
|
-
};
|
|
9612
|
-
if (signal) {
|
|
9613
|
-
signal.addEventListener("abort", cleanup, { once: true });
|
|
9614
|
-
}
|
|
9615
|
-
logger.debug("Safe interval created", {
|
|
9616
|
-
name,
|
|
9617
|
-
intervalMs,
|
|
9618
|
-
ref,
|
|
9619
|
-
immediate
|
|
9620
|
-
});
|
|
9621
|
-
return cleanup;
|
|
9622
|
-
}
|
|
9623
|
-
function createSafeTimeout(callback, delayMs, options = {}) {
|
|
9624
|
-
const { ref = false, name, signal } = options;
|
|
9625
|
-
if (signal?.aborted) {
|
|
9626
|
-
logger.debug("createSafeTimeout: already aborted", { name });
|
|
9627
|
-
return () => {
|
|
9628
|
-
};
|
|
9629
|
-
}
|
|
9630
|
-
let cleared = false;
|
|
9631
|
-
let timeoutId = null;
|
|
9632
|
-
const safeCallback = async () => {
|
|
9633
|
-
if (cleared) return;
|
|
9634
|
-
cleared = true;
|
|
9635
|
-
try {
|
|
9636
|
-
await callback();
|
|
9637
|
-
} catch (error) {
|
|
9638
|
-
logger.error("Safe timeout callback error", {
|
|
9639
|
-
name,
|
|
9640
|
-
error: error.message
|
|
9641
|
-
});
|
|
9642
|
-
}
|
|
9643
|
-
};
|
|
9644
|
-
timeoutId = setTimeout(safeCallback, delayMs);
|
|
9645
|
-
if (!ref && timeoutId.unref) {
|
|
9646
|
-
timeoutId.unref();
|
|
9647
|
-
}
|
|
9648
|
-
const cleanup = () => {
|
|
9649
|
-
if (cleared) return;
|
|
9650
|
-
cleared = true;
|
|
9651
|
-
if (timeoutId !== null) {
|
|
9652
|
-
clearTimeout(timeoutId);
|
|
9653
|
-
timeoutId = null;
|
|
9654
|
-
logger.debug("Safe timeout cleared", { name });
|
|
9655
|
-
}
|
|
9656
|
-
};
|
|
9657
|
-
if (signal) {
|
|
9658
|
-
signal.addEventListener("abort", cleanup, { once: true });
|
|
9659
|
-
}
|
|
9660
|
-
logger.debug("Safe timeout created", {
|
|
9661
|
-
name,
|
|
9662
|
-
delayMs,
|
|
9663
|
-
ref
|
|
9664
|
-
});
|
|
9665
|
-
return cleanup;
|
|
9666
|
-
}
|
|
9667
|
-
|
|
9668
|
-
// src/shared/utils/disposable.ts
|
|
10591
|
+
init_safe_timers();
|
|
9669
10592
|
var DisposableEventEmitter = class extends EventEmitter {
|
|
9670
10593
|
/** Registered cleanup tasks */
|
|
9671
10594
|
cleanupTasks = [];
|
|
@@ -13213,7 +14136,7 @@ var MemoryManager = class _MemoryManager {
|
|
|
13213
14136
|
if (this.db) {
|
|
13214
14137
|
try {
|
|
13215
14138
|
this.db.close();
|
|
13216
|
-
} catch
|
|
14139
|
+
} catch {
|
|
13217
14140
|
}
|
|
13218
14141
|
this.initialized = false;
|
|
13219
14142
|
this.entryCount = 0;
|
|
@@ -14054,9 +14977,9 @@ var MemoryManager = class _MemoryManager {
|
|
|
14054
14977
|
}
|
|
14055
14978
|
}
|
|
14056
14979
|
const {
|
|
14057
|
-
includeEmbeddings = false,
|
|
14980
|
+
includeEmbeddings: _includeEmbeddings = false,
|
|
14058
14981
|
filters = {},
|
|
14059
|
-
batchSize = 1e3,
|
|
14982
|
+
batchSize: _batchSize = 1e3,
|
|
14060
14983
|
pretty = false
|
|
14061
14984
|
} = options || {};
|
|
14062
14985
|
try {
|
|
@@ -15213,7 +16136,7 @@ var SessionManager = class _SessionManager {
|
|
|
15213
16136
|
if (this.pendingSave) {
|
|
15214
16137
|
try {
|
|
15215
16138
|
await this.pendingSave;
|
|
15216
|
-
} catch
|
|
16139
|
+
} catch {
|
|
15217
16140
|
}
|
|
15218
16141
|
}
|
|
15219
16142
|
this.pendingSave = this.doSave().finally(() => {
|
|
@@ -15281,7 +16204,7 @@ var SessionManager = class _SessionManager {
|
|
|
15281
16204
|
}
|
|
15282
16205
|
try {
|
|
15283
16206
|
await unlink(tempPath);
|
|
15284
|
-
} catch
|
|
16207
|
+
} catch {
|
|
15285
16208
|
}
|
|
15286
16209
|
throw renameError;
|
|
15287
16210
|
}
|
|
@@ -15289,7 +16212,7 @@ var SessionManager = class _SessionManager {
|
|
|
15289
16212
|
const tempPath = `${this.persistencePath}.tmp`;
|
|
15290
16213
|
try {
|
|
15291
16214
|
await unlink(tempPath);
|
|
15292
|
-
} catch
|
|
16215
|
+
} catch {
|
|
15293
16216
|
}
|
|
15294
16217
|
logger.error("Failed to save sessions to persistence", {
|
|
15295
16218
|
path: normalizePath(this.persistencePath),
|
|
@@ -15827,6 +16750,7 @@ init_esm_shims();
|
|
|
15827
16750
|
init_logger();
|
|
15828
16751
|
var MAX_CONTEXT_SIZE = 100 * 1024;
|
|
15829
16752
|
var DEFAULT_CACHE_TTL = 3e5;
|
|
16753
|
+
var STALE_THRESHOLD_MS = 24 * 60 * 60 * 1e3;
|
|
15830
16754
|
var ProjectContextLoader = class {
|
|
15831
16755
|
constructor(projectRoot, options) {
|
|
15832
16756
|
this.projectRoot = projectRoot;
|
|
@@ -15850,76 +16774,79 @@ var ProjectContextLoader = class {
|
|
|
15850
16774
|
});
|
|
15851
16775
|
const context = {};
|
|
15852
16776
|
try {
|
|
15853
|
-
const
|
|
15854
|
-
const resolvedPath = await realpath(
|
|
16777
|
+
const indexPath = path4__default.join(this.projectRoot, "ax.index.json");
|
|
16778
|
+
const resolvedPath = await realpath(indexPath).catch(() => null);
|
|
15855
16779
|
if (resolvedPath) {
|
|
15856
16780
|
const rel = path4__default.relative(this.projectRoot, resolvedPath);
|
|
15857
16781
|
if (!rel.startsWith("..") && !path4__default.isAbsolute(rel)) {
|
|
15858
16782
|
const stats = await stat(resolvedPath);
|
|
15859
16783
|
if (stats.size > MAX_CONTEXT_SIZE) {
|
|
15860
|
-
logger.warn("
|
|
16784
|
+
logger.warn("ax.index.json too large, ignoring", {
|
|
15861
16785
|
size: stats.size,
|
|
15862
16786
|
limit: MAX_CONTEXT_SIZE
|
|
15863
16787
|
});
|
|
15864
16788
|
} else {
|
|
15865
|
-
|
|
15866
|
-
|
|
15867
|
-
|
|
15868
|
-
|
|
16789
|
+
const indexContent = await readFile(resolvedPath, "utf-8");
|
|
16790
|
+
context.index = JSON.parse(indexContent);
|
|
16791
|
+
context.lastUpdated = stats.mtime;
|
|
16792
|
+
const age = Date.now() - stats.mtime.getTime();
|
|
16793
|
+
context.isStale = age > STALE_THRESHOLD_MS;
|
|
16794
|
+
logger.info("Loaded ax.index.json", {
|
|
16795
|
+
projectName: context.index.projectName,
|
|
16796
|
+
projectType: context.index.projectType,
|
|
16797
|
+
isStale: context.isStale,
|
|
16798
|
+
ageHours: Math.floor(age / (1e3 * 60 * 60))
|
|
15869
16799
|
});
|
|
15870
|
-
|
|
15871
|
-
|
|
15872
|
-
|
|
15873
|
-
|
|
16800
|
+
if (context.index.commands) {
|
|
16801
|
+
context.commands = {};
|
|
16802
|
+
for (const [name, cmd] of Object.entries(context.index.commands)) {
|
|
16803
|
+
context.commands[name] = cmd.script;
|
|
16804
|
+
}
|
|
16805
|
+
}
|
|
15874
16806
|
}
|
|
15875
16807
|
}
|
|
15876
16808
|
}
|
|
15877
16809
|
} catch (error) {
|
|
15878
16810
|
if (error && typeof error === "object" && "code" in error && error.code !== "ENOENT") {
|
|
15879
|
-
logger.warn("Error loading
|
|
16811
|
+
logger.warn("Error loading ax.index.json", { error });
|
|
15880
16812
|
}
|
|
15881
16813
|
}
|
|
15882
16814
|
try {
|
|
15883
|
-
const
|
|
15884
|
-
const resolvedPath = await realpath(
|
|
16815
|
+
const customMdPath = path4__default.join(this.projectRoot, ".automatosx", "CUSTOM.md");
|
|
16816
|
+
const resolvedPath = await realpath(customMdPath).catch(() => null);
|
|
15885
16817
|
if (resolvedPath) {
|
|
15886
16818
|
const rel = path4__default.relative(this.projectRoot, resolvedPath);
|
|
15887
16819
|
if (!rel.startsWith("..") && !path4__default.isAbsolute(rel)) {
|
|
15888
16820
|
const stats = await stat(resolvedPath);
|
|
15889
16821
|
if (stats.size > MAX_CONTEXT_SIZE) {
|
|
15890
|
-
logger.warn("
|
|
16822
|
+
logger.warn("CUSTOM.md too large, ignoring", {
|
|
15891
16823
|
size: stats.size,
|
|
15892
16824
|
limit: MAX_CONTEXT_SIZE
|
|
15893
16825
|
});
|
|
15894
16826
|
} else {
|
|
15895
|
-
|
|
15896
|
-
|
|
15897
|
-
|
|
15898
|
-
|
|
16827
|
+
context.customInstructions = await readFile(resolvedPath, "utf-8");
|
|
16828
|
+
logger.info("Loaded CUSTOM.md", {
|
|
16829
|
+
size: stats.size,
|
|
16830
|
+
lines: context.customInstructions.split("\n").length
|
|
15899
16831
|
});
|
|
15900
|
-
|
|
15901
|
-
context.commands = { ...context.commands, ...context.config.commands };
|
|
15902
|
-
}
|
|
15903
|
-
if (context.config.project) {
|
|
15904
|
-
context.metadata = { ...context.metadata, ...context.config.project };
|
|
15905
|
-
}
|
|
16832
|
+
context.guardrails = this.parseGuardrails(context.customInstructions);
|
|
15906
16833
|
}
|
|
15907
16834
|
}
|
|
15908
16835
|
}
|
|
15909
16836
|
} catch (error) {
|
|
15910
16837
|
if (error && typeof error === "object" && "code" in error && error.code !== "ENOENT") {
|
|
15911
|
-
logger.warn("Error loading
|
|
16838
|
+
logger.warn("Error loading CUSTOM.md", { error });
|
|
15912
16839
|
}
|
|
15913
16840
|
}
|
|
15914
16841
|
context.contextPrompt = this.buildContextPrompt(context);
|
|
15915
16842
|
this.cache = context;
|
|
15916
16843
|
this.cacheExpiry = Date.now() + this.cacheTTL;
|
|
15917
16844
|
logger.info("Project context loaded", {
|
|
15918
|
-
|
|
15919
|
-
|
|
15920
|
-
agentRules: context.agentRules?.length ?? 0,
|
|
16845
|
+
hasIndex: !!context.index,
|
|
16846
|
+
hasCustomInstructions: !!context.customInstructions,
|
|
15921
16847
|
guardrails: context.guardrails?.length ?? 0,
|
|
15922
|
-
commands: Object.keys(context.commands ?? {}).length
|
|
16848
|
+
commands: Object.keys(context.commands ?? {}).length,
|
|
16849
|
+
isStale: context.isStale
|
|
15923
16850
|
});
|
|
15924
16851
|
return context;
|
|
15925
16852
|
}
|
|
@@ -15935,8 +16862,8 @@ var ProjectContextLoader = class {
|
|
|
15935
16862
|
* Check if context exists (without loading)
|
|
15936
16863
|
*/
|
|
15937
16864
|
async exists() {
|
|
15938
|
-
const
|
|
15939
|
-
const
|
|
16865
|
+
const indexPath = path4__default.join(this.projectRoot, "ax.index.json");
|
|
16866
|
+
const customMdPath = path4__default.join(this.projectRoot, ".automatosx", "CUSTOM.md");
|
|
15940
16867
|
const checkExists = async (filePath) => {
|
|
15941
16868
|
try {
|
|
15942
16869
|
await access(filePath, constants.F_OK);
|
|
@@ -15945,57 +16872,48 @@ var ProjectContextLoader = class {
|
|
|
15945
16872
|
return false;
|
|
15946
16873
|
}
|
|
15947
16874
|
};
|
|
15948
|
-
const [
|
|
15949
|
-
checkExists(
|
|
15950
|
-
checkExists(
|
|
16875
|
+
const [indexExists, customMdExists] = await Promise.all([
|
|
16876
|
+
checkExists(indexPath),
|
|
16877
|
+
checkExists(customMdPath)
|
|
15951
16878
|
]);
|
|
15952
|
-
return
|
|
16879
|
+
return indexExists || customMdExists;
|
|
15953
16880
|
}
|
|
15954
16881
|
/**
|
|
15955
|
-
*
|
|
15956
|
-
|
|
15957
|
-
|
|
15958
|
-
|
|
15959
|
-
|
|
15960
|
-
|
|
15961
|
-
|
|
15962
|
-
|
|
15963
|
-
|
|
15964
|
-
|
|
15965
|
-
if (!match || !match[1]) {
|
|
15966
|
-
return rules;
|
|
15967
|
-
}
|
|
15968
|
-
const section = match[1];
|
|
15969
|
-
const lineRegex = /^[-*]\s+(.+?)\s+(?:→|->)+\s+(.+?)$/gm;
|
|
15970
|
-
let lineMatch;
|
|
15971
|
-
while ((lineMatch = lineRegex.exec(section)) !== null) {
|
|
15972
|
-
const taskType = lineMatch[1]?.trim() ?? "";
|
|
15973
|
-
const agentsText = lineMatch[2]?.trim() ?? "";
|
|
15974
|
-
const agents = agentsText.split(",").map((a) => a.trim()).filter(Boolean);
|
|
15975
|
-
const defaultAgent = agents[0];
|
|
15976
|
-
if (defaultAgent) {
|
|
15977
|
-
rules.push({
|
|
15978
|
-
taskType,
|
|
15979
|
-
patterns: [],
|
|
15980
|
-
// TODO: Parse file patterns if specified
|
|
15981
|
-
defaultAgent,
|
|
15982
|
-
autoReview: agents.length > 1
|
|
15983
|
-
});
|
|
15984
|
-
}
|
|
16882
|
+
* Check if ax.index.json is stale (older than 24 hours)
|
|
16883
|
+
*/
|
|
16884
|
+
async isStale() {
|
|
16885
|
+
try {
|
|
16886
|
+
const indexPath = path4__default.join(this.projectRoot, "ax.index.json");
|
|
16887
|
+
const stats = await stat(indexPath);
|
|
16888
|
+
const age = Date.now() - stats.mtime.getTime();
|
|
16889
|
+
return age > STALE_THRESHOLD_MS;
|
|
16890
|
+
} catch {
|
|
16891
|
+
return true;
|
|
15985
16892
|
}
|
|
15986
|
-
return rules;
|
|
15987
16893
|
}
|
|
15988
16894
|
/**
|
|
15989
|
-
* Parse guardrails
|
|
16895
|
+
* Parse guardrails from CUSTOM.md
|
|
15990
16896
|
*
|
|
15991
|
-
* Looks for
|
|
15992
|
-
* Extracts items marked with ⚠️ or under NEVER headings
|
|
16897
|
+
* Looks for DO/DON'T sections in ax-cli format
|
|
15993
16898
|
*/
|
|
15994
16899
|
parseGuardrails(markdown) {
|
|
15995
16900
|
const guardrails = [];
|
|
15996
|
-
const
|
|
16901
|
+
const dontRegex = /###\s+DON'T[^\n]*\n([\s\S]*?)(?=\n###|$)/i;
|
|
16902
|
+
const dontMatch = markdown.match(dontRegex);
|
|
16903
|
+
if (dontMatch && dontMatch[1]) {
|
|
16904
|
+
const section = dontMatch[1];
|
|
16905
|
+
const bulletRegex = /^[-*]\s+(.+?)$/gm;
|
|
16906
|
+
let bulletMatch;
|
|
16907
|
+
while ((bulletMatch = bulletRegex.exec(section)) !== null) {
|
|
16908
|
+
const rule = bulletMatch[1]?.trim();
|
|
16909
|
+
if (rule) {
|
|
16910
|
+
guardrails.push(rule);
|
|
16911
|
+
}
|
|
16912
|
+
}
|
|
16913
|
+
}
|
|
16914
|
+
const criticalRegex = /##\s+(Critical\s+Guardrails|Critical\s+Rules|Never)[^\n]*\n([\s\S]*?)(?=\n##|$)/gi;
|
|
15997
16915
|
let match;
|
|
15998
|
-
while ((match =
|
|
16916
|
+
while ((match = criticalRegex.exec(markdown)) !== null) {
|
|
15999
16917
|
const section = match[2];
|
|
16000
16918
|
if (!section) continue;
|
|
16001
16919
|
const bulletRegex = /^[-*]\s+(.+?)$/gm;
|
|
@@ -16005,106 +16923,58 @@ var ProjectContextLoader = class {
|
|
|
16005
16923
|
rule = rule.replace(/^[⚠️❌✅✓⚡🔒]+\s*/, "");
|
|
16006
16924
|
rule = rule.replace(/\*\*(.+?)\*\*/g, "$1");
|
|
16007
16925
|
rule = rule.replace(/`(.+?)`/g, "$1");
|
|
16008
|
-
if (rule.length > 0) {
|
|
16926
|
+
if (rule.length > 0 && !guardrails.includes(rule)) {
|
|
16009
16927
|
guardrails.push(rule);
|
|
16010
16928
|
}
|
|
16011
16929
|
}
|
|
16012
16930
|
}
|
|
16013
16931
|
return guardrails;
|
|
16014
16932
|
}
|
|
16015
|
-
/**
|
|
16016
|
-
* Parse commands from markdown code blocks
|
|
16017
|
-
*
|
|
16018
|
-
* Looks for "## Commands" or "## Canonical Commands" section
|
|
16019
|
-
*/
|
|
16020
|
-
parseCommands(markdown) {
|
|
16021
|
-
const commands = {};
|
|
16022
|
-
const sectionRegex = /##\s+(Canonical\s+)?Commands[^\n]*\n([\s\S]*?)(?=\n##|$)/i;
|
|
16023
|
-
const match = markdown.match(sectionRegex);
|
|
16024
|
-
if (!match) {
|
|
16025
|
-
return commands;
|
|
16026
|
-
}
|
|
16027
|
-
const section = match[2];
|
|
16028
|
-
if (!section) {
|
|
16029
|
-
return commands;
|
|
16030
|
-
}
|
|
16031
|
-
const codeBlockRegex = /```(?:bash|sh|shell)?\n([\s\S]*?)```/;
|
|
16032
|
-
const codeMatch = section.match(codeBlockRegex);
|
|
16033
|
-
if (codeMatch && codeMatch[1]) {
|
|
16034
|
-
const lines = codeMatch[1].split("\n");
|
|
16035
|
-
for (const line of lines) {
|
|
16036
|
-
const cmdMatch = line.match(/^([^\s#]+(?:\s+[^\s#]+)*)\s*#?\s*(.*)$/);
|
|
16037
|
-
if (cmdMatch && cmdMatch[1]) {
|
|
16038
|
-
const cmd = cmdMatch[1].trim();
|
|
16039
|
-
const desc = cmdMatch[2]?.trim() ?? "";
|
|
16040
|
-
const key = desc || cmd;
|
|
16041
|
-
commands[key] = cmd;
|
|
16042
|
-
}
|
|
16043
|
-
}
|
|
16044
|
-
}
|
|
16045
|
-
return commands;
|
|
16046
|
-
}
|
|
16047
|
-
/**
|
|
16048
|
-
* Parse project metadata from markdown frontmatter or first section
|
|
16049
|
-
*/
|
|
16050
|
-
parseMetadata(markdown) {
|
|
16051
|
-
const metadata = {};
|
|
16052
|
-
const lastUpdatedMatch = markdown.match(/>\s*Last\s+updated:\s*(.+?)$/im);
|
|
16053
|
-
if (lastUpdatedMatch && lastUpdatedMatch[1]) {
|
|
16054
|
-
metadata.lastUpdated = lastUpdatedMatch[1].trim();
|
|
16055
|
-
}
|
|
16056
|
-
const projectMatch = markdown.match(/>\s*Project:\s*(.+?)$/im);
|
|
16057
|
-
if (projectMatch && projectMatch[1]) {
|
|
16058
|
-
const parts = projectMatch[1].trim().split(/\s+v/);
|
|
16059
|
-
metadata.name = parts[0] || "";
|
|
16060
|
-
if (parts.length > 1 && parts[1]) {
|
|
16061
|
-
metadata.version = parts[1];
|
|
16062
|
-
}
|
|
16063
|
-
}
|
|
16064
|
-
const h1Match = markdown.match(/^#\s+(.+?)$/m);
|
|
16065
|
-
if (h1Match && h1Match[1] && !metadata.name) {
|
|
16066
|
-
metadata.name = h1Match[1].replace(/Project Context for AutomatosX/i, "").trim();
|
|
16067
|
-
}
|
|
16068
|
-
return metadata;
|
|
16069
|
-
}
|
|
16070
16933
|
/**
|
|
16071
16934
|
* Build formatted context prompt for agent injection
|
|
16072
16935
|
*/
|
|
16073
16936
|
buildContextPrompt(context) {
|
|
16074
|
-
if (!context.
|
|
16937
|
+
if (!context.index && !context.customInstructions) {
|
|
16075
16938
|
return "";
|
|
16076
16939
|
}
|
|
16077
16940
|
let prompt = "\n# PROJECT CONTEXT\n\n";
|
|
16078
|
-
if (context.
|
|
16079
|
-
prompt +=
|
|
16080
|
-
context.guardrails.forEach((rule) => {
|
|
16081
|
-
prompt += `- ${rule}
|
|
16941
|
+
if (context.index) {
|
|
16942
|
+
prompt += `**Project:** ${context.index.projectName} v${context.index.version}
|
|
16082
16943
|
`;
|
|
16083
|
-
}
|
|
16084
|
-
prompt += "\n";
|
|
16085
|
-
}
|
|
16086
|
-
if (context.agentRules && context.agentRules.length > 0) {
|
|
16087
|
-
prompt += "## Agent Delegation Rules:\n\n";
|
|
16088
|
-
context.agentRules.forEach((rule) => {
|
|
16089
|
-
prompt += `- ${rule.taskType} \u2192 ${rule.defaultAgent}
|
|
16944
|
+
prompt += `**Type:** ${context.index.projectType}
|
|
16090
16945
|
`;
|
|
16091
|
-
}
|
|
16092
|
-
|
|
16946
|
+
prompt += `**Language:** ${context.index.language}`;
|
|
16947
|
+
if (context.index.framework) {
|
|
16948
|
+
prompt += ` + ${context.index.framework}`;
|
|
16949
|
+
}
|
|
16950
|
+
prompt += "\n\n";
|
|
16951
|
+
if (context.index.modules.length > 0) {
|
|
16952
|
+
prompt += "## Project Structure:\n\n";
|
|
16953
|
+
for (const mod of context.index.modules.slice(0, 10)) {
|
|
16954
|
+
prompt += `- \`${mod.path}/\` - ${mod.purpose}
|
|
16955
|
+
`;
|
|
16956
|
+
}
|
|
16957
|
+
prompt += "\n";
|
|
16958
|
+
}
|
|
16959
|
+
if (context.commands && Object.keys(context.commands).length > 0) {
|
|
16960
|
+
prompt += "## Available Commands:\n\n";
|
|
16961
|
+
for (const [name, script] of Object.entries(context.commands).slice(0, 10)) {
|
|
16962
|
+
prompt += `- ${name}: \`${script}\`
|
|
16963
|
+
`;
|
|
16964
|
+
}
|
|
16965
|
+
prompt += "\n";
|
|
16966
|
+
}
|
|
16093
16967
|
}
|
|
16094
|
-
if (context.
|
|
16095
|
-
prompt += "##
|
|
16096
|
-
|
|
16097
|
-
prompt += `- ${
|
|
16968
|
+
if (context.guardrails && context.guardrails.length > 0) {
|
|
16969
|
+
prompt += "## CRITICAL RULES (NEVER VIOLATE):\n\n";
|
|
16970
|
+
for (const rule of context.guardrails) {
|
|
16971
|
+
prompt += `- ${rule}
|
|
16098
16972
|
`;
|
|
16099
|
-
}
|
|
16973
|
+
}
|
|
16100
16974
|
prompt += "\n";
|
|
16101
16975
|
}
|
|
16102
|
-
if (context.
|
|
16103
|
-
|
|
16104
|
-
const contextToAdd = context.markdown.length > MAX_PROMPT_LENGTH ? context.markdown.substring(0, MAX_PROMPT_LENGTH) + "\n\n[... context truncated for length ...]" : context.markdown;
|
|
16105
|
-
prompt += "## Full Project Context:\n\n";
|
|
16106
|
-
prompt += contextToAdd;
|
|
16107
|
-
prompt += "\n";
|
|
16976
|
+
if (context.isStale) {
|
|
16977
|
+
prompt += "\u26A0\uFE0F **Note:** Project index is stale (>24h old). Run `ax init` to update.\n\n";
|
|
16108
16978
|
}
|
|
16109
16979
|
return prompt;
|
|
16110
16980
|
}
|
|
@@ -16528,10 +17398,10 @@ var ContextManager = class {
|
|
|
16528
17398
|
return provider;
|
|
16529
17399
|
}
|
|
16530
17400
|
/**
|
|
16531
|
-
* Load project context from
|
|
17401
|
+
* Load project context from ax.index.json (v12.9.0+)
|
|
16532
17402
|
*
|
|
16533
|
-
* Loads project-specific
|
|
16534
|
-
* Falls back gracefully if
|
|
17403
|
+
* Loads project-specific context from ax.index.json and CUSTOM.md.
|
|
17404
|
+
* Falls back gracefully if files don't exist.
|
|
16535
17405
|
*
|
|
16536
17406
|
* @param projectDir - Project root directory
|
|
16537
17407
|
* @returns Project context or null if not found
|
|
@@ -16544,15 +17414,15 @@ var ContextManager = class {
|
|
|
16544
17414
|
const loader = this.projectContextLoader;
|
|
16545
17415
|
const exists = await loader.exists();
|
|
16546
17416
|
if (!exists) {
|
|
16547
|
-
logger.debug("No
|
|
17417
|
+
logger.debug("No ax.index.json or CUSTOM.md found, skipping project context");
|
|
16548
17418
|
return null;
|
|
16549
17419
|
}
|
|
16550
17420
|
const context = await loader.load();
|
|
16551
|
-
logger.debug("Project context loaded
|
|
16552
|
-
|
|
16553
|
-
|
|
16554
|
-
|
|
16555
|
-
|
|
17421
|
+
logger.debug("Project context loaded", {
|
|
17422
|
+
hasIndex: !!context.index,
|
|
17423
|
+
hasCustomInstructions: !!context.customInstructions,
|
|
17424
|
+
guardrails: context.guardrails?.length ?? 0,
|
|
17425
|
+
isStale: context.isStale
|
|
16556
17426
|
});
|
|
16557
17427
|
return context;
|
|
16558
17428
|
} catch (error) {
|
|
@@ -16922,7 +17792,11 @@ var ProfileLoader = class {
|
|
|
16922
17792
|
continue;
|
|
16923
17793
|
}
|
|
16924
17794
|
const data = load(content);
|
|
16925
|
-
|
|
17795
|
+
if (data && typeof data === "object" && !Array.isArray(data) && "displayName" in data) {
|
|
17796
|
+
const profile = data;
|
|
17797
|
+
return profile.displayName ?? null;
|
|
17798
|
+
}
|
|
17799
|
+
return null;
|
|
16926
17800
|
} catch (error) {
|
|
16927
17801
|
if (error.code === "ENOENT") {
|
|
16928
17802
|
continue;
|
|
@@ -16951,7 +17825,7 @@ var ProfileLoader = class {
|
|
|
16951
17825
|
});
|
|
16952
17826
|
return identifier;
|
|
16953
17827
|
} catch (error) {
|
|
16954
|
-
if (error.name === "AgentNotFoundError") {
|
|
17828
|
+
if (error instanceof Error && error.name === "AgentNotFoundError") {
|
|
16955
17829
|
logger.debug("Direct profile load failed, trying displayName lookup", { identifier });
|
|
16956
17830
|
await this.buildDisplayNameMap();
|
|
16957
17831
|
const resolved = this.displayNameMap.get(identifier.toLowerCase());
|
|
@@ -17280,7 +18154,7 @@ var ProfileLoader = class {
|
|
|
17280
18154
|
if (typeof orch !== "object" || orch === null || Array.isArray(orch)) {
|
|
17281
18155
|
throw new AgentValidationError("orchestration must be an object");
|
|
17282
18156
|
}
|
|
17283
|
-
if (orch.canDelegate !== void 0) {
|
|
18157
|
+
if ("canDelegate" in orch && orch.canDelegate !== void 0) {
|
|
17284
18158
|
logger.warn("orchestration.canDelegate is deprecated and ignored (v4.9.0+). All agents can delegate by default.", {
|
|
17285
18159
|
agent: profile.name
|
|
17286
18160
|
});
|
|
@@ -17326,17 +18200,18 @@ var ProfileLoader = class {
|
|
|
17326
18200
|
if (!data || typeof data !== "object" || Array.isArray(data)) {
|
|
17327
18201
|
throw new AgentValidationError(`Invalid profile data for ${name}: expected object, got ${typeof data}`);
|
|
17328
18202
|
}
|
|
17329
|
-
|
|
17330
|
-
|
|
17331
|
-
|
|
17332
|
-
|
|
18203
|
+
const profileData = data;
|
|
18204
|
+
if (profileData.name && typeof profileData.name === "string") {
|
|
18205
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(profileData.name)) {
|
|
18206
|
+
if (!profileData.displayName) {
|
|
18207
|
+
profileData.displayName = profileData.name;
|
|
17333
18208
|
}
|
|
17334
|
-
|
|
18209
|
+
profileData.name = name;
|
|
17335
18210
|
}
|
|
17336
|
-
} else if (!
|
|
17337
|
-
|
|
18211
|
+
} else if (!profileData.name) {
|
|
18212
|
+
profileData.name = name;
|
|
17338
18213
|
}
|
|
17339
|
-
const validationResult = safeValidateAgentProfile(
|
|
18214
|
+
const validationResult = safeValidateAgentProfile(profileData);
|
|
17340
18215
|
if (!validationResult.success) {
|
|
17341
18216
|
const validationErrors = validationResult.error.issues.map(
|
|
17342
18217
|
(e) => `${e.path.join(".")}: ${e.message}`
|
|
@@ -17346,22 +18221,22 @@ var ProfileLoader = class {
|
|
|
17346
18221
|
);
|
|
17347
18222
|
}
|
|
17348
18223
|
let teamConfig;
|
|
17349
|
-
if (
|
|
18224
|
+
if (profileData.team && this.teamManager) {
|
|
17350
18225
|
try {
|
|
17351
|
-
teamConfig = await this.teamManager.loadTeam(
|
|
18226
|
+
teamConfig = await this.teamManager.loadTeam(profileData.team);
|
|
17352
18227
|
logger.debug("Team configuration loaded for agent", {
|
|
17353
18228
|
agent: name,
|
|
17354
|
-
team:
|
|
18229
|
+
team: profileData.team
|
|
17355
18230
|
});
|
|
17356
18231
|
} catch (error) {
|
|
17357
18232
|
logger.warn("Failed to load team configuration, using agent defaults", {
|
|
17358
18233
|
agent: name,
|
|
17359
|
-
team:
|
|
18234
|
+
team: profileData.team,
|
|
17360
18235
|
error: error.message
|
|
17361
18236
|
});
|
|
17362
18237
|
}
|
|
17363
18238
|
}
|
|
17364
|
-
const abilities =
|
|
18239
|
+
const abilities = profileData.abilities || [];
|
|
17365
18240
|
if (teamConfig?.sharedAbilities) {
|
|
17366
18241
|
const allAbilities = [.../* @__PURE__ */ new Set([...teamConfig.sharedAbilities, ...abilities])];
|
|
17367
18242
|
logger.debug("Merged abilities from team", {
|
|
@@ -17373,7 +18248,7 @@ var ProfileLoader = class {
|
|
|
17373
18248
|
});
|
|
17374
18249
|
abilities.splice(0, abilities.length, ...allAbilities);
|
|
17375
18250
|
}
|
|
17376
|
-
let orchestration =
|
|
18251
|
+
let orchestration = profileData.orchestration;
|
|
17377
18252
|
if (teamConfig?.orchestration && !orchestration) {
|
|
17378
18253
|
orchestration = teamConfig.orchestration;
|
|
17379
18254
|
logger.debug("Using team orchestration defaults", {
|
|
@@ -17382,32 +18257,32 @@ var ProfileLoader = class {
|
|
|
17382
18257
|
});
|
|
17383
18258
|
}
|
|
17384
18259
|
const profile = {
|
|
17385
|
-
name:
|
|
17386
|
-
displayName:
|
|
17387
|
-
role:
|
|
17388
|
-
description:
|
|
18260
|
+
name: profileData.name || name,
|
|
18261
|
+
displayName: profileData.displayName,
|
|
18262
|
+
role: profileData.role,
|
|
18263
|
+
description: profileData.description,
|
|
17389
18264
|
// v4.10.0+: Team field
|
|
17390
|
-
team:
|
|
17391
|
-
systemPrompt:
|
|
18265
|
+
team: profileData.team,
|
|
18266
|
+
systemPrompt: profileData.systemPrompt,
|
|
17392
18267
|
abilities,
|
|
17393
|
-
dependencies:
|
|
17394
|
-
parallel:
|
|
18268
|
+
dependencies: profileData.dependencies,
|
|
18269
|
+
parallel: profileData.parallel,
|
|
17395
18270
|
// Enhanced v4.1+ features
|
|
17396
|
-
stages:
|
|
17397
|
-
personality:
|
|
17398
|
-
thinking_patterns:
|
|
17399
|
-
abilitySelection:
|
|
18271
|
+
stages: profileData.stages,
|
|
18272
|
+
personality: profileData.personality,
|
|
18273
|
+
thinking_patterns: profileData.thinking_patterns,
|
|
18274
|
+
abilitySelection: profileData.abilitySelection,
|
|
17400
18275
|
// v5.7.0+: Agent Selection Metadata
|
|
17401
|
-
selectionMetadata:
|
|
18276
|
+
selectionMetadata: profileData.selectionMetadata,
|
|
17402
18277
|
// Provider preferences (deprecated, kept for backward compatibility)
|
|
17403
|
-
provider:
|
|
17404
|
-
model:
|
|
17405
|
-
temperature:
|
|
17406
|
-
maxTokens:
|
|
18278
|
+
provider: profileData.provider,
|
|
18279
|
+
model: profileData.model,
|
|
18280
|
+
temperature: profileData.temperature,
|
|
18281
|
+
maxTokens: profileData.maxTokens,
|
|
17407
18282
|
// Optional
|
|
17408
|
-
tags:
|
|
17409
|
-
version:
|
|
17410
|
-
metadata:
|
|
18283
|
+
tags: profileData.tags,
|
|
18284
|
+
version: profileData.version,
|
|
18285
|
+
metadata: profileData.metadata,
|
|
17411
18286
|
// v4.7.0+ Orchestration (merged with team defaults)
|
|
17412
18287
|
orchestration
|
|
17413
18288
|
};
|
|
@@ -20579,6 +21454,24 @@ ${context.task}`;
|
|
|
20579
21454
|
// src/agents/agent-selector.ts
|
|
20580
21455
|
init_esm_shims();
|
|
20581
21456
|
init_logger();
|
|
21457
|
+
var regexCache = /* @__PURE__ */ new Map();
|
|
21458
|
+
function getCachedRegex(pattern) {
|
|
21459
|
+
if (regexCache.has(pattern)) {
|
|
21460
|
+
return regexCache.get(pattern) ?? null;
|
|
21461
|
+
}
|
|
21462
|
+
try {
|
|
21463
|
+
const regex = new RegExp(pattern, "i");
|
|
21464
|
+
regexCache.set(pattern, regex);
|
|
21465
|
+
return regex;
|
|
21466
|
+
} catch (error) {
|
|
21467
|
+
logger.debug("Invalid regex pattern cached as null", {
|
|
21468
|
+
pattern,
|
|
21469
|
+
error: error instanceof Error ? error.message : String(error)
|
|
21470
|
+
});
|
|
21471
|
+
regexCache.set(pattern, null);
|
|
21472
|
+
return null;
|
|
21473
|
+
}
|
|
21474
|
+
}
|
|
20582
21475
|
function scoreAgent(task, profile) {
|
|
20583
21476
|
let score = 0;
|
|
20584
21477
|
const taskLower = task.toLowerCase();
|
|
@@ -20616,16 +21509,9 @@ function scoreAgent(task, profile) {
|
|
|
20616
21509
|
}
|
|
20617
21510
|
if (profile.selectionMetadata?.redirectWhen) {
|
|
20618
21511
|
for (const rule of profile.selectionMetadata.redirectWhen) {
|
|
20619
|
-
|
|
20620
|
-
|
|
20621
|
-
|
|
20622
|
-
score -= 15;
|
|
20623
|
-
}
|
|
20624
|
-
} catch (error) {
|
|
20625
|
-
logger.debug("Invalid regex pattern in redirectWhen rule", {
|
|
20626
|
-
pattern: rule.phrase,
|
|
20627
|
-
error: error instanceof Error ? error.message : String(error)
|
|
20628
|
-
});
|
|
21512
|
+
const regex = getCachedRegex(rule.phrase);
|
|
21513
|
+
if (regex && regex.test(task)) {
|
|
21514
|
+
score -= 15;
|
|
20629
21515
|
}
|
|
20630
21516
|
}
|
|
20631
21517
|
}
|
|
@@ -22983,7 +23869,7 @@ var BugDetector = class {
|
|
|
22983
23869
|
});
|
|
22984
23870
|
let files;
|
|
22985
23871
|
if (fileFilter && fileFilter.length > 0) {
|
|
22986
|
-
files = fileFilter.map((f) => f
|
|
23872
|
+
files = fileFilter.map((f) => isAbsolute(f) ? f : join(rootDir, f)).filter((f) => {
|
|
22987
23873
|
const ext = extname$1(f);
|
|
22988
23874
|
return [".ts", ".js", ".mts", ".mjs", ".tsx", ".jsx"].includes(ext);
|
|
22989
23875
|
}).filter((f) => !this.isExcluded(relative(rootDir, f)));
|
|
@@ -23215,8 +24101,8 @@ var BugDetector = class {
|
|
|
23215
24101
|
async loadRulesFromFile(filePath) {
|
|
23216
24102
|
try {
|
|
23217
24103
|
const content = await readFile(filePath, "utf-8");
|
|
23218
|
-
const
|
|
23219
|
-
const parsed =
|
|
24104
|
+
const yaml = await import('js-yaml');
|
|
24105
|
+
const parsed = yaml.load(content);
|
|
23220
24106
|
if (parsed.rules && Array.isArray(parsed.rules)) {
|
|
23221
24107
|
for (const rule of parsed.rules) {
|
|
23222
24108
|
this.addRule(rule);
|
|
@@ -23648,7 +24534,6 @@ var BugFixer = class {
|
|
|
23648
24534
|
}
|
|
23649
24535
|
const directSetIntervalPattern = /setInterval\s*\(/;
|
|
23650
24536
|
if (directSetIntervalPattern.test(line)) {
|
|
23651
|
-
line.match(/^(\s*)/)?.[1] || "";
|
|
23652
24537
|
const newLine = line.replace(
|
|
23653
24538
|
/(setInterval\s*\([^)]+\))/,
|
|
23654
24539
|
"const _interval = $1; if (_interval.unref) _interval.unref()"
|
|
@@ -23675,7 +24560,6 @@ var BugFixer = class {
|
|
|
23675
24560
|
const match = currentLine.match(classPattern);
|
|
23676
24561
|
if (match && match[1]) {
|
|
23677
24562
|
classStartLine = i;
|
|
23678
|
-
match[1];
|
|
23679
24563
|
break;
|
|
23680
24564
|
}
|
|
23681
24565
|
}
|
|
@@ -23727,7 +24611,7 @@ var BugFixer = class {
|
|
|
23727
24611
|
/**
|
|
23728
24612
|
* Apply use DisposableEventEmitter fix
|
|
23729
24613
|
*/
|
|
23730
|
-
applyUseDisposableEventEmitterFix(finding, originalContent,
|
|
24614
|
+
applyUseDisposableEventEmitterFix(finding, originalContent, _lines) {
|
|
23731
24615
|
let fixedContent = originalContent.replace(
|
|
23732
24616
|
/extends\s+EventEmitter\b/g,
|
|
23733
24617
|
"extends DisposableEventEmitter"
|
|
@@ -24649,7 +25533,7 @@ var DUPLICATION_RULES = [
|
|
|
24649
25533
|
suggestion: "Extract to a named constant"
|
|
24650
25534
|
}
|
|
24651
25535
|
];
|
|
24652
|
-
function detectDuplication(filePath, content, lines, ignoreState,
|
|
25536
|
+
function detectDuplication(filePath, content, lines, ignoreState, _config) {
|
|
24653
25537
|
const findings = [];
|
|
24654
25538
|
findings.push(...detectDuplicateBlocks(filePath, content, lines, ignoreState));
|
|
24655
25539
|
findings.push(...detectRepeatedConditionals(filePath, content, lines, ignoreState));
|
|
@@ -24676,7 +25560,7 @@ function detectDuplicateBlocks(filePath, content, lines, ignoreState) {
|
|
|
24676
25560
|
}
|
|
24677
25561
|
blockHashes.get(blockHash).push({ start: i + 1, end: i + MIN_BLOCK_SIZE });
|
|
24678
25562
|
}
|
|
24679
|
-
for (const [
|
|
25563
|
+
for (const [_hash, locations] of blockHashes) {
|
|
24680
25564
|
if (locations.length > 1) {
|
|
24681
25565
|
for (let i = 1; i < locations.length; i++) {
|
|
24682
25566
|
const loc = locations[i];
|
|
@@ -24725,7 +25609,7 @@ function detectRepeatedConditionals(filePath, content, lines, ignoreState) {
|
|
|
24725
25609
|
}
|
|
24726
25610
|
conditionPattern.lastIndex = 0;
|
|
24727
25611
|
}
|
|
24728
|
-
for (const [
|
|
25612
|
+
for (const [_condition, lineNums] of conditionalCounts) {
|
|
24729
25613
|
if (lineNums.length >= 2) {
|
|
24730
25614
|
const firstLine = lineNums[0];
|
|
24731
25615
|
const secondLine = lineNums[1];
|
|
@@ -24888,7 +25772,7 @@ var THRESHOLDS = {
|
|
|
24888
25772
|
maxCyclomaticComplexity: 10,
|
|
24889
25773
|
maxChainedCalls: 4
|
|
24890
25774
|
};
|
|
24891
|
-
function detectReadability(filePath, content, lines, ignoreState,
|
|
25775
|
+
function detectReadability(filePath, content, lines, ignoreState, _config) {
|
|
24892
25776
|
const findings = [];
|
|
24893
25777
|
findings.push(...detectLongFunctions(filePath, content, lines, ignoreState));
|
|
24894
25778
|
findings.push(...detectDeepNesting(filePath, content, lines, ignoreState));
|
|
@@ -25264,7 +26148,7 @@ var PERFORMANCE_RULES = [
|
|
|
25264
26148
|
suggestion: "Remove await - async functions automatically wrap return values in promises"
|
|
25265
26149
|
}
|
|
25266
26150
|
];
|
|
25267
|
-
function detectPerformance(filePath, content, lines, ignoreState,
|
|
26151
|
+
function detectPerformance(filePath, content, lines, ignoreState, _config) {
|
|
25268
26152
|
const findings = [];
|
|
25269
26153
|
findings.push(...detectSyncInAsync(filePath, content, lines, ignoreState));
|
|
25270
26154
|
findings.push(...detectNPlusOne(filePath, content, lines, ignoreState));
|
|
@@ -25679,7 +26563,7 @@ var HARDCODE_RULES = [
|
|
|
25679
26563
|
suggestion: "Extract timeout to a named constant or config"
|
|
25680
26564
|
}
|
|
25681
26565
|
];
|
|
25682
|
-
function detectHardcode(filePath, content, lines, ignoreState,
|
|
26566
|
+
function detectHardcode(filePath, content, lines, ignoreState, _config) {
|
|
25683
26567
|
const findings = [];
|
|
25684
26568
|
findings.push(...detectMagicNumbers(filePath, content, lines, ignoreState));
|
|
25685
26569
|
findings.push(...detectHardcodedUrls(filePath, content, lines, ignoreState));
|
|
@@ -26035,7 +26919,7 @@ var NAMING_RULES = [
|
|
|
26035
26919
|
suggestion: "Use is/has/can/should prefix for boolean variables"
|
|
26036
26920
|
}
|
|
26037
26921
|
];
|
|
26038
|
-
function detectNaming(filePath, content, lines, ignoreState,
|
|
26922
|
+
function detectNaming(filePath, content, lines, ignoreState, _config) {
|
|
26039
26923
|
const findings = [];
|
|
26040
26924
|
findings.push(...detectSingleLetterVariables(filePath, content, lines, ignoreState));
|
|
26041
26925
|
findings.push(...detectHungarianNotation(filePath, content, lines, ignoreState));
|
|
@@ -26318,7 +27202,7 @@ var CONDITIONAL_RULES = [
|
|
|
26318
27202
|
suggestion: "Use the condition directly (or negate it)"
|
|
26319
27203
|
}
|
|
26320
27204
|
];
|
|
26321
|
-
function detectConditionals(filePath, content, lines, ignoreState,
|
|
27205
|
+
function detectConditionals(filePath, content, lines, ignoreState, _config) {
|
|
26322
27206
|
const findings = [];
|
|
26323
27207
|
findings.push(...detectDeeplyNestedIf(filePath, content, lines, ignoreState));
|
|
26324
27208
|
findings.push(...detectComplexConditions(filePath, content, lines, ignoreState));
|
|
@@ -26631,7 +27515,7 @@ var DEAD_CODE_RULES = [
|
|
|
26631
27515
|
suggestion: "Implement function or add TODO comment"
|
|
26632
27516
|
}
|
|
26633
27517
|
];
|
|
26634
|
-
function detectDeadCode(filePath, content, lines, ignoreState,
|
|
27518
|
+
function detectDeadCode(filePath, content, lines, ignoreState, _config) {
|
|
26635
27519
|
const findings = [];
|
|
26636
27520
|
findings.push(...detectUnusedImports(filePath, content, lines, ignoreState));
|
|
26637
27521
|
findings.push(...detectUnusedVariables(filePath, content, lines, ignoreState));
|
|
@@ -26925,7 +27809,7 @@ var TYPE_SAFETY_RULES = [
|
|
|
26925
27809
|
fileExtensions: [".ts", ".tsx"]
|
|
26926
27810
|
}
|
|
26927
27811
|
];
|
|
26928
|
-
function detectTypeSafety(filePath, content, lines, ignoreState,
|
|
27812
|
+
function detectTypeSafety(filePath, content, lines, ignoreState, _config) {
|
|
26929
27813
|
const findings = [];
|
|
26930
27814
|
if (!filePath.endsWith(".ts") && !filePath.endsWith(".tsx")) {
|
|
26931
27815
|
return findings;
|
|
@@ -27531,6 +28415,9 @@ function countAnyTypes(code) {
|
|
|
27531
28415
|
}
|
|
27532
28416
|
return count;
|
|
27533
28417
|
}
|
|
28418
|
+
function escapeRegex2(str) {
|
|
28419
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
28420
|
+
}
|
|
27534
28421
|
function countUnusedImports(code) {
|
|
27535
28422
|
const importMatches = code.match(/import\s+{([^}]+)}\s+from/g);
|
|
27536
28423
|
if (!importMatches) return 0;
|
|
@@ -27540,10 +28427,17 @@ function countUnusedImports(code) {
|
|
|
27540
28427
|
const namedImports = importMatch.match(/{([^}]+)}/);
|
|
27541
28428
|
const namedImportContent = namedImports?.[1];
|
|
27542
28429
|
if (namedImportContent) {
|
|
27543
|
-
const names = namedImportContent.split(",").map((n) =>
|
|
28430
|
+
const names = namedImportContent.split(",").map((n) => {
|
|
28431
|
+
const trimmed = n.trim();
|
|
28432
|
+
const withoutType = trimmed.replace(/^type\s+/, "");
|
|
28433
|
+
return withoutType.split(/\s+as\s+/).pop()?.trim() ?? "";
|
|
28434
|
+
}).filter((name) => name.length > 0 && /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name));
|
|
27544
28435
|
for (const name of names) {
|
|
27545
|
-
|
|
27546
|
-
|
|
28436
|
+
try {
|
|
28437
|
+
if (!new RegExp(`\\b${escapeRegex2(name)}\\b`).test(codeWithoutImports)) {
|
|
28438
|
+
unusedCount++;
|
|
28439
|
+
}
|
|
28440
|
+
} catch {
|
|
27547
28441
|
}
|
|
27548
28442
|
}
|
|
27549
28443
|
}
|
|
@@ -30999,6 +31893,7 @@ init_logger();
|
|
|
30999
31893
|
// src/core/task-engine/task-queue.ts
|
|
31000
31894
|
init_esm_shims();
|
|
31001
31895
|
init_logger();
|
|
31896
|
+
init_safe_timers();
|
|
31002
31897
|
|
|
31003
31898
|
// src/mcp/tools/task/create-task.ts
|
|
31004
31899
|
init_logger();
|
|
@@ -31123,7 +32018,7 @@ var createTaskSchema = {
|
|
|
31123
32018
|
// src/mcp/tools/task/run-task.ts
|
|
31124
32019
|
init_esm_shims();
|
|
31125
32020
|
init_logger();
|
|
31126
|
-
function createRunTaskHandler(
|
|
32021
|
+
function createRunTaskHandler(_deps) {
|
|
31127
32022
|
return async (input, context) => {
|
|
31128
32023
|
const startTime = Date.now();
|
|
31129
32024
|
if (context?.signal?.aborted) {
|
|
@@ -33673,6 +34568,17 @@ Use this tool first to understand what AutomatosX offers.`,
|
|
|
33673
34568
|
mode: "sdk"
|
|
33674
34569
|
}));
|
|
33675
34570
|
}
|
|
34571
|
+
if (config.providers["qwen"]?.enabled) {
|
|
34572
|
+
const { QwenProvider: QwenProvider2 } = await Promise.resolve().then(() => (init_qwen_provider(), qwen_provider_exports));
|
|
34573
|
+
const qwenConfig = config.providers["qwen"];
|
|
34574
|
+
providers.push(new QwenProvider2({
|
|
34575
|
+
name: "qwen",
|
|
34576
|
+
enabled: true,
|
|
34577
|
+
priority: qwenConfig.priority,
|
|
34578
|
+
timeout: qwenConfig.timeout,
|
|
34579
|
+
mode: qwenConfig.mode || "sdk"
|
|
34580
|
+
}));
|
|
34581
|
+
}
|
|
33676
34582
|
const healthCheckInterval = config.router?.healthCheckInterval;
|
|
33677
34583
|
this.router = new Router({
|
|
33678
34584
|
providers,
|