@defai.digital/automatosx 12.6.2 → 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/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;
@@ -2492,6 +2491,7 @@ function getRetryableErrors(provider) {
2492
2491
  return [...baseErrors, ...CODEX_RETRYABLE_ERRORS];
2493
2492
  case "glm":
2494
2493
  case "grok":
2494
+ case "qwen":
2495
2495
  return [...baseErrors, ...OPENAI_RETRYABLE_ERRORS];
2496
2496
  case "base":
2497
2497
  default:
@@ -2594,6 +2594,10 @@ var init_base_provider = __esm({
2594
2594
  // v12.0.0: Native Grok provider (xAI)
2595
2595
  "ax-grok",
2596
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
2597
2601
  "test-provider"
2598
2602
  // For unit tests
2599
2603
  ];
@@ -2956,7 +2960,7 @@ var init_base_provider = __esm({
2956
2960
  if (readlineInterface) {
2957
2961
  try {
2958
2962
  readlineInterface.close();
2959
- } catch (error) {
2963
+ } catch {
2960
2964
  } finally {
2961
2965
  readlineInterface = null;
2962
2966
  }
@@ -2964,7 +2968,7 @@ var init_base_provider = __esm({
2964
2968
  if (stderrInterface) {
2965
2969
  try {
2966
2970
  stderrInterface.close();
2967
- } catch (error) {
2971
+ } catch {
2968
2972
  } finally {
2969
2973
  stderrInterface = null;
2970
2974
  }
@@ -3158,7 +3162,7 @@ ${fullPrompt}
3158
3162
  this.health.consecutiveSuccesses = 0;
3159
3163
  }
3160
3164
  return available;
3161
- } catch (error) {
3165
+ } catch {
3162
3166
  this.health.available = false;
3163
3167
  this.health.errorRate = 1;
3164
3168
  this.health.lastCheck = Date.now();
@@ -3334,6 +3338,8 @@ ${fullPrompt}
3334
3338
  retryableProvider = "glm";
3335
3339
  } else if (providerName === "grok" || providerName === "ax-grok") {
3336
3340
  retryableProvider = "grok";
3341
+ } else if (providerName === "qwen" || providerName === "qwen-code") {
3342
+ retryableProvider = "qwen";
3337
3343
  }
3338
3344
  return shouldRetryError(error, retryableProvider);
3339
3345
  }
@@ -5788,13 +5794,21 @@ var init_types2 = __esm({
5788
5794
  "src/integrations/ax-glm/types.ts"() {
5789
5795
  init_esm_shims();
5790
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)
5791
5803
  "glm-4-plus": "glm-4.6",
5792
- "glm-4v": "glm-4.5v",
5804
+ "glm-4.5v": "glm-4.6v",
5805
+ "glm-4v": "glm-4.6v",
5806
+ "glm-4": "glm-4.6",
5793
5807
  "glm-4-air": "glm-4-flash",
5794
5808
  "glm-4-airx": "glm-4-flash"
5795
5809
  };
5796
5810
  GLM_DEFAULT_BASE_URL = "https://open.bigmodel.cn/api/paas/v4";
5797
- GLM_DEFAULT_MODEL = "glm-4";
5811
+ GLM_DEFAULT_MODEL = "glm-4.6";
5798
5812
  GLM_DEFAULT_COMMAND = "ax-glm";
5799
5813
  }
5800
5814
  });
@@ -6743,10 +6757,18 @@ var init_types3 = __esm({
6743
6757
  "src/integrations/ax-grok/types.ts"() {
6744
6758
  init_esm_shims();
6745
6759
  GROK_MODEL_MAPPING = {
6746
- "grok-beta": "grok-3"
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"
6747
6769
  };
6748
6770
  GROK_DEFAULT_BASE_URL = "https://api.x.ai/v1";
6749
- GROK_DEFAULT_MODEL = "grok-3";
6771
+ GROK_DEFAULT_MODEL = "grok-4-0709";
6750
6772
  GROK_DEFAULT_COMMAND = "ax-grok";
6751
6773
  }
6752
6774
  });
@@ -7678,6 +7700,902 @@ Mode: ${this.grokConfig.mode || "auto"}`;
7678
7700
  }
7679
7701
  });
7680
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
+
7681
8599
  // src/mcp/index.ts
7682
8600
  init_esm_shims();
7683
8601
 
@@ -8130,12 +9048,16 @@ init_logger();
8130
9048
 
8131
9049
  // src/shared/helpers/deep-merge.ts
8132
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
+ }
8133
9054
  function deepMerge(defaults, user) {
8134
9055
  if (user === null || user === void 0) {
8135
- return defaults;
9056
+ return { ...defaults };
8136
9057
  }
8137
- const result = { ...defaults };
8138
- for (const key in user) {
9058
+ const result = Object.assign({}, defaults);
9059
+ const userKeys = Object.keys(user);
9060
+ for (const key of userKeys) {
8139
9061
  const userValue = user[key];
8140
9062
  if (userValue === null) {
8141
9063
  result[key] = void 0;
@@ -8145,8 +9067,11 @@ function deepMerge(defaults, user) {
8145
9067
  continue;
8146
9068
  }
8147
9069
  const defaultValue = defaults[key];
8148
- if (typeof userValue === "object" && typeof defaultValue === "object" && !Array.isArray(userValue) && !Array.isArray(defaultValue) && userValue !== null && defaultValue !== null) {
8149
- result[key] = deepMerge(defaultValue, userValue);
9070
+ if (isPlainObject(userValue) && isPlainObject(defaultValue)) {
9071
+ result[key] = deepMerge(
9072
+ defaultValue,
9073
+ userValue
9074
+ );
8150
9075
  } else {
8151
9076
  result[key] = userValue;
8152
9077
  }
@@ -8788,7 +9713,7 @@ var PRECOMPILED_CONFIG = {
8788
9713
  "enableFreeTierPrioritization": true,
8789
9714
  "enableWorkloadAwareRouting": true
8790
9715
  },
8791
- "version": "12.6.1"
9716
+ "version": "12.6.3"
8792
9717
  };
8793
9718
 
8794
9719
  // src/core/config/schemas.ts
@@ -13211,7 +14136,7 @@ var MemoryManager = class _MemoryManager {
13211
14136
  if (this.db) {
13212
14137
  try {
13213
14138
  this.db.close();
13214
- } catch (closeError) {
14139
+ } catch {
13215
14140
  }
13216
14141
  this.initialized = false;
13217
14142
  this.entryCount = 0;
@@ -14052,9 +14977,9 @@ var MemoryManager = class _MemoryManager {
14052
14977
  }
14053
14978
  }
14054
14979
  const {
14055
- includeEmbeddings = false,
14980
+ includeEmbeddings: _includeEmbeddings = false,
14056
14981
  filters = {},
14057
- batchSize = 1e3,
14982
+ batchSize: _batchSize = 1e3,
14058
14983
  pretty = false
14059
14984
  } = options || {};
14060
14985
  try {
@@ -15211,7 +16136,7 @@ var SessionManager = class _SessionManager {
15211
16136
  if (this.pendingSave) {
15212
16137
  try {
15213
16138
  await this.pendingSave;
15214
- } catch (err) {
16139
+ } catch {
15215
16140
  }
15216
16141
  }
15217
16142
  this.pendingSave = this.doSave().finally(() => {
@@ -15279,7 +16204,7 @@ var SessionManager = class _SessionManager {
15279
16204
  }
15280
16205
  try {
15281
16206
  await unlink(tempPath);
15282
- } catch (unlinkError) {
16207
+ } catch {
15283
16208
  }
15284
16209
  throw renameError;
15285
16210
  }
@@ -15287,7 +16212,7 @@ var SessionManager = class _SessionManager {
15287
16212
  const tempPath = `${this.persistencePath}.tmp`;
15288
16213
  try {
15289
16214
  await unlink(tempPath);
15290
- } catch (unlinkError) {
16215
+ } catch {
15291
16216
  }
15292
16217
  logger.error("Failed to save sessions to persistence", {
15293
16218
  path: normalizePath(this.persistencePath),
@@ -15825,6 +16750,7 @@ init_esm_shims();
15825
16750
  init_logger();
15826
16751
  var MAX_CONTEXT_SIZE = 100 * 1024;
15827
16752
  var DEFAULT_CACHE_TTL = 3e5;
16753
+ var STALE_THRESHOLD_MS = 24 * 60 * 60 * 1e3;
15828
16754
  var ProjectContextLoader = class {
15829
16755
  constructor(projectRoot, options) {
15830
16756
  this.projectRoot = projectRoot;
@@ -15848,76 +16774,79 @@ var ProjectContextLoader = class {
15848
16774
  });
15849
16775
  const context = {};
15850
16776
  try {
15851
- const mdPath = path4__default.join(this.projectRoot, "AX.md");
15852
- const resolvedPath = await realpath(mdPath).catch(() => null);
16777
+ const indexPath = path4__default.join(this.projectRoot, "ax.index.json");
16778
+ const resolvedPath = await realpath(indexPath).catch(() => null);
15853
16779
  if (resolvedPath) {
15854
16780
  const rel = path4__default.relative(this.projectRoot, resolvedPath);
15855
16781
  if (!rel.startsWith("..") && !path4__default.isAbsolute(rel)) {
15856
16782
  const stats = await stat(resolvedPath);
15857
16783
  if (stats.size > MAX_CONTEXT_SIZE) {
15858
- logger.warn("AX.md too large, ignoring", {
16784
+ logger.warn("ax.index.json too large, ignoring", {
15859
16785
  size: stats.size,
15860
16786
  limit: MAX_CONTEXT_SIZE
15861
16787
  });
15862
16788
  } else {
15863
- context.markdown = await readFile(resolvedPath, "utf-8");
15864
- logger.info("Loaded AX.md", {
15865
- size: stats.size,
15866
- lines: context.markdown.split("\n").length
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))
15867
16799
  });
15868
- context.agentRules = this.parseAgentRules(context.markdown);
15869
- context.guardrails = this.parseGuardrails(context.markdown);
15870
- context.commands = this.parseCommands(context.markdown);
15871
- context.metadata = this.parseMetadata(context.markdown);
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
+ }
15872
16806
  }
15873
16807
  }
15874
16808
  }
15875
16809
  } catch (error) {
15876
16810
  if (error && typeof error === "object" && "code" in error && error.code !== "ENOENT") {
15877
- logger.warn("Error loading AX.md", { error });
16811
+ logger.warn("Error loading ax.index.json", { error });
15878
16812
  }
15879
16813
  }
15880
16814
  try {
15881
- const ymlPath = path4__default.join(this.projectRoot, "ax.config.yml");
15882
- const resolvedPath = await realpath(ymlPath).catch(() => null);
16815
+ const customMdPath = path4__default.join(this.projectRoot, ".automatosx", "CUSTOM.md");
16816
+ const resolvedPath = await realpath(customMdPath).catch(() => null);
15883
16817
  if (resolvedPath) {
15884
16818
  const rel = path4__default.relative(this.projectRoot, resolvedPath);
15885
16819
  if (!rel.startsWith("..") && !path4__default.isAbsolute(rel)) {
15886
16820
  const stats = await stat(resolvedPath);
15887
16821
  if (stats.size > MAX_CONTEXT_SIZE) {
15888
- logger.warn("ax.config.yml too large, ignoring", {
16822
+ logger.warn("CUSTOM.md too large, ignoring", {
15889
16823
  size: stats.size,
15890
16824
  limit: MAX_CONTEXT_SIZE
15891
16825
  });
15892
16826
  } else {
15893
- const ymlContent = await readFile(resolvedPath, "utf-8");
15894
- context.config = yaml.parse(ymlContent);
15895
- logger.info("Loaded ax.config.yml", {
15896
- size: stats.size
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
15897
16831
  });
15898
- if (context.config.commands) {
15899
- context.commands = { ...context.commands, ...context.config.commands };
15900
- }
15901
- if (context.config.project) {
15902
- context.metadata = { ...context.metadata, ...context.config.project };
15903
- }
16832
+ context.guardrails = this.parseGuardrails(context.customInstructions);
15904
16833
  }
15905
16834
  }
15906
16835
  }
15907
16836
  } catch (error) {
15908
16837
  if (error && typeof error === "object" && "code" in error && error.code !== "ENOENT") {
15909
- logger.warn("Error loading ax.config.yml", { error });
16838
+ logger.warn("Error loading CUSTOM.md", { error });
15910
16839
  }
15911
16840
  }
15912
16841
  context.contextPrompt = this.buildContextPrompt(context);
15913
16842
  this.cache = context;
15914
16843
  this.cacheExpiry = Date.now() + this.cacheTTL;
15915
16844
  logger.info("Project context loaded", {
15916
- hasMarkdown: !!context.markdown,
15917
- hasConfig: !!context.config,
15918
- agentRules: context.agentRules?.length ?? 0,
16845
+ hasIndex: !!context.index,
16846
+ hasCustomInstructions: !!context.customInstructions,
15919
16847
  guardrails: context.guardrails?.length ?? 0,
15920
- commands: Object.keys(context.commands ?? {}).length
16848
+ commands: Object.keys(context.commands ?? {}).length,
16849
+ isStale: context.isStale
15921
16850
  });
15922
16851
  return context;
15923
16852
  }
@@ -15933,8 +16862,8 @@ var ProjectContextLoader = class {
15933
16862
  * Check if context exists (without loading)
15934
16863
  */
15935
16864
  async exists() {
15936
- const mdPath = path4__default.join(this.projectRoot, "AX.md");
15937
- const ymlPath = path4__default.join(this.projectRoot, "ax.config.yml");
16865
+ const indexPath = path4__default.join(this.projectRoot, "ax.index.json");
16866
+ const customMdPath = path4__default.join(this.projectRoot, ".automatosx", "CUSTOM.md");
15938
16867
  const checkExists = async (filePath) => {
15939
16868
  try {
15940
16869
  await access(filePath, constants.F_OK);
@@ -15943,57 +16872,48 @@ var ProjectContextLoader = class {
15943
16872
  return false;
15944
16873
  }
15945
16874
  };
15946
- const [mdExists, ymlExists] = await Promise.all([
15947
- checkExists(mdPath),
15948
- checkExists(ymlPath)
16875
+ const [indexExists, customMdExists] = await Promise.all([
16876
+ checkExists(indexPath),
16877
+ checkExists(customMdPath)
15949
16878
  ]);
15950
- return mdExists || ymlExists;
16879
+ return indexExists || customMdExists;
15951
16880
  }
15952
16881
  /**
15953
- * Parse agent delegation rules from markdown
15954
- *
15955
- * Looks for patterns like:
15956
- * - Backend changes → @backend
15957
- * - API endpoints → @backend, @security
15958
- */
15959
- parseAgentRules(markdown) {
15960
- const rules = [];
15961
- const sectionRegex = /##\s+Agent\s+Delegation\s+Rules[^\n]*\n([\s\S]*?)(?=\n##|$)/i;
15962
- const match = markdown.match(sectionRegex);
15963
- if (!match || !match[1]) {
15964
- return rules;
15965
- }
15966
- const section = match[1];
15967
- const lineRegex = /^[-*]\s+(.+?)\s+(?:→|->)+\s+(.+?)$/gm;
15968
- let lineMatch;
15969
- while ((lineMatch = lineRegex.exec(section)) !== null) {
15970
- const taskType = lineMatch[1]?.trim() ?? "";
15971
- const agentsText = lineMatch[2]?.trim() ?? "";
15972
- const agents = agentsText.split(",").map((a) => a.trim()).filter(Boolean);
15973
- const defaultAgent = agents[0];
15974
- if (defaultAgent) {
15975
- rules.push({
15976
- taskType,
15977
- patterns: [],
15978
- // TODO: Parse file patterns if specified
15979
- defaultAgent,
15980
- autoReview: agents.length > 1
15981
- });
15982
- }
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;
15983
16892
  }
15984
- return rules;
15985
16893
  }
15986
16894
  /**
15987
- * Parse guardrails/prohibitions from markdown
16895
+ * Parse guardrails from CUSTOM.md
15988
16896
  *
15989
- * Looks for "## Critical Guardrails" or "## Critical Rules" section
15990
- * Extracts items marked with ⚠️ or under NEVER headings
16897
+ * Looks for DO/DON'T sections in ax-cli format
15991
16898
  */
15992
16899
  parseGuardrails(markdown) {
15993
16900
  const guardrails = [];
15994
- const sectionRegex = /##\s+(Critical\s+Guardrails|Critical\s+Rules|Never)[^\n]*\n([\s\S]*?)(?=\n##|$)/gi;
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;
15995
16915
  let match;
15996
- while ((match = sectionRegex.exec(markdown)) !== null) {
16916
+ while ((match = criticalRegex.exec(markdown)) !== null) {
15997
16917
  const section = match[2];
15998
16918
  if (!section) continue;
15999
16919
  const bulletRegex = /^[-*]\s+(.+?)$/gm;
@@ -16003,106 +16923,58 @@ var ProjectContextLoader = class {
16003
16923
  rule = rule.replace(/^[⚠️❌✅✓⚡🔒]+\s*/, "");
16004
16924
  rule = rule.replace(/\*\*(.+?)\*\*/g, "$1");
16005
16925
  rule = rule.replace(/`(.+?)`/g, "$1");
16006
- if (rule.length > 0) {
16926
+ if (rule.length > 0 && !guardrails.includes(rule)) {
16007
16927
  guardrails.push(rule);
16008
16928
  }
16009
16929
  }
16010
16930
  }
16011
16931
  return guardrails;
16012
16932
  }
16013
- /**
16014
- * Parse commands from markdown code blocks
16015
- *
16016
- * Looks for "## Commands" or "## Canonical Commands" section
16017
- */
16018
- parseCommands(markdown) {
16019
- const commands = {};
16020
- const sectionRegex = /##\s+(Canonical\s+)?Commands[^\n]*\n([\s\S]*?)(?=\n##|$)/i;
16021
- const match = markdown.match(sectionRegex);
16022
- if (!match) {
16023
- return commands;
16024
- }
16025
- const section = match[2];
16026
- if (!section) {
16027
- return commands;
16028
- }
16029
- const codeBlockRegex = /```(?:bash|sh|shell)?\n([\s\S]*?)```/;
16030
- const codeMatch = section.match(codeBlockRegex);
16031
- if (codeMatch && codeMatch[1]) {
16032
- const lines = codeMatch[1].split("\n");
16033
- for (const line of lines) {
16034
- const cmdMatch = line.match(/^([^\s#]+(?:\s+[^\s#]+)*)\s*#?\s*(.*)$/);
16035
- if (cmdMatch && cmdMatch[1]) {
16036
- const cmd = cmdMatch[1].trim();
16037
- const desc = cmdMatch[2]?.trim() ?? "";
16038
- const key = desc || cmd;
16039
- commands[key] = cmd;
16040
- }
16041
- }
16042
- }
16043
- return commands;
16044
- }
16045
- /**
16046
- * Parse project metadata from markdown frontmatter or first section
16047
- */
16048
- parseMetadata(markdown) {
16049
- const metadata = {};
16050
- const lastUpdatedMatch = markdown.match(/>\s*Last\s+updated:\s*(.+?)$/im);
16051
- if (lastUpdatedMatch && lastUpdatedMatch[1]) {
16052
- metadata.lastUpdated = lastUpdatedMatch[1].trim();
16053
- }
16054
- const projectMatch = markdown.match(/>\s*Project:\s*(.+?)$/im);
16055
- if (projectMatch && projectMatch[1]) {
16056
- const parts = projectMatch[1].trim().split(/\s+v/);
16057
- metadata.name = parts[0] || "";
16058
- if (parts.length > 1 && parts[1]) {
16059
- metadata.version = parts[1];
16060
- }
16061
- }
16062
- const h1Match = markdown.match(/^#\s+(.+?)$/m);
16063
- if (h1Match && h1Match[1] && !metadata.name) {
16064
- metadata.name = h1Match[1].replace(/Project Context for AutomatosX/i, "").trim();
16065
- }
16066
- return metadata;
16067
- }
16068
16933
  /**
16069
16934
  * Build formatted context prompt for agent injection
16070
16935
  */
16071
16936
  buildContextPrompt(context) {
16072
- if (!context.markdown && !context.config) {
16937
+ if (!context.index && !context.customInstructions) {
16073
16938
  return "";
16074
16939
  }
16075
16940
  let prompt = "\n# PROJECT CONTEXT\n\n";
16076
- if (context.guardrails && context.guardrails.length > 0) {
16077
- prompt += "## CRITICAL RULES (NEVER VIOLATE):\n\n";
16078
- context.guardrails.forEach((rule) => {
16079
- prompt += `- ${rule}
16941
+ if (context.index) {
16942
+ prompt += `**Project:** ${context.index.projectName} v${context.index.version}
16080
16943
  `;
16081
- });
16082
- prompt += "\n";
16083
- }
16084
- if (context.agentRules && context.agentRules.length > 0) {
16085
- prompt += "## Agent Delegation Rules:\n\n";
16086
- context.agentRules.forEach((rule) => {
16087
- prompt += `- ${rule.taskType} \u2192 ${rule.defaultAgent}
16944
+ prompt += `**Type:** ${context.index.projectType}
16088
16945
  `;
16089
- });
16090
- prompt += "\n";
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
+ }
16091
16967
  }
16092
- if (context.commands && Object.keys(context.commands).length > 0) {
16093
- prompt += "## Available Commands:\n\n";
16094
- Object.entries(context.commands).forEach(([desc, cmd]) => {
16095
- prompt += `- ${desc}: \`${cmd}\`
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}
16096
16972
  `;
16097
- });
16973
+ }
16098
16974
  prompt += "\n";
16099
16975
  }
16100
- if (context.markdown) {
16101
- const MAX_PROMPT_LENGTH = 1e4;
16102
- const contextToAdd = context.markdown.length > MAX_PROMPT_LENGTH ? context.markdown.substring(0, MAX_PROMPT_LENGTH) + "\n\n[... context truncated for length ...]" : context.markdown;
16103
- prompt += "## Full Project Context:\n\n";
16104
- prompt += contextToAdd;
16105
- prompt += "\n";
16976
+ if (context.isStale) {
16977
+ prompt += "\u26A0\uFE0F **Note:** Project index is stale (>24h old). Run `ax init` to update.\n\n";
16106
16978
  }
16107
16979
  return prompt;
16108
16980
  }
@@ -16526,10 +17398,10 @@ var ContextManager = class {
16526
17398
  return provider;
16527
17399
  }
16528
17400
  /**
16529
- * Load project context from AX.md (v7.1.0+)
17401
+ * Load project context from ax.index.json (v12.9.0+)
16530
17402
  *
16531
- * Loads project-specific instructions from AX.md file if it exists.
16532
- * Falls back gracefully if file doesn't exist.
17403
+ * Loads project-specific context from ax.index.json and CUSTOM.md.
17404
+ * Falls back gracefully if files don't exist.
16533
17405
  *
16534
17406
  * @param projectDir - Project root directory
16535
17407
  * @returns Project context or null if not found
@@ -16542,15 +17414,15 @@ var ContextManager = class {
16542
17414
  const loader = this.projectContextLoader;
16543
17415
  const exists = await loader.exists();
16544
17416
  if (!exists) {
16545
- logger.debug("No AX.md found, skipping project context");
17417
+ logger.debug("No ax.index.json or CUSTOM.md found, skipping project context");
16546
17418
  return null;
16547
17419
  }
16548
17420
  const context = await loader.load();
16549
- logger.debug("Project context loaded from AX.md", {
16550
- hasMarkdown: !!context.markdown,
16551
- hasConfig: !!context.config,
16552
- agentRules: context.agentRules?.length ?? 0,
16553
- guardrails: context.guardrails?.length ?? 0
17421
+ logger.debug("Project context loaded", {
17422
+ hasIndex: !!context.index,
17423
+ hasCustomInstructions: !!context.customInstructions,
17424
+ guardrails: context.guardrails?.length ?? 0,
17425
+ isStale: context.isStale
16554
17426
  });
16555
17427
  return context;
16556
17428
  } catch (error) {
@@ -20582,6 +21454,24 @@ ${context.task}`;
20582
21454
  // src/agents/agent-selector.ts
20583
21455
  init_esm_shims();
20584
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
+ }
20585
21475
  function scoreAgent(task, profile) {
20586
21476
  let score = 0;
20587
21477
  const taskLower = task.toLowerCase();
@@ -20619,16 +21509,9 @@ function scoreAgent(task, profile) {
20619
21509
  }
20620
21510
  if (profile.selectionMetadata?.redirectWhen) {
20621
21511
  for (const rule of profile.selectionMetadata.redirectWhen) {
20622
- try {
20623
- const regex = new RegExp(rule.phrase, "i");
20624
- if (regex.test(task)) {
20625
- score -= 15;
20626
- }
20627
- } catch (error) {
20628
- logger.debug("Invalid regex pattern in redirectWhen rule", {
20629
- pattern: rule.phrase,
20630
- error: error instanceof Error ? error.message : String(error)
20631
- });
21512
+ const regex = getCachedRegex(rule.phrase);
21513
+ if (regex && regex.test(task)) {
21514
+ score -= 15;
20632
21515
  }
20633
21516
  }
20634
21517
  }
@@ -23218,8 +24101,8 @@ var BugDetector = class {
23218
24101
  async loadRulesFromFile(filePath) {
23219
24102
  try {
23220
24103
  const content = await readFile(filePath, "utf-8");
23221
- const yaml2 = await import('js-yaml');
23222
- const parsed = yaml2.load(content);
24104
+ const yaml = await import('js-yaml');
24105
+ const parsed = yaml.load(content);
23223
24106
  if (parsed.rules && Array.isArray(parsed.rules)) {
23224
24107
  for (const rule of parsed.rules) {
23225
24108
  this.addRule(rule);
@@ -23651,7 +24534,6 @@ var BugFixer = class {
23651
24534
  }
23652
24535
  const directSetIntervalPattern = /setInterval\s*\(/;
23653
24536
  if (directSetIntervalPattern.test(line)) {
23654
- line.match(/^(\s*)/)?.[1] || "";
23655
24537
  const newLine = line.replace(
23656
24538
  /(setInterval\s*\([^)]+\))/,
23657
24539
  "const _interval = $1; if (_interval.unref) _interval.unref()"
@@ -23678,7 +24560,6 @@ var BugFixer = class {
23678
24560
  const match = currentLine.match(classPattern);
23679
24561
  if (match && match[1]) {
23680
24562
  classStartLine = i;
23681
- match[1];
23682
24563
  break;
23683
24564
  }
23684
24565
  }
@@ -23730,7 +24611,7 @@ var BugFixer = class {
23730
24611
  /**
23731
24612
  * Apply use DisposableEventEmitter fix
23732
24613
  */
23733
- applyUseDisposableEventEmitterFix(finding, originalContent, lines) {
24614
+ applyUseDisposableEventEmitterFix(finding, originalContent, _lines) {
23734
24615
  let fixedContent = originalContent.replace(
23735
24616
  /extends\s+EventEmitter\b/g,
23736
24617
  "extends DisposableEventEmitter"
@@ -24652,7 +25533,7 @@ var DUPLICATION_RULES = [
24652
25533
  suggestion: "Extract to a named constant"
24653
25534
  }
24654
25535
  ];
24655
- function detectDuplication(filePath, content, lines, ignoreState, config) {
25536
+ function detectDuplication(filePath, content, lines, ignoreState, _config) {
24656
25537
  const findings = [];
24657
25538
  findings.push(...detectDuplicateBlocks(filePath, content, lines, ignoreState));
24658
25539
  findings.push(...detectRepeatedConditionals(filePath, content, lines, ignoreState));
@@ -24679,7 +25560,7 @@ function detectDuplicateBlocks(filePath, content, lines, ignoreState) {
24679
25560
  }
24680
25561
  blockHashes.get(blockHash).push({ start: i + 1, end: i + MIN_BLOCK_SIZE });
24681
25562
  }
24682
- for (const [hash, locations] of blockHashes) {
25563
+ for (const [_hash, locations] of blockHashes) {
24683
25564
  if (locations.length > 1) {
24684
25565
  for (let i = 1; i < locations.length; i++) {
24685
25566
  const loc = locations[i];
@@ -24728,7 +25609,7 @@ function detectRepeatedConditionals(filePath, content, lines, ignoreState) {
24728
25609
  }
24729
25610
  conditionPattern.lastIndex = 0;
24730
25611
  }
24731
- for (const [condition, lineNums] of conditionalCounts) {
25612
+ for (const [_condition, lineNums] of conditionalCounts) {
24732
25613
  if (lineNums.length >= 2) {
24733
25614
  const firstLine = lineNums[0];
24734
25615
  const secondLine = lineNums[1];
@@ -24891,7 +25772,7 @@ var THRESHOLDS = {
24891
25772
  maxCyclomaticComplexity: 10,
24892
25773
  maxChainedCalls: 4
24893
25774
  };
24894
- function detectReadability(filePath, content, lines, ignoreState, config) {
25775
+ function detectReadability(filePath, content, lines, ignoreState, _config) {
24895
25776
  const findings = [];
24896
25777
  findings.push(...detectLongFunctions(filePath, content, lines, ignoreState));
24897
25778
  findings.push(...detectDeepNesting(filePath, content, lines, ignoreState));
@@ -25267,7 +26148,7 @@ var PERFORMANCE_RULES = [
25267
26148
  suggestion: "Remove await - async functions automatically wrap return values in promises"
25268
26149
  }
25269
26150
  ];
25270
- function detectPerformance(filePath, content, lines, ignoreState, config) {
26151
+ function detectPerformance(filePath, content, lines, ignoreState, _config) {
25271
26152
  const findings = [];
25272
26153
  findings.push(...detectSyncInAsync(filePath, content, lines, ignoreState));
25273
26154
  findings.push(...detectNPlusOne(filePath, content, lines, ignoreState));
@@ -25682,7 +26563,7 @@ var HARDCODE_RULES = [
25682
26563
  suggestion: "Extract timeout to a named constant or config"
25683
26564
  }
25684
26565
  ];
25685
- function detectHardcode(filePath, content, lines, ignoreState, config) {
26566
+ function detectHardcode(filePath, content, lines, ignoreState, _config) {
25686
26567
  const findings = [];
25687
26568
  findings.push(...detectMagicNumbers(filePath, content, lines, ignoreState));
25688
26569
  findings.push(...detectHardcodedUrls(filePath, content, lines, ignoreState));
@@ -26038,7 +26919,7 @@ var NAMING_RULES = [
26038
26919
  suggestion: "Use is/has/can/should prefix for boolean variables"
26039
26920
  }
26040
26921
  ];
26041
- function detectNaming(filePath, content, lines, ignoreState, config) {
26922
+ function detectNaming(filePath, content, lines, ignoreState, _config) {
26042
26923
  const findings = [];
26043
26924
  findings.push(...detectSingleLetterVariables(filePath, content, lines, ignoreState));
26044
26925
  findings.push(...detectHungarianNotation(filePath, content, lines, ignoreState));
@@ -26321,7 +27202,7 @@ var CONDITIONAL_RULES = [
26321
27202
  suggestion: "Use the condition directly (or negate it)"
26322
27203
  }
26323
27204
  ];
26324
- function detectConditionals(filePath, content, lines, ignoreState, config) {
27205
+ function detectConditionals(filePath, content, lines, ignoreState, _config) {
26325
27206
  const findings = [];
26326
27207
  findings.push(...detectDeeplyNestedIf(filePath, content, lines, ignoreState));
26327
27208
  findings.push(...detectComplexConditions(filePath, content, lines, ignoreState));
@@ -26634,7 +27515,7 @@ var DEAD_CODE_RULES = [
26634
27515
  suggestion: "Implement function or add TODO comment"
26635
27516
  }
26636
27517
  ];
26637
- function detectDeadCode(filePath, content, lines, ignoreState, config) {
27518
+ function detectDeadCode(filePath, content, lines, ignoreState, _config) {
26638
27519
  const findings = [];
26639
27520
  findings.push(...detectUnusedImports(filePath, content, lines, ignoreState));
26640
27521
  findings.push(...detectUnusedVariables(filePath, content, lines, ignoreState));
@@ -26928,7 +27809,7 @@ var TYPE_SAFETY_RULES = [
26928
27809
  fileExtensions: [".ts", ".tsx"]
26929
27810
  }
26930
27811
  ];
26931
- function detectTypeSafety(filePath, content, lines, ignoreState, config) {
27812
+ function detectTypeSafety(filePath, content, lines, ignoreState, _config) {
26932
27813
  const findings = [];
26933
27814
  if (!filePath.endsWith(".ts") && !filePath.endsWith(".tsx")) {
26934
27815
  return findings;
@@ -31137,7 +32018,7 @@ var createTaskSchema = {
31137
32018
  // src/mcp/tools/task/run-task.ts
31138
32019
  init_esm_shims();
31139
32020
  init_logger();
31140
- function createRunTaskHandler(deps) {
32021
+ function createRunTaskHandler(_deps) {
31141
32022
  return async (input, context) => {
31142
32023
  const startTime = Date.now();
31143
32024
  if (context?.signal?.aborted) {
@@ -33687,6 +34568,17 @@ Use this tool first to understand what AutomatosX offers.`,
33687
34568
  mode: "sdk"
33688
34569
  }));
33689
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
+ }
33690
34582
  const healthCheckInterval = config.router?.healthCheckInterval;
33691
34583
  this.router = new Router({
33692
34584
  providers,