bailian-cli-core 1.3.2 → 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,8 @@ interface Command {
903
919
  usage?: string;
904
920
  options?: OptionDef[];
905
921
  examples?: string[];
922
+ skipDefaultApiKeySetup?: boolean;
923
+ notes?: string[];
906
924
  execute: (config: Config, flags: GlobalFlags) => Promise<void>;
907
925
  }
908
926
  interface CommandSpec {
@@ -911,6 +929,8 @@ interface CommandSpec {
911
929
  usage?: string;
912
930
  options?: OptionDef[];
913
931
  examples?: string[];
932
+ skipDefaultApiKeySetup?: boolean;
933
+ notes?: string[];
914
934
  run: (config: Config, flags: GlobalFlags) => Promise<void>;
915
935
  }
916
936
  declare function defineCommand(spec: CommandSpec): Command;
@@ -1007,7 +1027,6 @@ interface TrackingEvent {
1007
1027
  httpStatus?: number;
1008
1028
  requestId?: string;
1009
1029
  cliVersion: string;
1010
- region: string;
1011
1030
  nodeVersion: string;
1012
1031
  os: string;
1013
1032
  authMethod?: string;
@@ -1023,7 +1042,6 @@ declare function createTrackingEvent(opts: {
1023
1042
  requestId?: string;
1024
1043
  };
1025
1044
  cliVersion: string;
1026
- region: string;
1027
1045
  authMethod?: string;
1028
1046
  params?: Record<string, unknown>;
1029
1047
  }): TrackingEvent;
@@ -1233,4 +1251,4 @@ interface ModelSource {
1233
1251
  load(): Promise<ModelProfile[]>;
1234
1252
  }
1235
1253
  //#endregion
1236
- 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,8 @@ function defineCommand(spec) {
921
964
  usage: spec.usage,
922
965
  options: spec.options,
923
966
  examples: spec.examples,
967
+ skipDefaultApiKeySetup: spec.skipDefaultApiKeySetup,
968
+ notes: spec.notes,
924
969
  execute: (config, flags) => spec.run(config, flags)
925
970
  };
926
971
  }
@@ -930,10 +975,6 @@ const GLOBAL_OPTIONS = [
930
975
  flag: "--api-key <key>",
931
976
  description: "API key"
932
977
  },
933
- {
934
- flag: "--region <region>",
935
- description: "API region: cn (default), us, intl"
936
- },
937
978
  {
938
979
  flag: "--base-url <url>",
939
980
  description: "API base URL"
@@ -972,6 +1013,19 @@ const GLOBAL_OPTIONS = [
972
1013
  description: "Run N parallel requests (default: 1)",
973
1014
  type: "number"
974
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
+ },
975
1029
  {
976
1030
  flag: "--help",
977
1031
  description: "Show help"
@@ -1150,7 +1204,6 @@ function createTrackingEvent(opts) {
1150
1204
  durationMs: opts.durationMs,
1151
1205
  success: opts.success,
1152
1206
  cliVersion: opts.cliVersion,
1153
- region: opts.region,
1154
1207
  nodeVersion: process.version,
1155
1208
  os: process.platform
1156
1209
  };
@@ -2057,7 +2110,6 @@ const GLOBAL_FLAG_KEYS = new Set([
2057
2110
  "help",
2058
2111
  "nonInteractive",
2059
2112
  "async",
2060
- "region",
2061
2113
  "console"
2062
2114
  ]);
2063
2115
  /**
@@ -2155,7 +2207,6 @@ async function trackCommandExecution(config, commandPath, flags, fn) {
2155
2207
  requestId
2156
2208
  },
2157
2209
  cliVersion: config.clientVersion ?? "unknown",
2158
- region: config.region,
2159
2210
  authMethod,
2160
2211
  params: extractParams(flags)
2161
2212
  });
@@ -2359,197 +2410,182 @@ const ModelCategories = {
2359
2410
  };
2360
2411
  //#endregion
2361
2412
  //#region src/advisor/constants/prompts.ts
2362
- const INTENT_MODEL = "qwen-turbo";
2413
+ const INTENT_MODEL = "qwen-flash";
2363
2414
  const RANKING_MODEL = "qwen3.6-flash";
2364
- const RANKING_MODEL_FAST = "qwen-turbo";
2365
- const INTENT_SYSTEM_PROMPT = `你是一个意图分析器。根据用户的需求描述,先理解用户场景,再提取结构化信息。
2366
-
2367
- ## 分析步骤
2368
- 1. 用一句话总结用户的核心需求(taskSummary),要体现具体场景而非泛泛描述
2369
- 2. 推断场景特征(scenarioHints),例如:["需要低延迟","面向C端用户","高并发","对话式交互","离线批处理","需要精准度"]
2370
- 3. 基于场景特征推断 budget 和 qualityPreference
2371
- - 只在用户明确表达或场景强烈暗示时偏离默认值
2372
- - 用户明确说"低成本"、"便宜"、"省钱" → budget:"low"
2373
- - 用户明确说"最好的"、"高精度"、"不计成本" → qualityPreference:"flagship"
2374
- - 场景本身有强约束时才推断:如"日均百万请求的客服" → budget:"low"(高并发=成本敏感)
2375
- - 其他情况保持 budget:"medium", qualityPreference:"balanced"
2376
- 4. 提取模态、能力、特性等结构化字段
2377
-
2378
- ## 示例
2379
-
2380
- 用户: "做一个低成本高并发的在线客服"
2381
- → 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.
2382
2417
 
2383
- 用户: "法律合同审查,要求高精准度"
2384
- → 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.
2385
2419
 
2386
- 用户: "我要做一个能理解图片的客服机器人"
2387
- 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.
2388
2430
 
2389
- 用户: "帮我选一个写代码的模型"
2390
- 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
2391
2440
 
2392
- 用户: "预算有限,做个简单的文本摘要功能"
2393
- budget:"low", qualityPreference:"cost-optimized"(用户说了预算有限)
2394
-
2395
- 用户: "企业级知识库问答,准确率是第一优先级"
2396
- 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? }
2397
2461
 
2398
- 用户: "个人学习项目,试试AI生成图片"
2399
- 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.
2400
2464
 
2401
- 用户: "做一个Agent自动根据用户意图生成动画片"
2402
- → 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.
2403
2466
 
2404
- ## 模型偏好识别
2405
- 分析用户是否提到了特定的模型、模型系列或厂商,据此判断推荐模式:
2406
- - 用户未提到任何模型/系列/厂商 mode:"unconstrained",不填 targets
2407
- - 用户限定了范围(如"deepseek系列哪个好"、"通义千问的模型推荐"、"开源的推理模型") → mode:"scoped",targets:["deepseek"] 或 ["通义千问"]
2408
- - 用户要对比特定模型(如"wan2.6和wan2.7哪个好"、"qwen-max和deepseek-v3对比"、"qwen-max适合做法律分析吗") → mode:"comparison",targets:["wan2.6","wan2.7"]
2409
- - 单模型评估也算 comparison,targets 只填一个
2410
- - 用户以某模型为参照找替代(如"有没有类似qwen-max但更便宜的") → mode:"alternative",targets:["qwen-max"]
2411
- - 用户明确排除某些模型/系列(如"除了qwen还有什么好的") → excludes:["qwen"],mode 根据其他条件判断
2412
- - 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.
2413
2470
 
2414
- ## 输出字段
2415
- - taskSummary: 一句话场景理解(必须具体,禁止"用户想用AI做某事"这种废话)
2416
- - scenarioHints: 推断的场景特征数组
2417
- - complexity: "single"(单一模型可完成)或 "pipeline"(需要多个模型协同)
2418
- - segments: 仅 pipeline 时填写,每步包含 step/inputModality/outputModality/requiredCapabilities。
2419
- - step 必须是一句话描述该步骤在用户任务中解决的具体问题,例如"解析天气预报数据,生成适合视频制作的场景描述文本",禁止用编号或泛化的模态标签
2420
- - segments 必须形成模态链路:每步的 inputModality 应包含上一步的 outputModality,确保上下游数据可以衔接
2421
- - inputModality: 用户输入涉及的模态 ["Text","Image","Video","Audio"]
2422
- - outputModality: 期望输出的模态
2423
- - requiredCapabilities: 需要的能力。可选代码(必须严格使用,不要自创):
2424
- TG=文本生成, Reasoning=推理, VU=视觉理解, IG=图像生成, VG=视频生成,
2425
- TTS=语音合成, ASR=语音识别, Realtime-ASR=实时语音识别,
2426
- Realtime-Text-to-Speech=实时语音合成, Realtime-Audio-Translate=实时音频翻译,
2427
- Realtime-Omni=实时全模态, Multimodal-Omni=全模态, ME=多模态嵌入,
2428
- TR=翻译, 3D-generation=3D生成
2429
- - requiredFeatures: 需要的特性 (function-calling, web-search, structured-outputs, prefix-completion)
2430
- - budget: "low"/"medium"/"high"(基于场景推断,不要默认 medium)
2431
- - contextNeed: "standard"/"large"/"extra-large"
2432
- - qualityPreference: "flagship"/"balanced"/"cost-optimized"(基于场景推断,不要默认 balanced)
2433
- - modelPreference: { mode, targets?, excludes? }(见上方"模型偏好识别")
2471
+ ## Recommendation Strategy
2434
2472
 
2435
- 只输出 JSON,不要有其他文字。`;
2436
- const SINGLE_SYSTEM_PROMPT = `你是阿里云百炼平台的模型推荐顾问。从以下候选模型中选出最佳推荐。
2473
+ Recommend 3 models at different tiers, but ordering must reflect the user's true needs:
2437
2474
 
2438
- ## 背景
2439
- 系统已根据用户意图预筛选了候选模型,你只需从中精选并排序。
2440
- 意图分析中包含 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
2441
2478
 
2442
- ## 推荐策略
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
2443
2483
 
2444
- 推荐 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.
2445
2485
 
2446
- - 推荐 #1(最佳推荐):根据 budget 和 qualityPreference 判断哪个档次最适合用户,把那个档次的最佳模型放在第一位
2447
- - 推荐 #2(次优选择):另一个档次中值得考虑的模型,说明与 #1 相比的 tradeoff
2448
- - 推荐 #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
2449
2497
 
2450
- 关键原则:
2451
- - budget:"low" / qualityPreference:"cost-optimized" → 推荐 #1 应该是性价比最高的模型,而非旗舰模型
2452
- - budget:"high" / qualityPreference:"flagship" → 推荐 #1 应该是能力最强的旗舰模型
2453
- - budget:"medium" / qualityPreference:"balanced" → 推荐 #1 应该是综合匹配度最高的模型,不预设档次偏好
2498
+ ## Output Format
2454
2499
 
2455
- 每个推荐都必须说明该模型为什么适合(或作为备选为什么值得考虑),理由必须关联用户的具体需求。
2500
+ Single task:
2501
+ {"type":"single","recommendations":[{"model":"model ID","reason":"recommendation reason","highlights":["key highlights"]}]}
2456
2502
 
2457
- ## 规则
2458
- - 只能推荐候选列表中的模型,严禁推荐列表外的模型
2459
- - 严禁使用泛泛的推荐理由(如"性能强大"、"综合能力好"、"效果不错"),每条 reason 必须说明该模型解决用户任务中的什么具体问题
2460
- - 三个推荐的理由不允许雷同,每个必须从不同维度论证
2461
- - 有定价信息时:结合 budget 字段权衡,把最符合用户预算的放在最前面
2462
- - 有家族信息时:避免推荐同一家族的多个模型,优先推荐稳定版本
2463
- - 有版本标签时:优先推荐 stable/latest 版本,除非用户明确需要特定版本
2464
- - 没有增强字段的模型:按能力和描述排序即可,不因缺少信息而降权
2465
- - 如果没有合适的模型,返回空数组
2466
- - 如果你认为该需求实际需要多模型协同完成(pipeline),可以输出 type:"pipeline" 格式
2467
- - 输出严格 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.
2468
2506
 
2469
- ## 输出格式
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.
2470
2508
 
2471
- 单一任务:
2472
- {"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.
2473
2512
 
2474
- 复合任务(仅当你确信需要多模型协同时):
2475
- {"type":"pipeline","summary":"一句话方案描述","steps":[{"step":"步骤描述","recommendations":[{"model":"模型ID","reason":"选择理由","highlights":["亮点"]}]}]}`;
2476
- const PIPELINE_SYSTEM_PROMPT = `你是阿里云百炼平台的模型推荐顾问。用户需求已被拆解为多步骤流水线,请为每步选出最佳模型。
2513
+ ## Recommendation Strategy
2477
2514
 
2478
- ## 背景
2479
- 系统已根据各步骤需求预筛选了候选模型。
2480
- 意图分析中包含 budget 和 qualityPreference 字段,这代表了用户的实际需求层次。
2515
+ Recommend 3 models at different tiers per step, ordering by user needs:
2481
2516
 
2482
- ## 推荐策略
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
2483
2520
 
2484
- 每步推荐 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
2485
2525
 
2486
- - 推荐 #1(最佳推荐):根据 budget 和 qualityPreference 判断哪个档次最适合用户,把那个档次的最佳模型放在第一位
2487
- - 推荐 #2(次优选择):另一个档次中值得考虑的模型,说明 tradeoff
2488
- - 推荐 #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
2489
2537
 
2490
- 关键原则:
2491
- - budget:"low" / qualityPreference:"cost-optimized" → 推荐 #1 应该是性价比最高的模型
2492
- - budget:"high" / qualityPreference:"flagship" → 推荐 #1 应该是能力最强的旗舰模型
2493
- - budget:"medium" / qualityPreference:"balanced" → 推荐 #1 应该是综合匹配度最高的模型
2538
+ ## Output Format
2494
2539
 
2495
- ## 规则
2496
- - 只能推荐候选列表中的模型
2497
- - 每步推荐多个模型,按优先级排序,每个推荐给出简短理由和关键亮点
2498
- - step 字段必须用一句话描述该步骤在用户任务中解决的具体问题,禁止用编号或泛化的模态标签(如"输出: Text")
2499
- - 严禁使用泛泛的推荐理由,每条 reason 必须说明该模型在这一步解决用户任务中的什么具体问题
2500
- - 有定价信息时:结合 budget 字段权衡,把最符合用户预算的放在最前面
2501
- - 有家族信息时:避免在相邻步骤使用同一家族的不同规格模型,除非确实需要
2502
- - 没有增强字段的模型:按能力和描述排序即可,不因缺少信息而降权
2503
- - 相邻步骤的模型必须模态兼容:上一步模型的输出模态必须被下一步模型的输入模态支持
2504
- - 如果你认为该需求其实单模型可以完成,可以输出 type:"single" 格式
2505
- - 输出严格 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"]}]}]}
2506
2541
 
2507
- ## 输出格式
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.
2508
2546
 
2509
- {"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.
2510
2548
 
2511
- 或者(如果你认为单模型即可):
2512
- {"type":"single","recommendations":[{"model":"模型ID","reason":"推荐理由","highlights":["亮点"]}]}`;
2513
- 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.
2514
2552
 
2515
- ## 背景
2516
- 用户指定了要对比的模型,系统已将这些模型和相关候选预筛选到列表中。
2517
- 意图分析中的 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
2518
2558
 
2519
- ## 对比策略
2520
- - 用户指定的模型必须全部出现在推荐结果中,按适合程度排序
2521
- - 每个模型的 reason 必须是对比性的,说明该模型相对于其他对比模型的优势和劣势
2522
- - 如果候选中有比用户指定的更合适的模型,可以额外推荐,但用户指定的必须优先包含
2523
- - 单模型评估场景(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
2524
2564
 
2525
- ## 规则
2526
- - 只能推荐候选列表中的模型
2527
- - reason 必须包含对比视角:该模型相比其他模型在哪些方面更好/更差
2528
- - highlights 突出各模型的差异化特点
2529
- - 输出严格 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.
2530
2568
 
2531
- ## 输出格式
2532
- {"type":"single","recommendations":[{"model":"模型ID","reason":"对比分析理由","highlights":["差异化亮点"]}]}`;
2533
- 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.
2534
2570
 
2535
- ## 背景
2536
- 用户以某个模型为参照点,想找到在特定维度上更优的替代方案(如更便宜、更快、更强)。
2537
- 意图分析中的 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.
2538
2574
 
2539
- ## 替代策略
2540
- - 推荐 #1:如果参照模型在候选中,先评估它是否满足用户需求,给出其基本定位
2541
- - 推荐 #2~#3:推荐替代方案,reason 必须说明相比参照模型在用户关注维度上的 tradeoff
2542
- - 关注用户提到的替代维度(如"更便宜"→重点对比定价,"更强"→重点对比能力)
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)
2543
2579
 
2544
- ## 规则
2545
- - 只能推荐候选列表中的模型
2546
- - 参照模型必须包含在结果中(如果在候选列表中)
2547
- - 替代推荐的 reason 必须说明与参照模型的具体差异
2548
- - 避免推荐和参照模型同系列的其他版本(除非确实有显著差异)
2549
- - 输出严格 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
2550
2586
 
2551
- ## 输出格式
2552
- {"type":"single","recommendations":[{"model":"模型ID","reason":"替代分析理由","highlights":["差异化亮点"]}]}`;
2587
+ ## Output Format
2588
+ {"type":"single","recommendations":[{"model":"model ID","reason":"alternative analysis","highlights":["differentiators"]}]}`;
2553
2589
  //#endregion
2554
2590
  //#region src/advisor/constants/defaults.ts
2555
2591
  const DEFAULT_INTENT = {
@@ -2844,19 +2880,19 @@ async function embedBatch(config, texts) {
2844
2880
  })).data.sort((left, right) => left.index - right.index).map((item) => item.embedding);
2845
2881
  }
2846
2882
  const CAPABILITY_LABELS = {
2847
- TG: "文本生成",
2848
- Reasoning: "推理",
2849
- VU: "视觉理解",
2850
- IG: "图像生成",
2851
- VG: "视频生成",
2852
- TTS: "语音合成",
2853
- 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"
2854
2890
  };
2855
2891
  const MODALITY_LABELS = {
2856
- Text: "文本",
2857
- Image: "图片/图像",
2858
- Video: "视频",
2859
- Audio: "音频/语音"
2892
+ Text: "Text",
2893
+ Image: "Image",
2894
+ Video: "Video",
2895
+ Audio: "Audio"
2860
2896
  };
2861
2897
  function loadGroupDescriptions() {
2862
2898
  const groupsDir = join$1(skillDataDir(), "groups");
@@ -2878,12 +2914,12 @@ function buildModelText(model, descriptions) {
2878
2914
  model.name,
2879
2915
  model.model,
2880
2916
  description,
2881
- caps ? `能力: ${caps}` : "",
2882
- inputMods ? `输入: ${inputMods}` : "",
2883
- outputMods ? `输出: ${outputMods}` : "",
2884
- 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(", ")}` : "",
2885
2921
  model.familyName || "",
2886
- model.category ? `定位: ${model.category}` : ""
2922
+ model.category ? `Category: ${model.category}` : ""
2887
2923
  ].filter(Boolean).join(" | ");
2888
2924
  }
2889
2925
  async function buildAndCacheEmbeddings(config, models) {
@@ -3123,51 +3159,51 @@ function buildCandidatesContext(candidates) {
3123
3159
  return candidates.map(({ model: profile }) => {
3124
3160
  const parts = [
3125
3161
  `ID: ${profile.model}`,
3126
- `名称: ${profile.name}`,
3127
- `描述: ${profile.shortDescription || profile.description}`,
3128
- `能力: ${profile.capabilities.join(", ")}`,
3129
- `特性: ${profile.features.join(", ")}`
3162
+ `Name: ${profile.name}`,
3163
+ `Description: ${profile.shortDescription || profile.description}`,
3164
+ `Capabilities: ${profile.capabilities.join(", ")}`,
3165
+ `Features: ${profile.features.join(", ")}`
3130
3166
  ];
3131
- if (profile.contextWindow) parts.push(`上下文窗口: ${profile.contextWindow}`);
3132
- if (profile.maxOutputTokens) parts.push(`最大输出: ${profile.maxOutputTokens}`);
3133
- 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}`);
3134
3170
  const modality = profile.inferenceMetadata;
3135
- if (modality?.request_modality?.length) parts.push(`输入模态: ${modality.request_modality.join(", ")}`);
3136
- 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(", ")}`);
3137
3173
  const prices = formatPrices(profile);
3138
- if (prices) parts.push(`定价: ${prices}`);
3174
+ if (prices) parts.push(`Pricing: ${prices}`);
3139
3175
  const qpm = formatQpm(profile);
3140
3176
  if (qpm) parts.push(`QPM: ${qpm}`);
3141
- if (profile.versionTag) parts.push(`版本: ${profile.versionTag}`);
3142
- if (profile.openSource !== void 0) parts.push(`开源: ${profile.openSource ? "" : ""}`);
3143
- 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}`);
3144
3180
  return parts.join(" | ");
3145
3181
  }).join("\n");
3146
3182
  }
3147
3183
  function buildIntentContext(intent) {
3148
3184
  const { taskSummary, scenarioHints, inputModality, outputModality, requiredCapabilities, requiredFeatures, budget, qualityPreference, contextNeed, segments, modelPreference } = intent;
3149
3185
  const parts = [];
3150
- if (taskSummary) parts.push(`场景理解: ${taskSummary}`);
3151
- if (scenarioHints.length) parts.push(`场景特征: ${scenarioHints.join(", ")}`);
3152
- if (inputModality.length) parts.push(`输入模态: ${inputModality.join(", ")}`);
3153
- if (outputModality.length) parts.push(`输出模态: ${outputModality.join(", ")}`);
3154
- if (requiredCapabilities.length) parts.push(`所需能力: ${requiredCapabilities.join(", ")}`);
3155
- if (requiredFeatures.length) parts.push(`所需特性: ${requiredFeatures.join(", ")}`);
3156
- parts.push(`预算倾向: ${budget}`);
3157
- parts.push(`质量偏好: ${qualityPreference}`);
3158
- 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}`);
3159
3195
  if (modelPreference && modelPreference.mode !== "unconstrained") {
3160
- parts.push(`模型偏好: ${modelPreference.mode}`);
3161
- if (modelPreference.targets?.length) parts.push(`目标模型: ${modelPreference.targets.join(", ")}`);
3162
- 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(", ")}`);
3163
3199
  }
3164
3200
  if (segments?.length) {
3165
- parts.push(`拆解步骤:`);
3201
+ parts.push(`Pipeline Steps:`);
3166
3202
  for (const seg of segments) {
3167
- const inMod = seg.inputModality.join(",") || "";
3168
- const outMod = seg.outputModality.join(",") || "";
3169
- const caps = seg.requiredCapabilities.join(",") || "";
3170
- 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})`);
3171
3207
  }
3172
3208
  }
3173
3209
  return parts.join("\n");
@@ -3213,7 +3249,7 @@ function validatePipelineCompatibility(steps, modelMap) {
3213
3249
  const warnings = [];
3214
3250
  for (const rec of currStep.recommendations) {
3215
3251
  const accepts = modelMap.get(rec.model)?.inferenceMetadata?.request_modality ?? [];
3216
- 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(", ")}]`);
3217
3253
  }
3218
3254
  if (warnings.length > 0) currStep.warnings = warnings;
3219
3255
  }
@@ -3226,11 +3262,11 @@ async function rankModels(config, candidates, intent, userInput, top, options) {
3226
3262
  if (preferenceMode === "comparison") systemPrompt = COMPARISON_SYSTEM_PROMPT;
3227
3263
  else if (preferenceMode === "alternative") systemPrompt = ALTERNATIVE_SYSTEM_PROMPT;
3228
3264
  else if (preferenceMode === "scoped") {
3229
- 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.` : "";
3230
3266
  systemPrompt = (intent.complexity === Complexities.Pipeline ? PIPELINE_SYSTEM_PROMPT : SINGLE_SYSTEM_PROMPT) + scopeNote;
3231
3267
  } else systemPrompt = intent.complexity === Complexities.Pipeline ? PIPELINE_SYSTEM_PROMPT : SINGLE_SYSTEM_PROMPT;
3232
3268
  const useThinkingModel = options?.enableThinking ?? false;
3233
- 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.`;
3234
3270
  const body = {
3235
3271
  model: useThinkingModel ? RANKING_MODEL : RANKING_MODEL_FAST,
3236
3272
  messages: [{
@@ -3315,4 +3351,4 @@ async function rankModels(config, candidates, intent, userInput, top, options) {
3315
3351
  };
3316
3352
  }
3317
3353
  //#endregion
3318
- 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.2",
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": {