@playwright/mcp 0.0.36-alpha-2025-09-03 → 0.0.36-alpha-2025-09-04
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/cli.js +1 -1
- package/index.d.ts +1 -1
- package/index.js +2 -2
- package/lib/{browserContextFactory.js → browser/browserContextFactory.js} +76 -36
- package/lib/{browserServerBackend.js → browser/browserServerBackend.js} +24 -22
- package/lib/{utils → browser}/codegen.js +8 -3
- package/lib/{config.js → browser/config.js} +43 -26
- package/lib/{context.js → browser/context.js} +27 -30
- package/lib/{response.js → browser/response.js} +14 -14
- package/lib/{sessionLog.js → browser/sessionLog.js} +23 -18
- package/lib/{tab.js → browser/tab.js} +29 -27
- package/lib/{tools → browser/tools}/common.js +11 -9
- package/lib/{tools → browser/tools}/console.js +7 -5
- package/lib/{tools → browser/tools}/dialogs.js +9 -7
- package/lib/browser/tools/evaluate.js +88 -0
- package/lib/{tools → browser/tools}/files.js +8 -6
- package/lib/browser/tools/form.js +92 -0
- package/lib/{tools → browser/tools}/install.js +18 -14
- package/lib/browser/tools/keyboard.js +113 -0
- package/lib/{tools → browser/tools}/mouse.js +18 -16
- package/lib/{tools → browser/tools}/navigate.js +10 -8
- package/lib/{tools → browser/tools}/network.js +7 -5
- package/lib/browser/tools/pdf.js +76 -0
- package/lib/browser/tools/screenshot.js +115 -0
- package/lib/browser/tools/snapshot.js +175 -0
- package/lib/{tools → browser/tools}/tabs.js +9 -7
- package/lib/{tools → browser/tools}/tool.js +6 -2
- package/lib/{tools → browser/tools}/utils.js +10 -5
- package/lib/{tools → browser/tools}/verify.js +59 -24
- package/lib/{tools → browser/tools}/wait.js +10 -8
- package/lib/browser/tools.js +61 -0
- package/lib/extension/cdpRelay.js +85 -48
- package/lib/extension/extensionContextFactory.js +48 -11
- package/lib/extension/protocol.js +4 -1
- package/lib/index.js +47 -12
- package/lib/{utils/log.js → log.js} +11 -4
- package/lib/{utils/package.js → package.js} +9 -5
- package/lib/program.js +68 -39
- package/lib/sdk/bundle.js +79 -0
- package/lib/{mcp → sdk}/http.js +57 -17
- package/lib/{mcp → sdk}/inProcessTransport.js +15 -20
- package/lib/{mcp → sdk}/manualPromise.js +11 -9
- package/lib/{mcp → sdk}/mdb.js +77 -38
- package/lib/{mcp → sdk}/proxyBackend.js +53 -16
- package/lib/sdk/server.js +164 -0
- package/lib/{mcp → sdk}/tool.js +8 -4
- package/lib/vscode/host.js +64 -35
- package/lib/vscode/main.js +48 -13
- package/package.json +6 -7
- package/lib/loop/loop.js +0 -69
- package/lib/loop/loopClaude.js +0 -152
- package/lib/loop/loopOpenAI.js +0 -141
- package/lib/loop/main.js +0 -60
- package/lib/loopTools/context.js +0 -67
- package/lib/loopTools/main.js +0 -54
- package/lib/loopTools/perform.js +0 -32
- package/lib/loopTools/snapshot.js +0 -29
- package/lib/loopTools/tool.js +0 -18
- package/lib/mcp/server.js +0 -123
- package/lib/tools/evaluate.js +0 -53
- package/lib/tools/form.js +0 -57
- package/lib/tools/keyboard.js +0 -78
- package/lib/tools/pdf.js +0 -40
- package/lib/tools/screenshot.js +0 -79
- package/lib/tools/snapshot.js +0 -139
- package/lib/tools.js +0 -54
- package/lib/utils/fileUtils.js +0 -36
- package/lib/utils/guid.js +0 -22
package/lib/vscode/host.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* Copyright (c) Microsoft Corporation.
|
|
3
4
|
*
|
|
@@ -13,38 +14,64 @@
|
|
|
13
14
|
* See the License for the specific language governing permissions and
|
|
14
15
|
* limitations under the License.
|
|
15
16
|
*/
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
17
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
20
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
21
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
22
|
+
}
|
|
23
|
+
Object.defineProperty(o, k2, desc);
|
|
24
|
+
}) : (function(o, m, k, k2) {
|
|
25
|
+
if (k2 === undefined) k2 = k;
|
|
26
|
+
o[k2] = m[k];
|
|
27
|
+
}));
|
|
28
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
29
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
30
|
+
}) : function(o, v) {
|
|
31
|
+
o["default"] = v;
|
|
32
|
+
});
|
|
33
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
34
|
+
var ownKeys = function(o) {
|
|
35
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
36
|
+
var ar = [];
|
|
37
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
38
|
+
return ar;
|
|
39
|
+
};
|
|
40
|
+
return ownKeys(o);
|
|
41
|
+
};
|
|
42
|
+
return function (mod) {
|
|
43
|
+
if (mod && mod.__esModule) return mod;
|
|
44
|
+
var result = {};
|
|
45
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
46
|
+
__setModuleDefault(result, mod);
|
|
47
|
+
return result;
|
|
48
|
+
};
|
|
49
|
+
})();
|
|
50
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
51
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
52
|
+
};
|
|
53
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
54
|
+
exports.runVSCodeTools = runVSCodeTools;
|
|
55
|
+
const path_1 = __importDefault(require("path"));
|
|
56
|
+
const mcpBundle = __importStar(require("../sdk/bundle"));
|
|
57
|
+
const mcpServer = __importStar(require("../sdk/server"));
|
|
58
|
+
const log_1 = require("../log");
|
|
59
|
+
const package_1 = require("../package");
|
|
60
|
+
const browserServerBackend_1 = require("../browser/browserServerBackend");
|
|
61
|
+
const browserContextFactory_1 = require("../browser/browserContextFactory");
|
|
62
|
+
const { z, zodToJsonSchema } = mcpBundle;
|
|
28
63
|
const contextSwitchOptions = z.object({
|
|
29
64
|
connectionString: z.string().optional().describe('The connection string to use to connect to the browser'),
|
|
30
65
|
lib: z.string().optional().describe('The library to use for the connection'),
|
|
31
66
|
debugController: z.boolean().optional().describe('Enable the debug controller')
|
|
32
67
|
});
|
|
33
68
|
class VSCodeProxyBackend {
|
|
34
|
-
_config;
|
|
35
|
-
_defaultTransportFactory;
|
|
36
|
-
name = 'Playwright MCP Client Switcher';
|
|
37
|
-
version = packageJSON.version;
|
|
38
|
-
_currentClient;
|
|
39
|
-
_contextSwitchTool;
|
|
40
|
-
_roots = [];
|
|
41
|
-
_clientVersion;
|
|
42
|
-
_context;
|
|
43
|
-
_browser;
|
|
44
|
-
_browserServer;
|
|
45
69
|
constructor(_config, _defaultTransportFactory) {
|
|
46
70
|
this._config = _config;
|
|
47
71
|
this._defaultTransportFactory = _defaultTransportFactory;
|
|
72
|
+
this.name = 'Playwright MCP Client Switcher';
|
|
73
|
+
this.version = package_1.packageJSON.version;
|
|
74
|
+
this._roots = [];
|
|
48
75
|
this._contextSwitchTool = this._defineContextSwitchTool();
|
|
49
76
|
}
|
|
50
77
|
async initialize(server, clientVersion, roots) {
|
|
@@ -69,7 +96,8 @@ class VSCodeProxyBackend {
|
|
|
69
96
|
});
|
|
70
97
|
}
|
|
71
98
|
serverClosed(server) {
|
|
72
|
-
|
|
99
|
+
var _a;
|
|
100
|
+
void ((_a = this._currentClient) === null || _a === void 0 ? void 0 : _a.close().catch(log_1.logUnhandledError));
|
|
73
101
|
}
|
|
74
102
|
onContext(context) {
|
|
75
103
|
this._context = context;
|
|
@@ -97,7 +125,7 @@ class VSCodeProxyBackend {
|
|
|
97
125
|
const lines = [`### Result`];
|
|
98
126
|
if (url) {
|
|
99
127
|
lines.push(`URL: ${url}`);
|
|
100
|
-
lines.push(`Version: ${packageJSON.dependencies.playwright}`);
|
|
128
|
+
lines.push(`Version: ${package_1.packageJSON.dependencies.playwright}`);
|
|
101
129
|
}
|
|
102
130
|
else {
|
|
103
131
|
lines.push(`No open browsers.`);
|
|
@@ -111,11 +139,11 @@ class VSCodeProxyBackend {
|
|
|
111
139
|
content: [{ type: 'text', text: '### Result\nSuccessfully disconnected.\n' }],
|
|
112
140
|
};
|
|
113
141
|
}
|
|
114
|
-
await this._setCurrentClient(new StdioClientTransport({
|
|
142
|
+
await this._setCurrentClient(new mcpBundle.StdioClientTransport({
|
|
115
143
|
command: process.execPath,
|
|
116
144
|
cwd: process.cwd(),
|
|
117
145
|
args: [
|
|
118
|
-
|
|
146
|
+
path_1.default.join(__dirname, 'main.js'),
|
|
119
147
|
JSON.stringify(this._config),
|
|
120
148
|
params.connectionString,
|
|
121
149
|
params.lib,
|
|
@@ -138,28 +166,29 @@ class VSCodeProxyBackend {
|
|
|
138
166
|
};
|
|
139
167
|
}
|
|
140
168
|
async _setCurrentClient(transport) {
|
|
141
|
-
|
|
169
|
+
var _a;
|
|
170
|
+
await ((_a = this._currentClient) === null || _a === void 0 ? void 0 : _a.close());
|
|
142
171
|
this._currentClient = undefined;
|
|
143
|
-
const client = new Client(this._clientVersion);
|
|
172
|
+
const client = new mcpBundle.Client(this._clientVersion);
|
|
144
173
|
client.registerCapabilities({
|
|
145
174
|
roots: {
|
|
146
175
|
listRoots: true,
|
|
147
176
|
},
|
|
148
177
|
});
|
|
149
|
-
client.setRequestHandler(ListRootsRequestSchema, () => ({ roots: this._roots }));
|
|
150
|
-
client.setRequestHandler(PingRequestSchema, () => ({}));
|
|
178
|
+
client.setRequestHandler(mcpBundle.ListRootsRequestSchema, () => ({ roots: this._roots }));
|
|
179
|
+
client.setRequestHandler(mcpBundle.PingRequestSchema, () => ({}));
|
|
151
180
|
await client.connect(transport);
|
|
152
181
|
this._currentClient = client;
|
|
153
182
|
}
|
|
154
183
|
}
|
|
155
|
-
|
|
184
|
+
async function runVSCodeTools(config) {
|
|
156
185
|
const serverBackendFactory = {
|
|
157
186
|
name: 'Playwright w/ vscode',
|
|
158
187
|
nameInConfig: 'playwright-vscode',
|
|
159
|
-
version: packageJSON.version,
|
|
160
|
-
create: () => new VSCodeProxyBackend(config, delegate => mcpServer.wrapInProcess(new BrowserServerBackend(config, {
|
|
188
|
+
version: package_1.packageJSON.version,
|
|
189
|
+
create: () => new VSCodeProxyBackend(config, delegate => mcpServer.wrapInProcess(new browserServerBackend_1.BrowserServerBackend(config, {
|
|
161
190
|
async createContext(clientInfo, abortSignal, toolName) {
|
|
162
|
-
const context = await contextFactory(config).createContext(clientInfo, abortSignal, toolName);
|
|
191
|
+
const context = await (0, browserContextFactory_1.contextFactory)(config).createContext(clientInfo, abortSignal, toolName);
|
|
163
192
|
delegate.onContext(context.browserContext);
|
|
164
193
|
return context;
|
|
165
194
|
},
|
package/lib/vscode/main.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* Copyright (c) Microsoft Corporation.
|
|
3
4
|
*
|
|
@@ -13,21 +14,53 @@
|
|
|
13
14
|
* See the License for the specific language governing permissions and
|
|
14
15
|
* limitations under the License.
|
|
15
16
|
*/
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
20
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
21
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
22
|
+
}
|
|
23
|
+
Object.defineProperty(o, k2, desc);
|
|
24
|
+
}) : (function(o, m, k, k2) {
|
|
25
|
+
if (k2 === undefined) k2 = k;
|
|
26
|
+
o[k2] = m[k];
|
|
27
|
+
}));
|
|
28
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
29
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
30
|
+
}) : function(o, v) {
|
|
31
|
+
o["default"] = v;
|
|
32
|
+
});
|
|
33
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
34
|
+
var ownKeys = function(o) {
|
|
35
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
36
|
+
var ar = [];
|
|
37
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
38
|
+
return ar;
|
|
39
|
+
};
|
|
40
|
+
return ownKeys(o);
|
|
41
|
+
};
|
|
42
|
+
return function (mod) {
|
|
43
|
+
if (mod && mod.__esModule) return mod;
|
|
44
|
+
var result = {};
|
|
45
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
46
|
+
__setModuleDefault(result, mod);
|
|
47
|
+
return result;
|
|
48
|
+
};
|
|
49
|
+
})();
|
|
50
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
51
|
+
const mcpBundle = __importStar(require("../sdk/bundle"));
|
|
52
|
+
const mcpServer = __importStar(require("../sdk/server"));
|
|
53
|
+
const browserServerBackend_1 = require("../browser/browserServerBackend");
|
|
19
54
|
class VSCodeBrowserContextFactory {
|
|
20
|
-
_config;
|
|
21
|
-
_playwright;
|
|
22
|
-
_connectionString;
|
|
23
|
-
name = 'vscode';
|
|
24
|
-
description = 'Connect to a browser running in the Playwright VS Code extension';
|
|
25
55
|
constructor(_config, _playwright, _connectionString) {
|
|
26
56
|
this._config = _config;
|
|
27
57
|
this._playwright = _playwright;
|
|
28
58
|
this._connectionString = _connectionString;
|
|
59
|
+
this.name = 'vscode';
|
|
60
|
+
this.description = 'Connect to a browser running in the Playwright VS Code extension';
|
|
29
61
|
}
|
|
30
62
|
async createContext(clientInfo, abortSignal) {
|
|
63
|
+
var _a;
|
|
31
64
|
let launchOptions = this._config.browser.launchOptions;
|
|
32
65
|
if (this._config.browser.userDataDir) {
|
|
33
66
|
launchOptions = {
|
|
@@ -40,7 +73,7 @@ class VSCodeBrowserContextFactory {
|
|
|
40
73
|
connectionString.searchParams.set('launch-options', JSON.stringify(launchOptions));
|
|
41
74
|
const browserType = this._playwright.chromium; // it could also be firefox or webkit, we just need some browser type to call `connect` on
|
|
42
75
|
const browser = await browserType.connect(connectionString.toString());
|
|
43
|
-
const context = browser.contexts()[0]
|
|
76
|
+
const context = (_a = browser.contexts()[0]) !== null && _a !== void 0 ? _a : await browser.newContext(this._config.browser.contextOptions);
|
|
44
77
|
return {
|
|
45
78
|
browserContext: context,
|
|
46
79
|
close: async () => {
|
|
@@ -50,13 +83,15 @@ class VSCodeBrowserContextFactory {
|
|
|
50
83
|
}
|
|
51
84
|
}
|
|
52
85
|
async function main(config, connectionString, lib) {
|
|
53
|
-
const playwright = await
|
|
86
|
+
const playwright = await Promise.resolve(`${lib}`).then(s => __importStar(require(s))).then(mod => { var _a; return (_a = mod.default) !== null && _a !== void 0 ? _a : mod; });
|
|
54
87
|
const factory = new VSCodeBrowserContextFactory(config, playwright, connectionString);
|
|
55
88
|
await mcpServer.connect({
|
|
56
89
|
name: 'Playwright MCP',
|
|
57
90
|
nameInConfig: 'playwright-vscode',
|
|
58
|
-
create: () => new BrowserServerBackend(config, factory),
|
|
91
|
+
create: () => new browserServerBackend_1.BrowserServerBackend(config, factory),
|
|
59
92
|
version: 'unused'
|
|
60
|
-
}, new StdioServerTransport(), false);
|
|
93
|
+
}, new mcpBundle.StdioServerTransport(), false);
|
|
61
94
|
}
|
|
62
|
-
|
|
95
|
+
void (async () => {
|
|
96
|
+
await main(JSON.parse(process.argv[2]), process.argv[3], process.argv[4]);
|
|
97
|
+
})();
|
package/package.json
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@playwright/mcp",
|
|
3
|
-
"version": "0.0.36-alpha-2025-09-
|
|
3
|
+
"version": "0.0.36-alpha-2025-09-04",
|
|
4
4
|
"description": "Playwright Tools for MCP",
|
|
5
|
-
"type": "module",
|
|
6
5
|
"repository": {
|
|
7
6
|
"type": "git",
|
|
8
7
|
"url": "git+https://github.com/microsoft/playwright-mcp.git"
|
|
@@ -38,21 +37,19 @@
|
|
|
38
37
|
}
|
|
39
38
|
},
|
|
40
39
|
"dependencies": {
|
|
41
|
-
"@modelcontextprotocol/sdk": "^1.16.0",
|
|
42
40
|
"commander": "^13.1.0",
|
|
43
41
|
"debug": "^4.4.1",
|
|
44
42
|
"dotenv": "^17.2.0",
|
|
45
43
|
"mime": "^4.0.7",
|
|
46
44
|
"playwright": "1.56.0-alpha-1756505518000",
|
|
47
45
|
"playwright-core": "1.56.0-alpha-1756505518000",
|
|
48
|
-
"ws": "^8.18.1"
|
|
49
|
-
"zod": "^3.24.1",
|
|
50
|
-
"zod-to-json-schema": "^3.24.4"
|
|
46
|
+
"ws": "^8.18.1"
|
|
51
47
|
},
|
|
52
48
|
"devDependencies": {
|
|
53
49
|
"@anthropic-ai/sdk": "^0.57.0",
|
|
54
50
|
"@eslint/eslintrc": "^3.2.0",
|
|
55
51
|
"@eslint/js": "^9.19.0",
|
|
52
|
+
"@modelcontextprotocol/sdk": "^1.16.0",
|
|
56
53
|
"@playwright/test": "1.56.0-alpha-1756505518000",
|
|
57
54
|
"@stylistic/eslint-plugin": "^3.0.1",
|
|
58
55
|
"@types/debug": "^4.1.12",
|
|
@@ -66,7 +63,9 @@
|
|
|
66
63
|
"eslint-plugin-import": "^2.31.0",
|
|
67
64
|
"eslint-plugin-notice": "^1.0.0",
|
|
68
65
|
"openai": "^5.10.2",
|
|
69
|
-
"typescript": "^5.8.2"
|
|
66
|
+
"typescript": "^5.8.2",
|
|
67
|
+
"zod": "^3.24.1",
|
|
68
|
+
"zod-to-json-schema": "^3.24.4"
|
|
70
69
|
},
|
|
71
70
|
"bin": {
|
|
72
71
|
"mcp-server-playwright": "cli.js"
|
package/lib/loop/loop.js
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) Microsoft Corporation.
|
|
3
|
-
*
|
|
4
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
* you may not use this file except in compliance with the License.
|
|
6
|
-
* You may obtain a copy of the License at
|
|
7
|
-
*
|
|
8
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
*
|
|
10
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
* See the License for the specific language governing permissions and
|
|
14
|
-
* limitations under the License.
|
|
15
|
-
*/
|
|
16
|
-
import debug from 'debug';
|
|
17
|
-
export async function runTask(delegate, client, task, oneShot = false) {
|
|
18
|
-
const { tools } = await client.listTools();
|
|
19
|
-
const taskContent = oneShot ? `Perform following task: ${task}.` : `Perform following task: ${task}. Once the task is complete, call the "done" tool.`;
|
|
20
|
-
const conversation = delegate.createConversation(taskContent, tools, oneShot);
|
|
21
|
-
for (let iteration = 0; iteration < 5; ++iteration) {
|
|
22
|
-
debug('history')('Making API call for iteration', iteration);
|
|
23
|
-
const toolCalls = await delegate.makeApiCall(conversation);
|
|
24
|
-
if (toolCalls.length === 0)
|
|
25
|
-
throw new Error('Call the "done" tool when the task is complete.');
|
|
26
|
-
const toolResults = [];
|
|
27
|
-
for (const toolCall of toolCalls) {
|
|
28
|
-
const doneResult = delegate.checkDoneToolCall(toolCall);
|
|
29
|
-
if (doneResult !== null)
|
|
30
|
-
return conversation.messages;
|
|
31
|
-
const { name, arguments: args, id } = toolCall;
|
|
32
|
-
try {
|
|
33
|
-
debug('tool')(name, args);
|
|
34
|
-
const response = await client.callTool({
|
|
35
|
-
name,
|
|
36
|
-
arguments: args,
|
|
37
|
-
});
|
|
38
|
-
const responseContent = (response.content || []);
|
|
39
|
-
debug('tool')(responseContent);
|
|
40
|
-
const text = responseContent.filter(part => part.type === 'text').map(part => part.text).join('\n');
|
|
41
|
-
toolResults.push({
|
|
42
|
-
toolCallId: id,
|
|
43
|
-
content: text,
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
catch (error) {
|
|
47
|
-
debug('tool')(error);
|
|
48
|
-
toolResults.push({
|
|
49
|
-
toolCallId: id,
|
|
50
|
-
content: `Error while executing tool "${name}": ${error instanceof Error ? error.message : String(error)}\n\nPlease try to recover and complete the task.`,
|
|
51
|
-
isError: true,
|
|
52
|
-
});
|
|
53
|
-
// Skip remaining tool calls for this iteration
|
|
54
|
-
for (const remainingToolCall of toolCalls.slice(toolCalls.indexOf(toolCall) + 1)) {
|
|
55
|
-
toolResults.push({
|
|
56
|
-
toolCallId: remainingToolCall.id,
|
|
57
|
-
content: `This tool call is skipped due to previous error.`,
|
|
58
|
-
isError: true,
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
break;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
delegate.addToolResults(conversation, toolResults);
|
|
65
|
-
if (oneShot)
|
|
66
|
-
return conversation.messages;
|
|
67
|
-
}
|
|
68
|
-
throw new Error('Failed to perform step, max attempts reached');
|
|
69
|
-
}
|
package/lib/loop/loopClaude.js
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) Microsoft Corporation.
|
|
3
|
-
*
|
|
4
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
* you may not use this file except in compliance with the License.
|
|
6
|
-
* You may obtain a copy of the License at
|
|
7
|
-
*
|
|
8
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
*
|
|
10
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
* See the License for the specific language governing permissions and
|
|
14
|
-
* limitations under the License.
|
|
15
|
-
*/
|
|
16
|
-
const model = 'claude-sonnet-4-20250514';
|
|
17
|
-
export class ClaudeDelegate {
|
|
18
|
-
_anthropic;
|
|
19
|
-
async anthropic() {
|
|
20
|
-
if (!this._anthropic) {
|
|
21
|
-
const anthropic = await import('@anthropic-ai/sdk');
|
|
22
|
-
this._anthropic = new anthropic.Anthropic();
|
|
23
|
-
}
|
|
24
|
-
return this._anthropic;
|
|
25
|
-
}
|
|
26
|
-
createConversation(task, tools, oneShot) {
|
|
27
|
-
const llmTools = tools.map(tool => ({
|
|
28
|
-
name: tool.name,
|
|
29
|
-
description: tool.description || '',
|
|
30
|
-
inputSchema: tool.inputSchema,
|
|
31
|
-
}));
|
|
32
|
-
if (!oneShot) {
|
|
33
|
-
llmTools.push({
|
|
34
|
-
name: 'done',
|
|
35
|
-
description: 'Call this tool when the task is complete.',
|
|
36
|
-
inputSchema: {
|
|
37
|
-
type: 'object',
|
|
38
|
-
properties: {},
|
|
39
|
-
},
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
return {
|
|
43
|
-
messages: [{
|
|
44
|
-
role: 'user',
|
|
45
|
-
content: task
|
|
46
|
-
}],
|
|
47
|
-
tools: llmTools,
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
async makeApiCall(conversation) {
|
|
51
|
-
// Convert generic messages to Claude format
|
|
52
|
-
const claudeMessages = [];
|
|
53
|
-
for (const message of conversation.messages) {
|
|
54
|
-
if (message.role === 'user') {
|
|
55
|
-
claudeMessages.push({
|
|
56
|
-
role: 'user',
|
|
57
|
-
content: message.content
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
else if (message.role === 'assistant') {
|
|
61
|
-
const content = [];
|
|
62
|
-
// Add text content
|
|
63
|
-
if (message.content) {
|
|
64
|
-
content.push({
|
|
65
|
-
type: 'text',
|
|
66
|
-
text: message.content,
|
|
67
|
-
citations: []
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
// Add tool calls
|
|
71
|
-
if (message.toolCalls) {
|
|
72
|
-
for (const toolCall of message.toolCalls) {
|
|
73
|
-
content.push({
|
|
74
|
-
type: 'tool_use',
|
|
75
|
-
id: toolCall.id,
|
|
76
|
-
name: toolCall.name,
|
|
77
|
-
input: toolCall.arguments
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
claudeMessages.push({
|
|
82
|
-
role: 'assistant',
|
|
83
|
-
content
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
else if (message.role === 'tool') {
|
|
87
|
-
// Tool results are added differently - we need to find if there's already a user message with tool results
|
|
88
|
-
const lastMessage = claudeMessages[claudeMessages.length - 1];
|
|
89
|
-
const toolResult = {
|
|
90
|
-
type: 'tool_result',
|
|
91
|
-
tool_use_id: message.toolCallId,
|
|
92
|
-
content: message.content,
|
|
93
|
-
is_error: message.isError,
|
|
94
|
-
};
|
|
95
|
-
if (lastMessage && lastMessage.role === 'user' && Array.isArray(lastMessage.content)) {
|
|
96
|
-
// Add to existing tool results message
|
|
97
|
-
lastMessage.content.push(toolResult);
|
|
98
|
-
}
|
|
99
|
-
else {
|
|
100
|
-
// Create new tool results message
|
|
101
|
-
claudeMessages.push({
|
|
102
|
-
role: 'user',
|
|
103
|
-
content: [toolResult]
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
// Convert generic tools to Claude format
|
|
109
|
-
const claudeTools = conversation.tools.map(tool => ({
|
|
110
|
-
name: tool.name,
|
|
111
|
-
description: tool.description,
|
|
112
|
-
input_schema: tool.inputSchema,
|
|
113
|
-
}));
|
|
114
|
-
const anthropic = await this.anthropic();
|
|
115
|
-
const response = await anthropic.messages.create({
|
|
116
|
-
model,
|
|
117
|
-
max_tokens: 10000,
|
|
118
|
-
messages: claudeMessages,
|
|
119
|
-
tools: claudeTools,
|
|
120
|
-
});
|
|
121
|
-
// Extract tool calls and add assistant message to generic conversation
|
|
122
|
-
const toolCalls = response.content.filter(block => block.type === 'tool_use');
|
|
123
|
-
const textContent = response.content.filter(block => block.type === 'text').map(block => block.text).join('');
|
|
124
|
-
const llmToolCalls = toolCalls.map(toolCall => ({
|
|
125
|
-
name: toolCall.name,
|
|
126
|
-
arguments: toolCall.input,
|
|
127
|
-
id: toolCall.id,
|
|
128
|
-
}));
|
|
129
|
-
// Add assistant message to generic conversation
|
|
130
|
-
conversation.messages.push({
|
|
131
|
-
role: 'assistant',
|
|
132
|
-
content: textContent,
|
|
133
|
-
toolCalls: llmToolCalls.length > 0 ? llmToolCalls : undefined
|
|
134
|
-
});
|
|
135
|
-
return llmToolCalls;
|
|
136
|
-
}
|
|
137
|
-
addToolResults(conversation, results) {
|
|
138
|
-
for (const result of results) {
|
|
139
|
-
conversation.messages.push({
|
|
140
|
-
role: 'tool',
|
|
141
|
-
toolCallId: result.toolCallId,
|
|
142
|
-
content: result.content,
|
|
143
|
-
isError: result.isError,
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
checkDoneToolCall(toolCall) {
|
|
148
|
-
if (toolCall.name === 'done')
|
|
149
|
-
return toolCall.arguments.result;
|
|
150
|
-
return null;
|
|
151
|
-
}
|
|
152
|
-
}
|
package/lib/loop/loopOpenAI.js
DELETED
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) Microsoft Corporation.
|
|
3
|
-
*
|
|
4
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
* you may not use this file except in compliance with the License.
|
|
6
|
-
* You may obtain a copy of the License at
|
|
7
|
-
*
|
|
8
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
*
|
|
10
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
* See the License for the specific language governing permissions and
|
|
14
|
-
* limitations under the License.
|
|
15
|
-
*/
|
|
16
|
-
const model = 'gpt-4.1';
|
|
17
|
-
export class OpenAIDelegate {
|
|
18
|
-
_openai;
|
|
19
|
-
async openai() {
|
|
20
|
-
if (!this._openai) {
|
|
21
|
-
const oai = await import('openai');
|
|
22
|
-
this._openai = new oai.OpenAI();
|
|
23
|
-
}
|
|
24
|
-
return this._openai;
|
|
25
|
-
}
|
|
26
|
-
createConversation(task, tools, oneShot) {
|
|
27
|
-
const genericTools = tools.map(tool => ({
|
|
28
|
-
name: tool.name,
|
|
29
|
-
description: tool.description || '',
|
|
30
|
-
inputSchema: tool.inputSchema,
|
|
31
|
-
}));
|
|
32
|
-
if (!oneShot) {
|
|
33
|
-
genericTools.push({
|
|
34
|
-
name: 'done',
|
|
35
|
-
description: 'Call this tool when the task is complete.',
|
|
36
|
-
inputSchema: {
|
|
37
|
-
type: 'object',
|
|
38
|
-
properties: {},
|
|
39
|
-
},
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
return {
|
|
43
|
-
messages: [{
|
|
44
|
-
role: 'user',
|
|
45
|
-
content: task
|
|
46
|
-
}],
|
|
47
|
-
tools: genericTools,
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
async makeApiCall(conversation) {
|
|
51
|
-
// Convert generic messages to OpenAI format
|
|
52
|
-
const openaiMessages = [];
|
|
53
|
-
for (const message of conversation.messages) {
|
|
54
|
-
if (message.role === 'user') {
|
|
55
|
-
openaiMessages.push({
|
|
56
|
-
role: 'user',
|
|
57
|
-
content: message.content
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
else if (message.role === 'assistant') {
|
|
61
|
-
const toolCalls = [];
|
|
62
|
-
if (message.toolCalls) {
|
|
63
|
-
for (const toolCall of message.toolCalls) {
|
|
64
|
-
toolCalls.push({
|
|
65
|
-
id: toolCall.id,
|
|
66
|
-
type: 'function',
|
|
67
|
-
function: {
|
|
68
|
-
name: toolCall.name,
|
|
69
|
-
arguments: JSON.stringify(toolCall.arguments)
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
const assistantMessage = {
|
|
75
|
-
role: 'assistant'
|
|
76
|
-
};
|
|
77
|
-
if (message.content)
|
|
78
|
-
assistantMessage.content = message.content;
|
|
79
|
-
if (toolCalls.length > 0)
|
|
80
|
-
assistantMessage.tool_calls = toolCalls;
|
|
81
|
-
openaiMessages.push(assistantMessage);
|
|
82
|
-
}
|
|
83
|
-
else if (message.role === 'tool') {
|
|
84
|
-
openaiMessages.push({
|
|
85
|
-
role: 'tool',
|
|
86
|
-
tool_call_id: message.toolCallId,
|
|
87
|
-
content: message.content,
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
// Convert generic tools to OpenAI format
|
|
92
|
-
const openaiTools = conversation.tools.map(tool => ({
|
|
93
|
-
type: 'function',
|
|
94
|
-
function: {
|
|
95
|
-
name: tool.name,
|
|
96
|
-
description: tool.description,
|
|
97
|
-
parameters: tool.inputSchema,
|
|
98
|
-
},
|
|
99
|
-
}));
|
|
100
|
-
const openai = await this.openai();
|
|
101
|
-
const response = await openai.chat.completions.create({
|
|
102
|
-
model,
|
|
103
|
-
messages: openaiMessages,
|
|
104
|
-
tools: openaiTools,
|
|
105
|
-
tool_choice: 'auto'
|
|
106
|
-
});
|
|
107
|
-
const message = response.choices[0].message;
|
|
108
|
-
// Extract tool calls and add assistant message to generic conversation
|
|
109
|
-
const toolCalls = message.tool_calls || [];
|
|
110
|
-
const genericToolCalls = toolCalls.map(toolCall => {
|
|
111
|
-
const functionCall = toolCall.function;
|
|
112
|
-
return {
|
|
113
|
-
name: functionCall.name,
|
|
114
|
-
arguments: JSON.parse(functionCall.arguments),
|
|
115
|
-
id: toolCall.id,
|
|
116
|
-
};
|
|
117
|
-
});
|
|
118
|
-
// Add assistant message to generic conversation
|
|
119
|
-
conversation.messages.push({
|
|
120
|
-
role: 'assistant',
|
|
121
|
-
content: message.content || '',
|
|
122
|
-
toolCalls: genericToolCalls.length > 0 ? genericToolCalls : undefined
|
|
123
|
-
});
|
|
124
|
-
return genericToolCalls;
|
|
125
|
-
}
|
|
126
|
-
addToolResults(conversation, results) {
|
|
127
|
-
for (const result of results) {
|
|
128
|
-
conversation.messages.push({
|
|
129
|
-
role: 'tool',
|
|
130
|
-
toolCallId: result.toolCallId,
|
|
131
|
-
content: result.content,
|
|
132
|
-
isError: result.isError,
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
checkDoneToolCall(toolCall) {
|
|
137
|
-
if (toolCall.name === 'done')
|
|
138
|
-
return toolCall.arguments.result;
|
|
139
|
-
return null;
|
|
140
|
-
}
|
|
141
|
-
}
|