mirror of
https://github.com/web-infra-dev/midscene.git
synced 2025-12-27 15:10:20 +00:00
feat(core): allow custom midscene_run dir (#631)
* feat(core): support custom midscene_run dir * feat(report): add search functionality to PlaywrightCaseSelector component * refactor(shared): simplify base directory resolution and remove unused environment variable * feat(shared): integrate shared environment variables across multiple packages * refactor(shared): update base directory resolution to use dynamic midscene_run directory * fix(puppeteer): increase screenshot timeout from 3s to 10s for improved reliability
This commit is contained in:
parent
f85cd6cd1b
commit
ca644d8914
@ -1,6 +1,6 @@
|
||||
import './App.less';
|
||||
import { overrideAIConfig } from '@midscene/core/env';
|
||||
import { SCRCPY_SERVER_PORT } from '@midscene/shared/constants';
|
||||
import { overrideAIConfig } from '@midscene/shared/env';
|
||||
import {
|
||||
EnvConfig,
|
||||
Logo,
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
"@midscene/web": "workspace:*",
|
||||
"@midscene/core": "workspace:*",
|
||||
"@midscene/report": "workspace:*",
|
||||
"@midscene/shared": "workspace:*",
|
||||
"antd": "^5.21.6",
|
||||
"dayjs": "1.11.11",
|
||||
"react": "^18.3.1",
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type { UIContext } from '@midscene/core';
|
||||
import { overrideAIConfig } from '@midscene/core/env';
|
||||
import { overrideAIConfig } from '@midscene/shared/env';
|
||||
import {
|
||||
ContextPreview,
|
||||
type PlaygroundResult,
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
"@midscene/core": "workspace:*",
|
||||
"@midscene/visualizer": "workspace:*",
|
||||
"@midscene/web": "workspace:*",
|
||||
"@midscene/shared": "workspace:*",
|
||||
"@modern-js/runtime": "2.60.6",
|
||||
"@rsbuild/core": "^1.3.1",
|
||||
"@rsbuild/plugin-less": "^1.1.1",
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import { DownOutlined } from '@ant-design/icons';
|
||||
import { DownOutlined, SearchOutlined } from '@ant-design/icons';
|
||||
import type { GroupedActionDump } from '@midscene/core';
|
||||
import { iconForStatus, timeCostStrElement } from '@midscene/visualizer';
|
||||
import { Dropdown } from 'antd';
|
||||
import { Dropdown, Input } from 'antd';
|
||||
import type React from 'react';
|
||||
import { useMemo, useState } from 'react';
|
||||
import type { ExecutionDumpWithPlaywrightAttributes } from '../types';
|
||||
|
||||
interface PlaywrightCaseSelectorProps {
|
||||
@ -18,6 +19,9 @@ export function PlaywrightCaseSelector({
|
||||
}: PlaywrightCaseSelectorProps): JSX.Element | null {
|
||||
if (!dumps || dumps.length <= 1) return null;
|
||||
|
||||
const [searchText, setSearchText] = useState('');
|
||||
const [dropdownVisible, setDropdownVisible] = useState(false);
|
||||
|
||||
const nameForDump = (dump: GroupedActionDump) =>
|
||||
`${dump.groupName} - ${dump.groupDescription}`;
|
||||
|
||||
@ -44,7 +48,14 @@ export function PlaywrightCaseSelector({
|
||||
return rowContent;
|
||||
};
|
||||
|
||||
const items = (dumps || []).map((dump, index) => {
|
||||
const filteredDumps = useMemo(() => {
|
||||
if (!searchText) return dumps || [];
|
||||
return (dumps || []).filter((dump) =>
|
||||
nameForDump(dump).toLowerCase().includes(searchText.toLowerCase()),
|
||||
);
|
||||
}, [dumps, searchText]);
|
||||
|
||||
const items = filteredDumps.map((dump, index) => {
|
||||
return {
|
||||
key: index,
|
||||
label: (
|
||||
@ -54,6 +65,7 @@ export function PlaywrightCaseSelector({
|
||||
if (onSelect) {
|
||||
onSelect(dump);
|
||||
}
|
||||
setDropdownVisible(false);
|
||||
}}
|
||||
>
|
||||
<div>{contentForDump(dump, index)}</div>
|
||||
@ -69,10 +81,40 @@ export function PlaywrightCaseSelector({
|
||||
)
|
||||
: 'Select a case';
|
||||
|
||||
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSearchText(e.target.value);
|
||||
};
|
||||
|
||||
const dropdownRender = (menu: React.ReactNode) => (
|
||||
<div>
|
||||
<div style={{ padding: '8px' }}>
|
||||
<Input
|
||||
placeholder="Search test case"
|
||||
value={searchText}
|
||||
onChange={handleSearchChange}
|
||||
prefix={<SearchOutlined />}
|
||||
allowClear
|
||||
autoFocus
|
||||
/>
|
||||
</div>
|
||||
{menu}
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="playwright-case-selector">
|
||||
<Dropdown menu={{ items }}>
|
||||
<a onClick={(e) => e.preventDefault()}>
|
||||
<Dropdown
|
||||
menu={{ items }}
|
||||
dropdownRender={dropdownRender}
|
||||
onOpenChange={setDropdownVisible}
|
||||
open={dropdownVisible}
|
||||
>
|
||||
<a
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
setDropdownVisible(!dropdownVisible);
|
||||
}}
|
||||
>
|
||||
{btnName} <DownOutlined />
|
||||
</a>
|
||||
</Dropdown>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type { UIContext } from '@midscene/core';
|
||||
import { overrideAIConfig } from '@midscene/core/env';
|
||||
import { overrideAIConfig } from '@midscene/shared/env';
|
||||
import {
|
||||
ContextPreview,
|
||||
Logo,
|
||||
|
||||
@ -440,6 +440,14 @@ Set the `MIDSCENE_DEBUG_AI_PROFILE` variable to view the execution time and usag
|
||||
export MIDSCENE_DEBUG_AI_PROFILE=1
|
||||
```
|
||||
|
||||
### Customize the run artifact directory
|
||||
|
||||
Set the `MIDSCENE_RUN_DIR` variable to customize the run artifact directory.
|
||||
|
||||
```bash
|
||||
export MIDSCENE_RUN_DIR=midscene_run # The default value is the midscene_run in the current working directory, you can set it to an absolute path or a relative path
|
||||
```
|
||||
|
||||
### Using LangSmith
|
||||
|
||||
LangSmith is a platform for debugging large language models. To integrate LangSmith, follow these steps:
|
||||
|
||||
@ -14,7 +14,7 @@ You can check the supported models in [Choose a model](./choose-a-model)
|
||||
|
||||
`adb` is a command-line tool that allows you to communicate with an Android device. There are two ways to install `adb`:
|
||||
|
||||
- way 1: use [Android Studio](https://developer.android.com/studio?hl=zh-cn) to install
|
||||
- way 1: use [Android Studio](https://developer.android.com/studio) to install
|
||||
- way 2: use [Android command-line tools](https://developer.android.com/studio#command-line-tools-only) to install
|
||||
|
||||
Verify adb is installed successfully:
|
||||
@ -32,6 +32,22 @@ Installed as /usr/local/bin//adb
|
||||
Running on Darwin 24.3.0 (arm64)
|
||||
```
|
||||
|
||||
### Set environment variable ANDROID_HOME
|
||||
|
||||
Reference [Android environment variables](https://developer.android.com/tools/variables), set the environment variable `ANDROID_HOME`.
|
||||
|
||||
Verify the `ANDROID_HOME` variable is set successfully:
|
||||
|
||||
```bash
|
||||
echo $ANDROID_HOME
|
||||
```
|
||||
|
||||
When the command has any output, the `ANDROID_HOME` variable is set successfully:
|
||||
|
||||
```log
|
||||
/Users/your_username/Library/Android/sdk
|
||||
```
|
||||
|
||||
### Connect Android device with adb
|
||||
|
||||
In the developer options of the system settings, enable the 'USB debugging' of the Android device, if the 'USB debugging (secure settings)' exists, also enable it, then connect the Android device with a USB cable
|
||||
|
||||
@ -124,7 +124,10 @@ export AZURE_OPENAI_DEPLOYMENT="gpt-4o"
|
||||
You can also override the config by javascript. Remember to call this before running Midscene codes.
|
||||
|
||||
```typescript
|
||||
import { overrideAIConfig } from "@midscene/core/env";
|
||||
import { overrideAIConfig } from "@midscene/web/puppeteer";
|
||||
// or import { overrideAIConfig } from "@midscene/web/playwright";
|
||||
// or import { overrideAIConfig } from "@midscene/android";
|
||||
|
||||
|
||||
overrideAIConfig({
|
||||
MIDSCENE_MODEL_NAME: "...",
|
||||
|
||||
@ -439,6 +439,14 @@ overrideAIConfig({
|
||||
export MIDSCENE_DEBUG_AI_PROFILE=1
|
||||
```
|
||||
|
||||
### 自定义运行产物目录
|
||||
|
||||
设置 `MIDSCENE_RUN_DIR` 变量,你可以自定义运行产物目录。
|
||||
|
||||
```bash
|
||||
export MIDSCENE_RUN_DIR=midscene_run # 默认值为当前运行目录下的 midscene_run 目录,支持设置为绝对路径或者相对于当前目录的相对路径
|
||||
```
|
||||
|
||||
### 使用 LangSmith
|
||||
|
||||
LangSmith 是一个用于调试大语言模型的平台。想要集成 LangSmith,请按以下步骤操作:
|
||||
|
||||
@ -32,6 +32,22 @@ Installed as /usr/local/bin//adb
|
||||
Running on Darwin 24.3.0 (arm64)
|
||||
```
|
||||
|
||||
### 设置环境 ANDROID_HOME 变量
|
||||
|
||||
参考[Android 环境变量](https://developer.android.com/tools/variables?hl=zh-cn),设置环境变量 `ANDROID_HOME`。
|
||||
|
||||
验证 `ANDROID_HOME` 变量是否设置成功:
|
||||
|
||||
```bash
|
||||
echo $ANDROID_HOME
|
||||
```
|
||||
|
||||
当上述命令有输出时,表示 `ANDROID_HOME` 变量设置成功:
|
||||
|
||||
```log
|
||||
/Users/your_username/Library/Android/sdk
|
||||
```
|
||||
|
||||
### 连接 Android 设备
|
||||
|
||||
在 Android 设备的开发者选项中,启用 'USB 调试',如果存在 'USB 调试(安全设置)',也启用它,然后使用 USB 线连接 Android 设备。
|
||||
|
||||
@ -125,7 +125,10 @@ export AZURE_OPENAI_DEPLOYMENT="gpt-4o"
|
||||
你也可以在运行 Midscene 代码之前,使用 Javascript 来配置 AI 服务。
|
||||
|
||||
```typescript
|
||||
import { overrideAIConfig } from "@midscene/core/env";
|
||||
import { overrideAIConfig } from "@midscene/web/puppeteer";
|
||||
// 或者 import { overrideAIConfig } from "@midscene/web/playwright";
|
||||
// 或者 import { overrideAIConfig } from "@midscene/android";
|
||||
|
||||
|
||||
overrideAIConfig({
|
||||
MIDSCENE_MODEL_NAME: "...",
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
"private": true,
|
||||
"version": "0.15.3",
|
||||
"scripts": {
|
||||
"dev": "nx run-many --target=build:watch --exclude=android-playground,chrome-extension,@midscene/report,doc --verbose",
|
||||
"build": "nx run-many --target=build --exclude=doc --verbose",
|
||||
"test": "nx run-many --target=test --projects=@midscene/core=@midscene/shared,@midscene/visualizer,@midscene/web,@midscene/cli --verbose",
|
||||
"test:ai": "nx run-many --target=test:ai --projects=@midscene/core,@midscene/web --verbose",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { PageAgent, type PageAgentOpt } from '@midscene/web/agent';
|
||||
import { AndroidDevice } from '../page';
|
||||
|
||||
import { vlLocateMode } from '@midscene/core/env';
|
||||
import { vlLocateMode } from '@midscene/shared/env';
|
||||
import { getConnectedDevices } from '../utils';
|
||||
|
||||
import { debugPage } from '../page';
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
export { AndroidDevice } from './page';
|
||||
export { AndroidAgent, agentFromAdbDevice } from './agent';
|
||||
export { getConnectedDevices } from './utils';
|
||||
export { overrideAIConfig } from '@midscene/shared/env';
|
||||
|
||||
@ -7,7 +7,6 @@ export default defineConfig({
|
||||
buildConfig: {
|
||||
input: {
|
||||
index: 'src/index.ts',
|
||||
env: 'src/env.ts',
|
||||
utils: 'src/utils.ts',
|
||||
tree: 'src/tree.ts',
|
||||
'ai-model': 'src/ai-model/index.ts',
|
||||
|
||||
@ -10,7 +10,6 @@
|
||||
"files": ["dist", "report", "README.md"],
|
||||
"exports": {
|
||||
".": "./dist/lib/index.js",
|
||||
"./env": "./dist/lib/env.js",
|
||||
"./utils": "./dist/lib/utils.js",
|
||||
"./ai-model": "./dist/lib/ai-model.js",
|
||||
"./tree": "./dist/lib/tree.js"
|
||||
@ -18,7 +17,6 @@
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
".": ["./dist/types/index.d.ts"],
|
||||
"env": ["./dist/types/env.d.ts"],
|
||||
"utils": ["./dist/types/utils.d.ts"],
|
||||
"ai-model": ["./dist/types/ai-model.d.ts"],
|
||||
"tree": ["./dist/types/tree.d.ts"]
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { MIDSCENE_MODEL_NAME, getAIConfig } from '@/env';
|
||||
import type {
|
||||
ExecutionDump,
|
||||
ExecutionTask,
|
||||
@ -9,6 +8,7 @@ import type {
|
||||
ExecutorContext,
|
||||
} from '@/types';
|
||||
import { getVersion } from '@/utils';
|
||||
import { MIDSCENE_MODEL_NAME, getAIConfig } from '@midscene/shared/env';
|
||||
import { assert } from '@midscene/shared/utils';
|
||||
|
||||
export class Executor {
|
||||
|
||||
@ -17,9 +17,9 @@ import {
|
||||
getModelName,
|
||||
} from './service-caller/index';
|
||||
|
||||
import { vlLocateMode } from '@/env';
|
||||
import type { PlanningLocateParam } from '@/types';
|
||||
import { NodeType } from '@midscene/shared/constants';
|
||||
import { vlLocateMode } from '@midscene/shared/env';
|
||||
import { treeToList } from '@midscene/shared/extractor';
|
||||
import { compositeElementInfoImg } from '@midscene/shared/img';
|
||||
import { getDebug } from '@midscene/shared/logger';
|
||||
|
||||
@ -1,9 +1,3 @@
|
||||
import {
|
||||
MIDSCENE_USE_QWEN_VL,
|
||||
MIDSCENE_USE_VLM_UI_TARS,
|
||||
getAIConfigInBoolean,
|
||||
vlLocateMode,
|
||||
} from '@/env';
|
||||
import type {
|
||||
AIAssertionResponse,
|
||||
AIDataExtractionResponse,
|
||||
@ -20,6 +14,12 @@ import type {
|
||||
Size,
|
||||
UIContext,
|
||||
} from '@/types';
|
||||
import {
|
||||
MIDSCENE_USE_QWEN_VL,
|
||||
MIDSCENE_USE_VLM_UI_TARS,
|
||||
getAIConfigInBoolean,
|
||||
vlLocateMode,
|
||||
} from '@midscene/shared/env';
|
||||
import { cropByRect, paddingToMatchBlockByBase64 } from '@midscene/shared/img';
|
||||
import { getDebug } from '@midscene/shared/logger';
|
||||
import { assert } from '@midscene/shared/utils';
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { vlLocateMode } from '@/env';
|
||||
import type { PageType, PlanningAIResponse, UIContext } from '@/types';
|
||||
import { vlLocateMode } from '@midscene/shared/env';
|
||||
import { paddingToMatchBlockByBase64 } from '@midscene/shared/img';
|
||||
import { assert } from '@midscene/shared/utils';
|
||||
import {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import type { vlLocateMode } from '../../env';
|
||||
import type { vlLocateMode } from '@midscene/shared/env';
|
||||
export function bboxDescription(vlMode: ReturnType<typeof vlLocateMode>) {
|
||||
if (vlMode === 'gemini') {
|
||||
return '2d bounding box as [ymin, xmin, ymax, xmax]';
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { PromptTemplate } from '@langchain/core/prompts';
|
||||
import type { vlLocateMode } from '@midscene/shared/env';
|
||||
import type { ResponseFormatJSONSchema } from 'openai/resources';
|
||||
import type { vlLocateMode } from '../../env';
|
||||
import { bboxDescription } from './common';
|
||||
export function systemPromptToLocateElement(
|
||||
vlMode: ReturnType<typeof vlLocateMode>,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import type { vlLocateMode } from '@/env';
|
||||
import type { PageType } from '@/types';
|
||||
import { PromptTemplate } from '@langchain/core/prompts';
|
||||
import type { vlLocateMode } from '@midscene/shared/env';
|
||||
import type { ResponseFormatJSONSchema } from 'openai/resources';
|
||||
import { bboxDescription } from './common';
|
||||
import { samplePageDescription } from './util';
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type { vlLocateMode } from '@/env';
|
||||
import { PromptTemplate } from '@langchain/core/prompts';
|
||||
import type { vlLocateMode } from '@midscene/shared/env';
|
||||
import { bboxDescription } from './common';
|
||||
|
||||
export function systemPromptToLocateSection(
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { vlLocateMode } from '@/env';
|
||||
import { imageInfoOfBase64 } from '@/image/index';
|
||||
import type { BaseElement, ElementTreeNode, Size, UIContext } from '@/types';
|
||||
import { NodeType } from '@midscene/shared/constants';
|
||||
import { vlLocateMode } from '@midscene/shared/env';
|
||||
import { descriptionOfTree, treeToList } from '@midscene/shared/extractor';
|
||||
import { assert } from '@midscene/shared/utils';
|
||||
import { generateHashId } from '@midscene/shared/utils';
|
||||
|
||||
@ -4,13 +4,6 @@ import {
|
||||
DefaultAzureCredential,
|
||||
getBearerTokenProvider,
|
||||
} from '@azure/identity';
|
||||
import { enableDebug, getDebug } from '@midscene/shared/logger';
|
||||
import { assert } from '@midscene/shared/utils';
|
||||
import { ifInBrowser } from '@midscene/shared/utils';
|
||||
import dJSON from 'dirty-json';
|
||||
import OpenAI, { AzureOpenAI } from 'openai';
|
||||
import type { ChatCompletionMessageParam } from 'openai/resources';
|
||||
import { SocksProxyAgent } from 'socks-proxy-agent';
|
||||
import {
|
||||
ANTHROPIC_API_KEY,
|
||||
AZURE_OPENAI_API_VERSION,
|
||||
@ -38,7 +31,14 @@ import {
|
||||
getAIConfigInBoolean,
|
||||
getAIConfigInJson,
|
||||
vlLocateMode,
|
||||
} from '../../env';
|
||||
} from '@midscene/shared/env';
|
||||
import { enableDebug, getDebug } from '@midscene/shared/logger';
|
||||
import { assert } from '@midscene/shared/utils';
|
||||
import { ifInBrowser } from '@midscene/shared/utils';
|
||||
import dJSON from 'dirty-json';
|
||||
import OpenAI, { AzureOpenAI } from 'openai';
|
||||
import type { ChatCompletionMessageParam } from 'openai/resources';
|
||||
import { SocksProxyAgent } from 'socks-proxy-agent';
|
||||
import { AIActionType } from '../common';
|
||||
import { assertSchema } from '../prompt/assertion';
|
||||
import { locatorSchema } from '../prompt/llm-locator';
|
||||
|
||||
@ -9,7 +9,7 @@ export {
|
||||
AiAssert,
|
||||
} from './ai-model/index';
|
||||
|
||||
export { getAIConfig, MIDSCENE_MODEL_NAME } from './env';
|
||||
export { getAIConfig, MIDSCENE_MODEL_NAME } from '@midscene/shared/env';
|
||||
|
||||
export type * from './types';
|
||||
export default Insight;
|
||||
|
||||
@ -1,11 +1,6 @@
|
||||
import { callAiFn } from '@/ai-model/common';
|
||||
import { AiExtractElementInfo, AiLocateElement } from '@/ai-model/index';
|
||||
import { AiAssert, AiLocateSection } from '@/ai-model/inspect';
|
||||
import {
|
||||
MIDSCENE_FORCE_DEEP_THINK,
|
||||
getAIConfigInBoolean,
|
||||
vlLocateMode,
|
||||
} from '@/env';
|
||||
import type {
|
||||
AIElementResponse,
|
||||
AISingleElementResponse,
|
||||
@ -23,6 +18,11 @@ import type {
|
||||
Rect,
|
||||
UIContext,
|
||||
} from '@/types';
|
||||
import {
|
||||
MIDSCENE_FORCE_DEEP_THINK,
|
||||
getAIConfigInBoolean,
|
||||
vlLocateMode,
|
||||
} from '@midscene/shared/env';
|
||||
import { getDebug } from '@midscene/shared/logger';
|
||||
import { assert } from '@midscene/shared/utils';
|
||||
import { emitInsightDump } from './utils';
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { MIDSCENE_MODEL_NAME, getAIConfig, vlLocateMode } from '@/env';
|
||||
import type {
|
||||
DumpMeta,
|
||||
DumpSubscriber,
|
||||
@ -6,6 +5,11 @@ import type {
|
||||
PartialInsightDumpFromSDK,
|
||||
} from '@/types';
|
||||
import { getVersion } from '@/utils';
|
||||
import {
|
||||
MIDSCENE_MODEL_NAME,
|
||||
getAIConfig,
|
||||
vlLocateMode,
|
||||
} from '@midscene/shared/env';
|
||||
import { uuid } from '@midscene/shared/utils';
|
||||
|
||||
export function emitInsightDump(
|
||||
|
||||
@ -4,19 +4,19 @@ import { tmpdir } from 'node:os';
|
||||
import * as path from 'node:path';
|
||||
import { dirname } from 'node:path';
|
||||
import {
|
||||
defaultRunDirName,
|
||||
getMidsceneRunSubDir,
|
||||
logDir,
|
||||
runDirName,
|
||||
} from '@midscene/shared/common';
|
||||
import { getRunningPkgInfo } from '@midscene/shared/fs';
|
||||
import { assert, getGlobalScope } from '@midscene/shared/utils';
|
||||
import { ifInBrowser, uuid } from '@midscene/shared/utils';
|
||||
import {
|
||||
MIDSCENE_DEBUG_MODE,
|
||||
MIDSCENE_OPENAI_INIT_CONFIG_JSON,
|
||||
getAIConfig,
|
||||
getAIConfigInJson,
|
||||
} from './env';
|
||||
} from '@midscene/shared/env';
|
||||
import { getRunningPkgInfo } from '@midscene/shared/fs';
|
||||
import { assert, getGlobalScope } from '@midscene/shared/utils';
|
||||
import { ifInBrowser, uuid } from '@midscene/shared/utils';
|
||||
import type { Rect, ReportDumpWithAttributes } from './types';
|
||||
|
||||
let logEnvReady = false;
|
||||
@ -176,19 +176,25 @@ export function writeLogFile(opts: {
|
||||
|
||||
// gitIgnore in the parent directory
|
||||
const gitIgnorePath = path.join(targetDir, '../../.gitignore');
|
||||
const gitPath = path.join(targetDir, '../../.git');
|
||||
let gitIgnoreContent = '';
|
||||
if (existsSync(gitIgnorePath)) {
|
||||
gitIgnoreContent = readFileSync(gitIgnorePath, 'utf-8');
|
||||
|
||||
if (existsSync(gitPath)) {
|
||||
// if the git path exists, we need to add the log folder to the git ignore file
|
||||
if (existsSync(gitIgnorePath)) {
|
||||
gitIgnoreContent = readFileSync(gitIgnorePath, 'utf-8');
|
||||
}
|
||||
|
||||
// ignore the log folder
|
||||
if (!gitIgnoreContent.includes(`${defaultRunDirName}/`)) {
|
||||
writeFileSync(
|
||||
gitIgnorePath,
|
||||
`${gitIgnoreContent}\n# Midscene.js dump files\n${defaultRunDirName}/dump\n${defaultRunDirName}/report\n${defaultRunDirName}/tmp\n${defaultRunDirName}/log\n`,
|
||||
'utf-8',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ignore the log folder
|
||||
if (!gitIgnoreContent.includes(`${runDirName}/`)) {
|
||||
writeFileSync(
|
||||
gitIgnorePath,
|
||||
`${gitIgnoreContent}\n# Midscene.js dump files\n${runDirName}/dump\n${runDirName}/report\n${runDirName}/tmp\n${runDirName}/log\n`,
|
||||
'utf-8',
|
||||
);
|
||||
}
|
||||
logEnvReady = true;
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { distance } from '@/ai-model/prompt/util';
|
||||
import { vlLocateMode } from '@/env';
|
||||
import Insight from '@/insight';
|
||||
import { sleep } from '@/utils';
|
||||
import { vlLocateMode } from '@midscene/shared/env';
|
||||
import { getContextFromFixture } from 'tests/evaluation';
|
||||
import { describe, expect, test, vi } from 'vitest';
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { plan } from '@/ai-model';
|
||||
import { vlLocateMode } from '@/env';
|
||||
import { vlLocateMode } from '@midscene/shared/env';
|
||||
import { getContextFromFixture } from 'tests/evaluation';
|
||||
/* eslint-disable max-lines-per-function */
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { AiLocateElement } from '@/ai-model';
|
||||
import { AiLocateSection } from '@/ai-model/inspect';
|
||||
import { vlLocateMode } from '@/env';
|
||||
import { saveBase64Image } from '@/image';
|
||||
import { getTmpFile } from '@/utils';
|
||||
import { vlLocateMode } from '@midscene/shared/env';
|
||||
import { getContextFromFixture } from 'tests/evaluation';
|
||||
import { expect, test } from 'vitest';
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { existsSync, readFileSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { vlLocateMode } from '@/env';
|
||||
import { describeUserPage } from '@/index';
|
||||
import { vlLocateMode } from '@midscene/shared/env';
|
||||
import { base64Encoded, imageInfoOfBase64 } from '@midscene/shared/img';
|
||||
|
||||
export async function buildContext(targetDir: string): Promise<{
|
||||
|
||||
@ -10,7 +10,7 @@ import {
|
||||
getAIConfigInJson,
|
||||
overrideAIConfig,
|
||||
vlLocateMode,
|
||||
} from '@/env';
|
||||
} from '@midscene/shared/env';
|
||||
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
||||
|
||||
describe('env', () => {
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import { describeUserPage } from '@/ai-model/prompt/util';
|
||||
import { vlLocateMode } from '@/env';
|
||||
import { vlLocateMode } from '@midscene/shared/env';
|
||||
import { getContextFromFixture } from 'tests/evaluation';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
// Mock vlLocateMode to return false during tests
|
||||
vi.mock('@/env', async () => {
|
||||
const actual = await vi.importActual('@/env');
|
||||
vi.mock('@midscene/shared/env', async () => {
|
||||
const actual = await vi.importActual('@midscene/shared/env');
|
||||
return {
|
||||
...actual,
|
||||
vlLocateMode: () => false,
|
||||
|
||||
@ -13,7 +13,6 @@ import {
|
||||
preprocessDoubaoBboxJson,
|
||||
safeParseJson,
|
||||
} from '@/ai-model/service-caller';
|
||||
import { getAIConfig, overrideAIConfig, vlLocateMode } from '@/env';
|
||||
import {
|
||||
getLogDir,
|
||||
getTmpDir,
|
||||
@ -22,6 +21,11 @@ import {
|
||||
reportHTMLContent,
|
||||
writeDumpReport,
|
||||
} from '@/utils';
|
||||
import {
|
||||
getAIConfig,
|
||||
overrideAIConfig,
|
||||
vlLocateMode,
|
||||
} from '@midscene/shared/env';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
describe('utils', () => {
|
||||
|
||||
@ -7,7 +7,7 @@ import type {
|
||||
plan,
|
||||
} from '@midscene/core';
|
||||
import type { AiLocateSection } from '@midscene/core/ai-model';
|
||||
import { vlLocateMode } from '@midscene/core/env';
|
||||
import { vlLocateMode } from '@midscene/shared/env';
|
||||
import type { TestCase } from '../tests/util';
|
||||
|
||||
type ActualResult =
|
||||
|
||||
@ -4,8 +4,8 @@ import Insight, {
|
||||
MIDSCENE_MODEL_NAME,
|
||||
getAIConfig,
|
||||
} from '@midscene/core';
|
||||
import { vlLocateMode } from '@midscene/core/env';
|
||||
import { sleep } from '@midscene/core/utils';
|
||||
import { vlLocateMode } from '@midscene/shared/env';
|
||||
import { saveBase64Image } from '@midscene/shared/img';
|
||||
import dotenv from 'dotenv';
|
||||
import { afterEach, expect, test } from 'vitest';
|
||||
|
||||
@ -7,8 +7,8 @@ import {
|
||||
plan,
|
||||
} from '@midscene/core';
|
||||
import { adaptBboxToRect } from '@midscene/core/ai-model';
|
||||
import { vlLocateMode } from '@midscene/core/env';
|
||||
import { sleep } from '@midscene/core/utils';
|
||||
import { vlLocateMode } from '@midscene/shared/env';
|
||||
import { saveBase64Image } from '@midscene/shared/img';
|
||||
import dotenv from 'dotenv';
|
||||
import { describe, expect, test } from 'vitest';
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { writeFileSync } from 'node:fs';
|
||||
import { MIDSCENE_MODEL_NAME, type Rect, getAIConfig } from '@midscene/core';
|
||||
import { AiLocateSection } from '@midscene/core/ai-model';
|
||||
import { vlLocateMode } from '@midscene/core/env';
|
||||
import { sleep } from '@midscene/core/utils';
|
||||
import { vlLocateMode } from '@midscene/shared/env';
|
||||
import { saveBase64Image } from '@midscene/shared/img';
|
||||
import dotenv from 'dotenv';
|
||||
import { afterAll, expect, test } from 'vitest';
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import type { PlanningAIResponse, Rect } from '@midscene/core';
|
||||
import { vlLocateMode } from '@midscene/core/env';
|
||||
import { vlLocateMode } from '@midscene/shared/env';
|
||||
import {
|
||||
base64Encoded,
|
||||
compositeElementInfoImg,
|
||||
|
||||
@ -2,7 +2,7 @@ import {
|
||||
MIDSCENE_MCP_USE_PUPPETEER_MODE,
|
||||
getAIConfig,
|
||||
getAIConfigInBoolean,
|
||||
} from '@midscene/core/env';
|
||||
} from '@midscene/shared/env';
|
||||
import {
|
||||
AgentOverChromeBridge,
|
||||
allConfigFromEnv,
|
||||
|
||||
@ -15,6 +15,7 @@ export default defineConfig({
|
||||
logger: './src/logger.ts',
|
||||
common: './src/common.ts',
|
||||
'us-keyboard-layout': './src/us-keyboard-layout.ts',
|
||||
env: './src/env.ts',
|
||||
},
|
||||
target: 'es2020',
|
||||
dts: {
|
||||
|
||||
@ -16,7 +16,8 @@
|
||||
"./extractor-debug": "./dist/lib/extractor-debug.js",
|
||||
"./keyboard-layout": "./dist/lib/us-keyboard-layout.js",
|
||||
"./logger": "./dist/lib/logger.js",
|
||||
"./common": "./dist/lib/common.js"
|
||||
"./common": "./dist/lib/common.js",
|
||||
"./env": "./dist/lib/env.js"
|
||||
},
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
@ -29,7 +30,8 @@
|
||||
"extractor-debug": ["./dist/types/extractor-debug.d.ts"],
|
||||
"keyboard-layout": ["./dist/types/us-keyboard-layout.d.ts"],
|
||||
"logger": ["./dist/types/logger.d.ts"],
|
||||
"common": ["./dist/types/common.d.ts"]
|
||||
"common": ["./dist/types/common.d.ts"],
|
||||
"env": ["./dist/types/env.d.ts"]
|
||||
}
|
||||
},
|
||||
"files": ["dist", "src", "README.md"],
|
||||
|
||||
@ -1,20 +1,29 @@
|
||||
import { existsSync, mkdirSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { MIDSCENE_RUN_DIR, getAIConfig } from './env';
|
||||
|
||||
export const runDirName = 'midscene_run';
|
||||
export const defaultRunDirName = 'midscene_run';
|
||||
// Define locally for now to avoid import issues
|
||||
export const isNodeEnv =
|
||||
typeof process !== 'undefined' &&
|
||||
process.versions != null &&
|
||||
process.versions.node != null;
|
||||
|
||||
export const getMidsceneRunDir = () => {
|
||||
if (!isNodeEnv) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return getAIConfig(MIDSCENE_RUN_DIR) || defaultRunDirName;
|
||||
};
|
||||
|
||||
export const getMidsceneRunBaseDir = () => {
|
||||
if (!isNodeEnv) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let basePath = path.join(process.cwd(), runDirName);
|
||||
let basePath = path.resolve(process.cwd(), getMidsceneRunDir());
|
||||
|
||||
// Create a base directory
|
||||
if (!existsSync(basePath)) {
|
||||
@ -22,7 +31,7 @@ export const getMidsceneRunBaseDir = () => {
|
||||
mkdirSync(basePath, { recursive: true });
|
||||
} catch (error) {
|
||||
// console.error(`Failed to create ${runDirName} directory: ${error}`);
|
||||
basePath = path.join(tmpdir(), runDirName);
|
||||
basePath = path.join(tmpdir(), defaultRunDirName);
|
||||
mkdirSync(basePath, { recursive: true });
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,6 +41,8 @@ export const AZURE_OPENAI_DEPLOYMENT = 'AZURE_OPENAI_DEPLOYMENT';
|
||||
export const MIDSCENE_USE_ANTHROPIC_SDK = 'MIDSCENE_USE_ANTHROPIC_SDK';
|
||||
export const ANTHROPIC_API_KEY = 'ANTHROPIC_API_KEY';
|
||||
|
||||
export const MIDSCENE_RUN_DIR = 'MIDSCENE_RUN_DIR';
|
||||
|
||||
// @deprecated
|
||||
export const OPENAI_USE_AZURE = 'OPENAI_USE_AZURE';
|
||||
|
||||
@ -94,6 +96,7 @@ export const allConfigFromEnv = () => {
|
||||
process.env[AZURE_OPENAI_DEPLOYMENT] || undefined,
|
||||
[MIDSCENE_MCP_USE_PUPPETEER_MODE]:
|
||||
process.env[MIDSCENE_MCP_USE_PUPPETEER_MODE] || undefined,
|
||||
[MIDSCENE_RUN_DIR]: process.env[MIDSCENE_RUN_DIR] || undefined,
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { overrideAIConfig } from '@midscene/core/env';
|
||||
import { overrideAIConfig } from '@midscene/shared/env';
|
||||
import { Button, Tooltip } from 'antd';
|
||||
import type React from 'react';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
@ -2,4 +2,4 @@ import { AgentOverChromeBridge } from './agent-cli-side';
|
||||
|
||||
export { AgentOverChromeBridge };
|
||||
|
||||
export { overrideAIConfig, allConfigFromEnv } from '@midscene/core/env';
|
||||
export { overrideAIConfig, allConfigFromEnv } from '@midscene/shared/env';
|
||||
|
||||
@ -2,7 +2,7 @@ import { ERROR_CODE_NOT_IMPLEMENTED_AS_DESIGNED } from '../common/utils';
|
||||
import { ChromeExtensionProxyPageAgent } from './agent';
|
||||
import ChromeExtensionProxyPage from './page';
|
||||
|
||||
export { overrideAIConfig } from '@midscene/core/env';
|
||||
export { overrideAIConfig } from '@midscene/shared/env';
|
||||
|
||||
export {
|
||||
ChromeExtensionProxyPage,
|
||||
|
||||
@ -14,7 +14,6 @@ import {
|
||||
} from '@midscene/core';
|
||||
|
||||
import { ScriptPlayer, parseYamlScript } from '@/yaml/index';
|
||||
import { vlLocateMode } from '@midscene/core/env';
|
||||
import {
|
||||
groupedActionDumpFileExt,
|
||||
reportHTMLContent,
|
||||
@ -25,6 +24,7 @@ import {
|
||||
DEFAULT_WAIT_FOR_NAVIGATION_TIMEOUT,
|
||||
DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT,
|
||||
} from '@midscene/shared/constants';
|
||||
import { vlLocateMode } from '@midscene/shared/env';
|
||||
import { getDebug } from '@midscene/shared/logger';
|
||||
import { assert } from '@midscene/shared/utils';
|
||||
import { PageTaskExecutor } from '../common/tasks';
|
||||
|
||||
@ -6,9 +6,9 @@ import type {
|
||||
PlanningAIResponse,
|
||||
} from '@midscene/core';
|
||||
import type { vlmPlanning } from '@midscene/core/ai-model';
|
||||
import { getAIConfigInBoolean } from '@midscene/core/env';
|
||||
import { stringifyDumpData, writeLogFile } from '@midscene/core/utils';
|
||||
import { getMidsceneRunSubDir } from '@midscene/shared/common';
|
||||
import { getAIConfigInBoolean } from '@midscene/shared/env';
|
||||
import { getRunningPkgInfo } from '@midscene/shared/fs';
|
||||
import { getDebug } from '@midscene/shared/logger';
|
||||
import { ifInBrowser } from '@midscene/shared/utils';
|
||||
|
||||
@ -4,8 +4,8 @@ import type {
|
||||
PlaywrightParserOpt,
|
||||
UIContext,
|
||||
} from '@midscene/core';
|
||||
import { MIDSCENE_REPORT_TAG_NAME, getAIConfig } from '@midscene/core/env';
|
||||
import { uploadTestInfoToServer } from '@midscene/core/utils';
|
||||
import { MIDSCENE_REPORT_TAG_NAME, getAIConfig } from '@midscene/shared/env';
|
||||
import type { ElementInfo } from '@midscene/shared/extractor';
|
||||
import { traverseTree, treeToList } from '@midscene/shared/extractor';
|
||||
import { resizeImgBase64 } from '@midscene/shared/img';
|
||||
|
||||
@ -3,9 +3,9 @@ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
||||
import type { Server } from 'node:http';
|
||||
import { join } from 'node:path';
|
||||
import { ERROR_CODE_NOT_IMPLEMENTED_AS_DESIGNED } from '@/common/utils';
|
||||
import { overrideAIConfig } from '@midscene/core/env';
|
||||
import { getTmpDir } from '@midscene/core/utils';
|
||||
import { PLAYGROUND_SERVER_PORT } from '@midscene/shared/constants';
|
||||
import { overrideAIConfig } from '@midscene/shared/env';
|
||||
import { ifInBrowser } from '@midscene/shared/utils';
|
||||
import cors from 'cors';
|
||||
import dotenv from 'dotenv';
|
||||
|
||||
@ -4,7 +4,7 @@ import { WebPage as PlaywrightWebPage } from './page';
|
||||
|
||||
export type { PlayWrightAiFixtureType } from './ai-fixture';
|
||||
export { PlaywrightAiFixture } from './ai-fixture';
|
||||
export { overrideAIConfig } from '@midscene/core/env';
|
||||
export { overrideAIConfig } from '@midscene/shared/env';
|
||||
export { WebPage as PlaywrightWebPage } from './page';
|
||||
|
||||
export class PlaywrightAgent extends PageAgent<PlaywrightWebPage> {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { getMidsceneRunSubDir } from '@midscene/shared/common';
|
||||
import inquirer from 'inquirer';
|
||||
|
||||
interface Task {
|
||||
@ -57,7 +58,7 @@ const formatTasks = (tasks: Task[]): string => {
|
||||
|
||||
// Main function
|
||||
export const getTask = async (): Promise<void> => {
|
||||
const targetDir = path.join(process.cwd(), 'midscene_run/cache');
|
||||
const targetDir = getMidsceneRunSubDir('cache');
|
||||
const jsonFiles = getJsonFiles(targetDir);
|
||||
|
||||
if (jsonFiles.length === 0) {
|
||||
|
||||
@ -137,7 +137,7 @@ export class Page<
|
||||
const buffer = await (this.underlyingPage as PlaywrightPage).screenshot({
|
||||
type: imgType,
|
||||
quality,
|
||||
timeout: 3 * 1000,
|
||||
timeout: 10 * 1000,
|
||||
});
|
||||
base64 = `data:image/jpeg;base64,${buffer.toString('base64')}`;
|
||||
} else {
|
||||
|
||||
@ -28,7 +28,7 @@ export class PuppeteerAgent extends PageAgent<PuppeteerWebPage> {
|
||||
}
|
||||
}
|
||||
|
||||
export { overrideAIConfig } from '@midscene/core/env';
|
||||
export { overrideAIConfig } from '@midscene/shared/env';
|
||||
|
||||
// Do NOT export this since it requires puppeteer
|
||||
// export { puppeteerAgentForTarget } from './agent-launcher';
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import path from 'node:path';
|
||||
import { PuppeteerAgent } from '@/puppeteer';
|
||||
import { vlLocateMode } from '@midscene/core/env';
|
||||
import { sleep } from '@midscene/core/utils';
|
||||
import { vlLocateMode } from '@midscene/shared/env';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
import { launchPage } from './utils';
|
||||
|
||||
|
||||
18
pnpm-lock.yaml
generated
18
pnpm-lock.yaml
generated
@ -150,6 +150,9 @@ importers:
|
||||
'@midscene/report':
|
||||
specifier: workspace:*
|
||||
version: link:../report
|
||||
'@midscene/shared':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/shared
|
||||
'@midscene/visualizer':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/visualizer
|
||||
@ -211,6 +214,9 @@ importers:
|
||||
'@midscene/core':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/core
|
||||
'@midscene/shared':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/shared
|
||||
'@midscene/visualizer':
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/visualizer
|
||||
@ -16245,7 +16251,7 @@ snapshots:
|
||||
'@modern-js/utils': 2.32.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@rspack/core': 0.2.12(type-fest@3.13.1)(webpack@5.99.5)
|
||||
'@rspack/dev-client': 0.2.12(react-refresh@0.14.0)(type-fest@3.13.1)(webpack@5.99.5)
|
||||
'@rspack/plugin-html': 0.2.12(@rspack/core@0.2.12(type-fest@3.13.1)(webpack@5.99.5))
|
||||
'@rspack/plugin-html': 0.2.12(@rspack/core@0.2.12(type-fest@3.13.1)(webpack@5.95.0))
|
||||
'@swc/helpers': 0.5.1
|
||||
caniuse-lite: 1.0.30001714
|
||||
core-js: 3.30.2
|
||||
@ -18493,16 +18499,6 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@rspack/core': 0.2.12(type-fest@3.13.1)(webpack@5.95.0)
|
||||
|
||||
'@rspack/plugin-html@0.2.12(@rspack/core@0.2.12(type-fest@3.13.1)(webpack@5.99.5))':
|
||||
dependencies:
|
||||
'@types/html-minifier-terser': 7.0.0
|
||||
html-minifier-terser: 7.0.0
|
||||
lodash.template: 4.5.0
|
||||
parse5: 7.1.1
|
||||
tapable: 2.2.1
|
||||
optionalDependencies:
|
||||
'@rspack/core': 0.2.12(type-fest@3.13.1)(webpack@5.99.5)
|
||||
|
||||
'@rspack/plugin-react-refresh@1.0.1(react-refresh@0.16.0)':
|
||||
dependencies:
|
||||
error-stack-parser: 2.1.4
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user