@midscene/shared 0.28.2 → 0.28.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/es/env/{model-config.mjs → decide-model-config.mjs} +52 -50
  2. package/dist/es/env/global-config-manager.mjs +91 -0
  3. package/dist/es/env/index.mjs +3 -2
  4. package/dist/es/env/model-config-manager.mjs +95 -0
  5. package/dist/es/env/parse.mjs +8 -23
  6. package/dist/es/env/types.mjs +16 -1
  7. package/dist/es/env/utils.mjs +7 -52
  8. package/dist/lib/env/{model-config.js → decide-model-config.js} +57 -52
  9. package/dist/lib/env/global-config-manager.js +125 -0
  10. package/dist/lib/env/index.js +17 -8
  11. package/dist/lib/env/model-config-manager.js +129 -0
  12. package/dist/lib/env/parse.js +9 -27
  13. package/dist/lib/env/types.js +23 -2
  14. package/dist/lib/env/utils.js +12 -69
  15. package/dist/types/env/decide-model-config.d.ts +14 -0
  16. package/dist/types/env/global-config-manager.d.ts +32 -0
  17. package/dist/types/env/helper.d.ts +1 -1
  18. package/dist/types/env/index.d.ts +2 -1
  19. package/dist/types/env/model-config-manager.d.ts +23 -0
  20. package/dist/types/env/parse.d.ts +2 -13
  21. package/dist/types/env/types.d.ts +52 -2
  22. package/dist/types/env/utils.d.ts +4 -8
  23. package/package.json +1 -1
  24. package/src/env/{model-config.ts → decide-model-config.ts} +91 -139
  25. package/src/env/global-config-manager.ts +174 -0
  26. package/src/env/helper.ts +1 -1
  27. package/src/env/index.ts +2 -1
  28. package/src/env/model-config-manager.ts +135 -0
  29. package/src/env/parse.ts +5 -24
  30. package/src/env/types.ts +61 -3
  31. package/src/env/utils.ts +7 -98
  32. package/dist/es/env/global-config.mjs +0 -192
  33. package/dist/lib/env/global-config.js +0 -229
  34. package/dist/types/env/global-config.d.ts +0 -52
  35. package/dist/types/env/model-config.d.ts +0 -70
  36. package/src/env/global-config.ts +0 -329
@@ -0,0 +1,174 @@
1
+ import { getDebug } from '../logger';
2
+ import { initDebugConfig } from './init-debug';
3
+ import type { ModelConfigManager } from './model-config-manager';
4
+ import {
5
+ BOOLEAN_ENV_KEYS,
6
+ GLOBAL_ENV_KEYS,
7
+ NUMBER_ENV_KEYS,
8
+ STRING_ENV_KEYS,
9
+ } from './types';
10
+
11
+ import {
12
+ ALL_ENV_KEYS,
13
+ MATCH_BY_POSITION,
14
+ MODEL_ENV_KEYS,
15
+ type TGlobalConfig,
16
+ } from './types';
17
+
18
+ /**
19
+ * Collect global configs from process.env, overrideAIConfig, etc.
20
+ * And provider methods to get merged config value
21
+ */
22
+ export class GlobalConfigManager {
23
+ private override:
24
+ | {
25
+ newConfig?: Partial<TGlobalConfig>;
26
+ extendMode?: boolean;
27
+ }
28
+ | undefined;
29
+
30
+ private keysHaveBeenRead: Record<string, boolean> = {};
31
+
32
+ private globalModelConfigManager: ModelConfigManager | undefined = undefined;
33
+
34
+ constructor() {
35
+ initDebugConfig();
36
+ }
37
+
38
+ /**
39
+ * recalculate allEnvConfig every time because process.env can be updated any time
40
+ */
41
+ public getAllEnvConfig() {
42
+ const envConfig = ALL_ENV_KEYS.reduce(
43
+ (p, name) => {
44
+ p[name] = process.env[name];
45
+ return p;
46
+ },
47
+ Object.create(null) as Record<string, string | undefined>,
48
+ );
49
+
50
+ if (this.override) {
51
+ const { newConfig, extendMode } = this.override;
52
+ if (extendMode) {
53
+ return { ...envConfig, ...newConfig };
54
+ } else {
55
+ return { ...newConfig };
56
+ }
57
+ } else {
58
+ return envConfig;
59
+ }
60
+ }
61
+
62
+ getEnvConfigValue(key: (typeof STRING_ENV_KEYS)[number]) {
63
+ const allConfig = this.getAllEnvConfig();
64
+
65
+ if (!STRING_ENV_KEYS.includes(key)) {
66
+ throw new Error(`getEnvConfigValue with key ${key} is not supported.`);
67
+ }
68
+ if (key === MATCH_BY_POSITION) {
69
+ throw new Error(
70
+ 'MATCH_BY_POSITION is deprecated, use MIDSCENE_USE_VL_MODEL instead',
71
+ );
72
+ }
73
+ const value = allConfig[key];
74
+ this.keysHaveBeenRead[key] = true;
75
+ if (typeof value === 'string') {
76
+ return value.trim();
77
+ }
78
+ return value;
79
+ }
80
+
81
+ /**
82
+ * read number only from process.env
83
+ */
84
+ getEnvConfigInNumber(key: (typeof NUMBER_ENV_KEYS)[number]): number {
85
+ const allConfig = this.getAllEnvConfig();
86
+
87
+ if (!NUMBER_ENV_KEYS.includes(key)) {
88
+ throw new Error(`getEnvConfigInNumber with key ${key} is not supported`);
89
+ }
90
+ const value = allConfig[key];
91
+ this.keysHaveBeenRead[key] = true;
92
+ return Number(value || '');
93
+ }
94
+
95
+ /**
96
+ * read boolean only from process.env
97
+ */
98
+ getEnvConfigInBoolean(key: (typeof BOOLEAN_ENV_KEYS)[number]): boolean {
99
+ const allConfig = this.getAllEnvConfig();
100
+
101
+ if (!BOOLEAN_ENV_KEYS.includes(key)) {
102
+ throw new Error(`getEnvConfigInBoolean with key ${key} is not supported`);
103
+ }
104
+
105
+ const value = allConfig[key];
106
+ this.keysHaveBeenRead[key] = true;
107
+
108
+ if (!value) {
109
+ return false;
110
+ }
111
+ if (/^(true|1)$/i.test(value)) {
112
+ return true;
113
+ }
114
+ if (/^(false|0)$/i.test(value)) {
115
+ return false;
116
+ }
117
+ return !!value.trim();
118
+ }
119
+
120
+ registerModelConfigManager(globalModelConfigManager: ModelConfigManager) {
121
+ this.globalModelConfigManager = globalModelConfigManager;
122
+ }
123
+
124
+ /**
125
+ * for overrideAIConfig
126
+ * can only override keys in MODEL_ENV_KEYS
127
+ */
128
+ overrideAIConfig(
129
+ newConfig: Partial<
130
+ Record<
131
+ (typeof GLOBAL_ENV_KEYS)[number] | (typeof MODEL_ENV_KEYS)[number],
132
+ string
133
+ >
134
+ >,
135
+ extendMode = false, // true: merge with global config, false: override global config
136
+ ) {
137
+ for (const key in newConfig) {
138
+ if (![...GLOBAL_ENV_KEYS, ...MODEL_ENV_KEYS].includes(key as never)) {
139
+ throw new Error(`Failed to override AI config, invalid key: ${key}`);
140
+ }
141
+ const value = newConfig[key as keyof typeof newConfig];
142
+ if (typeof value !== 'string') {
143
+ throw new Error(
144
+ `Failed to override AI config, value for key ${key} must be a string, but got with type ${typeof value}`,
145
+ );
146
+ }
147
+ if (this.keysHaveBeenRead[key]) {
148
+ console.warn(
149
+ `Warning: try to override AI config with key ${key} ,but it has been read.`,
150
+ );
151
+ }
152
+ }
153
+ const savedNewConfig = extendMode
154
+ ? {
155
+ ...this.override?.newConfig,
156
+ ...newConfig,
157
+ }
158
+ : newConfig;
159
+
160
+ this.override = {
161
+ newConfig: {
162
+ ...savedNewConfig,
163
+ },
164
+ extendMode,
165
+ };
166
+
167
+ if (!this.globalModelConfigManager) {
168
+ throw new Error(
169
+ 'globalModelConfigManager is not registered, which should not happen',
170
+ );
171
+ }
172
+ this.globalModelConfigManager.clearModelConfigMap();
173
+ }
174
+ }
package/src/env/helper.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { assert } from '../utils';
2
- import type { IModelConfig } from './model-config';
2
+ import type { IModelConfig } from './types';
3
3
 
4
4
  const maskKey = (key: string, maskChar = '*') => {
5
5
  if (typeof key !== 'string' || key.length === 0) {
package/src/env/index.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './utils';
2
2
  export * from './types';
3
- export { UITarsModelVersion } from './parse';
3
+ export { ModelConfigManager } from './model-config-manager';
4
+ export { GlobalConfigManager } from './global-config-manager';
@@ -0,0 +1,135 @@
1
+ import {
2
+ decideModelConfigFromEnv,
3
+ decideModelConfigFromIntentConfig,
4
+ } from './decide-model-config';
5
+ import type { GlobalConfigManager } from './global-config-manager';
6
+
7
+ import type { IModelConfig, TIntent, TModelConfigFn } from './types';
8
+
9
+ const ALL_INTENTS: TIntent[] = ['VQA', 'default', 'grounding', 'planning'];
10
+
11
+ export type TIntentConfigMap = Record<
12
+ TIntent,
13
+ ReturnType<TModelConfigFn> | undefined
14
+ >;
15
+
16
+ export class ModelConfigManager {
17
+ private modelConfigMap: Record<TIntent, IModelConfig> | undefined = undefined;
18
+
19
+ // once modelConfigFn is set, isolatedMode will be true
20
+ // modelConfigMap will only depend on modelConfigFn and not effect by process.env
21
+ private isolatedMode = false;
22
+
23
+ private globalConfigManager: GlobalConfigManager | undefined = undefined;
24
+
25
+ constructor(modelConfigFn?: TModelConfigFn) {
26
+ if (modelConfigFn) {
27
+ this.isolatedMode = true;
28
+ const intentConfigMap = this.calcIntentConfigMap(modelConfigFn);
29
+ this.modelConfigMap =
30
+ this.calcModelConfigMapBaseOnIntent(intentConfigMap);
31
+ }
32
+ }
33
+
34
+ private calcIntentConfigMap(modelConfigFn: TModelConfigFn): TIntentConfigMap {
35
+ const intentConfigMap: TIntentConfigMap = {
36
+ VQA: undefined,
37
+ default: undefined,
38
+ grounding: undefined,
39
+ planning: undefined,
40
+ };
41
+
42
+ for (const i of ALL_INTENTS) {
43
+ const result = modelConfigFn({ intent: i });
44
+ if (!result) {
45
+ throw new Error(
46
+ `The agent has an option named modelConfig is a function, but it return ${result} when call with intent ${i}, which should be a object.`,
47
+ );
48
+ }
49
+ intentConfigMap[i] = result;
50
+ }
51
+ return intentConfigMap;
52
+ }
53
+
54
+ private calcModelConfigMapBaseOnIntent(intentConfigMap: TIntentConfigMap) {
55
+ const modelConfigMap: Record<TIntent, IModelConfig | undefined> = {
56
+ VQA: undefined,
57
+ default: undefined,
58
+ grounding: undefined,
59
+ planning: undefined,
60
+ };
61
+ for (const i of ALL_INTENTS) {
62
+ const result = decideModelConfigFromIntentConfig(
63
+ i,
64
+ intentConfigMap[i] as unknown as Record<string, string | undefined>,
65
+ );
66
+ modelConfigMap[i] = result;
67
+ }
68
+ return modelConfigMap as Record<TIntent, IModelConfig>;
69
+ }
70
+
71
+ private calcModelConfigMapBaseOnEnv(
72
+ allEnvConfig: Record<string, string | undefined>,
73
+ ) {
74
+ const modelConfigMap: Record<TIntent, IModelConfig | undefined> = {
75
+ VQA: undefined,
76
+ default: undefined,
77
+ grounding: undefined,
78
+ planning: undefined,
79
+ };
80
+ for (const i of ALL_INTENTS) {
81
+ const result = decideModelConfigFromEnv(i, allEnvConfig);
82
+ modelConfigMap[i] = result;
83
+ }
84
+ return modelConfigMap as Record<TIntent, IModelConfig>;
85
+ }
86
+
87
+ /**
88
+ * should only be called by GlobalConfigManager
89
+ */
90
+ clearModelConfigMap() {
91
+ if (this.isolatedMode) {
92
+ throw new Error(
93
+ 'ModelConfigManager work in isolated mode, so clearModelConfigMap should not be called',
94
+ );
95
+ }
96
+ this.modelConfigMap = undefined;
97
+ }
98
+
99
+ /**
100
+ * if isolatedMode is true, modelConfigMap was initialized in constructor and can't be changed
101
+ * if isolatedMode is false, modelConfigMap can be changed by process.env so we need to recalculate it when it's undefined
102
+ */
103
+ getModelConfig(intent: TIntent): IModelConfig {
104
+ if (this.isolatedMode) {
105
+ if (!this.modelConfigMap) {
106
+ throw new Error(
107
+ 'modelConfigMap is not initialized in isolated mode, which should not happen',
108
+ );
109
+ }
110
+ return this.modelConfigMap[intent];
111
+ } else {
112
+ if (!this.modelConfigMap) {
113
+ if (!this.globalConfigManager) {
114
+ throw new Error(
115
+ 'globalConfigManager is not registered, which should not happen',
116
+ );
117
+ }
118
+ this.modelConfigMap = this.calcModelConfigMapBaseOnEnv(
119
+ this.globalConfigManager.getAllEnvConfig(),
120
+ );
121
+ }
122
+ return this.modelConfigMap[intent];
123
+ }
124
+ }
125
+
126
+ getUploadTestServerUrl(): string | undefined {
127
+ const { openaiExtraConfig } = this.getModelConfig('default');
128
+ const serverUrl = openaiExtraConfig?.REPORT_SERVER_URL as string;
129
+ return serverUrl;
130
+ }
131
+
132
+ registerGlobalConfigManager(globalConfigManager: GlobalConfigManager) {
133
+ this.globalConfigManager = globalConfigManager;
134
+ }
135
+ }
package/src/env/parse.ts CHANGED
@@ -5,30 +5,11 @@ import {
5
5
  MIDSCENE_USE_VLM_UI_TARS,
6
6
  type TVlModeTypes,
7
7
  type TVlModeValues,
8
+ UITarsModelVersion,
9
+ VL_MODE_RAW_VALID_VALUES,
8
10
  } from './types';
9
11
 
10
- export enum UITarsModelVersion {
11
- V1_0 = '1.0',
12
- V1_5 = '1.5',
13
- DOUBAO_1_5_15B = 'doubao-1.5-15B',
14
- DOUBAO_1_5_20B = 'doubao-1.5-20B',
15
- }
16
-
17
- const vlModeRawValidValues: TVlModeValues[] = [
18
- 'doubao-vision',
19
- 'gemini',
20
- 'qwen-vl',
21
- 'vlm-ui-tars',
22
- 'vlm-ui-tars-doubao',
23
- 'vlm-ui-tars-doubao-1.5',
24
- ];
25
-
26
- /**
27
- *
28
- * @param vlModeRaw
29
- * @returns
30
- */
31
- export const parseVlModeAndUiTarsFromRaw = (
12
+ export const parseVlModeAndUiTarsModelVersionFromRawValue = (
32
13
  vlModeRaw?: string,
33
14
  ): {
34
15
  vlMode?: TVlModeTypes;
@@ -41,9 +22,9 @@ export const parseVlModeAndUiTarsFromRaw = (
41
22
  };
42
23
  }
43
24
 
44
- if (!vlModeRawValidValues.includes(vlModeRaw as never)) {
25
+ if (!VL_MODE_RAW_VALID_VALUES.includes(vlModeRaw as never)) {
45
26
  throw new Error(
46
- `the value ${vlModeRaw} is not a valid VL_MODE value, must be one of ${vlModeRawValidValues}`,
27
+ `the value ${vlModeRaw} is not a valid VL_MODE value, must be one of ${VL_MODE_RAW_VALID_VALUES}`,
47
28
  );
48
29
  }
49
30
  const raw = vlModeRaw as TVlModeValues;
package/src/env/types.ts CHANGED
@@ -484,9 +484,67 @@ export type TModelConfigFn = (options: {
484
484
  | IModelConfigForVQA
485
485
  | IModelConfigForPlanning
486
486
  | IModeConfigForGrounding
487
- | IModelConfigForDefault
488
- | IModelConfigForDefaultLegacy;
487
+ | IModelConfigForDefault;
489
488
 
490
- export interface IModelPreferences {
489
+ export enum UITarsModelVersion {
490
+ V1_0 = '1.0',
491
+ V1_5 = '1.5',
492
+ DOUBAO_1_5_15B = 'doubao-1.5-15B',
493
+ DOUBAO_1_5_20B = 'doubao-1.5-20B',
494
+ }
495
+
496
+ export const VL_MODE_RAW_VALID_VALUES: TVlModeValues[] = [
497
+ 'doubao-vision',
498
+ 'gemini',
499
+ 'qwen-vl',
500
+ 'vlm-ui-tars',
501
+ 'vlm-ui-tars-doubao',
502
+ 'vlm-ui-tars-doubao-1.5',
503
+ ];
504
+
505
+ export interface IModelConfig {
506
+ /**
507
+ * proxy
508
+ */
509
+ socksProxy?: string;
510
+ httpProxy?: string;
511
+ /**
512
+ * model
513
+ */
514
+ modelName: string;
515
+ /**
516
+ * OpenAI
517
+ */
518
+ openaiBaseURL?: string;
519
+ openaiApiKey?: string;
520
+ openaiExtraConfig?: Record<string, unknown>;
521
+ /**
522
+ * Azure
523
+ */
524
+ openaiUseAzureDeprecated?: boolean;
525
+ useAzureOpenai?: boolean;
526
+ azureOpenaiScope?: string;
527
+ azureOpenaiKey?: string;
528
+ azureOpenaiEndpoint?: string;
529
+ azureOpenaiApiVersion?: string;
530
+ azureOpenaiDeployment?: string;
531
+ azureExtraConfig?: Record<string, unknown>;
532
+ /**
533
+ * Anthropic
534
+ */
535
+ useAnthropicSdk?: boolean;
536
+ anthropicApiKey?: string;
537
+ /**
538
+ * - vlModeRaw: exists only in non-legacy logic. value can be 'doubao-vision', 'gemini', 'qwen-vl', 'vlm-ui-tars', 'vlm-ui-tars-doubao', 'vlm-ui-tars-doubao-1.5'
539
+ * - vlMode: based on the results of the vlModoRaw classification,value can be 'doubao-vision', 'gemini', 'qwen-vl', 'vlm-ui-tars'
540
+ */
541
+ vlModeRaw?: string;
542
+ vlMode?: TVlModeTypes;
543
+ uiTarsModelVersion?: UITarsModelVersion;
544
+ modelDescription: string;
545
+ /**
546
+ * for debug
547
+ */
491
548
  intent: TIntent;
549
+ from: 'modelConfig' | 'env' | 'legacy-env';
492
550
  }
package/src/env/utils.ts CHANGED
@@ -1,91 +1,17 @@
1
- import {
2
- GLOBAL_CONFIG_MANAGER_UNINITIALIZED_FLAG,
3
- GlobalConfigManager,
4
- } from './global-config';
5
- import type { UITarsModelVersion } from './parse';
1
+ import { GlobalConfigManager } from './global-config-manager';
2
+ import { ModelConfigManager } from './model-config-manager';
6
3
  import {
7
4
  type GLOBAL_ENV_KEYS,
8
- type IModelPreferences,
9
5
  MIDSCENE_PREFERRED_LANGUAGE,
10
6
  type MODEL_ENV_KEYS,
11
- type TVlModeTypes,
12
7
  } from './types';
13
8
 
14
- export const globalConfigManager = new GlobalConfigManager();
15
-
16
- export const uiTarsModelVersion = (
17
- modelPreferences: IModelPreferences,
18
- ): UITarsModelVersion | undefined => {
19
- try {
20
- const result = globalConfigManager.getModelConfigByIntent(
21
- modelPreferences.intent,
22
- );
23
- return result.uiTarsVersion;
24
- } catch (e) {
25
- if ((e as any)?.[GLOBAL_CONFIG_MANAGER_UNINITIALIZED_FLAG]) {
26
- console.warn(
27
- "Call uiTarsModelVersion before globalConfig init, will return undefined. This warning should only appear in midscene's own unit tests.",
28
- );
29
- return undefined;
30
- }
31
- throw e;
32
- }
33
- };
34
-
35
- export const vlLocateMode = (
36
- modelPreferences: IModelPreferences,
37
- ): TVlModeTypes | undefined => {
38
- try {
39
- const result = globalConfigManager.getModelConfigByIntent(
40
- modelPreferences.intent,
41
- );
42
- return result.vlMode as TVlModeTypes;
43
- } catch (e) {
44
- if ((e as any)?.[GLOBAL_CONFIG_MANAGER_UNINITIALIZED_FLAG]) {
45
- console.warn(
46
- "Call vlLocateMode before globalConfig init, will return undefined. This warning should only appear in midscene's own unit tests.",
47
- );
48
- return undefined;
49
- }
50
- throw e;
51
- }
52
- };
9
+ export const globalModelConfigManager = new ModelConfigManager();
53
10
 
54
- export const getIsUseQwenVl = (modelPreferences: IModelPreferences) => {
55
- try {
56
- const result = globalConfigManager.getModelConfigByIntent(
57
- modelPreferences.intent,
58
- );
59
- return result.vlMode === 'qwen-vl';
60
- } catch (e) {
61
- if ((e as any)?.[GLOBAL_CONFIG_MANAGER_UNINITIALIZED_FLAG]) {
62
- console.warn(
63
- "Call getIsUseQwenVl before globalConfig init, will return false. This warning should only appear in midscene's own unit tests.",
64
- );
65
- return false;
66
- }
67
- throw e;
68
- }
69
- };
11
+ export const globalConfigManager = new GlobalConfigManager();
70
12
 
71
- export function getModelName(
72
- modelPreferences: IModelPreferences,
73
- ): string | undefined {
74
- try {
75
- const result = globalConfigManager.getModelConfigByIntent(
76
- modelPreferences.intent,
77
- );
78
- return result?.modelName;
79
- } catch (e) {
80
- if ((e as any)?.[GLOBAL_CONFIG_MANAGER_UNINITIALIZED_FLAG]) {
81
- console.warn(
82
- "Call getModelName before globalConfig init, will return undefined. This warning should only appear in midscene's own unit tests.",
83
- );
84
- return undefined;
85
- }
86
- throw e;
87
- }
88
- }
13
+ globalConfigManager.registerModelConfigManager(globalModelConfigManager);
14
+ globalModelConfigManager.registerGlobalConfigManager(globalConfigManager);
89
15
 
90
16
  export const getPreferredLanguage = () => {
91
17
  const prefer = globalConfigManager.getEnvConfigValue(
@@ -100,23 +26,6 @@ export const getPreferredLanguage = () => {
100
26
  return isChina ? 'Chinese' : 'English';
101
27
  };
102
28
 
103
- export const getUploadTestServerUrl = (): string | undefined => {
104
- try {
105
- const { openaiExtraConfig } =
106
- globalConfigManager.getModelConfigByIntent('default');
107
- const serverUrl = openaiExtraConfig?.REPORT_SERVER_URL as string;
108
- return serverUrl;
109
- } catch (e) {
110
- if ((e as any)?.[GLOBAL_CONFIG_MANAGER_UNINITIALIZED_FLAG]) {
111
- console.warn(
112
- "Call getUploadTestServerUrl before globalConfig init, will return undefined. This warning should only appear in midscene's own unit tests.",
113
- );
114
- return undefined;
115
- }
116
- throw e;
117
- }
118
- };
119
-
120
29
  export const overrideAIConfig = (
121
30
  newConfig: Partial<
122
31
  Record<
@@ -126,5 +35,5 @@ export const overrideAIConfig = (
126
35
  >,
127
36
  extendMode = false, // true: merge with global config, false: override global config
128
37
  ) => {
129
- globalConfigManager.registerOverride(newConfig, extendMode);
38
+ globalConfigManager.overrideAIConfig(newConfig, extendMode);
130
39
  };