@chen-rmag/ai-runner 0.1.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.
Files changed (102) hide show
  1. package/README.md +263 -0
  2. package/SUMMARY_USAGE.md +359 -0
  3. package/TOOLS_INTEGRATION_SUMMARY.md +206 -0
  4. package/dist/agents/error-analyzer.d.ts +62 -0
  5. package/dist/agents/error-analyzer.d.ts.map +1 -0
  6. package/dist/agents/error-analyzer.js +168 -0
  7. package/dist/agents/error-analyzer.js.map +1 -0
  8. package/dist/agents/heal-agent.d.ts +30 -0
  9. package/dist/agents/heal-agent.d.ts.map +1 -0
  10. package/dist/agents/heal-agent.js +76 -0
  11. package/dist/agents/heal-agent.js.map +1 -0
  12. package/dist/agents/healer.d.ts +73 -0
  13. package/dist/agents/healer.d.ts.map +1 -0
  14. package/dist/agents/healer.js +538 -0
  15. package/dist/agents/healer.js.map +1 -0
  16. package/dist/agents/langgraph-agent.d.ts +44 -0
  17. package/dist/agents/langgraph-agent.d.ts.map +1 -0
  18. package/dist/agents/langgraph-agent.js +328 -0
  19. package/dist/agents/langgraph-agent.js.map +1 -0
  20. package/dist/agents/react-agent.d.ts +52 -0
  21. package/dist/agents/react-agent.d.ts.map +1 -0
  22. package/dist/agents/react-agent.js +262 -0
  23. package/dist/agents/react-agent.js.map +1 -0
  24. package/dist/agents/tools/form.d.ts +22 -0
  25. package/dist/agents/tools/form.d.ts.map +1 -0
  26. package/dist/agents/tools/form.js +134 -0
  27. package/dist/agents/tools/form.js.map +1 -0
  28. package/dist/agents/tools/index.d.ts +13 -0
  29. package/dist/agents/tools/index.d.ts.map +1 -0
  30. package/dist/agents/tools/index.js +33 -0
  31. package/dist/agents/tools/index.js.map +1 -0
  32. package/dist/agents/tools/navigate.d.ts +22 -0
  33. package/dist/agents/tools/navigate.d.ts.map +1 -0
  34. package/dist/agents/tools/navigate.js +74 -0
  35. package/dist/agents/tools/navigate.js.map +1 -0
  36. package/dist/agents/tools/snapshot.d.ts +22 -0
  37. package/dist/agents/tools/snapshot.d.ts.map +1 -0
  38. package/dist/agents/tools/snapshot.js +110 -0
  39. package/dist/agents/tools/snapshot.js.map +1 -0
  40. package/dist/agents/tools/verify.d.ts +34 -0
  41. package/dist/agents/tools/verify.d.ts.map +1 -0
  42. package/dist/agents/tools/verify.js +169 -0
  43. package/dist/agents/tools/verify.js.map +1 -0
  44. package/dist/agents/tools/wait.d.ts +22 -0
  45. package/dist/agents/tools/wait.d.ts.map +1 -0
  46. package/dist/agents/tools/wait.js +104 -0
  47. package/dist/agents/tools/wait.js.map +1 -0
  48. package/dist/agents/types.d.ts +51 -0
  49. package/dist/agents/types.d.ts.map +1 -0
  50. package/dist/agents/types.js +6 -0
  51. package/dist/agents/types.js.map +1 -0
  52. package/dist/core/ai-heal.d.ts +89 -0
  53. package/dist/core/ai-heal.d.ts.map +1 -0
  54. package/dist/core/ai-heal.js +468 -0
  55. package/dist/core/ai-heal.js.map +1 -0
  56. package/dist/core/execution-engine.d.ts +16 -0
  57. package/dist/core/execution-engine.d.ts.map +1 -0
  58. package/dist/core/execution-engine.js +44 -0
  59. package/dist/core/execution-engine.js.map +1 -0
  60. package/dist/core/runner.d.ts +195 -0
  61. package/dist/core/runner.d.ts.map +1 -0
  62. package/dist/core/runner.js +658 -0
  63. package/dist/core/runner.js.map +1 -0
  64. package/dist/index.d.ts +8 -0
  65. package/dist/index.d.ts.map +1 -0
  66. package/dist/index.js +11 -0
  67. package/dist/index.js.map +1 -0
  68. package/dist/types/external.d.ts +6 -0
  69. package/dist/types/external.d.ts.map +1 -0
  70. package/dist/types/external.js +7 -0
  71. package/dist/types/external.js.map +1 -0
  72. package/dist/types/index.d.ts +153 -0
  73. package/dist/types/index.d.ts.map +1 -0
  74. package/dist/types/index.js +26 -0
  75. package/dist/types/index.js.map +1 -0
  76. package/dist/utils/object-registry.d.ts +48 -0
  77. package/dist/utils/object-registry.d.ts.map +1 -0
  78. package/dist/utils/object-registry.js +133 -0
  79. package/dist/utils/object-registry.js.map +1 -0
  80. package/package.json +37 -0
  81. package/playwright.config.ts +38 -0
  82. package/src/agents/heal-agent.ts +85 -0
  83. package/src/agents/healer.ts +619 -0
  84. package/src/agents/tools/EXAMPLES.md +347 -0
  85. package/src/agents/tools/README.md +207 -0
  86. package/src/agents/tools/form.ts +138 -0
  87. package/src/agents/tools/index.ts +29 -0
  88. package/src/agents/tools/navigate.ts +69 -0
  89. package/src/agents/tools/snapshot.ts +109 -0
  90. package/src/agents/tools/verify.ts +168 -0
  91. package/src/agents/tools/wait.ts +103 -0
  92. package/src/agents/types.ts +79 -0
  93. package/src/core/runner.ts +756 -0
  94. package/src/index.ts +29 -0
  95. package/src/types/external.ts +7 -0
  96. package/src/types/index.ts +200 -0
  97. package/tests/agent/test-heal-agent.spec.ts +81 -0
  98. package/tests/tools/README.md +227 -0
  99. package/tests/tools/TEST_SUMMARY.md +214 -0
  100. package/tests/tools/quick-test.ts +88 -0
  101. package/tests/tools/tools.test.ts +491 -0
  102. package/tsconfig.json +22 -0
package/src/index.ts ADDED
@@ -0,0 +1,29 @@
1
+ /**
2
+ * ai-runner SDK 主入口
3
+ * 提供 AI 驱动的测试运行能力
4
+ */
5
+
6
+ // 类型
7
+ export type {
8
+ AIHealConfig,
9
+ ExecutionContext,
10
+ ExecutionResult,
11
+ HealContext,
12
+ HealSummary,
13
+ HealingDetail,
14
+ RunStepOptions,
15
+ VariableBindings
16
+ } from './types';
17
+
18
+
19
+ // 核心类
20
+ export { Runner } from './core/runner';
21
+
22
+
23
+ // Agent
24
+ export type {
25
+ HealAgentState,
26
+ HealAgentResult,
27
+ HealAgentConfig
28
+ } from './agents/types';
29
+
@@ -0,0 +1,7 @@
1
+ /**
2
+ * 外部类型定义
3
+ * 直接从 core-infra 导入
4
+ */
5
+
6
+ // 从 core-infra 重新导出 ModelConfig 相关类型
7
+ export type { ModelConfig, ModelProvider } from '@ai-test/core-infra/dist/types';
@@ -0,0 +1,200 @@
1
+ /**
2
+ * ai-heal 核心类型定义 (MVP)
3
+ * 保持简洁,只包含必要的类型
4
+ */
5
+
6
+ import type { Page, BrowserContext } from 'playwright';
7
+
8
+ // ============================================================================
9
+ // Ref<T>: 变量包装器
10
+ // ============================================================================
11
+
12
+ /**
13
+ * 变量包装器,支持跨作用域赋值
14
+ */
15
+ export class Ref<T> {
16
+ constructor(public value: T) {}
17
+
18
+ get current(): T {
19
+ return this.value;
20
+ }
21
+
22
+ set current(value: T) {
23
+ this.value = value;
24
+ }
25
+ }
26
+
27
+ // ============================================================================
28
+ // AIHeal 配置
29
+ // ============================================================================
30
+
31
+ /**
32
+ * AIHeal 配置选项
33
+ */
34
+ export interface AIHealConfig {
35
+ /** 测试用例 ID */
36
+ testCaseId?: string;
37
+ /** 项目 ID */
38
+ projectId?: string;
39
+ /** 手动注入的脚本内容 */
40
+ scriptContent?: string;
41
+ /** 是否自动保存修复后的脚本 */
42
+ enableAutoSave?: boolean;
43
+ /** 最大自愈重试次数 */
44
+ /** 模型配置 ID(用于加载模型配置) */
45
+ modelConfigId?: string;
46
+ /** Agent 最大执行步数 */
47
+ agentMaxSteps?: number;
48
+ /** 是否开启调试模式 */
49
+ debugMode?: boolean;
50
+ }
51
+
52
+ // ============================================================================
53
+ // 执行上下文
54
+ // ============================================================================
55
+
56
+ /**
57
+ * 执行上下文,包含用户的 Playwright 对象
58
+ */
59
+ export interface ExecutionContext {
60
+ context: BrowserContext;
61
+ page: Page;
62
+ }
63
+
64
+ // ============================================================================
65
+ // 变量绑定
66
+ // ============================================================================
67
+
68
+ /**
69
+ * 变量绑定映射
70
+ */
71
+ export type VariableBindings = Record<string, Ref<any>>;
72
+
73
+ // ============================================================================
74
+ // Step 选项
75
+ // ============================================================================
76
+
77
+ /**
78
+ * runStep 选项
79
+ */
80
+ export interface RunStepOptions {
81
+ /** 步骤描述,用于 AI 理解 */
82
+ description: string;
83
+ /** 需要传递的变量绑定 */
84
+ variables?: VariableBindings;
85
+ /** Playwright 上下文对象 */
86
+ context?: ExecutionContext;
87
+ }
88
+
89
+ // ============================================================================
90
+ // 自愈上下文
91
+ // ============================================================================
92
+
93
+ /**
94
+ * ReAct 循环步骤记录
95
+ */
96
+ export interface ReActStep {
97
+ /** 步骤序号 */
98
+ stepNumber: number;
99
+ /** 步骤类型 */
100
+ stepType: 'thought' | 'action' | 'observation' | 'reflection';
101
+ /** 时间戳 */
102
+ timestamp: number;
103
+ /** LLM 的思考内容(thought 步骤) */
104
+ thought?: string;
105
+ /** 工具调用信息(action 步骤) */
106
+ toolCall?: {
107
+ name: string;
108
+ input: any;
109
+ };
110
+ /** 工具执行结果(observation 步骤) */
111
+ toolResult?: {
112
+ output: string;
113
+ success: boolean;
114
+ duration?: number;
115
+ };
116
+ /** 反思内容(reflection 步骤) */
117
+ reflection?: string;
118
+ }
119
+
120
+ /**
121
+ * 单次自愈过程的上下文信息
122
+ */
123
+ export interface HealContext {
124
+ /** 时间戳 */
125
+ timestamp: number;
126
+ /** 步骤描述 */
127
+ stepDescription: string;
128
+ /** 错误对象 */
129
+ error?: Error;
130
+ /** 堆栈信息 */
131
+ stackTrace?: string;
132
+ /** 原始代码 */
133
+ originalCode: string;
134
+ /** 恢复尝试次数 */
135
+ recoveryAttempts: number;
136
+ /** 变量快照(执行前) */
137
+ variablesBefore: Record<string, any>;
138
+ /** 变量快照(执行后) */
139
+ variablesAfter: Record<string, any>;
140
+ /** 是否成功 */
141
+ success: boolean;
142
+ /** 自愈耗时 */
143
+ healingTime?: number;
144
+ /** ReAct 循环详细记录(如果使用了 Agent) */
145
+ reactSteps?: ReActStep[];
146
+ /** Agent 的推理过程总结 */
147
+ reasoning?: string;
148
+ /** Agent 执行的总步数 */
149
+ agentSteps?: number;
150
+ }
151
+
152
+ // ============================================================================
153
+ // 执行结果
154
+ // ============================================================================
155
+
156
+ /**
157
+ * 代码执行结果
158
+ */
159
+ export interface ExecutionResult {
160
+ /** 是否成功 */
161
+ success: boolean;
162
+ /** 返回值 */
163
+ returnValue: any;
164
+ /** 局部变量 */
165
+ locals: Record<string, any>;
166
+ /** 错误信息 */
167
+ error?: Error;
168
+ }
169
+
170
+ // ============================================================================
171
+ // 自愈摘要
172
+ // ============================================================================
173
+
174
+ /**
175
+ * 自愈摘要信息
176
+ */
177
+ export interface HealSummary {
178
+ /** 总步骤数 */
179
+ totalSteps: number;
180
+ /** 自愈成功的步骤数 */
181
+ healedSteps: number;
182
+ /** 修复后的脚本 */
183
+ modifiedScript?: string;
184
+ /** 自愈详情列表 */
185
+ healingDetails: HealingDetail[];
186
+ }
187
+
188
+ /**
189
+ * 单次自愈详情
190
+ */
191
+ export interface HealingDetail {
192
+ /** 步骤描述 */
193
+ step: string;
194
+ /** 错误信息 */
195
+ error: string;
196
+ /** 恢复时间 */
197
+ recoveryTime: number;
198
+ /** LLM 交互次数 */
199
+ llmInteractions: number;
200
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * 自愈 Agent 测试
3
+ */
4
+
5
+ import { test, expect } from '@playwright/test';
6
+ import { Runner } from '../../src/index';
7
+
8
+ // const heal = new AIHeal({ modelConfigId:'f7858370-daae-4ce9-ba2e-a5cf2270bdc9', scriptContent: ` test('应该调用 ReAct Agent 接管执行', async ({ page, context }) => {
9
+
10
+ // await page.goto('https://example.com');
11
+
12
+ // // 成功步骤不需要 Agent
13
+ // await heal.runStep({
14
+ // description: '获取标题',
15
+ // context: { page, context }
16
+ // }, async () => {
17
+ // const title = await page.title();
18
+ // expect(title).toBeTruthy();
19
+ // });
20
+
21
+
22
+ // const userUrl = new Ref<string>('');
23
+ // // 失败步骤 - Agent 会接管并尝试修复(可能会失败,但至少执行了)
24
+ // try {
25
+ // await heal.runStep({
26
+ // description: '尝试点击不存在的元素',
27
+ // context: { page, context },
28
+ // variables: {userUrl: userUrl} // key 必须和 Agent set_variable 使用的名称一致
29
+ // }, async () => {
30
+ // await page.click('#non-existent', { timeout: 100 });
31
+ // userUrl.value = await page.url();
32
+ // });
33
+ // } catch (error) {
34
+ // // Agent 可能无法修复,但已经执行了 ReAct 循环
35
+ // }
36
+
37
+ // // 验证变量被 Agent 更新
38
+ // console.log('userUrl.value:', userUrl.value);
39
+
40
+ // const summary = await heal.summary();
41
+ // expect(summary.totalSteps).toBe(2);
42
+ // });` });
43
+
44
+ test.describe('AIHeal - ReAct Agent 集成', () => {
45
+ test.setTimeout(100000000)
46
+
47
+ const runner = Runner.NewInstance('12c57655-0ae2-4580-92f8-b4dc2388a7f5','71692142-7170-4246-898f-21a650dfa6d5' );
48
+ // heal.map()
49
+ test('应该调用 ReAct Agent 接管执行', async ({ page, context }) => {
50
+ await page.goto('https://example.com');
51
+
52
+ // 成功步骤不需要 Agent
53
+ await runner.runStep({
54
+ description: '获取标题',
55
+ context: { page, context }
56
+ }, async () => {
57
+ const title = await page.title();
58
+
59
+ expect(title).toBeTruthy();
60
+ });
61
+
62
+
63
+ // 失败步骤 - Agent 会接管并尝试修复(可能会失败,但至少执行了)
64
+ await runner.runStep({
65
+ description: '尝试点击不存在的元素',
66
+ context: { page, context },
67
+ }, async () => {
68
+ runner.set('current_url', await page.url())
69
+ await page.click('#non-existent', { timeout: 100 });
70
+ });
71
+
72
+ // 验证变量被 Agent 更新
73
+ console.log('userUrl.value:', runner.get('current_url'));
74
+
75
+ const summary = await runner.summary();
76
+ console.log('summary', summary.modifiedScript);
77
+ });
78
+
79
+
80
+ });
81
+
@@ -0,0 +1,227 @@
1
+ # Playwright 工具测试
2
+
3
+ 本目录包含 LangChain 兼容的 Playwright 工具测试。
4
+
5
+ ## 测试文件
6
+
7
+ - **[tools.test.ts](tools.test.ts)** - 完整的工具集成测试
8
+ - **[unit.test.ts](unit.test.ts)** - 单个工具的单元测试
9
+
10
+ ## 运行测试
11
+
12
+ ### 运行所有工具测试
13
+
14
+ ```bash
15
+ # 从 ai-heal 目录运行
16
+ npm run test -- tests/tools/tools.test.ts
17
+
18
+ # 或者使用 Playwright CLI
19
+ npx playwright test tests/tools/
20
+ ```
21
+
22
+ ### 运行单元测试
23
+
24
+ ```bash
25
+ npm run test -- tests/tools/unit.test.ts
26
+ ```
27
+
28
+ ### 运行特定测试
29
+
30
+ ```bash
31
+ # 只测试导航工具
32
+ npm run test -- tests/tools/tools.test.ts -g "Navigation Tools"
33
+
34
+ # 只测试表单工具
35
+ npm run test -- tests/tools/tools.test.ts -g "Form Tools"
36
+
37
+ # 只测试错误处理
38
+ npm run test -- tests/tools/tools.test.ts -g "Error Handling"
39
+ ```
40
+
41
+ ### 调试模式
42
+
43
+ ```bash
44
+ # 显示浏览器
45
+ HEADED=true npm run test -- tests/tools/
46
+
47
+ # 使用 Playwright Inspector
48
+ npm run test:debug -- tests/tools/
49
+
50
+ # 慢速模式
51
+ SLOW_MO=1000 npm run test -- tests/tools/
52
+ ```
53
+
54
+ ## 测试覆盖
55
+
56
+ ### 工具功能测试
57
+
58
+ ✅ **导航工具**
59
+ - 导航到 URL
60
+ - 前进/后退
61
+
62
+ ✅ **交互工具**
63
+ - 点击元素(文本选择器)
64
+ - 点击元素(CSS 选择器)
65
+ - 多选择器支持
66
+ - 悬停元素
67
+
68
+ ✅ **表单工具**
69
+ - 填写文本输入
70
+ - 通过 label 填写
71
+ - 选择下拉选项
72
+ - 勾选/取消复选框
73
+
74
+ ✅ **等待工具**
75
+ - 等待指定时间
76
+ - 等待元素出现
77
+ - 等待 URL 匹配
78
+ - 超时参数
79
+
80
+ ✅ **验证工具**
81
+ - 获取 URL
82
+ - 获取页面内容
83
+ - 获取元素文本
84
+ - 截图
85
+ - 验证文本可见
86
+ - 验证元素可见
87
+
88
+ ### 错误处理测试
89
+
90
+ - 无效 JSON 输入
91
+ - 不存在的元素
92
+ - 超时处理
93
+ - 选择器失败
94
+
95
+ ### 集成测试
96
+
97
+ - 完整表单工作流
98
+ - 导航和交互
99
+ - 等待和验证
100
+ - 多选择器回退
101
+
102
+ ## 测试结果
103
+
104
+ 运行测试后,结果将保存在:
105
+ - `test-results/` - 测试结果和截图
106
+ - `playwright-report/` - HTML 报告
107
+
108
+ 查看报告:
109
+
110
+ ```bash
111
+ npx playwright show-report
112
+ ```
113
+
114
+ ## 调试技巧
115
+
116
+ ### 1. 查看 Playwright Inspector
117
+
118
+ ```bash
119
+ npm run test:debug -- tests/tools/tools.test.ts
120
+ ```
121
+
122
+ ### 2. 保留浏览器窗口
123
+
124
+ ```bash
125
+ HEADED=true npm run test -- tests/tools/tools.test.ts
126
+ ```
127
+
128
+ ### 3. 保留追踪
129
+
130
+ ```typescript
131
+ test.use({ trace: 'on' });
132
+
133
+ test('my test', async ({ page }) => {
134
+ // 测试代码
135
+ });
136
+ ```
137
+
138
+ ### 4. 查看控制台日志
139
+
140
+ 测试中的 `console.log` 会显示在终端输出中。
141
+
142
+ ## 添加新测试
143
+
144
+ ### 测试新工具
145
+
146
+ ```typescript
147
+ test('my new tool - should do something', async ({ page }) => {
148
+ // 准备测试页面
149
+ await page.setContent(`...`);
150
+
151
+ // 创建工具实例
152
+ const tools = getAllTools(page);
153
+ const myTool = tools.find(t => t.name === 'browser_my_tool');
154
+
155
+ // 调用工具
156
+ const result = await myTool!.invoke('input');
157
+
158
+ // 验证结果
159
+ expect(result).toContain('expected output');
160
+ });
161
+ ```
162
+
163
+ ### 测试错误场景
164
+
165
+ ```typescript
166
+ test('should handle error gracefully', async ({ page }) => {
167
+ const tools = getAllTools(page);
168
+ const tool = tools.find(t => t.name === 'browser_tool');
169
+
170
+ try {
171
+ await tool!.invoke('invalid input');
172
+ expect.fail('Should have thrown an error');
173
+ } catch (error) {
174
+ expect((error as Error).message).toContain('expected error');
175
+ }
176
+ });
177
+ ```
178
+
179
+ ## 已知问题
180
+
181
+ ### 1. ariaSnapshot 兼容性
182
+
183
+ `browser_snapshot` 工具使用了 `ariaSnapshot()` API,这在较旧版本的 Playwright 中可能不可用。
184
+
185
+ **解决方案**:确保使用 Playwright 1.40 或更高版本。
186
+
187
+ ### 2. 多选择器性能
188
+
189
+ 当提供多个选择器时,工具会依次尝试,这可能影响性能。
190
+
191
+ **优化建议**:按最可能成功到最不可能成功的顺序排列选择器。
192
+
193
+ ## 持续集成
194
+
195
+ ### GitHub Actions 示例
196
+
197
+ ```yaml
198
+ name: Test Tools
199
+
200
+ on: [push, pull_request]
201
+
202
+ jobs:
203
+ test:
204
+ runs-on: ubuntu-latest
205
+
206
+ steps:
207
+ - uses: actions/checkout@v3
208
+ - uses: actions/setup-node@v3
209
+ with:
210
+ node-version: 18
211
+
212
+ - run: npm ci
213
+ - run: npm run test -- tests/tools/
214
+
215
+ - uses: actions/upload-artifact@v3
216
+ if: failure()
217
+ with:
218
+ name: test-results
219
+ path: test-results/
220
+ ```
221
+
222
+ ## 相关文档
223
+
224
+ - [Playwright Testing Guide](https://playwright.dev/docs/intro)
225
+ - [LangChain Tools](https://js.langchain.com/docs/concepts/tools)
226
+ - [工具 README](../../src/agents/tools/README.md)
227
+ - [工具示例](../../src/agents/tools/EXAMPLES.md)