bailian-cli-core 1.3.3 → 1.4.0

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/index.d.mts CHANGED
@@ -604,7 +604,6 @@ interface ConfigFile {
604
604
  api_key?: string;
605
605
  /** OAuth-style token from `bl auth login --console` callback; sent as `Authorization: Bearer …` */
606
606
  access_token?: string;
607
- region?: Region;
608
607
  base_url?: string;
609
608
  output?: "text" | "json";
610
609
  output_dir?: string;
@@ -617,7 +616,9 @@ interface ConfigFile {
617
616
  access_key_id?: string;
618
617
  access_key_secret?: string;
619
618
  workspace_id?: string;
620
- console_gateway_url?: string;
619
+ console_site?: "domestic" | "international";
620
+ console_region?: string;
621
+ console_switch_agent?: number;
621
622
  telemetry?: boolean;
622
623
  }
623
624
  declare function parseConfigFile(raw: unknown): ConfigFile;
@@ -630,9 +631,7 @@ interface Config {
630
631
  /** `access_token` in config file (console login). */
631
632
  fileAccessToken?: string;
632
633
  fileApiKey?: string;
633
- fileRegion?: Region;
634
634
  configPath?: string;
635
- region: Region;
636
635
  baseUrl: string;
637
636
  output: "text" | "json";
638
637
  outputDir?: string;
@@ -645,7 +644,9 @@ interface Config {
645
644
  accessKeyId?: string;
646
645
  accessKeySecret?: string;
647
646
  workspaceId?: string;
648
- consoleGatewayUrl: string;
647
+ consoleSite?: "domestic" | "international";
648
+ consoleRegion?: string;
649
+ consoleSwitchAgent?: number;
649
650
  verbose: boolean;
650
651
  quiet: boolean;
651
652
  noColor: boolean;
@@ -792,23 +793,36 @@ interface ServerSentEvent {
792
793
  declare function parseSSE(response: Response): AsyncGenerator<ServerSentEvent>;
793
794
  //#endregion
794
795
  //#region src/console/gateway.d.ts
796
+ type ConsoleSite = "domestic" | "international";
797
+ /** Resolved console gateway settings (same defaults as {@link callConsoleGateway}). */
798
+ declare function effectiveConsoleGatewayConfig(config: Config): {
799
+ consoleRegion: string;
800
+ consoleSite: ConsoleSite;
801
+ consoleSwitchAgent?: number;
802
+ };
795
803
  interface ConsoleGatewayRequest {
796
804
  /** Console API name, e.g. zeldaEasy.broadscope-bailian.freeTrial.queryFreeTierQuota */
797
805
  api: string;
798
806
  data: Record<string, unknown>;
799
- /** Console region (default: cn-beijing), distinct from DashScope `config.region`. */
807
+ /** Console region (e.g. cn-beijing, ap-southeast-1). Falls back to config.consoleRegion, then "cn-beijing". */
800
808
  region?: string;
809
+ /** Console site. Falls back to config.consoleSite, then "domestic". */
810
+ site?: ConsoleSite;
811
+ /** Switch-agent UID for delegated access. Falls back to config.consoleSwitchAgent. */
812
+ switchAgent?: number;
801
813
  }
802
814
  /**
803
815
  * Invoke a Bailian **console** OpenAPI via the CLI gateway (`/cli/api.json`).
804
816
  * `token` is the console `access_token` (from `bl auth login --console`); when
805
817
  * omitted the request is sent without an Authorization header, which works for
806
818
  * public console APIs that don't require a login session.
819
+ *
820
+ * Gateway URL and action are resolved from `region + site` via {@link REGION_GATEWAYS}.
821
+ * Each parameter falls back to the corresponding config value, then to a hardcoded default.
807
822
  */
808
823
  declare function callConsoleGateway(config: Config, token: string | undefined, {
809
824
  api,
810
- data,
811
- region
825
+ data
812
826
  }: ConsoleGatewayRequest): Promise<unknown>;
813
827
  //#endregion
814
828
  //#region src/console/models.d.ts
@@ -818,7 +832,6 @@ interface ModelListParams {
818
832
  name?: string;
819
833
  providers?: string[];
820
834
  capabilities?: string[];
821
- region?: string;
822
835
  }
823
836
  interface ModelListResult {
824
837
  total: number;
@@ -840,6 +853,9 @@ interface GlobalFlags {
840
853
  help: boolean;
841
854
  nonInteractive: boolean;
842
855
  async: boolean;
856
+ consoleRegion?: string;
857
+ consoleSite?: string;
858
+ consoleSwitchAgent?: number;
843
859
  [key: string]: unknown;
844
860
  }
845
861
  //#endregion
@@ -903,6 +919,7 @@ interface Command {
903
919
  usage?: string;
904
920
  options?: OptionDef[];
905
921
  examples?: string[];
922
+ skipDefaultApiKeySetup?: boolean;
906
923
  notes?: string[];
907
924
  execute: (config: Config, flags: GlobalFlags) => Promise<void>;
908
925
  }
@@ -912,6 +929,7 @@ interface CommandSpec {
912
929
  usage?: string;
913
930
  options?: OptionDef[];
914
931
  examples?: string[];
932
+ skipDefaultApiKeySetup?: boolean;
915
933
  notes?: string[];
916
934
  run: (config: Config, flags: GlobalFlags) => Promise<void>;
917
935
  }
@@ -1009,7 +1027,6 @@ interface TrackingEvent {
1009
1027
  httpStatus?: number;
1010
1028
  requestId?: string;
1011
1029
  cliVersion: string;
1012
- region: string;
1013
1030
  nodeVersion: string;
1014
1031
  os: string;
1015
1032
  authMethod?: string;
@@ -1025,7 +1042,6 @@ declare function createTrackingEvent(opts: {
1025
1042
  requestId?: string;
1026
1043
  };
1027
1044
  cliVersion: string;
1028
- region: string;
1029
1045
  authMethod?: string;
1030
1046
  params?: Record<string, unknown>;
1031
1047
  }): TrackingEvent;
@@ -1235,4 +1251,4 @@ interface ModelSource {
1235
1251
  load(): Promise<ModelProfile[]>;
1236
1252
  }
1237
1253
  //#endregion
1238
- export { AkSignConfig, type ApiErrorBody, AppCompletionRequest, AppCompletionResponse, AppStreamChunk, AuthMethod, BAILIAN_HOST, BailianError, Budget, Budgets, CHANNEL, CONSOLE_GATEWAY_NO_TOKEN_MESSAGE, Capabilities, Capability, ChatChoice, ChatMessage, ChatMessageContent, ChatRequest, ChatResponse, ChatTool, Command, CommandSpec, Complexities, Complexity, Config, ConfigFile, ConsoleGatewayRequest, ContextNeed, ContextNeeds, DOCS_HOSTS, DashScopeASRRequest, DashScopeASRTaskResult, DashScopeAsyncResponse, DashScopeImageRequest, DashScopeImageSyncResponse, DashScopeKnowledgeRetrieveRequest, DashScopeKnowledgeRetrieveResponse, DashScopeTTSRequest, DashScopeTTSResponse, DashScopeTTSStreamChunk, DashScopeTaskResponse, DashScopeVideoEditRequest, DashScopeVideoRefRequest, DashScopeVideoRequest, ExitCode, Feature, Features, GLOBAL_OPTIONS, GetModelsOptions, GlobalFlags, IntentProfile, IntentSegment, KnowledgeRetrieveRequest, KnowledgeRetrieveResponse, McpClient, McpTool, McpToolResult, MemoryAddRequest, MemoryAddResponse, MemoryMessage, MemoryNode, MemoryNodeListResponse, MemoryNodeUpdateRequest, MemorySearchRequest, MemorySearchResponse, Modalities, Modality, ModelCategories, ModelCategory, ModelListParams, ModelListResult, ModelPreference, ModelPrice, ModelProfile, ModelSource, OptionDef, OutputFormat, PipelineResult, PipelineStep, PreferenceMode, ProfileAttribute, ProfileSchemaCreateRequest, ProfileSchemaCreateResponse, QpmLimit, QualityPreference, QualityPreferences, REGIONS, RecommendOptions, RecommendResult, RecommendedModel, Region, RequestOpts, ResolvedCredential, SOURCE_CONFIG, ScoredCandidate, ServerSentEvent, SingleResult, StreamChoice, StreamChunk, TAGS, TrackingEvent, UserProfileResponse, analyzeIntent, appCompletionEndpoint, bailianMcpUrl, buildDocLink, callConsoleGateway, chatEndpoint, clearApiKey, createTrackingEvent, defineCommand, detectOutputFormat, ensureConfigDir, fetchModelList, flushTelemetry, formatErrorJson, formatJson, formatOutput, formatText, generateFilename, generateToolSchema, getConfigDir, getConfigPath, getCredentialsPath, getModels, imageEndpoint, imageSyncEndpoint, isCI, isInteractive, isLocalFile, isSemanticAvailable, knowledgeRetrieveEndpoint, loadApiKeyFromConfig, loadConfig, localSink, mapApiError, maskToken, mcpWebSearchEndpoint, memoryAddEndpoint, memoryListEndpoint, memoryNodeEndpoint, memorySearchEndpoint, parseBooleanValue, parseConfigFile, parseOptionalBooleanValue, parseSSE, profileSchemaEndpoint, rankModels, readConfigFile, recallCandidates, recallSemantic, remoteSink, request, requestJson, resolveBooleanFlag, resolveConsoleGatewayCredential, resolveCredential, resolveFileUrl, resolveOutputDir, resolveWatermark, saveApiKeyToConfig, signRequest, speechRecognizeEndpoint, speechSynthesizeEndpoint, stripUndefined, taskEndpoint, trackCommandExecution, trackingHeaders, uploadFile, userProfileEndpoint, videoGenerateEndpoint, writeConfigFile };
1254
+ export { AkSignConfig, type ApiErrorBody, AppCompletionRequest, AppCompletionResponse, AppStreamChunk, AuthMethod, BAILIAN_HOST, BailianError, Budget, Budgets, CHANNEL, CONSOLE_GATEWAY_NO_TOKEN_MESSAGE, Capabilities, Capability, ChatChoice, ChatMessage, ChatMessageContent, ChatRequest, ChatResponse, ChatTool, Command, CommandSpec, Complexities, Complexity, Config, ConfigFile, ConsoleGatewayRequest, ConsoleSite, ContextNeed, ContextNeeds, DOCS_HOSTS, DashScopeASRRequest, DashScopeASRTaskResult, DashScopeAsyncResponse, DashScopeImageRequest, DashScopeImageSyncResponse, DashScopeKnowledgeRetrieveRequest, DashScopeKnowledgeRetrieveResponse, DashScopeTTSRequest, DashScopeTTSResponse, DashScopeTTSStreamChunk, DashScopeTaskResponse, DashScopeVideoEditRequest, DashScopeVideoRefRequest, DashScopeVideoRequest, ExitCode, Feature, Features, GLOBAL_OPTIONS, GetModelsOptions, GlobalFlags, IntentProfile, IntentSegment, KnowledgeRetrieveRequest, KnowledgeRetrieveResponse, McpClient, McpTool, McpToolResult, MemoryAddRequest, MemoryAddResponse, MemoryMessage, MemoryNode, MemoryNodeListResponse, MemoryNodeUpdateRequest, MemorySearchRequest, MemorySearchResponse, Modalities, Modality, ModelCategories, ModelCategory, ModelListParams, ModelListResult, ModelPreference, ModelPrice, ModelProfile, ModelSource, OptionDef, OutputFormat, PipelineResult, PipelineStep, PreferenceMode, ProfileAttribute, ProfileSchemaCreateRequest, ProfileSchemaCreateResponse, QpmLimit, QualityPreference, QualityPreferences, REGIONS, RecommendOptions, RecommendResult, RecommendedModel, Region, RequestOpts, ResolvedCredential, SOURCE_CONFIG, ScoredCandidate, ServerSentEvent, SingleResult, StreamChoice, StreamChunk, TAGS, TrackingEvent, UserProfileResponse, analyzeIntent, appCompletionEndpoint, bailianMcpUrl, buildDocLink, callConsoleGateway, chatEndpoint, clearApiKey, createTrackingEvent, defineCommand, detectOutputFormat, effectiveConsoleGatewayConfig, ensureConfigDir, fetchModelList, flushTelemetry, formatErrorJson, formatJson, formatOutput, formatText, generateFilename, generateToolSchema, getConfigDir, getConfigPath, getCredentialsPath, getModels, imageEndpoint, imageSyncEndpoint, isCI, isInteractive, isLocalFile, isSemanticAvailable, knowledgeRetrieveEndpoint, loadApiKeyFromConfig, loadConfig, localSink, mapApiError, maskToken, mcpWebSearchEndpoint, memoryAddEndpoint, memoryListEndpoint, memoryNodeEndpoint, memorySearchEndpoint, parseBooleanValue, parseConfigFile, parseOptionalBooleanValue, parseSSE, profileSchemaEndpoint, rankModels, readConfigFile, recallCandidates, recallSemantic, remoteSink, request, requestJson, resolveBooleanFlag, resolveConsoleGatewayCredential, resolveCredential, resolveFileUrl, resolveOutputDir, resolveWatermark, saveApiKeyToConfig, signRequest, speechRecognizeEndpoint, speechSynthesizeEndpoint, stripUndefined, taskEndpoint, trackCommandExecution, trackingHeaders, uploadFile, userProfileEndpoint, videoGenerateEndpoint, writeConfigFile };
package/dist/index.mjs CHANGED
@@ -108,15 +108,11 @@ const DOCS_HOSTS = {
108
108
  intl: "https://help.aliyun.com/zh/model-studio"
109
109
  };
110
110
  const BAILIAN_HOST = "https://bailian.cn-beijing.aliyuncs.com";
111
- const VALID_REGIONS = new Set([
112
- "cn",
113
- "us",
114
- "intl"
115
- ]);
116
111
  const VALID_OUTPUTS = new Set(["text", "json"]);
112
+ const VALID_CONSOLE_SITES = new Set(["domestic", "international"]);
117
113
  /**
118
- * A syntactically valid absolute http(s) URL. Used to validate `base_url` and
119
- * `console_gateway_url` from the config file: the credential-bearing client
114
+ * A syntactically valid absolute http(s) URL. Used to validate `base_url`
115
+ * from the config file: the credential-bearing client
120
116
  * sends the Bearer token to these origins, so a bare `startsWith("http")` check
121
117
  * (which also accepts e.g. "httpfoo://…") is too loose.
122
118
  */
@@ -135,7 +131,6 @@ function parseConfigFile(raw) {
135
131
  if (typeof obj.api_key === "string") out.api_key = obj.api_key;
136
132
  if (typeof obj.access_token === "string" && obj.access_token.length > 0) out.access_token = obj.access_token;
137
133
  else if (typeof obj.accessToken === "string" && obj.accessToken.length > 0) out.access_token = obj.accessToken;
138
- if (typeof obj.region === "string" && VALID_REGIONS.has(obj.region)) out.region = obj.region;
139
134
  if (typeof obj.base_url === "string" && isHttpUrl(obj.base_url)) out.base_url = obj.base_url;
140
135
  if (typeof obj.output === "string" && VALID_OUTPUTS.has(obj.output)) out.output = obj.output;
141
136
  if (typeof obj.output_dir === "string" && obj.output_dir.length > 0) out.output_dir = obj.output_dir;
@@ -148,7 +143,9 @@ function parseConfigFile(raw) {
148
143
  if (typeof obj.access_key_id === "string" && obj.access_key_id.length > 0) out.access_key_id = obj.access_key_id;
149
144
  if (typeof obj.access_key_secret === "string" && obj.access_key_secret.length > 0) out.access_key_secret = obj.access_key_secret;
150
145
  if (typeof obj.workspace_id === "string" && obj.workspace_id.length > 0) out.workspace_id = obj.workspace_id;
151
- if (typeof obj.console_gateway_url === "string" && isHttpUrl(obj.console_gateway_url)) out.console_gateway_url = obj.console_gateway_url;
146
+ if (typeof obj.console_site === "string" && VALID_CONSOLE_SITES.has(obj.console_site)) out.console_site = obj.console_site;
147
+ if (typeof obj.console_region === "string" && obj.console_region.length > 0) out.console_region = obj.console_region;
148
+ if (typeof obj.console_switch_agent === "number" && obj.console_switch_agent > 0) out.console_switch_agent = obj.console_switch_agent;
152
149
  if (typeof obj.telemetry === "boolean") out.telemetry = obj.telemetry;
153
150
  return out;
154
151
  }
@@ -232,10 +229,7 @@ function loadConfig(flags) {
232
229
  const fileApiKey = file.api_key;
233
230
  const accessTokenEnv = process.env.DASHSCOPE_ACCESS_TOKEN?.trim() || void 0;
234
231
  const fileAccessToken = file.access_token?.trim() || void 0;
235
- const explicitRegion = flags.region || process.env.DASHSCOPE_REGION || void 0;
236
- const cachedRegion = file.region;
237
- const region = explicitRegion || cachedRegion || "cn";
238
- const baseUrl = flags.baseUrl || process.env.DASHSCOPE_BASE_URL || file.base_url || REGIONS[region] || REGIONS.cn;
232
+ const baseUrl = flags.baseUrl || file.base_url || process.env.DASHSCOPE_BASE_URL || REGIONS.cn;
239
233
  const output = detectOutputFormat(flags.output || process.env.DASHSCOPE_OUTPUT || file.output);
240
234
  const envTimeout = process.env.DASHSCOPE_TIMEOUT ? Number(process.env.DASHSCOPE_TIMEOUT) : void 0;
241
235
  const validEnvTimeout = envTimeout !== void 0 && Number.isFinite(envTimeout) && envTimeout > 0 ? envTimeout : void 0;
@@ -246,9 +240,7 @@ function loadConfig(flags) {
246
240
  accessTokenEnv,
247
241
  fileAccessToken,
248
242
  fileApiKey,
249
- fileRegion: file.region,
250
243
  configPath: getConfigPath(),
251
- region,
252
244
  baseUrl,
253
245
  output,
254
246
  outputDir: file.output_dir || void 0,
@@ -261,7 +253,9 @@ function loadConfig(flags) {
261
253
  accessKeyId: process.env.ALIBABA_CLOUD_ACCESS_KEY_ID || file.access_key_id || void 0,
262
254
  accessKeySecret: process.env.ALIBABA_CLOUD_ACCESS_KEY_SECRET || file.access_key_secret || void 0,
263
255
  workspaceId: process.env.BAILIAN_WORKSPACE_ID || file.workspace_id || void 0,
264
- consoleGatewayUrl: process.env.BAILIAN_CONSOLE_GATEWAY_URL || file.console_gateway_url || "https://bailian-cs.console.aliyun.com",
256
+ consoleSite: flags.consoleSite || file.console_site || void 0,
257
+ consoleRegion: flags.consoleRegion || file.console_region || void 0,
258
+ consoleSwitchAgent: flags.consoleSwitchAgent || file.console_switch_agent || void 0,
265
259
  verbose: flags.verbose || process.env.DASHSCOPE_VERBOSE === "1",
266
260
  quiet: flags.quiet || false,
267
261
  noColor: flags.noColor || process.env.NO_COLOR !== void 0 || !process.stdout.isTTY,
@@ -722,9 +716,47 @@ async function* parseSSE(response) {
722
716
  }
723
717
  //#endregion
724
718
  //#region src/console/gateway.ts
725
- const GATEWAY_ACTION = "BroadScopeAspnGateway";
726
719
  const GATEWAY_PRODUCT = "sfm_bailian";
727
- function buildGatewayParams(api, data) {
720
+ const REGION_GATEWAYS = {
721
+ "cn-beijing": {
722
+ domestic: {
723
+ csGateway: "bailian-cs.console.aliyun.com",
724
+ action: "BroadScopeAspnGateway"
725
+ },
726
+ international: {
727
+ csGateway: "bailian-cs.console.alibabacloud.com",
728
+ action: "BroadScopeAspnGateway"
729
+ }
730
+ },
731
+ "ap-southeast-1": {
732
+ domestic: {
733
+ csGateway: "modelstudio-cs.console.aliyun.com",
734
+ action: "IntlBroadScopeAspnGateway"
735
+ },
736
+ international: {
737
+ csGateway: "bailian-singapore-cs.alibabacloud.com",
738
+ action: "IntlBroadScopeAspnGateway"
739
+ }
740
+ }
741
+ };
742
+ function resolveGateway(region, site) {
743
+ return REGION_GATEWAYS[region]?.[site] ?? REGION_GATEWAYS["cn-beijing"][site];
744
+ }
745
+ /** Resolved console gateway settings (same defaults as {@link callConsoleGateway}). */
746
+ function effectiveConsoleGatewayConfig(config) {
747
+ const consoleRegion = config.consoleRegion ?? "cn-beijing";
748
+ const consoleSite = config.consoleSite ?? "domestic";
749
+ const consoleSwitchAgent = config.consoleSwitchAgent;
750
+ return consoleSwitchAgent != null ? {
751
+ consoleRegion,
752
+ consoleSite,
753
+ consoleSwitchAgent
754
+ } : {
755
+ consoleRegion,
756
+ consoleSite
757
+ };
758
+ }
759
+ function buildGatewayParams(api, data, switchAgent) {
728
760
  return JSON.stringify({
729
761
  Api: api,
730
762
  V: "1.0",
@@ -735,6 +767,7 @@ function buildGatewayParams(api, data) {
735
767
  console: "ONE_CONSOLE",
736
768
  productCode: "p_efm",
737
769
  consoleSite: "BAILIAN_ALIYUN",
770
+ ...switchAgent != null ? { switchAgent } : {},
738
771
  ...typeof data.cornerstoneParam === "object" && data.cornerstoneParam !== null ? data.cornerstoneParam : {}
739
772
  }
740
773
  }
@@ -745,21 +778,27 @@ function buildGatewayParams(api, data) {
745
778
  * `token` is the console `access_token` (from `bl auth login --console`); when
746
779
  * omitted the request is sent without an Authorization header, which works for
747
780
  * public console APIs that don't require a login session.
781
+ *
782
+ * Gateway URL and action are resolved from `region + site` via {@link REGION_GATEWAYS}.
783
+ * Each parameter falls back to the corresponding config value, then to a hardcoded default.
748
784
  */
749
- async function callConsoleGateway(config, token, { api, data, region = "cn-beijing" }) {
750
- const params = buildGatewayParams(api, data);
785
+ async function callConsoleGateway(config, token, { api, data }) {
786
+ const { consoleRegion: effectiveRegion, consoleSite: effectiveSite, consoleSwitchAgent: effectiveSwitchAgent } = effectiveConsoleGatewayConfig(config);
787
+ const resolved = resolveGateway(effectiveRegion, effectiveSite);
788
+ const gatewayBase = `https://${resolved.csGateway}`;
789
+ const action = resolved.action;
790
+ const params = buildGatewayParams(api, data, effectiveSwitchAgent);
751
791
  const body = new URLSearchParams({
752
792
  params,
753
- region
793
+ region: effectiveRegion
754
794
  });
755
795
  const timeoutMs = config.timeout * 1e3;
756
- const gatewayBase = config.consoleGatewayUrl;
757
796
  const headers = {
758
797
  Accept: "*/*",
759
798
  "Content-Type": "application/x-www-form-urlencoded"
760
799
  };
761
800
  if (token) headers.Authorization = `Bearer ${token}`;
762
- const res = await fetch(`${gatewayBase}/cli/api.json?action=${GATEWAY_ACTION}&product=${GATEWAY_PRODUCT}&api=${encodeURIComponent(api)}`, {
801
+ const res = await fetch(`${gatewayBase}/cli/api.json?action=${action}&product=${GATEWAY_PRODUCT}&api=${encodeURIComponent(api)}`, {
763
802
  method: "POST",
764
803
  headers,
765
804
  body: body.toString(),
@@ -771,14 +810,19 @@ async function callConsoleGateway(config, token, { api, data, region = "cn-beiji
771
810
  }
772
811
  const json = await res.json();
773
812
  const innerData = json.data;
774
- if (innerData?.success === false && innerData.errorCode) throw new BailianError(`Console gateway error: ${innerData.errorCode}`, ExitCode.GENERAL, typeof innerData.errorMsg === "string" ? innerData.errorMsg : void 0);
813
+ if (innerData?.success === false && innerData.errorCode) {
814
+ const errorCode = String(innerData.errorCode);
815
+ const notLogined = errorCode.includes("NotLogined");
816
+ const errorMsg = typeof innerData.errorMsg === "string" ? innerData.errorMsg : void 0;
817
+ throw new BailianError(notLogined ? "Console session is not logged in or has expired." : `Console gateway error: ${errorCode}`, notLogined ? ExitCode.AUTH : ExitCode.GENERAL, notLogined ? "Run `bl auth login --console` to sign in or refresh your console session." : errorMsg && errorMsg !== errorCode ? errorMsg : void 0);
818
+ }
775
819
  return json;
776
820
  }
777
821
  //#endregion
778
822
  //#region src/console/models.ts
779
823
  const MODEL_LIST_API = "zeldaHttp.dashscopeModel./zelda/api/v1/modelCenter/listFoundationModels";
780
824
  async function fetchModelList(config, token, params = {}) {
781
- const { pageNo = 1, pageSize = 50, name = "", providers = [], capabilities = [], region = "cn-beijing" } = params;
825
+ const { pageNo = 1, pageSize = 50, name = "", providers = [], capabilities = [] } = params;
782
826
  const result = await callConsoleGateway(config, token, {
783
827
  api: MODEL_LIST_API,
784
828
  data: { input: {
@@ -791,8 +835,7 @@ async function fetchModelList(config, token, params = {}) {
791
835
  group: true,
792
836
  capabilities,
793
837
  contextWindows: []
794
- } },
795
- region
838
+ } }
796
839
  });
797
840
  const responseData = result?.data?.DataV2?.data ?? result?.data ?? {};
798
841
  const total = responseData?.data?.total ?? responseData?.total ?? 0;
@@ -921,6 +964,7 @@ function defineCommand(spec) {
921
964
  usage: spec.usage,
922
965
  options: spec.options,
923
966
  examples: spec.examples,
967
+ skipDefaultApiKeySetup: spec.skipDefaultApiKeySetup,
924
968
  notes: spec.notes,
925
969
  execute: (config, flags) => spec.run(config, flags)
926
970
  };
@@ -931,10 +975,6 @@ const GLOBAL_OPTIONS = [
931
975
  flag: "--api-key <key>",
932
976
  description: "API key"
933
977
  },
934
- {
935
- flag: "--region <region>",
936
- description: "API region: cn (default), us, intl"
937
- },
938
978
  {
939
979
  flag: "--base-url <url>",
940
980
  description: "API base URL"
@@ -973,6 +1013,19 @@ const GLOBAL_OPTIONS = [
973
1013
  description: "Run N parallel requests (default: 1)",
974
1014
  type: "number"
975
1015
  },
1016
+ {
1017
+ flag: "--console-region <region>",
1018
+ description: "Console gateway region (e.g. cn-beijing, ap-southeast-1)"
1019
+ },
1020
+ {
1021
+ flag: "--console-site <site>",
1022
+ description: "Console site: domestic, international"
1023
+ },
1024
+ {
1025
+ flag: "--console-switch-agent <uid>",
1026
+ description: "Switch agent UID for delegated access",
1027
+ type: "number"
1028
+ },
976
1029
  {
977
1030
  flag: "--help",
978
1031
  description: "Show help"
@@ -1151,7 +1204,6 @@ function createTrackingEvent(opts) {
1151
1204
  durationMs: opts.durationMs,
1152
1205
  success: opts.success,
1153
1206
  cliVersion: opts.cliVersion,
1154
- region: opts.region,
1155
1207
  nodeVersion: process.version,
1156
1208
  os: process.platform
1157
1209
  };
@@ -2058,7 +2110,6 @@ const GLOBAL_FLAG_KEYS = new Set([
2058
2110
  "help",
2059
2111
  "nonInteractive",
2060
2112
  "async",
2061
- "region",
2062
2113
  "console"
2063
2114
  ]);
2064
2115
  /**
@@ -2156,7 +2207,6 @@ async function trackCommandExecution(config, commandPath, flags, fn) {
2156
2207
  requestId
2157
2208
  },
2158
2209
  cliVersion: config.clientVersion ?? "unknown",
2159
- region: config.region,
2160
2210
  authMethod,
2161
2211
  params: extractParams(flags)
2162
2212
  });
@@ -2360,197 +2410,182 @@ const ModelCategories = {
2360
2410
  };
2361
2411
  //#endregion
2362
2412
  //#region src/advisor/constants/prompts.ts
2363
- const INTENT_MODEL = "qwen-turbo";
2413
+ const INTENT_MODEL = "qwen-flash";
2364
2414
  const RANKING_MODEL = "qwen3.6-flash";
2365
- const RANKING_MODEL_FAST = "qwen-turbo";
2366
- const INTENT_SYSTEM_PROMPT = `你是一个意图分析器。根据用户的需求描述,先理解用户场景,再提取结构化信息。
2367
-
2368
- ## 分析步骤
2369
- 1. 用一句话总结用户的核心需求(taskSummary),要体现具体场景而非泛泛描述
2370
- 2. 推断场景特征(scenarioHints),例如:["需要低延迟","面向C端用户","高并发","对话式交互","离线批处理","需要精准度"]
2371
- 3. 基于场景特征推断 budget 和 qualityPreference
2372
- - 只在用户明确表达或场景强烈暗示时偏离默认值
2373
- - 用户明确说"低成本"、"便宜"、"省钱" → budget:"low"
2374
- - 用户明确说"最好的"、"高精度"、"不计成本" → qualityPreference:"flagship"
2375
- - 场景本身有强约束时才推断:如"日均百万请求的客服" → budget:"low"(高并发=成本敏感)
2376
- - 其他情况保持 budget:"medium", qualityPreference:"balanced"
2377
- 4. 提取模态、能力、特性等结构化字段
2378
-
2379
- ## 示例
2380
-
2381
- 用户: "做一个低成本高并发的在线客服"
2382
- → budget:"low", qualityPreference:"cost-optimized"(用户明确说了低成本)
2415
+ const RANKING_MODEL_FAST = "qwen-flash";
2416
+ const INTENT_SYSTEM_PROMPT = `You are an intent analyzer. Given the user's requirement, understand the scenario first, then extract structured information.
2383
2417
 
2384
- 用户: "法律合同审查,要求高精准度"
2385
- → budget:"medium", qualityPreference:"flagship"(用户明确要求高精准度,但没提预算)
2418
+ CRITICAL: You MUST respond entirely in English. Do not use any Chinese characters anywhere in your response. All text fields (taskSummary, scenarioHints) must be in English.
2386
2419
 
2387
- 用户: "我要做一个能理解图片的客服机器人"
2388
- budget:"medium", qualityPreference:"balanced"(用户没提成本和质量要求,不过度推断)
2420
+ ## Analysis Steps
2421
+ 1. Summarize the user's core need in one sentence (taskSummary) — be specific about the scenario, not generic
2422
+ 2. Infer scenario hints (scenarioHints), e.g.: ["low-latency", "consumer-facing", "high-concurrency", "conversational", "offline-batch", "high-precision"]
2423
+ 3. Infer budget and qualityPreference from scenario hints
2424
+ - Only deviate from defaults when the user explicitly states or the scenario strongly implies
2425
+ - User says "low cost", "cheap", "save money" → budget:"low"
2426
+ - User says "best", "high precision", "cost no object" → qualityPreference:"flagship"
2427
+ - Infer from scenario constraints only when strong: e.g. "1M requests/day customer service" → budget:"low" (high concurrency = cost-sensitive)
2428
+ - Otherwise keep budget:"medium", qualityPreference:"balanced"
2429
+ 4. Extract modalities, capabilities, features etc.
2389
2430
 
2390
- 用户: "帮我选一个写代码的模型"
2391
- budget:"medium", qualityPreference:"balanced"(通用需求,无明确倾向)
2431
+ ## Model preference detection
2432
+ Analyze whether the user mentioned specific models, model families, or vendors:
2433
+ - No models/families/vendors mentioned → mode:"unconstrained", no targets
2434
+ - User scoped the range (e.g. "recommend from the deepseek family", "open-source reasoning models") → mode:"scoped", targets:["deepseek"]
2435
+ - User wants to compare specific models (e.g. "compare wan2.6 and wan2.7", "is qwen-max good for legal analysis") → mode:"comparison", targets:["wan2.6","wan2.7"]
2436
+ - Single model evaluation is also comparison with one target
2437
+ - User wants alternatives to a reference model (e.g. "something like qwen-max but cheaper") → mode:"alternative", targets:["qwen-max"]
2438
+ - User explicitly excludes certain models/families (e.g. "good models besides qwen") → excludes:["qwen"], mode determined by other signals
2439
+ - targets should capture the model/family names as the user wrote them
2392
2440
 
2393
- 用户: "预算有限,做个简单的文本摘要功能"
2394
- budget:"low", qualityPreference:"cost-optimized"(用户说了预算有限)
2395
-
2396
- 用户: "企业级知识库问答,准确率是第一优先级"
2397
- budget:"high", qualityPreference:"flagship"(企业级+准确率第一=愿投入高成本)
2441
+ ## Output fields
2442
+ - taskSummary: one-sentence scenario understanding (must be specific, never generic like "user wants AI")
2443
+ - scenarioHints: array of inferred scenario features
2444
+ - complexity: "single" or "pipeline"
2445
+ - segments: only for pipeline, each with step/inputModality/outputModality/requiredCapabilities
2446
+ - step must describe the specific problem this step solves in the user's task, no numbered or generic modal labels
2447
+ - segments must form a modality chain: each step's inputModality should cover the previous step's outputModality
2448
+ - inputModality: user input modalities ["Text","Image","Video","Audio"]
2449
+ - outputModality: expected output modalities
2450
+ - requiredCapabilities: capability codes (use strictly from the list, don't invent):
2451
+ TG=Text Generation, Reasoning=Reasoning, VU=Vision Understanding, IG=Image Generation, VG=Video Generation,
2452
+ TTS=Text-to-Speech, ASR=Speech-to-Text, Realtime-ASR=Realtime Speech-to-Text,
2453
+ Realtime-Text-to-Speech=Realtime Text-to-Speech, Realtime-Audio-Translate=Realtime Audio Translation,
2454
+ Realtime-Omni=Realtime Omni-modal, Multimodal-Omni=Multimodal Omni, ME=Multimodal Embedding,
2455
+ TR=Translation, 3D-generation=3D Generation
2456
+ - requiredFeatures: required features (function-calling, web-search, structured-outputs, prefix-completion)
2457
+ - budget: "low"/"medium"/"high"
2458
+ - contextNeed: "standard"/"large"/"extra-large"
2459
+ - qualityPreference: "flagship"/"balanced"/"cost-optimized"
2460
+ - modelPreference: { mode, targets?, excludes? }
2398
2461
 
2399
- 用户: "个人学习项目,试试AI生成图片"
2400
- budget:"low", qualityPreference:"cost-optimized"(个人学习=成本敏感)
2462
+ Output only JSON, no other text.`;
2463
+ const SINGLE_SYSTEM_PROMPT = `You are a model recommendation advisor for Alibaba Cloud Model Studio. From the candidate models below, select the best recommendations.
2401
2464
 
2402
- 用户: "做一个Agent自动根据用户意图生成动画片"
2403
- → budget:"medium", qualityPreference:"balanced"(复杂pipeline,但没明确成本/质量约束)
2465
+ CRITICAL: You MUST respond entirely in English. Do not use any Chinese characters anywhere in your response. Every field — reason, highlights, step, summary — must be written in English.
2404
2466
 
2405
- ## 模型偏好识别
2406
- 分析用户是否提到了特定的模型、模型系列或厂商,据此判断推荐模式:
2407
- - 用户未提到任何模型/系列/厂商 mode:"unconstrained",不填 targets
2408
- - 用户限定了范围(如"deepseek系列哪个好"、"通义千问的模型推荐"、"开源的推理模型") → mode:"scoped",targets:["deepseek"] 或 ["通义千问"]
2409
- - 用户要对比特定模型(如"wan2.6和wan2.7哪个好"、"qwen-max和deepseek-v3对比"、"qwen-max适合做法律分析吗") → mode:"comparison",targets:["wan2.6","wan2.7"]
2410
- - 单模型评估也算 comparison,targets 只填一个
2411
- - 用户以某模型为参照找替代(如"有没有类似qwen-max但更便宜的") → mode:"alternative",targets:["qwen-max"]
2412
- - 用户明确排除某些模型/系列(如"除了qwen还有什么好的") → excludes:["qwen"],mode 根据其他条件判断
2413
- - targets 填写用户原文中的模型/系列名称,保持原文写法
2467
+ ## Background
2468
+ The system has pre-filtered candidate models based on intent analysis. Your job is to rank and pick from these candidates.
2469
+ The intent includes budget and qualityPreference fields representing the user's actual needs.
2414
2470
 
2415
- ## 输出字段
2416
- - taskSummary: 一句话场景理解(必须具体,禁止"用户想用AI做某事"这种废话)
2417
- - scenarioHints: 推断的场景特征数组
2418
- - complexity: "single"(单一模型可完成)或 "pipeline"(需要多个模型协同)
2419
- - segments: 仅 pipeline 时填写,每步包含 step/inputModality/outputModality/requiredCapabilities。
2420
- - step 必须是一句话描述该步骤在用户任务中解决的具体问题,例如"解析天气预报数据,生成适合视频制作的场景描述文本",禁止用编号或泛化的模态标签
2421
- - segments 必须形成模态链路:每步的 inputModality 应包含上一步的 outputModality,确保上下游数据可以衔接
2422
- - inputModality: 用户输入涉及的模态 ["Text","Image","Video","Audio"]
2423
- - outputModality: 期望输出的模态
2424
- - requiredCapabilities: 需要的能力。可选代码(必须严格使用,不要自创):
2425
- TG=文本生成, Reasoning=推理, VU=视觉理解, IG=图像生成, VG=视频生成,
2426
- TTS=语音合成, ASR=语音识别, Realtime-ASR=实时语音识别,
2427
- Realtime-Text-to-Speech=实时语音合成, Realtime-Audio-Translate=实时音频翻译,
2428
- Realtime-Omni=实时全模态, Multimodal-Omni=全模态, ME=多模态嵌入,
2429
- TR=翻译, 3D-generation=3D生成
2430
- - requiredFeatures: 需要的特性 (function-calling, web-search, structured-outputs, prefix-completion)
2431
- - budget: "low"/"medium"/"high"(基于场景推断,不要默认 medium)
2432
- - contextNeed: "standard"/"large"/"extra-large"
2433
- - qualityPreference: "flagship"/"balanced"/"cost-optimized"(基于场景推断,不要默认 balanced)
2434
- - modelPreference: { mode, targets?, excludes? }(见上方"模型偏好识别")
2471
+ ## Recommendation Strategy
2435
2472
 
2436
- 只输出 JSON,不要有其他文字。`;
2437
- const SINGLE_SYSTEM_PROMPT = `你是阿里云百炼平台的模型推荐顾问。从以下候选模型中选出最佳推荐。
2473
+ Recommend 3 models at different tiers, but ordering must reflect the user's true needs:
2438
2474
 
2439
- ## 背景
2440
- 系统已根据用户意图预筛选了候选模型,你只需从中精选并排序。
2441
- 意图分析中包含 budget qualityPreference 字段,这代表了用户的实际需求层次。
2475
+ - #1 (Best Pick): Based on budget and qualityPreference, pick the best-fitting tier and put its top model first
2476
+ - #2 (Runner-Up): A worthy consideration from another tier, explaining tradeoffs vs #1
2477
+ - #3 (Alternative): A third-perspective choice, explaining scenario differences
2442
2478
 
2443
- ## 推荐策略
2479
+ Key principles:
2480
+ - budget:"low" / qualityPreference:"cost-optimized" → #1 should be the best value model, not a flagship
2481
+ - budget:"high" / qualityPreference:"flagship" → #1 should be the most capable flagship model
2482
+ - budget:"medium" / qualityPreference:"balanced" → #1 should be the best all-around match
2444
2483
 
2445
- 推荐 3 个不同档次的模型,但排序必须反映用户的真实需求:
2484
+ Each recommendation must explain why the model fits (or as an alternative, why it's worth considering), with reasoning tied to the user's specific needs.
2446
2485
 
2447
- - 推荐 #1(最佳推荐):根据 budget 和 qualityPreference 判断哪个档次最适合用户,把那个档次的最佳模型放在第一位
2448
- - 推荐 #2(次优选择):另一个档次中值得考虑的模型,说明与 #1 相比的 tradeoff
2449
- - 推荐 #3(备选参考):第三个视角的选择,说明适用场景差异
2486
+ ## Rules
2487
+ - Only recommend models from the candidate list — never recommend outside it
2488
+ - No generic reasons ("powerful", "good performance", "effective"). Each reason must describe how the model solves a specific aspect of the user's task
2489
+ - All three recommendations must have distinct reasoning angles, not duplicate reasons
2490
+ - When pricing is available: factor in budget, put the most budget-friendly option first
2491
+ - When family info is available: avoid recommending multiple models from the same family, prefer stable versions
2492
+ - When version tags are available: prefer stable/latest versions unless the user explicitly needs a specific version
2493
+ - Models without enriched fields: rank by capability and description — don't penalize for missing info
2494
+ - If no model fits, return an empty array
2495
+ - If you believe the task actually requires multi-model collaboration (pipeline), you may output type:"pipeline" format
2496
+ - Output strict JSON, no other text
2450
2497
 
2451
- 关键原则:
2452
- - budget:"low" / qualityPreference:"cost-optimized" → 推荐 #1 应该是性价比最高的模型,而非旗舰模型
2453
- - budget:"high" / qualityPreference:"flagship" → 推荐 #1 应该是能力最强的旗舰模型
2454
- - budget:"medium" / qualityPreference:"balanced" → 推荐 #1 应该是综合匹配度最高的模型,不预设档次偏好
2498
+ ## Output Format
2455
2499
 
2456
- 每个推荐都必须说明该模型为什么适合(或作为备选为什么值得考虑),理由必须关联用户的具体需求。
2500
+ Single task:
2501
+ {"type":"single","recommendations":[{"model":"model ID","reason":"recommendation reason","highlights":["key highlights"]}]}
2457
2502
 
2458
- ## 规则
2459
- - 只能推荐候选列表中的模型,严禁推荐列表外的模型
2460
- - 严禁使用泛泛的推荐理由(如"性能强大"、"综合能力好"、"效果不错"),每条 reason 必须说明该模型解决用户任务中的什么具体问题
2461
- - 三个推荐的理由不允许雷同,每个必须从不同维度论证
2462
- - 有定价信息时:结合 budget 字段权衡,把最符合用户预算的放在最前面
2463
- - 有家族信息时:避免推荐同一家族的多个模型,优先推荐稳定版本
2464
- - 有版本标签时:优先推荐 stable/latest 版本,除非用户明确需要特定版本
2465
- - 没有增强字段的模型:按能力和描述排序即可,不因缺少信息而降权
2466
- - 如果没有合适的模型,返回空数组
2467
- - 如果你认为该需求实际需要多模型协同完成(pipeline),可以输出 type:"pipeline" 格式
2468
- - 输出严格 JSON,不要输出其他内容
2503
+ Pipeline (only when confident multi-model is needed):
2504
+ {"type":"pipeline","summary":"one-line solution description","steps":[{"step":"step description","recommendations":[{"model":"model ID","reason":"reason for choosing","highlights":["highlights"]}]}]}`;
2505
+ const PIPELINE_SYSTEM_PROMPT = `You are a model recommendation advisor for Alibaba Cloud Model Studio. The user's need has been decomposed into multi-step pipeline. Select the best model for each step.
2469
2506
 
2470
- ## 输出格式
2507
+ CRITICAL: You MUST respond entirely in English. Do not use any Chinese characters anywhere in your response. Every field — reason, highlights, step, summary — must be written in English.
2471
2508
 
2472
- 单一任务:
2473
- {"type":"single","recommendations":[{"model":"模型ID","reason":"推荐理由","highlights":["亮点"]}]}
2509
+ ## Background
2510
+ The system has pre-filtered candidate models for each step's requirements.
2511
+ The intent includes budget and qualityPreference fields representing the user's actual needs.
2474
2512
 
2475
- 复合任务(仅当你确信需要多模型协同时):
2476
- {"type":"pipeline","summary":"一句话方案描述","steps":[{"step":"步骤描述","recommendations":[{"model":"模型ID","reason":"选择理由","highlights":["亮点"]}]}]}`;
2477
- const PIPELINE_SYSTEM_PROMPT = `你是阿里云百炼平台的模型推荐顾问。用户需求已被拆解为多步骤流水线,请为每步选出最佳模型。
2513
+ ## Recommendation Strategy
2478
2514
 
2479
- ## 背景
2480
- 系统已根据各步骤需求预筛选了候选模型。
2481
- 意图分析中包含 budget 和 qualityPreference 字段,这代表了用户的实际需求层次。
2515
+ Recommend 3 models at different tiers per step, ordering by user needs:
2482
2516
 
2483
- ## 推荐策略
2517
+ - #1 (Best Pick): Based on budget and qualityPreference, pick the best-fitting tier and put its top model first
2518
+ - #2 (Runner-Up): A worthy consideration from another tier, explaining tradeoffs
2519
+ - #3 (Alternative): A third-perspective choice
2484
2520
 
2485
- 每步推荐 3 个不同档次的模型,但排序必须反映用户的真实需求:
2521
+ Key principles:
2522
+ - budget:"low" / qualityPreference:"cost-optimized" → #1 should be the best value model
2523
+ - budget:"high" / qualityPreference:"flagship" → #1 should be the most capable flagship model
2524
+ - budget:"medium" / qualityPreference:"balanced" → #1 should be the best all-around match
2486
2525
 
2487
- - 推荐 #1(最佳推荐):根据 budget 和 qualityPreference 判断哪个档次最适合用户,把那个档次的最佳模型放在第一位
2488
- - 推荐 #2(次优选择):另一个档次中值得考虑的模型,说明 tradeoff
2489
- - 推荐 #3(备选参考):第三个视角的选择,说明适用场景差异
2526
+ ## Rules
2527
+ - Only recommend models from the candidate list
2528
+ - Each step recommends multiple models sorted by priority, each with brief reason and key highlights
2529
+ - The "step" field must describe the specific problem this step solves in the user's task — no numbered or generic modal labels (e.g. "Output: Text")
2530
+ - No generic reasons. Each reason must describe how the model solves a specific aspect of the user's task at this step
2531
+ - When pricing is available: factor in budget, put the most budget-friendly option first
2532
+ - When family info is available: avoid using different tiers of the same family in adjacent steps unless truly needed
2533
+ - Models without enriched fields: rank by capability and description — don't penalize for missing info
2534
+ - Adjacent steps must be modality-compatible: the previous step's output modalities must be supported as input modalities by the next step
2535
+ - If you believe the task can be done with a single model, output type:"single" format
2536
+ - Output strict JSON
2490
2537
 
2491
- 关键原则:
2492
- - budget:"low" / qualityPreference:"cost-optimized" → 推荐 #1 应该是性价比最高的模型
2493
- - budget:"high" / qualityPreference:"flagship" → 推荐 #1 应该是能力最强的旗舰模型
2494
- - budget:"medium" / qualityPreference:"balanced" → 推荐 #1 应该是综合匹配度最高的模型
2538
+ ## Output Format
2495
2539
 
2496
- ## 规则
2497
- - 只能推荐候选列表中的模型
2498
- - 每步推荐多个模型,按优先级排序,每个推荐给出简短理由和关键亮点
2499
- - step 字段必须用一句话描述该步骤在用户任务中解决的具体问题,禁止用编号或泛化的模态标签(如"输出: Text")
2500
- - 严禁使用泛泛的推荐理由,每条 reason 必须说明该模型在这一步解决用户任务中的什么具体问题
2501
- - 有定价信息时:结合 budget 字段权衡,把最符合用户预算的放在最前面
2502
- - 有家族信息时:避免在相邻步骤使用同一家族的不同规格模型,除非确实需要
2503
- - 没有增强字段的模型:按能力和描述排序即可,不因缺少信息而降权
2504
- - 相邻步骤的模型必须模态兼容:上一步模型的输出模态必须被下一步模型的输入模态支持
2505
- - 如果你认为该需求其实单模型可以完成,可以输出 type:"single" 格式
2506
- - 输出严格 JSON
2540
+ {"type":"pipeline","summary":"one-line solution description","steps":[{"step":"specific problem this step solves in the user's task","recommendations":[{"model":"model ID","reason":"how this model solves the specific problem at this step","highlights":["highlights"]}]}]}
2507
2541
 
2508
- ## 输出格式
2542
+ Or (if single model suffices):
2543
+ {"type":"single","recommendations":[{"model":"model ID","reason":"recommendation reason","highlights":
2544
+ ["key highlights"]}]}`;
2545
+ const COMPARISON_SYSTEM_PROMPT = `You are a model comparison advisor for Alibaba Cloud Model Studio. The user wants to compare specific models — analyze them against the use case.
2509
2546
 
2510
- {"type":"pipeline","summary":"一句话方案描述","steps":[{"step":"该步骤在用户任务中解决的具体问题","recommendations":[{"model":"模型ID","reason":"该模型如何解决这一步的具体问题","highlights":["亮点"]}]}]}
2547
+ CRITICAL: You MUST respond entirely in English. Do not use any Chinese characters anywhere in your response. Every field — reason, highlights — must be written in English.
2511
2548
 
2512
- 或者(如果你认为单模型即可):
2513
- {"type":"single","recommendations":[{"model":"模型ID","reason":"推荐理由","highlights":["亮点"]}]}`;
2514
- const COMPARISON_SYSTEM_PROMPT = `你是阿里云百炼平台的模型对比顾问。用户想对比特定模型,请根据使用场景进行对比分析。
2549
+ ## Background
2550
+ The user specified models to compare. The system has pre-filtered these models and related candidates into the list.
2551
+ The intent's modelPreference.targets are the models to compare.
2515
2552
 
2516
- ## 背景
2517
- 用户指定了要对比的模型,系统已将这些模型和相关候选预筛选到列表中。
2518
- 意图分析中的 modelPreference.targets 是用户要对比的模型。
2553
+ ## Comparison Strategy
2554
+ - All user-specified models must appear in the results, sorted by suitability
2555
+ - Each model's reason must be comparative: describe strengths and weaknesses relative to other models being compared
2556
+ - If candidates contain better fits than what the user specified, they can be additionally recommended, but user-specified models take priority
2557
+ - Single-model evaluation (one target): evaluate if the model fits, and recommend better alternatives
2519
2558
 
2520
- ## 对比策略
2521
- - 用户指定的模型必须全部出现在推荐结果中,按适合程度排序
2522
- - 每个模型的 reason 必须是对比性的,说明该模型相对于其他对比模型的优势和劣势
2523
- - 如果候选中有比用户指定的更合适的模型,可以额外推荐,但用户指定的必须优先包含
2524
- - 单模型评估场景(targets 只有一个):评估该模型是否适合用户需求,同时推荐更优的替代
2559
+ ## Rules
2560
+ - Only recommend models from the candidate list
2561
+ - reason must include comparative perspective: how this model is better/worse compared to others
2562
+ - highlights should emphasize differentiating characteristics
2563
+ - Output strict JSON
2525
2564
 
2526
- ## 规则
2527
- - 只能推荐候选列表中的模型
2528
- - reason 必须包含对比视角:该模型相比其他模型在哪些方面更好/更差
2529
- - highlights 突出各模型的差异化特点
2530
- - 输出严格 JSON,不要输出其他内容
2565
+ ## Output Format
2566
+ {"type":"single","recommendations":[{"model":"model ID","reason":"comparative analysis","highlights":["differentiators"]}]}`;
2567
+ const ALTERNATIVE_SYSTEM_PROMPT = `You are a model alternative advisor for Alibaba Cloud Model Studio. The user has a reference model and wants to find alternatives.
2531
2568
 
2532
- ## 输出格式
2533
- {"type":"single","recommendations":[{"model":"模型ID","reason":"对比分析理由","highlights":["差异化亮点"]}]}`;
2534
- const ALTERNATIVE_SYSTEM_PROMPT = `你是阿里云百炼平台的模型替代顾问。用户以某个模型为参照,寻找替代方案。
2569
+ CRITICAL: You MUST respond entirely in English. Do not use any Chinese characters anywhere in your response. Every field — reason, highlights — must be written in English.
2535
2570
 
2536
- ## 背景
2537
- 用户以某个模型为参照点,想找到在特定维度上更优的替代方案(如更便宜、更快、更强)。
2538
- 意图分析中的 modelPreference.targets 是参照模型。
2571
+ ## Background
2572
+ The user has a reference model and wants to find alternatives that are better in specific dimensions (cheaper, faster, more capable).
2573
+ The intent's modelPreference.targets is the reference model.
2539
2574
 
2540
- ## 替代策略
2541
- - 推荐 #1:如果参照模型在候选中,先评估它是否满足用户需求,给出其基本定位
2542
- - 推荐 #2~#3:推荐替代方案,reason 必须说明相比参照模型在用户关注维度上的 tradeoff
2543
- - 关注用户提到的替代维度(如"更便宜"→重点对比定价,"更强"→重点对比能力)
2575
+ ## Alternative Strategy
2576
+ - #1: If the reference model is in candidates, first evaluate if it meets the user's needs — give its positioning
2577
+ - #2~#3: Recommend alternatives. reason must explain the tradeoff vs the reference model in the user's dimensions of interest
2578
+ - Focus on the user's stated alternative dimension (e.g. "cheaper" → focus on pricing comparison, "better" → focus on capability comparison)
2544
2579
 
2545
- ## 规则
2546
- - 只能推荐候选列表中的模型
2547
- - 参照模型必须包含在结果中(如果在候选列表中)
2548
- - 替代推荐的 reason 必须说明与参照模型的具体差异
2549
- - 避免推荐和参照模型同系列的其他版本(除非确实有显著差异)
2550
- - 输出严格 JSON,不要输出其他内容
2580
+ ## Rules
2581
+ - Only recommend models from the candidate list
2582
+ - The reference model must be included in results if it's in the candidate list
2583
+ - Alternative recommendations must explain concrete differences from the reference model
2584
+ - Avoid recommending other versions from the same family unless there's a significant difference
2585
+ - Output strict JSON
2551
2586
 
2552
- ## 输出格式
2553
- {"type":"single","recommendations":[{"model":"模型ID","reason":"替代分析理由","highlights":["差异化亮点"]}]}`;
2587
+ ## Output Format
2588
+ {"type":"single","recommendations":[{"model":"model ID","reason":"alternative analysis","highlights":["differentiators"]}]}`;
2554
2589
  //#endregion
2555
2590
  //#region src/advisor/constants/defaults.ts
2556
2591
  const DEFAULT_INTENT = {
@@ -2845,19 +2880,19 @@ async function embedBatch(config, texts) {
2845
2880
  })).data.sort((left, right) => left.index - right.index).map((item) => item.embedding);
2846
2881
  }
2847
2882
  const CAPABILITY_LABELS = {
2848
- TG: "文本生成",
2849
- Reasoning: "推理",
2850
- VU: "视觉理解",
2851
- IG: "图像生成",
2852
- VG: "视频生成",
2853
- TTS: "语音合成",
2854
- ASR: "语音识别"
2883
+ TG: "Text Generation",
2884
+ Reasoning: "Reasoning",
2885
+ VU: "Vision Understanding",
2886
+ IG: "Image Generation",
2887
+ VG: "Video Generation",
2888
+ TTS: "Text-to-Speech",
2889
+ ASR: "Speech-to-Text"
2855
2890
  };
2856
2891
  const MODALITY_LABELS = {
2857
- Text: "文本",
2858
- Image: "图片/图像",
2859
- Video: "视频",
2860
- Audio: "音频/语音"
2892
+ Text: "Text",
2893
+ Image: "Image",
2894
+ Video: "Video",
2895
+ Audio: "Audio"
2861
2896
  };
2862
2897
  function loadGroupDescriptions() {
2863
2898
  const groupsDir = join$1(skillDataDir(), "groups");
@@ -2879,12 +2914,12 @@ function buildModelText(model, descriptions) {
2879
2914
  model.name,
2880
2915
  model.model,
2881
2916
  description,
2882
- caps ? `能力: ${caps}` : "",
2883
- inputMods ? `输入: ${inputMods}` : "",
2884
- outputMods ? `输出: ${outputMods}` : "",
2885
- model.features?.length ? `特性: ${model.features.join(", ")}` : "",
2917
+ caps ? `Capabilities: ${caps}` : "",
2918
+ inputMods ? `Input: ${inputMods}` : "",
2919
+ outputMods ? `Output: ${outputMods}` : "",
2920
+ model.features?.length ? `Features: ${model.features.join(", ")}` : "",
2886
2921
  model.familyName || "",
2887
- model.category ? `定位: ${model.category}` : ""
2922
+ model.category ? `Category: ${model.category}` : ""
2888
2923
  ].filter(Boolean).join(" | ");
2889
2924
  }
2890
2925
  async function buildAndCacheEmbeddings(config, models) {
@@ -3124,51 +3159,51 @@ function buildCandidatesContext(candidates) {
3124
3159
  return candidates.map(({ model: profile }) => {
3125
3160
  const parts = [
3126
3161
  `ID: ${profile.model}`,
3127
- `名称: ${profile.name}`,
3128
- `描述: ${profile.shortDescription || profile.description}`,
3129
- `能力: ${profile.capabilities.join(", ")}`,
3130
- `特性: ${profile.features.join(", ")}`
3162
+ `Name: ${profile.name}`,
3163
+ `Description: ${profile.shortDescription || profile.description}`,
3164
+ `Capabilities: ${profile.capabilities.join(", ")}`,
3165
+ `Features: ${profile.features.join(", ")}`
3131
3166
  ];
3132
- if (profile.contextWindow) parts.push(`上下文窗口: ${profile.contextWindow}`);
3133
- if (profile.maxOutputTokens) parts.push(`最大输出: ${profile.maxOutputTokens}`);
3134
- if (profile.category) parts.push(`类别: ${profile.category}`);
3167
+ if (profile.contextWindow) parts.push(`Context Window: ${profile.contextWindow}`);
3168
+ if (profile.maxOutputTokens) parts.push(`Max Output: ${profile.maxOutputTokens}`);
3169
+ if (profile.category) parts.push(`Category: ${profile.category}`);
3135
3170
  const modality = profile.inferenceMetadata;
3136
- if (modality?.request_modality?.length) parts.push(`输入模态: ${modality.request_modality.join(", ")}`);
3137
- if (modality?.response_modality?.length) parts.push(`输出模态: ${modality.response_modality.join(", ")}`);
3171
+ if (modality?.request_modality?.length) parts.push(`Input Modality: ${modality.request_modality.join(", ")}`);
3172
+ if (modality?.response_modality?.length) parts.push(`Output Modality: ${modality.response_modality.join(", ")}`);
3138
3173
  const prices = formatPrices(profile);
3139
- if (prices) parts.push(`定价: ${prices}`);
3174
+ if (prices) parts.push(`Pricing: ${prices}`);
3140
3175
  const qpm = formatQpm(profile);
3141
3176
  if (qpm) parts.push(`QPM: ${qpm}`);
3142
- if (profile.versionTag) parts.push(`版本: ${profile.versionTag}`);
3143
- if (profile.openSource !== void 0) parts.push(`开源: ${profile.openSource ? "" : ""}`);
3144
- if (profile.family) parts.push(`家族: ${profile.family}`);
3177
+ if (profile.versionTag) parts.push(`Version: ${profile.versionTag}`);
3178
+ if (profile.openSource !== void 0) parts.push(`Open Source: ${profile.openSource ? "Yes" : "No"}`);
3179
+ if (profile.family) parts.push(`Family: ${profile.family}`);
3145
3180
  return parts.join(" | ");
3146
3181
  }).join("\n");
3147
3182
  }
3148
3183
  function buildIntentContext(intent) {
3149
3184
  const { taskSummary, scenarioHints, inputModality, outputModality, requiredCapabilities, requiredFeatures, budget, qualityPreference, contextNeed, segments, modelPreference } = intent;
3150
3185
  const parts = [];
3151
- if (taskSummary) parts.push(`场景理解: ${taskSummary}`);
3152
- if (scenarioHints.length) parts.push(`场景特征: ${scenarioHints.join(", ")}`);
3153
- if (inputModality.length) parts.push(`输入模态: ${inputModality.join(", ")}`);
3154
- if (outputModality.length) parts.push(`输出模态: ${outputModality.join(", ")}`);
3155
- if (requiredCapabilities.length) parts.push(`所需能力: ${requiredCapabilities.join(", ")}`);
3156
- if (requiredFeatures.length) parts.push(`所需特性: ${requiredFeatures.join(", ")}`);
3157
- parts.push(`预算倾向: ${budget}`);
3158
- parts.push(`质量偏好: ${qualityPreference}`);
3159
- if (contextNeed !== ContextNeeds.Standard) parts.push(`上下文需求: ${contextNeed}`);
3186
+ if (taskSummary) parts.push(`Task: ${taskSummary}`);
3187
+ if (scenarioHints.length) parts.push(`Scenario: ${scenarioHints.join(", ")}`);
3188
+ if (inputModality.length) parts.push(`Input: ${inputModality.join(", ")}`);
3189
+ if (outputModality.length) parts.push(`Output: ${outputModality.join(", ")}`);
3190
+ if (requiredCapabilities.length) parts.push(`Capabilities: ${requiredCapabilities.join(", ")}`);
3191
+ if (requiredFeatures.length) parts.push(`Features: ${requiredFeatures.join(", ")}`);
3192
+ parts.push(`Budget: ${budget}`);
3193
+ parts.push(`Quality: ${qualityPreference}`);
3194
+ if (contextNeed !== ContextNeeds.Standard) parts.push(`Context: ${contextNeed}`);
3160
3195
  if (modelPreference && modelPreference.mode !== "unconstrained") {
3161
- parts.push(`模型偏好: ${modelPreference.mode}`);
3162
- if (modelPreference.targets?.length) parts.push(`目标模型: ${modelPreference.targets.join(", ")}`);
3163
- if (modelPreference.excludes?.length) parts.push(`排除模型: ${modelPreference.excludes.join(", ")}`);
3196
+ parts.push(`Mode: ${modelPreference.mode}`);
3197
+ if (modelPreference.targets?.length) parts.push(`Targets: ${modelPreference.targets.join(", ")}`);
3198
+ if (modelPreference.excludes?.length) parts.push(`Excludes: ${modelPreference.excludes.join(", ")}`);
3164
3199
  }
3165
3200
  if (segments?.length) {
3166
- parts.push(`拆解步骤:`);
3201
+ parts.push(`Pipeline Steps:`);
3167
3202
  for (const seg of segments) {
3168
- const inMod = seg.inputModality.join(",") || "";
3169
- const outMod = seg.outputModality.join(",") || "";
3170
- const caps = seg.requiredCapabilities.join(",") || "";
3171
- parts.push(` - ${seg.step} (输入: ${inMod} → 输出: ${outMod}, 能力: ${caps})`);
3203
+ const inMod = seg.inputModality.join(",") || "none";
3204
+ const outMod = seg.outputModality.join(",") || "none";
3205
+ const caps = seg.requiredCapabilities.join(",") || "none";
3206
+ parts.push(` - ${seg.step} (Input: ${inMod} → Output: ${outMod}, Capabilities: ${caps})`);
3172
3207
  }
3173
3208
  }
3174
3209
  return parts.join("\n");
@@ -3214,7 +3249,7 @@ function validatePipelineCompatibility(steps, modelMap) {
3214
3249
  const warnings = [];
3215
3250
  for (const rec of currStep.recommendations) {
3216
3251
  const accepts = modelMap.get(rec.model)?.inferenceMetadata?.request_modality ?? [];
3217
- if (!accepts.some((mod) => prevOutputs.has(mod)) && accepts.length > 0) warnings.push(`${rec.name} 的输入模态 [${accepts.join(", ")}] 可能不兼容上一步的输出模态 [${[...prevOutputs].join(", ")}]`);
3252
+ if (!accepts.some((mod) => prevOutputs.has(mod)) && accepts.length > 0) warnings.push(`${rec.name}'s input modalities [${accepts.join(", ")}] may not be compatible with the previous step's output modalities [${[...prevOutputs].join(", ")}]`);
3218
3253
  }
3219
3254
  if (warnings.length > 0) currStep.warnings = warnings;
3220
3255
  }
@@ -3227,11 +3262,11 @@ async function rankModels(config, candidates, intent, userInput, top, options) {
3227
3262
  if (preferenceMode === "comparison") systemPrompt = COMPARISON_SYSTEM_PROMPT;
3228
3263
  else if (preferenceMode === "alternative") systemPrompt = ALTERNATIVE_SYSTEM_PROMPT;
3229
3264
  else if (preferenceMode === "scoped") {
3230
- const scopeNote = intent.modelPreference?.targets?.length ? `\n\n## 范围限定\n用户明确要求在以下范围内推荐:${intent.modelPreference.targets.join("")}。请优先从匹配该范围的模型中选择。` : "";
3265
+ const scopeNote = intent.modelPreference?.targets?.length ? `\n\n## Scope Restriction\nThe user explicitly requested recommendations from: ${intent.modelPreference.targets.join(", ")}. Prioritize models within this scope.` : "";
3231
3266
  systemPrompt = (intent.complexity === Complexities.Pipeline ? PIPELINE_SYSTEM_PROMPT : SINGLE_SYSTEM_PROMPT) + scopeNote;
3232
3267
  } else systemPrompt = intent.complexity === Complexities.Pipeline ? PIPELINE_SYSTEM_PROMPT : SINGLE_SYSTEM_PROMPT;
3233
3268
  const useThinkingModel = options?.enableThinking ?? false;
3234
- const userMessage = intent.complexity === Complexities.Pipeline ? `意图分析结果:\n${intentContext}\n\n候选模型列表:\n${candidatesContext}\n\n用户原始需求:${userInput}\n\n请为流水线各步骤各推荐最多 ${top} 个模型。` : `意图分析结果:\n${intentContext}\n\n候选模型列表:\n${candidatesContext}\n\n用户原始需求:${userInput}\n\n请推荐最多 ${top} 个模型。`;
3269
+ const userMessage = intent.complexity === Complexities.Pipeline ? `Intent Analysis:\n${intentContext}\n\nCandidate Models:\n${candidatesContext}\n\nUser Request: ${userInput}\n\nRecommend up to ${top} models for each pipeline step. Respond in English only.` : `Intent Analysis:\n${intentContext}\n\nCandidate Models:\n${candidatesContext}\n\nUser Request: ${userInput}\n\nRecommend up to ${top} models. Respond in English only.`;
3235
3270
  const body = {
3236
3271
  model: useThinkingModel ? RANKING_MODEL : RANKING_MODEL_FAST,
3237
3272
  messages: [{
@@ -3316,4 +3351,4 @@ async function rankModels(config, candidates, intent, userInput, top, options) {
3316
3351
  };
3317
3352
  }
3318
3353
  //#endregion
3319
- export { BAILIAN_HOST, BailianError, Budgets, CHANNEL, CONSOLE_GATEWAY_NO_TOKEN_MESSAGE, Capabilities, Complexities, ContextNeeds, DOCS_HOSTS, ExitCode, Features, GLOBAL_OPTIONS, McpClient, Modalities, ModelCategories, QualityPreferences, REGIONS, SOURCE_CONFIG, TAGS, analyzeIntent, appCompletionEndpoint, bailianMcpUrl, buildDocLink, callConsoleGateway, chatEndpoint, clearApiKey, createTrackingEvent, defineCommand, detectOutputFormat, ensureConfigDir, fetchModelList, flushTelemetry, formatErrorJson, formatJson, formatOutput, formatText, generateFilename, generateToolSchema, getConfigDir, getConfigPath, getCredentialsPath, getModels, imageEndpoint, imageSyncEndpoint, isCI, isInteractive, isLocalFile, isSemanticAvailable, knowledgeRetrieveEndpoint, loadApiKeyFromConfig, loadConfig, localSink, mapApiError, maskToken, mcpWebSearchEndpoint, memoryAddEndpoint, memoryListEndpoint, memoryNodeEndpoint, memorySearchEndpoint, parseBooleanValue, parseConfigFile, parseOptionalBooleanValue, parseSSE, profileSchemaEndpoint, rankModels, readConfigFile, recallCandidates, recallSemantic, remoteSink, request, requestJson, resolveBooleanFlag, resolveConsoleGatewayCredential, resolveCredential, resolveFileUrl, resolveOutputDir, resolveWatermark, saveApiKeyToConfig, signRequest, speechRecognizeEndpoint, speechSynthesizeEndpoint, stripUndefined, taskEndpoint, trackCommandExecution, trackingHeaders, uploadFile, userProfileEndpoint, videoGenerateEndpoint, writeConfigFile };
3354
+ export { BAILIAN_HOST, BailianError, Budgets, CHANNEL, CONSOLE_GATEWAY_NO_TOKEN_MESSAGE, Capabilities, Complexities, ContextNeeds, DOCS_HOSTS, ExitCode, Features, GLOBAL_OPTIONS, McpClient, Modalities, ModelCategories, QualityPreferences, REGIONS, SOURCE_CONFIG, TAGS, analyzeIntent, appCompletionEndpoint, bailianMcpUrl, buildDocLink, callConsoleGateway, chatEndpoint, clearApiKey, createTrackingEvent, defineCommand, detectOutputFormat, effectiveConsoleGatewayConfig, ensureConfigDir, fetchModelList, flushTelemetry, formatErrorJson, formatJson, formatOutput, formatText, generateFilename, generateToolSchema, getConfigDir, getConfigPath, getCredentialsPath, getModels, imageEndpoint, imageSyncEndpoint, isCI, isInteractive, isLocalFile, isSemanticAvailable, knowledgeRetrieveEndpoint, loadApiKeyFromConfig, loadConfig, localSink, mapApiError, maskToken, mcpWebSearchEndpoint, memoryAddEndpoint, memoryListEndpoint, memoryNodeEndpoint, memorySearchEndpoint, parseBooleanValue, parseConfigFile, parseOptionalBooleanValue, parseSSE, profileSchemaEndpoint, rankModels, readConfigFile, recallCandidates, recallSemantic, remoteSink, request, requestJson, resolveBooleanFlag, resolveConsoleGatewayCredential, resolveCredential, resolveFileUrl, resolveOutputDir, resolveWatermark, saveApiKeyToConfig, signRequest, speechRecognizeEndpoint, speechSynthesizeEndpoint, stripUndefined, taskEndpoint, trackCommandExecution, trackingHeaders, uploadFile, userProfileEndpoint, videoGenerateEndpoint, writeConfigFile };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bailian-cli-core",
3
- "version": "1.3.3",
3
+ "version": "1.4.0",
4
4
  "description": "Core SDK for bailian-cli. See https://www.npmjs.com/package/bailian-cli for usage.",
5
5
  "homepage": "https://bailian.console.aliyun.com/cli",
6
6
  "bugs": {