@cotestdev/ai-runner 0.0.11 → 0.0.12
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/agents/playwright-executor.d.ts +1 -0
- package/dist/agents/playwright-executor.d.ts.map +1 -1
- package/dist/agents/playwright-executor.js +61 -54
- package/dist/agents/playwright-executor.js.map +1 -1
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +16 -7
- package/dist/runner.js.map +1 -1
- package/dist/tools/index.d.ts +14 -3
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +31 -2
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/playwright-groups.d.ts +1 -1
- package/dist/tools/playwright-groups.d.ts.map +1 -1
- package/dist/tools/playwright-groups.js +1 -1
- package/dist/tools/playwright-groups.js.map +1 -1
- package/package.json +4 -4
- package/playwright.config.ts +33 -38
- package/src/agents/playwright-executor.ts +60 -23
- package/src/runner.ts +19 -8
- package/src/tools/index.ts +50 -4
- package/src/tools/playwright-groups.ts +1 -1
- package/tests/test-heal-agent-2.spec.ts +67 -0
- package/tests/test-heal-agent.spec.ts +46 -0
- package/tests/agent/playwright.config.ts +0 -32
- package/tests/agent/test-heal-agent.spec.ts +0 -42
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"playwright-executor.d.ts","sourceRoot":"","sources":["../../src/agents/playwright-executor.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAE/C,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,MAAM,CAAc;gBAEhB,KAAK,EAAE,oBAAoB,EAAE,MAAM,EAAE,WAAW;YAK9C,qBAAqB;
|
|
1
|
+
{"version":3,"file":"playwright-executor.d.ts","sourceRoot":"","sources":["../../src/agents/playwright-executor.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAE/C,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,MAAM,CAAc;gBAEhB,KAAK,EAAE,oBAAoB,EAAE,MAAM,EAAE,WAAW;YAK9C,qBAAqB;IAsFnC;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAKtB,OAAO,CAAC,OAAO,EAAE,WAAW;IA4ElC,OAAO,CAAC,gBAAgB;IAUxB,OAAO,CAAC,iBAAiB;YAuBX,kBAAkB;IA+BhC,OAAO,CAAC,gBAAgB;IAmBxB;;;;SAIK;IACL,OAAO,CAAC,cAAc;CAuCvB"}
|
|
@@ -3,52 +3,22 @@
|
|
|
3
3
|
* Playwright Executor - Uses LangChain's createAgent API to implement ReAct loop
|
|
4
4
|
*/
|
|
5
5
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
6
|
-
var
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
-
}
|
|
12
|
-
Object.defineProperty(o, k2, desc);
|
|
13
|
-
}) : (function(o, m, k, k2) {
|
|
14
|
-
if (k2 === undefined) k2 = k;
|
|
15
|
-
o[k2] = m[k];
|
|
16
|
-
}));
|
|
17
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
-
}) : function(o, v) {
|
|
20
|
-
o["default"] = v;
|
|
21
|
-
});
|
|
22
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
-
var ownKeys = function(o) {
|
|
24
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
-
var ar = [];
|
|
26
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
-
return ar;
|
|
28
|
-
};
|
|
29
|
-
return ownKeys(o);
|
|
30
|
-
};
|
|
31
|
-
return function (mod) {
|
|
32
|
-
if (mod && mod.__esModule) return mod;
|
|
33
|
-
var result = {};
|
|
34
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
-
__setModuleDefault(result, mod);
|
|
36
|
-
return result;
|
|
37
|
-
};
|
|
38
|
-
})();
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
39
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
10
|
exports.PlaywrightExecutor = void 0;
|
|
41
11
|
const langchain_1 = require("langchain");
|
|
42
12
|
const tools_1 = require("@langchain/core/tools");
|
|
43
|
-
const zod_1 =
|
|
13
|
+
const zod_1 = __importDefault(require("zod"));
|
|
14
|
+
const nanoid_1 = require("nanoid");
|
|
44
15
|
class PlaywrightExecutor {
|
|
45
16
|
constructor(state, signal) {
|
|
46
17
|
this.state = state;
|
|
47
18
|
this.signal = signal;
|
|
48
19
|
}
|
|
49
20
|
async createPlaywrightTools(healContext) {
|
|
50
|
-
const standardTools = this.state.playwrightGroup.
|
|
51
|
-
const playwrightToolGroups = this.state.playwrightGroup.getNonDefaultGroupInfo();
|
|
21
|
+
const standardTools = this.state.playwrightGroup.getDefaultDynamicTools();
|
|
52
22
|
const getToolGroupsTool = {
|
|
53
23
|
name: "get_tools",
|
|
54
24
|
description: "Get available tools in a group.",
|
|
@@ -58,7 +28,7 @@ class PlaywrightExecutor {
|
|
|
58
28
|
func: async (param) => {
|
|
59
29
|
if (!param.group_name)
|
|
60
30
|
throw new Error('Missing group_name parameter');
|
|
61
|
-
return JSON.stringify(
|
|
31
|
+
return JSON.stringify(this.state.playwrightGroup.getAvailableTools(param.group_name));
|
|
62
32
|
},
|
|
63
33
|
};
|
|
64
34
|
const callToolTool = {
|
|
@@ -161,44 +131,77 @@ The complete fixed test script, leave empty if the step fails:
|
|
|
161
131
|
recursionLimit: 25,
|
|
162
132
|
streamMode: 'updates',
|
|
163
133
|
});
|
|
134
|
+
const aiMessages = [];
|
|
164
135
|
for await (const event of stream) {
|
|
165
136
|
// Check for abort signal
|
|
166
137
|
if (this.signal.aborted) {
|
|
167
138
|
throw new Error('Execution aborted');
|
|
168
139
|
}
|
|
169
140
|
// Process AI messages (thoughts and tool calls)
|
|
170
|
-
const messages = event.model_request?.messages || event.messages;
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
141
|
+
const messages = event.model_request?.messages || event.messages || event.tools.messages || [];
|
|
142
|
+
for (const message of messages) {
|
|
143
|
+
if (message.type === 'ai') {
|
|
144
|
+
const content = this.extractContent(message.content);
|
|
145
|
+
// Record thought
|
|
146
|
+
if (content) {
|
|
147
|
+
console.log(`${content}`);
|
|
148
|
+
}
|
|
149
|
+
aiMessages.push(message);
|
|
150
|
+
}
|
|
151
|
+
else if (message.type === 'tool') {
|
|
152
|
+
const toolMsg = message;
|
|
153
|
+
let name = toolMsg.name;
|
|
154
|
+
if (name === 'get_tools' || name === 'finish_test') {
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
if (name === 'call_tool') {
|
|
158
|
+
const foundName = this.findToolCallName(aiMessages, toolMsg.tool_call_id);
|
|
159
|
+
name = foundName || name;
|
|
160
|
+
}
|
|
161
|
+
let content = toolMsg.content;
|
|
162
|
+
// If string, return as-is
|
|
163
|
+
if (typeof content === 'string') {
|
|
164
|
+
const parsed = JSON.parse(content);
|
|
165
|
+
if (parsed) {
|
|
166
|
+
content = parsed;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
const isError = toolMsg.status === 'error' || content.isError;
|
|
170
|
+
const output = this.extractContent(content);
|
|
171
|
+
this.state.logger.log(`${isError ? '❌' : '✅'} [${name}]:`, output.length > 100 ? output.substring(0, 100) + '...' : output);
|
|
177
172
|
}
|
|
178
173
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
findToolCallName(msgs, toolCallId) {
|
|
177
|
+
for (const msg of msgs) {
|
|
178
|
+
const toolCall = msg.tool_calls?.find(tc => tc.id === toolCallId);
|
|
179
|
+
if (toolCall) {
|
|
180
|
+
return toolCall.name;
|
|
184
181
|
}
|
|
185
182
|
}
|
|
183
|
+
return undefined;
|
|
186
184
|
}
|
|
187
185
|
buildSystemPrompt() {
|
|
186
|
+
const toolGroupsPrompt = JSON.stringify(this.state.playwrightGroup.getNonDefaultGroupInfo(), null, 2);
|
|
188
187
|
return `
|
|
189
|
-
You are a Playwright test expert, skilled at
|
|
188
|
+
You are a Playwright test expert, skilled at executing test and fixing script errors.
|
|
190
189
|
|
|
191
190
|
## ** Critial Rules **
|
|
192
191
|
- You MUST run the step using tools first before fixing the script
|
|
193
192
|
- When you step finishes or fails, you MUST call 'finish_test' tool and set the 'isSuccess' parameter correctly.
|
|
193
|
+
- Use 'get_tools' tool to retrieve other available tools from a tool group ONLY if existing tools are not appropriate.
|
|
194
194
|
- Analyze the current step code, errors and page context and what variables are being set
|
|
195
195
|
- Make sure the fixed code is concise and consistent with the original code in logic and style
|
|
196
|
-
-
|
|
196
|
+
- When calling 'finish_test', analyze the full test script to identify variables defined in the current step that are used in subsequent steps
|
|
197
197
|
|
|
198
198
|
## ** Constraints **
|
|
199
199
|
- NEVER set 'isSuccess' to true if the step goal is not fully achieved
|
|
200
200
|
- Fail the step fast and DON'T do unnecessary or unreansonable retries
|
|
201
201
|
- Always check if variables assigned in the current step are referenced in later steps - if so, extract their actual values and include in 'variables'
|
|
202
|
+
|
|
203
|
+
## Tool Groups:
|
|
204
|
+
\`\`\`\n${toolGroupsPrompt}\n\`\`\`
|
|
202
205
|
`.trim();
|
|
203
206
|
}
|
|
204
207
|
async getSnapshotContext() {
|
|
@@ -207,7 +210,7 @@ You are a Playwright test expert, skilled at analyzing and fixing errors in brow
|
|
|
207
210
|
this.state.logger.warn(`Failed to get browser snapshot: ${snapshot.error}`);
|
|
208
211
|
return undefined;
|
|
209
212
|
}
|
|
210
|
-
const callId =
|
|
213
|
+
const callId = (0, nanoid_1.nanoid)(10);
|
|
211
214
|
const aiMessage = new langchain_1.AIMessage({
|
|
212
215
|
tool_calls: [
|
|
213
216
|
{
|
|
@@ -217,8 +220,12 @@ You are a Playwright test expert, skilled at analyzing and fixing errors in brow
|
|
|
217
220
|
},
|
|
218
221
|
]
|
|
219
222
|
});
|
|
223
|
+
let toolContent = '';
|
|
224
|
+
if (snapshot.content && Array.isArray(snapshot.content) && snapshot.content.length > 0) {
|
|
225
|
+
toolContent = snapshot.content[0].text;
|
|
226
|
+
}
|
|
220
227
|
const toolMessage = new langchain_1.ToolMessage({
|
|
221
|
-
content:
|
|
228
|
+
content: toolContent,
|
|
222
229
|
tool_call_id: callId,
|
|
223
230
|
name: 'browser_snapshot',
|
|
224
231
|
status: 'success',
|
|
@@ -254,7 +261,7 @@ ${this.state.originalScript}
|
|
|
254
261
|
if (asAny.content) {
|
|
255
262
|
content = asAny.content;
|
|
256
263
|
}
|
|
257
|
-
// If string, return as-is
|
|
264
|
+
// If string, return as-is
|
|
258
265
|
if (typeof content === 'string') {
|
|
259
266
|
return content;
|
|
260
267
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"playwright-executor.js","sourceRoot":"","sources":["../../src/agents/playwright-executor.ts"],"names":[],"mappings":";AAAA;;GAEG;AACH,uDAAuD
|
|
1
|
+
{"version":3,"file":"playwright-executor.js","sourceRoot":"","sources":["../../src/agents/playwright-executor.ts"],"names":[],"mappings":"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"}
|
package/dist/runner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAUvD,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,KAAK,CAAC,CAAoB;IAClC,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,KAAK,CAAmC;IAChD,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,eAAe,CAAkB;IAEzC,OAAO;IAOP,MAAM,CAAC,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,GAAE,OAAc,GAAG,MAAM;IAgCpF,IAAI;IAOJ,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAuB1F,OAAO,CAAC,kBAAkB;
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAUvD,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,KAAK,CAAC,CAAoB;IAClC,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,KAAK,CAAmC;IAChD,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,eAAe,CAAkB;IAEzC,OAAO;IAOP,MAAM,CAAC,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,GAAE,OAAc,GAAG,MAAM;IAgCpF,IAAI;IAOJ,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAuB1F,OAAO,CAAC,kBAAkB;IAapB,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC;IAgD1D;;KAEC;IACD,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,eAAe;IAsBvB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI;IAIlC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAI5C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG;IAQrB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IASzB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI5B,KAAK,IAAI,IAAI;IAIb,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAI3B,SAAS,CAAC,aAAa,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CA+B/F"}
|
package/dist/runner.js
CHANGED
|
@@ -77,7 +77,6 @@ class Runner {
|
|
|
77
77
|
if (!this.config.testCaseId) {
|
|
78
78
|
throw new Error('Cannot load original script: testCaseId is not provided');
|
|
79
79
|
}
|
|
80
|
-
this.logger.log(`Attempting to load script from database: ${this.config.testCaseId}`);
|
|
81
80
|
const script = this.storageService.loadTestScript(this.config.testCaseId);
|
|
82
81
|
if (!script) {
|
|
83
82
|
throw new Error(`Cannot load original script: Test case not found in database (ID: ${this.config.testCaseId})`);
|
|
@@ -92,8 +91,10 @@ class Runner {
|
|
|
92
91
|
success: false
|
|
93
92
|
};
|
|
94
93
|
try {
|
|
94
|
+
this.logger.log(`Starting step: ${description}`);
|
|
95
95
|
await fn();
|
|
96
96
|
context.success = true;
|
|
97
|
+
this.logger.log(`Step successful: ${description}`);
|
|
97
98
|
return;
|
|
98
99
|
}
|
|
99
100
|
catch (error) {
|
|
@@ -107,7 +108,11 @@ class Runner {
|
|
|
107
108
|
context.error = error.message;
|
|
108
109
|
context.stackTrace = this.removeAnsiCodes(error.stack || '');
|
|
109
110
|
this.logger.error(`Step failed: ${description}, Error: ${context.error}`);
|
|
110
|
-
this.logger.log(`Agent
|
|
111
|
+
this.logger.log(`Agent wll attempt to self-heal...`);
|
|
112
|
+
if (!this.executor) {
|
|
113
|
+
this.logger.error('Executor is not initialized, can not heal.');
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
111
116
|
await this.executor.execute(context);
|
|
112
117
|
const duration = (Date.now() - startTime) / 1000;
|
|
113
118
|
if (context.success) {
|
|
@@ -155,6 +160,7 @@ class Runner {
|
|
|
155
160
|
if (!value) {
|
|
156
161
|
return this.state.fixedVariables[key];
|
|
157
162
|
}
|
|
163
|
+
return value;
|
|
158
164
|
}
|
|
159
165
|
has(key) {
|
|
160
166
|
const value = this.state.variables[key];
|
|
@@ -181,11 +187,14 @@ class Runner {
|
|
|
181
187
|
await reuseRunner.init(this.state.page, this.state.context, { ...this.getAll() });
|
|
182
188
|
this.logger.log(`Starting to execute reusable test case: ${description}`);
|
|
183
189
|
try {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
190
|
+
// IMPORTANT: Use regular string (single quotes) instead of template string
|
|
191
|
+
// to avoid premature interpolation of ${} placeholders inside scriptContent
|
|
192
|
+
const functionBody = [
|
|
193
|
+
'return (async () => {',
|
|
194
|
+
scriptContent,
|
|
195
|
+
'})();'
|
|
196
|
+
].join('\n');
|
|
197
|
+
const executeScript = new Function('runner', 'page', 'context', 'expect', functionBody);
|
|
189
198
|
await executeScript(reuseRunner, this.state.page, this.state.context, test_1.expect);
|
|
190
199
|
this.logger.log(`Reusable test case executed successfully`);
|
|
191
200
|
return { ...reuseRunner.state?.variables || {} };
|
package/dist/runner.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":";;;AAMA,sDAAoE;AACpE,2CAA0C;AAE1C,4CAAyC;AACzC,sEAAkE;AAClE,iEAA4D;AAC5D,0FAAqF;AAGrF,MAAa,MAAM;IAWjB,YAAoB,MAAoB;QANhC,YAAO,GAAY,KAAK,CAAC;QAO/B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,cAAc,GAAG,2BAAc,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACnE,IAAI,CAAC,MAAM,GAAG,IAAI,eAAM,EAAE,CAAC;QAC3B,IAAI,CAAC,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;IAC/C,CAAC;IAED,MAAM,CAAC,WAAW,CAAC,SAAiB,EAAE,UAAkB,EAAE,UAAmB,IAAI;QAC/E,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC;QACrD,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;QACzB,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,OAAO,EAAE,CAAC;YACzD,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC;YACvB,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,CAAC,kBAAkB,EAAE,CAAC;YAC3C,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;gBACpE,OAAO,MAAM,CAAC;YAChB,CAAC;YACD,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;YAEvB,WAAW;YACX,MAAM,UAAU,GAAG,MAAM,CAAC,cAAc,CAAC,oBAAoB,EAAE,CAAC;YAChE,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC;YAC1D,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,KAAK,GAAG,IAAA,wBAAW,EAAC,MAAM,CAAC,CAAC;gBACnC,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;YACxB,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;YACjF,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,KAAK,EAAE,CAAC,CAAC;QAC/D,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;QAC7B,MAAM,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;QAClC,MAAM,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;QAC/B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;IAC/C,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,IAAU,EAAE,OAAuB,EAAE,IAA0B;QACxE,MAAM,OAAO,GAAG,MAAM,qDAAwB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC/D,IAAI,CAAC,KAAK,GAAG;YACX,IAAI;YACJ,OAAO;YACP,SAAS,EAAE,EAAE;YACb,cAAc,EAAE,IAAI,IAAI,EAAE;YAC1B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,cAAc,EAAE,IAAI,CAAC,KAAK,EAAE,cAAc,IAAI,IAAI,CAAC,MAAM,IAAI,EAAE;YAC/D,OAAO,EAAE,OAAO;YAChB,eAAe,EAAE,IAAI,mCAAe,CAAC,OAAO,CAAC;YAC7C,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU;YAClC,cAAc,EAAE,IAAI,CAAC,cAAc;SACpC,CAAC;QACF,IAAI,IAAI,EAAE,CAAC;YACT,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;gBAChD,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,wCAAkB,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;IAClF,CAAC;IAEO,kBAAkB;QACxB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;QAC7E,CAAC;QAED,
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":";;;AAMA,sDAAoE;AACpE,2CAA0C;AAE1C,4CAAyC;AACzC,sEAAkE;AAClE,iEAA4D;AAC5D,0FAAqF;AAGrF,MAAa,MAAM;IAWjB,YAAoB,MAAoB;QANhC,YAAO,GAAY,KAAK,CAAC;QAO/B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,cAAc,GAAG,2BAAc,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACnE,IAAI,CAAC,MAAM,GAAG,IAAI,eAAM,EAAE,CAAC;QAC3B,IAAI,CAAC,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;IAC/C,CAAC;IAED,MAAM,CAAC,WAAW,CAAC,SAAiB,EAAE,UAAkB,EAAE,UAAmB,IAAI;QAC/E,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC;QACrD,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;QACzB,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,OAAO,EAAE,CAAC;YACzD,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC;YACvB,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,CAAC,kBAAkB,EAAE,CAAC;YAC3C,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;gBACpE,OAAO,MAAM,CAAC;YAChB,CAAC;YACD,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;YAEvB,WAAW;YACX,MAAM,UAAU,GAAG,MAAM,CAAC,cAAc,CAAC,oBAAoB,EAAE,CAAC;YAChE,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC;YAC1D,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,KAAK,GAAG,IAAA,wBAAW,EAAC,MAAM,CAAC,CAAC;gBACnC,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;YACxB,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;YACjF,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,KAAK,EAAE,CAAC,CAAC;QAC/D,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;QAC7B,MAAM,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;QAClC,MAAM,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;QAC/B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;IAC/C,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,IAAU,EAAE,OAAuB,EAAE,IAA0B;QACxE,MAAM,OAAO,GAAG,MAAM,qDAAwB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC/D,IAAI,CAAC,KAAK,GAAG;YACX,IAAI;YACJ,OAAO;YACP,SAAS,EAAE,EAAE;YACb,cAAc,EAAE,IAAI,IAAI,EAAE;YAC1B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,cAAc,EAAE,IAAI,CAAC,KAAK,EAAE,cAAc,IAAI,IAAI,CAAC,MAAM,IAAI,EAAE;YAC/D,OAAO,EAAE,OAAO;YAChB,eAAe,EAAE,IAAI,mCAAe,CAAC,OAAO,CAAC;YAC7C,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU;YAClC,cAAc,EAAE,IAAI,CAAC,cAAc;SACpC,CAAC;QACF,IAAI,IAAI,EAAE,CAAC;YACT,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;gBAChD,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,wCAAkB,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;IAClF,CAAC;IAEO,kBAAkB;QACxB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;QAC7E,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC1E,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,qEAAqE,IAAI,CAAC,MAAM,CAAC,UAAU,GAAG,CAAC,CAAC;QAClH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,WAAmB,EAAE,EAAuB;QACxD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAgB;YAC3B,eAAe,EAAE,WAAW;YAC5B,YAAY,EAAE,EAAE,CAAC,QAAQ,EAAE;YAC3B,OAAO,EAAE,KAAK;SACf,CAAC;QAEF,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,kBAAkB,WAAW,EAAE,CAAC,CAAC;YACjD,MAAM,EAAE,EAAE,CAAC;YACX,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;YACvB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,oBAAoB,WAAW,EAAE,CAAC,CAAC;YACnD,OAAO;QACT,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,EAAE,CAAC;gBAC/C,MAAM,KAAK,CAAC;YACd,CAAC;YAED,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;YAC7C,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,MAAM,KAAK,CAAC;YACd,CAAC;YAED,OAAO,CAAC,KAAK,GAAI,KAAe,CAAC,OAAO,CAAC;YACzC,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,eAAe,CAAE,KAAe,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;YAExE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,WAAW,YAAY,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;YAC1E,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;YAErD,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACnB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;gBAChE,MAAM,KAAK,CAAC;YACd,CAAC;YAED,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YAErC,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC;YACjD,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBACpB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,+BAA+B,QAAQ,GAAG,CAAC,CAAC;gBAC5D,OAAO;YACT,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,uBAAuB,OAAO,CAAC,SAAS,eAAe,QAAQ,GAAG,CAAC,CAAC;YACtF,MAAM,IAAI,KAAK,CAAC,mBAAmB,OAAO,CAAC,KAAK,iBAAiB,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;QACxF,CAAC;IACH,CAAC;IAED;;KAEC;IACO,eAAe,CAAC,GAAW;QACjC,4DAA4D;QAC5D,OAAO,GAAG,CAAC,OAAO,CAAC,uDAAuD,EAAE,EAAE,CAAC,CAAC;IAClF,CAAC;IAEO,eAAe,CAAC,GAAU;QAChC,4BAA4B;QAC5B,MAAM,OAAO,GAAG,MAAM,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC;QAElD,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;YAC1B,IAAI,CAAC;gBACH,MAAM,KAAK,GAAI,GAAW,CAAC,GAAG,CAAC,CAAC;gBAEhC,kCAAkC;gBAClC,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,UAAU,IAAI,KAAK,EAAE,CAAC;oBAC9D,IAAI,KAAK,CAAC,QAAQ,KAAK,QAAQ,IAAI,KAAK,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;wBAC/D,OAAO,IAAI,CAAC;oBACd,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,eAAe;YACjB,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,KAAU;QACzB,IAAI,CAAC,KAAM,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACrC,CAAC;IAED,MAAM,CAAC,SAA8B;QACnC,IAAI,CAAC,KAAM,CAAC,SAAS,GAAG,EAAE,GAAG,IAAI,CAAC,KAAM,CAAC,SAAS,EAAE,GAAG,SAAS,EAAE,CAAC;IACrE,CAAC;IAED,GAAG,CAAC,GAAW;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,KAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACzC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,IAAI,CAAC,KAAM,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;QACzC,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC;IAED,GAAG,CAAC,GAAW;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,KAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACzC,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,GAAG,IAAI,IAAI,CAAC,KAAM,CAAC,cAAc,CAAC;IAC3C,CAAC;IAED,MAAM,CAAC,GAAW;QAChB,OAAO,OAAO,IAAI,CAAC,KAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK;QACH,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAM,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,IAAI,CAAC,KAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;IACvF,CAAC;IAED,MAAM;QACJ,OAAO,EAAE,GAAG,IAAI,CAAC,KAAM,CAAC,cAAc,EAAE,GAAG,IAAI,CAAC,KAAM,CAAC,SAAS,EAAE,CAAC;IACrE,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,aAAqB,EAAE,WAAoB;QACzD,MAAM,aAAa,GAAG,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;QACxE,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,mCAAmC,aAAa,EAAE,CAAC,CAAC;QACtE,CAAC;QAED,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QAC7E,MAAM,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,KAAM,CAAC,IAAI,EAAE,IAAI,CAAC,KAAM,CAAC,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAEpF,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,2CAA2C,WAAW,EAAE,CAAC,CAAC;QAE1E,IAAI,CAAC;YACH,2EAA2E;YAC3E,4EAA4E;YAC5E,MAAM,YAAY,GAAG;gBACnB,uBAAuB;gBACvB,aAAa;gBACb,OAAO;aACR,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAEb,MAAM,aAAa,GAAG,IAAI,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC;YAExF,MAAM,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,KAAM,CAAC,IAAI,EAAE,IAAI,CAAC,KAAM,CAAC,OAAO,EAAE,aAAM,CAAC,CAAC;YAEhF,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;YAE5D,OAAO,EAAE,GAAG,WAAW,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,EAAE,CAAC;QACnD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,sCAAsC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAClH,CAAC;IACH,CAAC;CACF;AA/OD,wBA+OC"}
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -5,12 +5,23 @@ export interface ToolGroup {
|
|
|
5
5
|
tools?: string[];
|
|
6
6
|
loadByDefault: boolean;
|
|
7
7
|
}
|
|
8
|
+
export interface MCPTool {
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
inputSchema: Record<string, unknown>;
|
|
12
|
+
}
|
|
13
|
+
export interface ToolGroupInfo {
|
|
14
|
+
groupId: string;
|
|
15
|
+
description: string;
|
|
16
|
+
}
|
|
8
17
|
export declare abstract class AbstractGroup {
|
|
9
18
|
groups: ToolGroup[];
|
|
10
19
|
constructor(groups: ToolGroup[]);
|
|
11
|
-
abstract
|
|
12
|
-
|
|
13
|
-
|
|
20
|
+
abstract getAllDynamicTools(): DynamicStructuredTool[];
|
|
21
|
+
getAllTools(): MCPTool[];
|
|
22
|
+
getDefaultDynamicTools(): DynamicStructuredTool[];
|
|
23
|
+
getAvailableTools(groupName: string): MCPTool[];
|
|
14
24
|
getNonDefaultGroupInfo(): Record<string, string>;
|
|
25
|
+
private normalizeInputSchema;
|
|
15
26
|
}
|
|
16
27
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAElD,MAAM,WAAW,SAAS;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;CAC1B;AAED,8BAAsB,aAAa;IAC/B,MAAM,EAAE,SAAS,EAAE,CAAC;gBAER,MAAM,EAAE,SAAS,EAAE;IAI/B,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAElD,MAAM,WAAW,SAAS;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,OAAO;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,aAAa;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACvB;AAED,8BAAsB,aAAa;IAC/B,MAAM,EAAE,SAAS,EAAE,CAAC;gBAER,MAAM,EAAE,SAAS,EAAE;IAI/B,QAAQ,CAAC,kBAAkB,IAAI,qBAAqB,EAAE;IAEtD,WAAW,IAAI,OAAO,EAAE;IAQxB,sBAAsB,IAAI,qBAAqB,EAAE;IAMjD,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,EAAE;IAe/C,sBAAsB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAShD,OAAO,CAAC,oBAAoB;CA0B/B"}
|
package/dist/tools/index.js
CHANGED
|
@@ -5,8 +5,15 @@ class AbstractGroup {
|
|
|
5
5
|
constructor(groups) {
|
|
6
6
|
this.groups = groups;
|
|
7
7
|
}
|
|
8
|
-
|
|
9
|
-
return this.
|
|
8
|
+
getAllTools() {
|
|
9
|
+
return this.getAllDynamicTools().map((tool) => ({
|
|
10
|
+
name: tool.name,
|
|
11
|
+
description: tool.description || '',
|
|
12
|
+
inputSchema: this.normalizeInputSchema(tool.name, tool.schema),
|
|
13
|
+
}));
|
|
14
|
+
}
|
|
15
|
+
getDefaultDynamicTools() {
|
|
16
|
+
return this.getAllDynamicTools().filter(tool => {
|
|
10
17
|
return this.groups.some(group => group.loadByDefault && (!group.tools || group.tools.includes(tool.name)));
|
|
11
18
|
});
|
|
12
19
|
}
|
|
@@ -30,6 +37,28 @@ class AbstractGroup {
|
|
|
30
37
|
return acc;
|
|
31
38
|
}, {});
|
|
32
39
|
}
|
|
40
|
+
normalizeInputSchema(name, inputSchema) {
|
|
41
|
+
const schema = (inputSchema ?? {});
|
|
42
|
+
// Ensure the schema is explicitly an object schema so MCP SDK validation passes
|
|
43
|
+
const properties = schema.properties || {};
|
|
44
|
+
const required = Array.isArray(schema.required)
|
|
45
|
+
? schema.required
|
|
46
|
+
: [];
|
|
47
|
+
if (schema.type === 'object') {
|
|
48
|
+
return {
|
|
49
|
+
type: 'object',
|
|
50
|
+
properties,
|
|
51
|
+
required,
|
|
52
|
+
additionalProperties: schema.additionalProperties ?? false,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
type: 'object',
|
|
57
|
+
properties,
|
|
58
|
+
required,
|
|
59
|
+
additionalProperties: false,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
33
62
|
}
|
|
34
63
|
exports.AbstractGroup = AbstractGroup;
|
|
35
64
|
//# sourceMappingURL=index.js.map
|
package/dist/tools/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,6 +14,6 @@ export declare class PlaywrightGroup extends AbstractGroup {
|
|
|
14
14
|
private adapter;
|
|
15
15
|
constructor(adapter: PlaywrightBackendAdapter);
|
|
16
16
|
callTool(toolName: string, args: any): Promise<any>;
|
|
17
|
-
|
|
17
|
+
getAllDynamicTools(): DynamicStructuredTool[];
|
|
18
18
|
}
|
|
19
19
|
//# sourceMappingURL=playwright-groups.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"playwright-groups.d.ts","sourceRoot":"","sources":["../../src/tools/playwright-groups.ts"],"names":[],"mappings":"AACA;;;GAGG;AACH,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,GAAG,CAAC;AAClC,OAAO,EAAE,wBAAwB,EAAE,MAAM,6CAA6C,CAAC;AACvF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,qBAAa,eAAgB,SAAQ,aAAa;IAChD,OAAO,CAAC,QAAQ,CAA0B;IAC1C,OAAO,CAAC,OAAO,CAA2B;gBAE9B,OAAO,EAAE,wBAAwB;IAqCvC,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAIzD,
|
|
1
|
+
{"version":3,"file":"playwright-groups.d.ts","sourceRoot":"","sources":["../../src/tools/playwright-groups.ts"],"names":[],"mappings":"AACA;;;GAGG;AACH,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,GAAG,CAAC;AAClC,OAAO,EAAE,wBAAwB,EAAE,MAAM,6CAA6C,CAAC;AACvF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,qBAAa,eAAgB,SAAQ,aAAa;IAChD,OAAO,CAAC,QAAQ,CAA0B;IAC1C,OAAO,CAAC,OAAO,CAA2B;gBAE9B,OAAO,EAAE,wBAAwB;IAqCvC,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAIzD,kBAAkB,IAAI,qBAAqB,EAAE;CAG9C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"playwright-groups.js","sourceRoot":"","sources":["../../src/tools/playwright-groups.ts"],"names":[],"mappings":";;;AAMA,wBAAkC;AAOlC,MAAa,eAAgB,SAAQ,gBAAa;IAIhD,YAAY,OAAiC;QAC3C,KAAK,CAAC,CAAC;gBACL,IAAI,EAAE,kBAAkB;gBACxB,WAAW,EAAE,iDAAiD;gBAC9D,KAAK,EAAE,CAAC,kBAAkB,EAAE,eAAe,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,cAAc,EAAE,kBAAkB,CAAC;gBACtK,aAAa,EAAE,IAAI;aACpB;YACD;gBACE,IAAI,EAAE,oBAAoB;gBAC1B,WAAW,EAAE,2FAA2F;gBACxG,KAAK,EAAE,CAAC,cAAc,EAAE,eAAe,CAAC;gBACxC,aAAa,EAAE,KAAK;aACrB;YACD;gBACE,IAAI,EAAE,qBAAqB;gBAC3B,WAAW,EAAE;;oDAEiC;gBAC9C,KAAK,EAAE,CAAC,mBAAmB,EAAE,4BAA4B,EAAE,iBAAiB,EAAE,eAAe,CAAC;gBAC9F,aAAa,EAAE,KAAK;aACrB;YACD;gBACE,IAAI,EAAE,kBAAkB;gBACxB,WAAW,EAAE;;;;;qDAKkC;gBAC/C,KAAK,EAAE,CAAC,eAAe,EAAE,cAAc,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,eAAe,EAAE,kBAAkB,CAAC;gBAC7H,aAAa,EAAE,KAAK;aACrB;SACA,CAAC,CAAC;QACH,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,QAAgB,EAAE,IAAS;QACxC,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC/C,CAAC;IAED,
|
|
1
|
+
{"version":3,"file":"playwright-groups.js","sourceRoot":"","sources":["../../src/tools/playwright-groups.ts"],"names":[],"mappings":";;;AAMA,wBAAkC;AAOlC,MAAa,eAAgB,SAAQ,gBAAa;IAIhD,YAAY,OAAiC;QAC3C,KAAK,CAAC,CAAC;gBACL,IAAI,EAAE,kBAAkB;gBACxB,WAAW,EAAE,iDAAiD;gBAC9D,KAAK,EAAE,CAAC,kBAAkB,EAAE,eAAe,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,cAAc,EAAE,kBAAkB,CAAC;gBACtK,aAAa,EAAE,IAAI;aACpB;YACD;gBACE,IAAI,EAAE,oBAAoB;gBAC1B,WAAW,EAAE,2FAA2F;gBACxG,KAAK,EAAE,CAAC,cAAc,EAAE,eAAe,CAAC;gBACxC,aAAa,EAAE,KAAK;aACrB;YACD;gBACE,IAAI,EAAE,qBAAqB;gBAC3B,WAAW,EAAE;;oDAEiC;gBAC9C,KAAK,EAAE,CAAC,mBAAmB,EAAE,4BAA4B,EAAE,iBAAiB,EAAE,eAAe,CAAC;gBAC9F,aAAa,EAAE,KAAK;aACrB;YACD;gBACE,IAAI,EAAE,kBAAkB;gBACxB,WAAW,EAAE;;;;;qDAKkC;gBAC/C,KAAK,EAAE,CAAC,eAAe,EAAE,cAAc,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,eAAe,EAAE,kBAAkB,CAAC;gBAC7H,aAAa,EAAE,KAAK;aACrB;SACA,CAAC,CAAC;QACH,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,QAAgB,EAAE,IAAS;QACxC,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC/C,CAAC;IAED,kBAAkB;QAChB,OAAO,IAAI,CAAC,QAAQ,CAAA;IACtB,CAAC;CACF;AAhDD,0CAgDC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cotestdev/ai-runner",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.12",
|
|
4
4
|
"description": "AI-powered self-healing SDK for Playwright test scripts",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"license": "MIT",
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@anthropic-ai/sdk": "^0.71.2",
|
|
29
|
-
"@cotestdev/core-infra": "^0.0.
|
|
29
|
+
"@cotestdev/core-infra": "^0.0.4",
|
|
30
30
|
"@langchain/anthropic": "^1.3.10",
|
|
31
31
|
"@langchain/core": "^1.1.15",
|
|
32
32
|
"@langchain/langgraph": "^1.0.15",
|
|
@@ -35,10 +35,10 @@
|
|
|
35
35
|
"langchain": "^1.2.10"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@playwright/test": "^1.58.0",
|
|
39
38
|
"@modelcontextprotocol/sdk": "^1.25.2",
|
|
39
|
+
"@playwright/test": "^1.58.0",
|
|
40
40
|
"@types/node": "^20.0.0",
|
|
41
41
|
"ts-node": "^10.9.2",
|
|
42
42
|
"typescript": "^5.0.0"
|
|
43
43
|
}
|
|
44
|
-
}
|
|
44
|
+
}
|
package/playwright.config.ts
CHANGED
|
@@ -1,38 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
'
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
{
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
// Use slow motion in debug mode
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
],
|
|
38
|
-
});
|
|
1
|
+
|
|
2
|
+
import { defineConfig, devices } from '@playwright/test';
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
timeout: 600000,
|
|
6
|
+
reporter: [['list'], ['html'], ['json']],
|
|
7
|
+
use: {
|
|
8
|
+
actionTimeout: 5000,
|
|
9
|
+
navigationTimeout: 60000,
|
|
10
|
+
locale: 'zh-CN',
|
|
11
|
+
headless: false,
|
|
12
|
+
},
|
|
13
|
+
expect: {
|
|
14
|
+
timeout: 5000,
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
// 重点在这里:定义 project
|
|
18
|
+
projects: [
|
|
19
|
+
{
|
|
20
|
+
name: 'chrome', // 项目名称,随意起,但建议有意义
|
|
21
|
+
use: {
|
|
22
|
+
...devices['Desktop Chrome'], // 继承桌面 Chrome 的常见设置(视口、UA 等)
|
|
23
|
+
channel: 'chrome', // ← 关键!使用系统安装的 Google Chrome
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
// 你也可以同时保留原生的 chromium(做对比用)
|
|
28
|
+
// {
|
|
29
|
+
// name: 'chromium',
|
|
30
|
+
// use: { ...devices['Desktop Chrome'] },
|
|
31
|
+
// },
|
|
32
|
+
],
|
|
33
|
+
});
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
import { AIMessage, BaseMessage, createAgent, ToolMessage } from 'langchain';
|
|
7
7
|
import { DynamicStructuredTool } from '@langchain/core/tools';
|
|
8
8
|
import type { HealContext } from '../types';
|
|
9
|
-
import z
|
|
9
|
+
import z from 'zod';
|
|
10
10
|
import { PlaywrightAgentState } from './types';
|
|
11
|
-
|
|
11
|
+
import { nanoid } from 'nanoid';
|
|
12
12
|
export class PlaywrightExecutor {
|
|
13
13
|
private state: PlaywrightAgentState;
|
|
14
14
|
private signal: AbortSignal;
|
|
@@ -19,8 +19,7 @@ export class PlaywrightExecutor {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
private async createPlaywrightTools(healContext: HealContext): Promise<DynamicStructuredTool[]> {
|
|
22
|
-
const standardTools = this.state.playwrightGroup.
|
|
23
|
-
const playwrightToolGroups = this.state.playwrightGroup.getNonDefaultGroupInfo();
|
|
22
|
+
const standardTools = this.state.playwrightGroup.getDefaultDynamicTools();
|
|
24
23
|
|
|
25
24
|
const getToolGroupsTool = {
|
|
26
25
|
name: "get_tools",
|
|
@@ -30,7 +29,7 @@ export class PlaywrightExecutor {
|
|
|
30
29
|
}),
|
|
31
30
|
func: async (param: any) => {
|
|
32
31
|
if (!param.group_name) throw new Error('Missing group_name parameter');
|
|
33
|
-
return JSON.stringify(
|
|
32
|
+
return JSON.stringify(this.state.playwrightGroup.getAvailableTools(param.group_name));
|
|
34
33
|
},
|
|
35
34
|
};
|
|
36
35
|
|
|
@@ -144,6 +143,7 @@ The complete fixed test script, leave empty if the step fails:
|
|
|
144
143
|
streamMode: 'updates',
|
|
145
144
|
});
|
|
146
145
|
|
|
146
|
+
const aiMessages: AIMessage[] = [];
|
|
147
147
|
for await (const event of stream) {
|
|
148
148
|
// Check for abort signal
|
|
149
149
|
if (this.signal.aborted) {
|
|
@@ -151,41 +151,73 @@ The complete fixed test script, leave empty if the step fails:
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
// Process AI messages (thoughts and tool calls)
|
|
154
|
-
const messages = event.model_request?.messages || event.messages;
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
154
|
+
const messages = event.model_request?.messages || event.messages || event.tools.messages || [];
|
|
155
|
+
for (const message of messages) {
|
|
156
|
+
if (message.type === 'ai') {
|
|
157
|
+
const content = this.extractContent(message.content);
|
|
158
|
+
// Record thought
|
|
159
|
+
if (content) {
|
|
160
|
+
console.log(`${content}`);
|
|
161
|
+
}
|
|
162
|
+
aiMessages.push(message as AIMessage);
|
|
163
|
+
} else if (message.type === 'tool') {
|
|
164
|
+
const toolMsg = message as ToolMessage;
|
|
165
|
+
let name = toolMsg.name;
|
|
166
|
+
if (name === 'get_tools' || name === 'finish_test') {
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (name === 'call_tool') {
|
|
171
|
+
const foundName = this.findToolCallName(aiMessages, toolMsg.tool_call_id);
|
|
172
|
+
name = foundName || name;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
let content = toolMsg.content;
|
|
176
|
+
// If string, return as-is
|
|
177
|
+
if (typeof content === 'string') {
|
|
178
|
+
const parsed = JSON.parse(content) as any;
|
|
179
|
+
if (parsed){
|
|
180
|
+
content = parsed;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
const isError = toolMsg.status === 'error' || (content as any).isError;
|
|
184
|
+
const output = this.extractContent(content) as string;
|
|
185
|
+
this.state.logger.log(`${isError ? '❌' : '✅'} [${name}]:`, output.length > 100 ? output.substring(0, 100) + '...' : output);
|
|
162
186
|
}
|
|
163
187
|
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
164
190
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
191
|
+
private findToolCallName(msgs: AIMessage[], toolCallId: string): string | undefined {
|
|
192
|
+
for (const msg of msgs) {
|
|
193
|
+
const toolCall = msg.tool_calls?.find(tc => tc.id === toolCallId);
|
|
194
|
+
if (toolCall) {
|
|
195
|
+
return toolCall.name;
|
|
170
196
|
}
|
|
171
197
|
}
|
|
198
|
+
return undefined;
|
|
172
199
|
}
|
|
173
200
|
|
|
174
201
|
private buildSystemPrompt(): string {
|
|
202
|
+
const toolGroupsPrompt = JSON.stringify(this.state.playwrightGroup.getNonDefaultGroupInfo(), null, 2);
|
|
175
203
|
return `
|
|
176
|
-
You are a Playwright test expert, skilled at
|
|
204
|
+
You are a Playwright test expert, skilled at executing test and fixing script errors.
|
|
177
205
|
|
|
178
206
|
## ** Critial Rules **
|
|
179
207
|
- You MUST run the step using tools first before fixing the script
|
|
180
208
|
- When you step finishes or fails, you MUST call 'finish_test' tool and set the 'isSuccess' parameter correctly.
|
|
209
|
+
- Use 'get_tools' tool to retrieve other available tools from a tool group ONLY if existing tools are not appropriate.
|
|
181
210
|
- Analyze the current step code, errors and page context and what variables are being set
|
|
182
211
|
- Make sure the fixed code is concise and consistent with the original code in logic and style
|
|
183
|
-
-
|
|
212
|
+
- When calling 'finish_test', analyze the full test script to identify variables defined in the current step that are used in subsequent steps
|
|
184
213
|
|
|
185
214
|
## ** Constraints **
|
|
186
215
|
- NEVER set 'isSuccess' to true if the step goal is not fully achieved
|
|
187
216
|
- Fail the step fast and DON'T do unnecessary or unreansonable retries
|
|
188
217
|
- Always check if variables assigned in the current step are referenced in later steps - if so, extract their actual values and include in 'variables'
|
|
218
|
+
|
|
219
|
+
## Tool Groups:
|
|
220
|
+
\`\`\`\n${toolGroupsPrompt}\n\`\`\`
|
|
189
221
|
`.trim();
|
|
190
222
|
}
|
|
191
223
|
|
|
@@ -196,7 +228,7 @@ You are a Playwright test expert, skilled at analyzing and fixing errors in brow
|
|
|
196
228
|
return undefined;
|
|
197
229
|
}
|
|
198
230
|
|
|
199
|
-
const callId =
|
|
231
|
+
const callId = nanoid(10);
|
|
200
232
|
const aiMessage = new AIMessage({
|
|
201
233
|
tool_calls: [
|
|
202
234
|
{
|
|
@@ -206,8 +238,13 @@ You are a Playwright test expert, skilled at analyzing and fixing errors in brow
|
|
|
206
238
|
},
|
|
207
239
|
]
|
|
208
240
|
});
|
|
241
|
+
|
|
242
|
+
let toolContent = '';
|
|
243
|
+
if (snapshot.content && Array.isArray(snapshot.content) && snapshot.content.length > 0) {
|
|
244
|
+
toolContent = snapshot.content[0].text
|
|
245
|
+
}
|
|
209
246
|
const toolMessage = new ToolMessage({
|
|
210
|
-
content:
|
|
247
|
+
content: toolContent,
|
|
211
248
|
tool_call_id: callId,
|
|
212
249
|
name: 'browser_snapshot',
|
|
213
250
|
status: 'success',
|
|
@@ -245,7 +282,7 @@ ${this.state.originalScript}
|
|
|
245
282
|
if (asAny.content) {
|
|
246
283
|
content = asAny.content;
|
|
247
284
|
}
|
|
248
|
-
// If string, return as-is
|
|
285
|
+
// If string, return as-is
|
|
249
286
|
if (typeof content === 'string') {
|
|
250
287
|
return content;
|
|
251
288
|
}
|
package/src/runner.ts
CHANGED
|
@@ -98,7 +98,6 @@ export class Runner {
|
|
|
98
98
|
throw new Error('Cannot load original script: testCaseId is not provided');
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
this.logger.log(`Attempting to load script from database: ${this.config.testCaseId}`);
|
|
102
101
|
const script = this.storageService.loadTestScript(this.config.testCaseId);
|
|
103
102
|
if (!script) {
|
|
104
103
|
throw new Error(`Cannot load original script: Test case not found in database (ID: ${this.config.testCaseId})`);
|
|
@@ -116,8 +115,10 @@ export class Runner {
|
|
|
116
115
|
};
|
|
117
116
|
|
|
118
117
|
try {
|
|
118
|
+
this.logger.log(`Starting step: ${description}`);
|
|
119
119
|
await fn();
|
|
120
120
|
context.success = true;
|
|
121
|
+
this.logger.log(`Step successful: ${description}`);
|
|
121
122
|
return;
|
|
122
123
|
} catch (error) {
|
|
123
124
|
if (!this.canHeal || !(error instanceof Error)) {
|
|
@@ -133,9 +134,14 @@ export class Runner {
|
|
|
133
134
|
context.stackTrace = this.removeAnsiCodes((error as Error).stack || '');
|
|
134
135
|
|
|
135
136
|
this.logger.error(`Step failed: ${description}, Error: ${context.error}`);
|
|
136
|
-
this.logger.log(`Agent
|
|
137
|
+
this.logger.log(`Agent wll attempt to self-heal...`);
|
|
137
138
|
|
|
138
|
-
|
|
139
|
+
if (!this.executor) {
|
|
140
|
+
this.logger.error('Executor is not initialized, can not heal.');
|
|
141
|
+
throw error;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
await this.executor.execute(context);
|
|
139
145
|
|
|
140
146
|
const duration = (Date.now() - startTime) / 1000;
|
|
141
147
|
if (context.success) {
|
|
@@ -191,6 +197,7 @@ export class Runner {
|
|
|
191
197
|
if (!value) {
|
|
192
198
|
return this.state!.fixedVariables[key];
|
|
193
199
|
}
|
|
200
|
+
return value
|
|
194
201
|
}
|
|
195
202
|
|
|
196
203
|
has(key: string): boolean {
|
|
@@ -226,11 +233,15 @@ export class Runner {
|
|
|
226
233
|
this.logger.log(`Starting to execute reusable test case: ${description}`);
|
|
227
234
|
|
|
228
235
|
try {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
236
|
+
// IMPORTANT: Use regular string (single quotes) instead of template string
|
|
237
|
+
// to avoid premature interpolation of ${} placeholders inside scriptContent
|
|
238
|
+
const functionBody = [
|
|
239
|
+
'return (async () => {',
|
|
240
|
+
scriptContent,
|
|
241
|
+
'})();'
|
|
242
|
+
].join('\n');
|
|
243
|
+
|
|
244
|
+
const executeScript = new Function('runner', 'page', 'context', 'expect', functionBody);
|
|
234
245
|
|
|
235
246
|
await executeScript(reuseRunner, this.state!.page, this.state!.context, expect);
|
|
236
247
|
|
package/src/tools/index.ts
CHANGED
|
@@ -7,6 +7,17 @@ export interface ToolGroup {
|
|
|
7
7
|
loadByDefault: boolean;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
export interface MCPTool {
|
|
11
|
+
name: string;
|
|
12
|
+
description: string;
|
|
13
|
+
inputSchema: Record<string, unknown>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface ToolGroupInfo {
|
|
17
|
+
groupId: string;
|
|
18
|
+
description: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
10
21
|
export abstract class AbstractGroup {
|
|
11
22
|
groups: ToolGroup[];
|
|
12
23
|
|
|
@@ -14,15 +25,23 @@ export abstract class AbstractGroup {
|
|
|
14
25
|
this.groups = groups;
|
|
15
26
|
}
|
|
16
27
|
|
|
17
|
-
abstract
|
|
28
|
+
abstract getAllDynamicTools(): DynamicStructuredTool[];
|
|
29
|
+
|
|
30
|
+
getAllTools(): MCPTool[] {
|
|
31
|
+
return this.getAllDynamicTools().map((tool: DynamicStructuredTool) => ({
|
|
32
|
+
name: tool.name,
|
|
33
|
+
description: tool.description || '',
|
|
34
|
+
inputSchema: this.normalizeInputSchema(tool.name, tool.schema),
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
18
37
|
|
|
19
|
-
|
|
20
|
-
return this.
|
|
38
|
+
getDefaultDynamicTools(): DynamicStructuredTool[] {
|
|
39
|
+
return this.getAllDynamicTools().filter(tool => {
|
|
21
40
|
return this.groups.some(group => group.loadByDefault && (!group.tools || group.tools.includes(tool.name)));
|
|
22
41
|
});
|
|
23
42
|
}
|
|
24
43
|
|
|
25
|
-
getAvailableTools(groupName: string):
|
|
44
|
+
getAvailableTools(groupName: string): MCPTool[] {
|
|
26
45
|
const group = this.groups.find(g => g.name === groupName);
|
|
27
46
|
if (group) {
|
|
28
47
|
const toolNames = group.tools;
|
|
@@ -45,4 +64,31 @@ export abstract class AbstractGroup {
|
|
|
45
64
|
return acc;
|
|
46
65
|
}, {} as Record<string, string>);
|
|
47
66
|
}
|
|
67
|
+
|
|
68
|
+
private normalizeInputSchema(name: string, inputSchema: unknown): Record<string, unknown> {
|
|
69
|
+
const schema = (inputSchema ?? {}) as Record<string, unknown>;
|
|
70
|
+
|
|
71
|
+
// Ensure the schema is explicitly an object schema so MCP SDK validation passes
|
|
72
|
+
const properties = (schema as { properties?: Record<string, unknown> }).properties || {};
|
|
73
|
+
const required = Array.isArray((schema as { required?: unknown }).required)
|
|
74
|
+
? ((schema as { required?: unknown }).required as string[])
|
|
75
|
+
: [];
|
|
76
|
+
|
|
77
|
+
if (schema.type === 'object') {
|
|
78
|
+
return {
|
|
79
|
+
type: 'object',
|
|
80
|
+
properties,
|
|
81
|
+
required,
|
|
82
|
+
additionalProperties: schema.additionalProperties ?? false,
|
|
83
|
+
} as Record<string, unknown>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
type: 'object',
|
|
88
|
+
properties,
|
|
89
|
+
required,
|
|
90
|
+
additionalProperties: false,
|
|
91
|
+
} as Record<string, unknown>;
|
|
92
|
+
}
|
|
93
|
+
|
|
48
94
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
|
|
2
|
+
import { test, expect } from '@playwright/test';
|
|
3
|
+
import { Runner } from '../src/runner';
|
|
4
|
+
test.describe(`Login user`, () => {
|
|
5
|
+
test.setTimeout(1000000);
|
|
6
|
+
const runner = Runner.NewInstance('43af4db4-3249-4135-b279-97b24f27106b', '607db298-206e-4539-b893-7e0a5215b51f');
|
|
7
|
+
|
|
8
|
+
test.afterEach(async () => {
|
|
9
|
+
runner.clear();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
[
|
|
13
|
+
{
|
|
14
|
+
"username": "user222476566122asddaabasdghjg",
|
|
15
|
+
"password": "password111"
|
|
16
|
+
}
|
|
17
|
+
].forEach((data, index) => {
|
|
18
|
+
test(`#${index + 1}`, async ({ page, context }) => {
|
|
19
|
+
runner.init(page, context, data)
|
|
20
|
+
await runner.runStep('导航到网站', async () => {
|
|
21
|
+
await page.goto('https://practice.expandtesting.com/');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
await runner.runStep('进入注册页面', async () => {
|
|
25
|
+
await page.getByRole('link', { name: 'Try it out' }).nth(2).click();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
await runner.runStep('使用测试参数填写并提交注册表单', async () => {
|
|
29
|
+
const result = await runner.reuseTest('2e189c6f-6c2b-4086-8fe7-837bf1a6b1df', '注册新用户');
|
|
30
|
+
// 假设可复用测试返回用户名和密码
|
|
31
|
+
// runner.set('userName', result.get('userName'));
|
|
32
|
+
// runner.set('password', result.get('password'));
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
await runner.runStep('使用新凭据填写并提交登录表单', async () => {
|
|
36
|
+
const result = await runner.reuseTest('13bcfb12-4add-4b7d-ac4b-b46a4280141c', '登录用户');
|
|
37
|
+
// 假设可复用测试返回登录成功后的关键信息,如欢迎文本
|
|
38
|
+
// runner.set('welcomeText', result.get('welcomeText'));
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
await runner.runStep('确认登录成功', async () => {
|
|
42
|
+
// 验证页面标题
|
|
43
|
+
const title = await page.title();
|
|
44
|
+
console.log('页面标题:', title);
|
|
45
|
+
// 验证欢迎信息
|
|
46
|
+
const welcomeText = await page.locator('h3').textContent();
|
|
47
|
+
console.log('欢迎信息:', welcomeText);
|
|
48
|
+
// 验证安全区域信息
|
|
49
|
+
const secureAreaText = await page.locator('h4.subheader').textContent();
|
|
50
|
+
console.log('安全区域信息:', secureAreaText);
|
|
51
|
+
// 验证登出按钮存在
|
|
52
|
+
const logoutButton = page.locator('a[href="/logout"]');
|
|
53
|
+
const logoutExists = await logoutButton.isVisible();
|
|
54
|
+
const logoutText = await logoutButton.textContent();
|
|
55
|
+
console.log('登出按钮存在:', logoutExists);
|
|
56
|
+
console.log('登出按钮文本:', logoutText);
|
|
57
|
+
// 验证URL包含secure
|
|
58
|
+
const url = page.url();
|
|
59
|
+
console.log('当前URL:', url);
|
|
60
|
+
// 断言验证
|
|
61
|
+
await expect(page).toHaveURL(/secure/);
|
|
62
|
+
await expect(page.locator('h3')).toContainText(runner.get('welcomeText'));
|
|
63
|
+
await expect(logoutButton).toBeVisible();
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
|
|
2
|
+
import { test, expect } from '@playwright/test';
|
|
3
|
+
import { Runner } from '../src/runner';
|
|
4
|
+
|
|
5
|
+
const runner = Runner.NewInstance('43af4db4-3249-4135-b279-97b24f27106b', '85d685cb-8102-4f25-a812-122dbb68b1f1');
|
|
6
|
+
|
|
7
|
+
test(`#$wefwef`, async ({ page, context }) => {
|
|
8
|
+
await runner.init(page, context);
|
|
9
|
+
|
|
10
|
+
await runner.runStep('访问百度首页', async () => {
|
|
11
|
+
await page.goto('https://www.baidu.com');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
await runner.runStep('在搜索框输入关键词并选择第一个下拉选项提交搜索', async () => {
|
|
15
|
+
// 在搜索框输入关键字'aaa'
|
|
16
|
+
await page.getByRole('combobox', { name: '搜索' }).fill('aaa');
|
|
17
|
+
|
|
18
|
+
// 等待下拉框出现并选择第一个选项
|
|
19
|
+
await page.waitForSelector('.suggest-wrap');
|
|
20
|
+
await page.keyboard.press('ArrowDown');
|
|
21
|
+
await page.keyboard.press('Enter');
|
|
22
|
+
|
|
23
|
+
// 等待搜索结果页面加载完成
|
|
24
|
+
await page.waitForLoadState('networkidle');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
await runner.runStep('验证搜索结果是否与关键字"aaa"相关', async () => {
|
|
28
|
+
// 验证搜索框输入值是否包含'aaa'或其衍生内容
|
|
29
|
+
const searchInputValue = await page.getByRole('combobox', { name: '搜索' }).inputValue();
|
|
30
|
+
if (!searchInputValue.includes('aaa') && !searchInputValue.includes('啊唉唉')) {
|
|
31
|
+
throw new Error('搜索框输入值不符合预期');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// 验证页面标题是否包含'aaa'相关内容
|
|
35
|
+
const pageTitle = await page.title();
|
|
36
|
+
if (!pageTitle.includes('aaa') && !pageTitle.includes('啊唉唉')) {
|
|
37
|
+
throw new Error('页面标题不符合预期');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// 验证URL是否包含'aaa'相关搜索参数
|
|
41
|
+
const pageURL = page.url();
|
|
42
|
+
if (!pageURL.includes('wd=aaa') && !pageURL.includes('wd=%E5%95%8A%E5%94%89%E5%94%89')) {
|
|
43
|
+
throw new Error('页面URL不符合预期');
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { defineConfig, devices } from '@playwright/test';
|
|
3
|
-
|
|
4
|
-
export default defineConfig({
|
|
5
|
-
timeout: 600000,
|
|
6
|
-
reporter: 'json',
|
|
7
|
-
use: {
|
|
8
|
-
actionTimeout: 15000,
|
|
9
|
-
navigationTimeout: 60000,
|
|
10
|
-
locale: 'zh-CN',
|
|
11
|
-
},
|
|
12
|
-
expect: {
|
|
13
|
-
timeout: 5000,
|
|
14
|
-
},
|
|
15
|
-
/* Configure projects for major browsers */
|
|
16
|
-
projects: [
|
|
17
|
-
{
|
|
18
|
-
name: 'chromium',
|
|
19
|
-
use: { ...devices['Desktop Chrome'] },
|
|
20
|
-
},
|
|
21
|
-
|
|
22
|
-
{
|
|
23
|
-
name: 'firefox',
|
|
24
|
-
use: { ...devices['Desktop Firefox'] },
|
|
25
|
-
},
|
|
26
|
-
|
|
27
|
-
{
|
|
28
|
-
name: 'webkit',
|
|
29
|
-
use: { ...devices['Desktop Safari'] },
|
|
30
|
-
}
|
|
31
|
-
]
|
|
32
|
-
});
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { test, expect } from '@playwright/test';
|
|
3
|
-
import { Runner } from '../../src/runner';
|
|
4
|
-
test.describe(`Login user`, () => {
|
|
5
|
-
test.setTimeout(1000000);
|
|
6
|
-
const runner = Runner.NewInstance('43af4db4-3249-4135-b279-97b24f27106b', '13bcfb12-4add-4b7d-ac4b-b46a4280141c');
|
|
7
|
-
|
|
8
|
-
test.afterEach(async () => {
|
|
9
|
-
runner.clear();
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
[
|
|
13
|
-
{
|
|
14
|
-
"username": "practice",
|
|
15
|
-
"password": "SuperSecretPassword!"
|
|
16
|
-
}
|
|
17
|
-
].forEach((data, index) => {
|
|
18
|
-
test(`#${index + 1}`, async ({ page, context }) => {
|
|
19
|
-
await runner.init(page, context, data);
|
|
20
|
-
|
|
21
|
-
// FIXED
|
|
22
|
-
await runner.runStep('进入登录页面', async () => {
|
|
23
|
-
await page.goto('https://parabank.parasoft.com/parabank/index.htm');
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
await runner.runStep('输入有效凭据并提交登录表单', async () => {
|
|
27
|
-
const username = runner.get('username');
|
|
28
|
-
const password = runner.get('password');
|
|
29
|
-
|
|
30
|
-
// 填写用户名
|
|
31
|
-
await page.locator('input[name="User_name"]').fill(username, { timeout: 3000 });
|
|
32
|
-
// 填写密码
|
|
33
|
-
await page.locator('input[name="password"]').fill(password);
|
|
34
|
-
// 点击登录按钮
|
|
35
|
-
await page.getByRole('button', { name: 'Log In' }).click();
|
|
36
|
-
|
|
37
|
-
// 验证登录成功(URL变化)
|
|
38
|
-
await expect(page).toHaveURL(/overview.htm/);
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
});
|
|
42
|
-
});
|