@xoxoai/checkmate 0.4.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.
- package/LICENSE +21 -0
- package/README.md +244 -0
- package/dist/ai/client.d.ts +49 -0
- package/dist/ai/client.d.ts.map +1 -0
- package/dist/ai/client.js +244 -0
- package/dist/ai/client.js.map +1 -0
- package/dist/ai/message-handler.d.ts +11 -0
- package/dist/ai/message-handler.d.ts.map +1 -0
- package/dist/ai/message-handler.js +33 -0
- package/dist/ai/message-handler.js.map +1 -0
- package/dist/ai/message-history.d.ts +19 -0
- package/dist/ai/message-history.d.ts.map +1 -0
- package/dist/ai/message-history.js +48 -0
- package/dist/ai/message-history.js.map +1 -0
- package/dist/ai/prompts.d.ts +4 -0
- package/dist/ai/prompts.d.ts.map +1 -0
- package/dist/ai/prompts.js +24 -0
- package/dist/ai/prompts.js.map +1 -0
- package/dist/ai/rate-limit-policy.d.ts +7 -0
- package/dist/ai/rate-limit-policy.d.ts.map +1 -0
- package/dist/ai/rate-limit-policy.js +17 -0
- package/dist/ai/rate-limit-policy.js.map +1 -0
- package/dist/ai/response-processor.d.ts +20 -0
- package/dist/ai/response-processor.d.ts.map +1 -0
- package/dist/ai/response-processor.js +62 -0
- package/dist/ai/response-processor.js.map +1 -0
- package/dist/ai/token-pricing.d.ts +13 -0
- package/dist/ai/token-pricing.d.ts.map +1 -0
- package/dist/ai/token-pricing.js +348 -0
- package/dist/ai/token-pricing.js.map +1 -0
- package/dist/ai/token-tracker.d.ts +33 -0
- package/dist/ai/token-tracker.d.ts.map +1 -0
- package/dist/ai/token-tracker.js +138 -0
- package/dist/ai/token-tracker.js.map +1 -0
- package/dist/ai/tool-response-handler.d.ts +21 -0
- package/dist/ai/tool-response-handler.d.ts.map +1 -0
- package/dist/ai/tool-response-handler.js +54 -0
- package/dist/ai/tool-response-handler.js.map +1 -0
- package/dist/config/runtime-config.d.ts +21 -0
- package/dist/config/runtime-config.d.ts.map +1 -0
- package/dist/config/runtime-config.js +98 -0
- package/dist/config/runtime-config.js.map +1 -0
- package/dist/core.d.ts +8 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +4 -0
- package/dist/core.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/salesforce/authenticator.d.ts +27 -0
- package/dist/integrations/salesforce/authenticator.d.ts.map +1 -0
- package/dist/integrations/salesforce/authenticator.js +27 -0
- package/dist/integrations/salesforce/authenticator.js.map +1 -0
- package/dist/integrations/salesforce/cli-handler.d.ts +14 -0
- package/dist/integrations/salesforce/cli-handler.d.ts.map +1 -0
- package/dist/integrations/salesforce/cli-handler.js +50 -0
- package/dist/integrations/salesforce/cli-handler.js.map +1 -0
- package/dist/logging/index.d.ts +2 -0
- package/dist/logging/index.d.ts.map +1 -0
- package/dist/logging/index.js +4 -0
- package/dist/logging/index.js.map +1 -0
- package/dist/logging/logger.d.ts +5 -0
- package/dist/logging/logger.d.ts.map +1 -0
- package/dist/logging/logger.js +15 -0
- package/dist/logging/logger.js.map +1 -0
- package/dist/playwright.d.ts +102 -0
- package/dist/playwright.d.ts.map +1 -0
- package/dist/playwright.js +116 -0
- package/dist/playwright.js.map +1 -0
- package/dist/runtime/extension.d.ts +274 -0
- package/dist/runtime/extension.d.ts.map +1 -0
- package/dist/runtime/extension.js +171 -0
- package/dist/runtime/extension.js.map +1 -0
- package/dist/runtime/runner.d.ts +94 -0
- package/dist/runtime/runner.d.ts.map +1 -0
- package/dist/runtime/runner.js +86 -0
- package/dist/runtime/runner.js.map +1 -0
- package/dist/runtime/step-execution.d.ts +17 -0
- package/dist/runtime/step-execution.d.ts.map +1 -0
- package/dist/runtime/step-execution.js +49 -0
- package/dist/runtime/step-execution.js.map +1 -0
- package/dist/runtime/types.d.ts +79 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +2 -0
- package/dist/runtime/types.js.map +1 -0
- package/dist/salesforce.d.ts +71 -0
- package/dist/salesforce.d.ts.map +1 -0
- package/dist/salesforce.js +73 -0
- package/dist/salesforce.js.map +1 -0
- package/dist/tools/browser/screenshot-service.d.ts +10 -0
- package/dist/tools/browser/screenshot-service.d.ts.map +1 -0
- package/dist/tools/browser/screenshot-service.js +23 -0
- package/dist/tools/browser/screenshot-service.js.map +1 -0
- package/dist/tools/browser/snapshot-filter/index.d.ts +4 -0
- package/dist/tools/browser/snapshot-filter/index.d.ts.map +1 -0
- package/dist/tools/browser/snapshot-filter/index.js +4 -0
- package/dist/tools/browser/snapshot-filter/index.js.map +1 -0
- package/dist/tools/browser/snapshot-filter/semantic-scorer.d.ts +15 -0
- package/dist/tools/browser/snapshot-filter/semantic-scorer.d.ts.map +1 -0
- package/dist/tools/browser/snapshot-filter/semantic-scorer.js +99 -0
- package/dist/tools/browser/snapshot-filter/semantic-scorer.js.map +1 -0
- package/dist/tools/browser/snapshot-filter/snapshot-filter.d.ts +4 -0
- package/dist/tools/browser/snapshot-filter/snapshot-filter.d.ts.map +1 -0
- package/dist/tools/browser/snapshot-filter/snapshot-filter.js +57 -0
- package/dist/tools/browser/snapshot-filter/snapshot-filter.js.map +1 -0
- package/dist/tools/browser/snapshot-filter/tree-reconstructor.d.ts +3 -0
- package/dist/tools/browser/snapshot-filter/tree-reconstructor.d.ts.map +1 -0
- package/dist/tools/browser/snapshot-filter/tree-reconstructor.js +85 -0
- package/dist/tools/browser/snapshot-filter/tree-reconstructor.js.map +1 -0
- package/dist/tools/browser/snapshot-service.d.ts +19 -0
- package/dist/tools/browser/snapshot-service.d.ts.map +1 -0
- package/dist/tools/browser/snapshot-service.js +67 -0
- package/dist/tools/browser/snapshot-service.js.map +1 -0
- package/dist/tools/browser/tool.d.ts +34 -0
- package/dist/tools/browser/tool.d.ts.map +1 -0
- package/dist/tools/browser/tool.js +226 -0
- package/dist/tools/browser/tool.js.map +1 -0
- package/dist/tools/browser/transient-state-tracker.d.ts +16 -0
- package/dist/tools/browser/transient-state-tracker.d.ts.map +1 -0
- package/dist/tools/browser/transient-state-tracker.js +266 -0
- package/dist/tools/browser/transient-state-tracker.js.map +1 -0
- package/dist/tools/define-agent-tool.d.ts +45 -0
- package/dist/tools/define-agent-tool.d.ts.map +1 -0
- package/dist/tools/define-agent-tool.js +55 -0
- package/dist/tools/define-agent-tool.js.map +1 -0
- package/dist/tools/dispatcher.d.ts +11 -0
- package/dist/tools/dispatcher.d.ts.map +1 -0
- package/dist/tools/dispatcher.js +49 -0
- package/dist/tools/dispatcher.js.map +1 -0
- package/dist/tools/loop-detector.d.ts +27 -0
- package/dist/tools/loop-detector.d.ts.map +1 -0
- package/dist/tools/loop-detector.js +76 -0
- package/dist/tools/loop-detector.js.map +1 -0
- package/dist/tools/registry.d.ts +21 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +46 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/salesforce/login-tool.d.ts +7 -0
- package/dist/tools/salesforce/login-tool.d.ts.map +1 -0
- package/dist/tools/salesforce/login-tool.js +25 -0
- package/dist/tools/salesforce/login-tool.js.map +1 -0
- package/dist/tools/step/result-tool.d.ts +7 -0
- package/dist/tools/step/result-tool.d.ts.map +1 -0
- package/dist/tools/step/result-tool.js +32 -0
- package/dist/tools/step/result-tool.js.map +1 -0
- package/dist/tools/tool-contract.d.ts +3 -0
- package/dist/tools/tool-contract.d.ts.map +1 -0
- package/dist/tools/tool-contract.js +2 -0
- package/dist/tools/tool-contract.js.map +1 -0
- package/dist/tools/types.d.ts +139 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +4 -0
- package/dist/tools/types.js.map +1 -0
- package/docs/EXTENSIONS.md +233 -0
- package/docs/GUIDE.md +467 -0
- package/docs/ROADMAP.md +47 -0
- package/package.json +106 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Dawid Dobrowolski SoftQA
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# **_checkmate_**
|
|
2
|
+
|
|
3
|
+
AI test automation that actually works. Write tests in plain English, without locators, and with less code.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+
[](LICENSE)
|
|
10
|
+
|
|
11
|
+
## Why?
|
|
12
|
+
|
|
13
|
+
Spending countless hours building and maintaining E2E tests that look like this?
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
await page.goto('https://www.google.com')
|
|
17
|
+
const searchBox = page.getByRole('combobox', { name: 'Search', exact: true })
|
|
18
|
+
await searchBox.fill('playwright test automation')
|
|
19
|
+
await searchBox.press('Enter')
|
|
20
|
+
await expect(page.getByRole('link', { name: 'playwright' })
|
|
21
|
+
.filter({ hasText: 'playwright.dev' })
|
|
22
|
+
.first(), 'playwright.dev link should be visible')
|
|
23
|
+
.toBeVisible( { timeout: 30 * 1000 } )
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Try **_checkmate_**!
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
await ai.run({
|
|
30
|
+
action: `
|
|
31
|
+
Navigate to google.com
|
|
32
|
+
Type 'playwright test automation' in the search bar
|
|
33
|
+
Press Enter key`,
|
|
34
|
+
expect: `
|
|
35
|
+
Search results contain the playwright.dev link`,
|
|
36
|
+
})
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## What You Get
|
|
40
|
+
|
|
41
|
+
✅ **Zero Locators** - Write tests in plain English
|
|
42
|
+
✅ **Self-Healing** - Tests adapt to UI changes automatically
|
|
43
|
+
✅ **Any Provider** - Gemini, Claude, Groq, GPT, xAI, or local models
|
|
44
|
+
✅ **Web & Salesforce** - Basic support out of the box
|
|
45
|
+
✅ **Cost Optimized** - Built-in token management and budgeting
|
|
46
|
+
✅ **Playwright Test** - Native reports, traces and debugging
|
|
47
|
+
✅ **Fully Customizable** - Build your own [extensions](docs/EXTENSIONS.md) and tools
|
|
48
|
+
|
|
49
|
+
<img src="docs/img/gpt-oss-20b-e2e-checkout.gif" alt="example-e2e-test" width="100%"/>
|
|
50
|
+
|
|
51
|
+
## Get Started in 5 Minutes
|
|
52
|
+
|
|
53
|
+
### Prerequisites
|
|
54
|
+
|
|
55
|
+
- Node.js [LTS](https://nodejs.org/en/download)
|
|
56
|
+
- OpenAI [API key](https://platform.openai.com/api-keys) or compatible provider [Groq](https://console.groq.com/keys) [Gemini](https://aistudio.google.com/app/api-keys) [xAI](https://x.ai/api) etc.
|
|
57
|
+
|
|
58
|
+
### 1. Install
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm install -D @playwright/test @xoxoai/checkmate
|
|
62
|
+
npx playwright install
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### 2. Configure `.env`
|
|
66
|
+
|
|
67
|
+
_using [OpenAI API](https://platform.openai.com/settings/organization/api-keys) key and default settings:_
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
OPENAI_API_KEY=#your_api_key_here
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
_for other providers, set the base url and model:_
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
OPENAI_BASE_URL=https://api.groq.com/openai/v1
|
|
77
|
+
OPENAI_MODEL=openai/gpt-oss-20b
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 3. Run Tests
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
npm run test:web:example
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 4. View Report
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
npm run show:report
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Writing Tests
|
|
93
|
+
|
|
94
|
+
Import `test` and `expect` from `@xoxoai/checkmate/playwright` and use the `ai` fixture to run AI-driven tests alongside standard Playwright assertions.
|
|
95
|
+
**_checkmate_** tests are written using natural language by specifying `action` and `expect`:
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
import { expect, test } from '@xoxoai/checkmate/playwright'
|
|
99
|
+
|
|
100
|
+
test('google search', async ({ ai }) => {
|
|
101
|
+
await ai.run({
|
|
102
|
+
action: `
|
|
103
|
+
Open the browser and navigate to google.com.
|
|
104
|
+
Type 'playwright test automation' in the search bar.
|
|
105
|
+
Press Enter key.`,
|
|
106
|
+
expect: `
|
|
107
|
+
Search results contain the 'playwright.dev' link`,
|
|
108
|
+
})
|
|
109
|
+
})
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
That's it. No page objects, no selectors. No locators. Peace on Earth.
|
|
113
|
+
|
|
114
|
+
Browser settings (viewport, headless mode, video recording, timeouts, etc.) are configured in [playwright.config.ts](playwright.config.ts) using Playwright's [standard](https://playwright.dev/docs/test-configuration) configuration mechanism.
|
|
115
|
+
|
|
116
|
+
See [guide](docs/GUIDE.md#best-practices) for detailed examples and best practices.
|
|
117
|
+
|
|
118
|
+
### Programmatic API
|
|
119
|
+
|
|
120
|
+
If you use **_checkmate_** without the fixture wrapper, compose a runner from `@xoxoai/checkmate/core` and extensions:
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
import { createRunner } from '@xoxoai/checkmate/core'
|
|
124
|
+
import { web } from '@xoxoai/checkmate/playwright'
|
|
125
|
+
|
|
126
|
+
const ai = createRunner({
|
|
127
|
+
extensions: [web({ page })],
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
await ai.run({
|
|
131
|
+
action: 'Open the pricing page',
|
|
132
|
+
expect: 'Pricing details are visible',
|
|
133
|
+
})
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
See [guide](docs/GUIDE.md#advanced-topics) for advanced topics and [extensions](docs/EXTENSIONS.md) for building custom tools, extensions, and runners.
|
|
137
|
+
|
|
138
|
+
Published entry points:
|
|
139
|
+
|
|
140
|
+
`@xoxoai/checkmate/core`: Build your own runner with extensions.
|
|
141
|
+
`@xoxoai/checkmate/playwright`: Use the built-in web extension with Playwright `test` and `expect`.
|
|
142
|
+
`@xoxoai/checkmate/salesforce`: Use the built-in web + Salesforce extensions with the same `ai` fixture shape.
|
|
143
|
+
|
|
144
|
+
The repository keeps runnable consumer-style examples under `test/examples/`.
|
|
145
|
+
|
|
146
|
+
## Costs
|
|
147
|
+
|
|
148
|
+
Costs vary based on model and provider, test complexity and number of steps.
|
|
149
|
+
**_checkmate_** includes built-in token usage [monitoring](docs/GUIDE.md#cost-management).
|
|
150
|
+
|
|
151
|
+
Cost estimates with [gpt-oss-20b hosted on groq.com](https://console.groq.com/docs/model/openai/gpt-oss-20b) for optimal balance:
|
|
152
|
+
|
|
153
|
+
- Simple test (~5 steps): ~$0.001 - $0.01
|
|
154
|
+
- Complex test (~20 steps): ~$0.01 - $0.05
|
|
155
|
+
- Full E2E suite (~50 complex tests): ~$1.00 - $2.00
|
|
156
|
+
|
|
157
|
+
See [guide](docs/GUIDE.md#cost-management) for detailed cost control and monitoring options.
|
|
158
|
+
|
|
159
|
+
## Common Issues
|
|
160
|
+
|
|
161
|
+
**AI makes incorrect decisions**
|
|
162
|
+
|
|
163
|
+
- Provide precise descriptions in `action` and more focused assertions in `expect`
|
|
164
|
+
- Reference specific element identifiers and roles (for example: text, label, button, list)
|
|
165
|
+
- Break complex workflows into single-action steps; use a step-by-step approach
|
|
166
|
+
|
|
167
|
+
**Tests loop during step execution**
|
|
168
|
+
|
|
169
|
+
- Increase `OPENAI_TEMPERATURE` to encourage exploration
|
|
170
|
+
- Use a reasoning/thinking model (if available) to improve planning and avoid repetitive loops
|
|
171
|
+
|
|
172
|
+
**High token costs**
|
|
173
|
+
|
|
174
|
+
- Enable [snapshot filtering](docs/GUIDE.md#using-snapshot-filtering-for-token-optimization) with `CHECKMATE_SNAPSHOT_FILTERING=true` to score and narrow the elements automatically from `action` and `expect`. Use `topPercent` to dial how much of the scored snapshot to keep for a step.
|
|
175
|
+
- Set a lower reasoning effort: `OPENAI_REASONING_EFFORT`
|
|
176
|
+
- Consider disabling `OPENAI_INCLUDE_SCREENSHOT_IN_SNAPSHOT`
|
|
177
|
+
- Use a cheaper model, lower-end models often perform well (e.g., `gpt-5.4-nano` or `gpt-oss-20b`)
|
|
178
|
+
|
|
179
|
+
See [guide](docs/GUIDE.md#openai-api-settings) for detailed configuration options and troubleshooting tips.
|
|
180
|
+
|
|
181
|
+
## FAQ
|
|
182
|
+
|
|
183
|
+
**Which models work best?**
|
|
184
|
+
You can use any model that was trained for tool use. Here are the best picks based on extensive testing:
|
|
185
|
+
|
|
186
|
+
- Highly recommended: [`gpt-oss-20b` hosted on groq.com](https://console.groq.com/docs/model/openai/gpt-oss-20b). Groq's infrastructure is optimized for minimal latency and fast inference, making it ideal for E2E test automation.
|
|
187
|
+
- Google's `gemini-2.5-flash` offers an excellent balance of cost and performance if you prefer major cloud providers.
|
|
188
|
+
- OpenAI's `gpt-5-mini`, `gpt-5.4-nano` and xAI's `grok-4-1-fast-reasoning` also work well and keep costs relatively low.
|
|
189
|
+
|
|
190
|
+
**Can I use local models?**
|
|
191
|
+
Yes - **_checkmate_** works with any OpenAI‑compatible API, including local models via LM Studio, Ollama, or llama.cpp. I recommend [qwen3.5-4b](https://huggingface.co/Qwen/Qwen3.5-4B). It is fast (≈100 tokens/sec on an RTX 3060 Ti; ≈40 tokens/sec on Apple M3) and performs surprisingly well for E2E testing.
|
|
192
|
+
|
|
193
|
+
**Does it work with CI/CD?**
|
|
194
|
+
Absolutely. Use **_checkmate_** as part of your existing [Playwright Test suites in any CI/CD pipeline](https://playwright.dev/docs/best-practices#run-tests-on-ci). You can mix AI‑driven steps and traditional tests as needed.
|
|
195
|
+
|
|
196
|
+
**Is this production-ready?**
|
|
197
|
+
It depends. If you can accept some non‑deterministic behavior and leverage LLMs' randomness to help address the [pesticide paradox](https://medium.com/@suwekasansiluni/the-pesticide-paradox-what-farming-teaches-us-about-software-testing-ab5d625d4de1), **_checkmate_** can be production-ready. In many cases, the maintenance savings, faster development, and benefits of non‑linear execution outweigh occasional hiccups.
|
|
198
|
+
|
|
199
|
+
If you require 100% deterministic tests at all times, traditional Playwright remains the better choice.
|
|
200
|
+
|
|
201
|
+
**Best part?**
|
|
202
|
+
You can mix both approaches within the same test suite, combining AI‑driven and traditional tests as needed:
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
// traditional playwright actions:
|
|
206
|
+
await page.goto('https://www.google.com')
|
|
207
|
+
const searchBox = page.getByRole('combobox', { name: 'Search', exact: true })
|
|
208
|
+
await searchBox.fill('playwright test automation')
|
|
209
|
+
await searchBox.press('Enter')
|
|
210
|
+
|
|
211
|
+
// ai-driven actions and assertions:
|
|
212
|
+
await ai.run({
|
|
213
|
+
action: 'Click on the link that leads to playwright.dev',
|
|
214
|
+
expect: 'The playwright.dev homepage is displayed',
|
|
215
|
+
})
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Documentation
|
|
219
|
+
|
|
220
|
+
- [**_checkmate_**](docs/GUIDE.md)
|
|
221
|
+
- [Playwright](https://playwright.dev/)
|
|
222
|
+
|
|
223
|
+
## Contributing
|
|
224
|
+
|
|
225
|
+
I'd love your help! Key areas:
|
|
226
|
+
|
|
227
|
+
- Additional tool integrations (API testing, Salesforce, etc.)
|
|
228
|
+
- Further cost optimization techniques
|
|
229
|
+
- Context and prompt engineering improvements
|
|
230
|
+
- Error handling and recovery
|
|
231
|
+
|
|
232
|
+
See [roadmap](docs/ROADMAP.md) for future plans and development
|
|
233
|
+
|
|
234
|
+
## MIT License
|
|
235
|
+
|
|
236
|
+
See [license](LICENSE) file for details
|
|
237
|
+
|
|
238
|
+
## Why I build this?
|
|
239
|
+
|
|
240
|
+
Test automation shouldn't require a PhD in XPath. This project explores how AI can make it accessible to anyone.
|
|
241
|
+
|
|
242
|
+
Less coding, more testing.
|
|
243
|
+
|
|
244
|
+
Built with ❤️ by [Dawid Dobrowolski](https://github.com/dawiddiwad)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { ChatCompletion, ChatCompletionMessageParam } from 'openai/resources/chat/completions';
|
|
2
|
+
import { RuntimeConfig } from '../config/runtime-config';
|
|
3
|
+
import { ToolRegistry } from '../tools/registry';
|
|
4
|
+
import { Step, ResolveStepResult } from '../runtime/types';
|
|
5
|
+
import { ExtensionHost } from '../runtime/extension';
|
|
6
|
+
export type AiClientDependencies = {
|
|
7
|
+
runtimeConfig: RuntimeConfig;
|
|
8
|
+
toolRegistry: ToolRegistry;
|
|
9
|
+
extensionHost: ExtensionHost;
|
|
10
|
+
};
|
|
11
|
+
export declare class AiClient {
|
|
12
|
+
private client;
|
|
13
|
+
private messages;
|
|
14
|
+
private readonly responseProcessor;
|
|
15
|
+
private readonly retryableStatus;
|
|
16
|
+
private step;
|
|
17
|
+
private resolveStepResult;
|
|
18
|
+
temperature: number;
|
|
19
|
+
private readonly messageHistory;
|
|
20
|
+
constructor({ runtimeConfig, toolRegistry, extensionHost }: AiClientDependencies);
|
|
21
|
+
private readonly runtimeConfig;
|
|
22
|
+
private readonly toolRegistry;
|
|
23
|
+
initialize(step: Step, resolveStepResult: ResolveStepResult): Promise<void>;
|
|
24
|
+
getMessages(): ChatCompletionMessageParam[];
|
|
25
|
+
getToolRegistry(): ToolRegistry;
|
|
26
|
+
getRuntimeConfig(): RuntimeConfig;
|
|
27
|
+
sendMessage(userMessage: string | ChatCompletionMessageParam[]): Promise<void>;
|
|
28
|
+
addToolResponse(toolCallId: string, content: string): Promise<void>;
|
|
29
|
+
addUserMessage(content: string): Promise<void>;
|
|
30
|
+
addToolExecutionSummaryMessage(content: string): Promise<void>;
|
|
31
|
+
addCurrentSnapshotMessage(snapshotContent: string): Promise<void>;
|
|
32
|
+
addCurrentScreenshotMessage(base64Data: string, mimeType?: string): Promise<void>;
|
|
33
|
+
sendToolResponseWithRetry(): Promise<ChatCompletion>;
|
|
34
|
+
private createChatCompletion;
|
|
35
|
+
private appendResponseMessages;
|
|
36
|
+
private sanitizeAssistantMessage;
|
|
37
|
+
private executeWithRetry;
|
|
38
|
+
private getStatus;
|
|
39
|
+
private isRetryable;
|
|
40
|
+
private getRetryAfterSeconds;
|
|
41
|
+
private calculateBackoff;
|
|
42
|
+
private sleep;
|
|
43
|
+
countHistoryTokens(): number;
|
|
44
|
+
replaceHistory(history: ChatCompletionMessageParam[]): void;
|
|
45
|
+
private enhanceError;
|
|
46
|
+
private isToolError;
|
|
47
|
+
private countContentChars;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/ai/client.ts"],"names":[],"mappings":"AACA,OAAO,EACN,cAAc,EAEd,0BAA0B,EAC1B,MAAM,mCAAmC,CAAA;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAIxD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAG1D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAEpD,MAAM,MAAM,oBAAoB,GAAG;IAClC,aAAa,EAAE,aAAa,CAAA;IAC5B,YAAY,EAAE,YAAY,CAAA;IAC1B,aAAa,EAAE,aAAa,CAAA;CAC5B,CAAA;AAED,qBAAa,QAAQ;IACpB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAmB;IACrD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAS/B;IACD,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAuB;gBAE1C,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,EAAE,oBAAoB;IAOhF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAe;IAC7C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAc;IAErC,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,iBAAiB,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBjF,WAAW,IAAI,0BAA0B,EAAE;IAI3C,eAAe,IAAI,YAAY;IAI/B,gBAAgB,IAAI,aAAa;IAI3B,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,0BAA0B,EAAE;IAe9D,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAInE,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9C,8BAA8B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO9D,yBAAyB,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjE,2BAA2B,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9F,yBAAyB,IAAI,OAAO,CAAC,cAAc,CAAC;YAS5C,oBAAoB;IAalC,OAAO,CAAC,sBAAsB;IAQ9B,OAAO,CAAC,wBAAwB;YAgClB,gBAAgB;IAmC9B,OAAO,CAAC,SAAS;IAYjB,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,oBAAoB;IAqB5B,OAAO,CAAC,gBAAgB;IAKxB,OAAO,CAAC,KAAK;IAIb,kBAAkB,IAAI,MAAM;IAK5B,cAAc,CAAC,OAAO,EAAE,0BAA0B,EAAE,GAAG,IAAI;IAI3D,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,WAAW;IAanB,OAAO,CAAC,iBAAiB;CA0BzB"}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import OpenAI from 'openai';
|
|
2
|
+
import { logger } from '../logging';
|
|
3
|
+
import { CheckmateLogger } from '../logging/logger';
|
|
4
|
+
import { LoopDetectedError } from '../tools/loop-detector';
|
|
5
|
+
import { MessageHistory } from './message-history';
|
|
6
|
+
import { ResponseProcessor } from './response-processor';
|
|
7
|
+
export class AiClient {
|
|
8
|
+
client;
|
|
9
|
+
messages = [];
|
|
10
|
+
responseProcessor;
|
|
11
|
+
retryableStatus = [
|
|
12
|
+
408,
|
|
13
|
+
409,
|
|
14
|
+
429,
|
|
15
|
+
500,
|
|
16
|
+
502,
|
|
17
|
+
503,
|
|
18
|
+
504,
|
|
19
|
+
LoopDetectedError.STATUS,
|
|
20
|
+
];
|
|
21
|
+
step;
|
|
22
|
+
resolveStepResult;
|
|
23
|
+
temperature;
|
|
24
|
+
messageHistory = new MessageHistory();
|
|
25
|
+
constructor({ runtimeConfig, toolRegistry, extensionHost }) {
|
|
26
|
+
this.runtimeConfig = runtimeConfig;
|
|
27
|
+
this.toolRegistry = toolRegistry;
|
|
28
|
+
this.responseProcessor = new ResponseProcessor({ aiClient: this, extensionHost });
|
|
29
|
+
this.temperature = this.runtimeConfig.getTemperature();
|
|
30
|
+
}
|
|
31
|
+
runtimeConfig;
|
|
32
|
+
toolRegistry;
|
|
33
|
+
async initialize(step, resolveStepResult) {
|
|
34
|
+
this.client = new OpenAI({
|
|
35
|
+
apiKey: this.runtimeConfig.getApiKey(),
|
|
36
|
+
baseURL: this.runtimeConfig.getBaseURL(),
|
|
37
|
+
timeout: this.runtimeConfig.getTimeout(),
|
|
38
|
+
maxRetries: 0,
|
|
39
|
+
logLevel: this.runtimeConfig.getLogLevel(),
|
|
40
|
+
logger: CheckmateLogger.create('ai_client', this.runtimeConfig.getLogLevel()),
|
|
41
|
+
});
|
|
42
|
+
this.messages = [];
|
|
43
|
+
this.step = step;
|
|
44
|
+
this.resolveStepResult = resolveStepResult;
|
|
45
|
+
this.responseProcessor.resetStepTokens();
|
|
46
|
+
this.temperature = this.runtimeConfig.getTemperature();
|
|
47
|
+
}
|
|
48
|
+
getMessages() {
|
|
49
|
+
return this.messages;
|
|
50
|
+
}
|
|
51
|
+
getToolRegistry() {
|
|
52
|
+
return this.toolRegistry;
|
|
53
|
+
}
|
|
54
|
+
getRuntimeConfig() {
|
|
55
|
+
return this.runtimeConfig;
|
|
56
|
+
}
|
|
57
|
+
async sendMessage(userMessage) {
|
|
58
|
+
if (typeof userMessage === 'string') {
|
|
59
|
+
this.messages.push({ role: 'user', content: userMessage });
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
this.messages.push(...userMessage);
|
|
63
|
+
}
|
|
64
|
+
return this.executeWithRetry(async () => {
|
|
65
|
+
const tools = await this.toolRegistry.getTools();
|
|
66
|
+
const response = await this.createChatCompletion(tools, true);
|
|
67
|
+
this.appendResponseMessages(response);
|
|
68
|
+
await this.responseProcessor.handleResponse(response, this.step, this.resolveStepResult);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
async addToolResponse(toolCallId, content) {
|
|
72
|
+
this.messages.push({ role: 'tool', tool_call_id: toolCallId, content });
|
|
73
|
+
}
|
|
74
|
+
async addUserMessage(content) {
|
|
75
|
+
this.messages.push({ role: 'user', content });
|
|
76
|
+
}
|
|
77
|
+
async addToolExecutionSummaryMessage(content) {
|
|
78
|
+
this.messages.push({
|
|
79
|
+
role: 'user',
|
|
80
|
+
content: `${MessageHistory.TOOL_EXECUTION_SUMMARY_IDENTIFIER}:\n${content}`,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
async addCurrentSnapshotMessage(snapshotContent) {
|
|
84
|
+
this.messages.push(this.messageHistory.createSnapshotMessage(snapshotContent));
|
|
85
|
+
}
|
|
86
|
+
async addCurrentScreenshotMessage(base64Data, mimeType = 'image/png') {
|
|
87
|
+
this.messages.push(this.messageHistory.createScreenshotMessage(base64Data, mimeType));
|
|
88
|
+
}
|
|
89
|
+
async sendToolResponseWithRetry() {
|
|
90
|
+
return this.executeWithRetry(async () => {
|
|
91
|
+
const tools = await this.toolRegistry.getTools();
|
|
92
|
+
const response = await this.createChatCompletion(tools, false);
|
|
93
|
+
this.appendResponseMessages(response);
|
|
94
|
+
return response;
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
async createChatCompletion(tools, includeN) {
|
|
98
|
+
return this.client.chat.completions.create({
|
|
99
|
+
model: this.runtimeConfig.getModel(),
|
|
100
|
+
messages: this.messages,
|
|
101
|
+
tools,
|
|
102
|
+
tool_choice: this.runtimeConfig.getToolChoice(),
|
|
103
|
+
parallel_tool_calls: false,
|
|
104
|
+
temperature: this.temperature,
|
|
105
|
+
reasoning_effort: this.runtimeConfig.getReasoningEffort(),
|
|
106
|
+
...(includeN ? { n: 1 } : {}),
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
appendResponseMessages(response) {
|
|
110
|
+
response.choices.forEach((choice) => {
|
|
111
|
+
if (choice.message) {
|
|
112
|
+
this.messages.push(this.sanitizeAssistantMessage(choice.message));
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
sanitizeAssistantMessage(message) {
|
|
117
|
+
const sanitizedMessage = { role: 'assistant' };
|
|
118
|
+
if (message.content !== undefined) {
|
|
119
|
+
sanitizedMessage.content = message.content;
|
|
120
|
+
}
|
|
121
|
+
if ('refusal' in message && message.refusal !== undefined) {
|
|
122
|
+
sanitizedMessage.refusal = message.refusal;
|
|
123
|
+
}
|
|
124
|
+
if ('tool_calls' in message && message.tool_calls !== undefined) {
|
|
125
|
+
sanitizedMessage.tool_calls = message.tool_calls;
|
|
126
|
+
}
|
|
127
|
+
if ('function_call' in message && message.function_call !== undefined) {
|
|
128
|
+
sanitizedMessage.function_call = message.function_call;
|
|
129
|
+
}
|
|
130
|
+
if ('name' in message && typeof message.name === 'string') {
|
|
131
|
+
sanitizedMessage.name = message.name;
|
|
132
|
+
}
|
|
133
|
+
if ('audio' in message && message.audio !== undefined) {
|
|
134
|
+
sanitizedMessage.audio = message.audio;
|
|
135
|
+
}
|
|
136
|
+
return sanitizedMessage;
|
|
137
|
+
}
|
|
138
|
+
async executeWithRetry(operation) {
|
|
139
|
+
const maxRetries = this.runtimeConfig.getMaxRetries();
|
|
140
|
+
let lastError = null;
|
|
141
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
142
|
+
try {
|
|
143
|
+
return await operation();
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
147
|
+
if ((!this.isRetryable(error) && !this.isToolError(error)) || attempt === maxRetries) {
|
|
148
|
+
throw this.enhanceError(error);
|
|
149
|
+
}
|
|
150
|
+
if (error instanceof LoopDetectedError) {
|
|
151
|
+
const antiLoopTempChange = Math.round(Math.random() * 10) / 10;
|
|
152
|
+
logger.warn(`repeated tool calls detected: adjusting temperature from ${this.temperature} to ${antiLoopTempChange} to mitigate looping`);
|
|
153
|
+
this.temperature = antiLoopTempChange;
|
|
154
|
+
}
|
|
155
|
+
const retryAfter = this.getRetryAfterSeconds(error);
|
|
156
|
+
const delay = retryAfter ? retryAfter * 1000 : this.calculateBackoff(attempt);
|
|
157
|
+
logger.warn(`status: ${this.getStatus(error)} retry attempt: ${attempt + 1}/${maxRetries} starting in: ${delay}ms ...`);
|
|
158
|
+
logger.debug(`retryable error details:\n${JSON.stringify(error, null, 2)}`);
|
|
159
|
+
await this.sleep(delay);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
throw lastError || new Error('Unexpected error in retry loop');
|
|
163
|
+
}
|
|
164
|
+
getStatus(error) {
|
|
165
|
+
if (typeof error !== 'object' || error === null) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
const status = error.status ??
|
|
169
|
+
error.statusCode ??
|
|
170
|
+
error.code;
|
|
171
|
+
return typeof status === 'number' || typeof status === 'string' ? status : null;
|
|
172
|
+
}
|
|
173
|
+
isRetryable(error) {
|
|
174
|
+
const statusCode = this.getStatus(error);
|
|
175
|
+
return statusCode !== null && this.retryableStatus.includes(statusCode);
|
|
176
|
+
}
|
|
177
|
+
getRetryAfterSeconds(error) {
|
|
178
|
+
if (typeof error !== 'object' || error === null) {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
const headers = error.headers;
|
|
182
|
+
if (!headers) {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
const retryAfter = headers.get?.('retry-after') ??
|
|
186
|
+
headers['retry-after'];
|
|
187
|
+
if (!retryAfter) {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
const seconds = parseInt(retryAfter, 10);
|
|
191
|
+
return Number.isNaN(seconds) ? null : seconds;
|
|
192
|
+
}
|
|
193
|
+
calculateBackoff(attempt) {
|
|
194
|
+
const delays = [1_000, 10_000, 60_000];
|
|
195
|
+
return delays[Math.min(attempt, delays.length - 1)];
|
|
196
|
+
}
|
|
197
|
+
sleep(ms) {
|
|
198
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
199
|
+
}
|
|
200
|
+
countHistoryTokens() {
|
|
201
|
+
const totalChars = this.messages.reduce((sum, msg) => sum + this.countContentChars(msg.content), 0);
|
|
202
|
+
return Math.ceil(totalChars / 4);
|
|
203
|
+
}
|
|
204
|
+
replaceHistory(history) {
|
|
205
|
+
this.messages = [...history];
|
|
206
|
+
}
|
|
207
|
+
enhanceError(error) {
|
|
208
|
+
const status = this.getStatus(error) ?? 'unknown';
|
|
209
|
+
const message = error instanceof Error ? error.message : null;
|
|
210
|
+
return new Error(`OpenAI API error [${status}]: ${message ?? JSON.stringify(error, null, 2)}`);
|
|
211
|
+
}
|
|
212
|
+
isToolError(error) {
|
|
213
|
+
const errorAsString = JSON.stringify(error, null, 2).toLowerCase();
|
|
214
|
+
if (this.getStatus(error) === 400 && errorAsString.includes('tool')) {
|
|
215
|
+
logger.warn('tool call error detected [400]');
|
|
216
|
+
void this.addUserMessage('you did not call a tool or called it incorrectly, try again and always only call a tool with correct parameters to proceed with the step.');
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
countContentChars(content) {
|
|
222
|
+
if (typeof content === 'string') {
|
|
223
|
+
return content.length;
|
|
224
|
+
}
|
|
225
|
+
if (!Array.isArray(content)) {
|
|
226
|
+
return 0;
|
|
227
|
+
}
|
|
228
|
+
let totalChars = 0;
|
|
229
|
+
for (const part of content) {
|
|
230
|
+
if ('text' in part && typeof part.text === 'string') {
|
|
231
|
+
totalChars += part.text.length;
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
if ('image_url' in part) {
|
|
235
|
+
const imageUrl = part.image_url;
|
|
236
|
+
if (typeof imageUrl.url === 'string') {
|
|
237
|
+
totalChars += imageUrl.url.length;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return totalChars;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/ai/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ChatCompletion } from 'openai/resources/chat/completions';
|
|
2
|
+
import { Step, ResolveStepResult } from '../runtime/types';
|
|
3
|
+
import { AiClient } from './client';
|
|
4
|
+
import { ResponseProcessor } from './response-processor';
|
|
5
|
+
export declare class MessageHandler {
|
|
6
|
+
private readonly aiClient;
|
|
7
|
+
private readonly responseProcessor;
|
|
8
|
+
constructor(aiClient: AiClient, responseProcessor: ResponseProcessor);
|
|
9
|
+
handle(choice: ChatCompletion.Choice, step: Step, resolveStepResult: ResolveStepResult): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=message-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-handler.d.ts","sourceRoot":"","sources":["../../src/ai/message-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAA;AAElE,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAE1D,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AACnC,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAExD,qBAAa,cAAc;IAEzB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,iBAAiB;gBADjB,QAAQ,EAAE,QAAQ,EAClB,iBAAiB,EAAE,iBAAiB;IAGhD,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,iBAAiB,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;CA8B5G"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { logger } from '../logging';
|
|
2
|
+
import { StepResultTool } from '../tools/step/result-tool';
|
|
3
|
+
export class MessageHandler {
|
|
4
|
+
aiClient;
|
|
5
|
+
responseProcessor;
|
|
6
|
+
constructor(aiClient, responseProcessor) {
|
|
7
|
+
this.aiClient = aiClient;
|
|
8
|
+
this.responseProcessor = responseProcessor;
|
|
9
|
+
}
|
|
10
|
+
async handle(choice, step, resolveStepResult) {
|
|
11
|
+
const { message } = choice;
|
|
12
|
+
if (choice.finish_reason === 'stop' || message.content) {
|
|
13
|
+
logger.warn(`text: ${message.content}`);
|
|
14
|
+
logger.warn(`warning: model responded with text but no tool call. Prompting to use ${StepResultTool.TOOL_PASS_TEST_STEP} or ${StepResultTool.TOOL_FAIL_TEST_STEP}.`);
|
|
15
|
+
await this.aiClient.addUserMessage(`You provided a text response but did not call a tool. Based on your analysis, call either '${StepResultTool.TOOL_PASS_TEST_STEP}' or '${StepResultTool.TOOL_FAIL_TEST_STEP}' with the actual result. Do not respond with text. Only use the tool.`);
|
|
16
|
+
const followUpResponse = await this.aiClient.sendToolResponseWithRetry();
|
|
17
|
+
await this.responseProcessor.handleResponse(followUpResponse, step, resolveStepResult);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (choice.finish_reason && choice.finish_reason !== 'tool_calls') {
|
|
21
|
+
resolveStepResult({
|
|
22
|
+
passed: false,
|
|
23
|
+
actual: `OpenAI API finished unexpectedly with reason: ${choice.finish_reason}`,
|
|
24
|
+
});
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (!choice.message.content && (!choice.message.tool_calls || choice.message.tool_calls.length === 0)) {
|
|
28
|
+
throw new Error(`No content or tool calls found in message:\n${JSON.stringify(choice.message, null, 2)}`);
|
|
29
|
+
}
|
|
30
|
+
throw new Error(`Unhandled choice on response from model:\n${JSON.stringify(choice, null, 2)}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=message-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-handler.js","sourceRoot":"","sources":["../../src/ai/message-handler.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAEnC,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAI1D,MAAM,OAAO,cAAc;IAER;IACA;IAFlB,YACkB,QAAkB,EAClB,iBAAoC;QADpC,aAAQ,GAAR,QAAQ,CAAU;QAClB,sBAAiB,GAAjB,iBAAiB,CAAmB;IACnD,CAAC;IAEJ,KAAK,CAAC,MAAM,CAAC,MAA6B,EAAE,IAAU,EAAE,iBAAoC;QAC3F,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAAA;QAE1B,IAAI,MAAM,CAAC,aAAa,KAAK,MAAM,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACxD,MAAM,CAAC,IAAI,CAAC,SAAS,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;YACvC,MAAM,CAAC,IAAI,CACV,yEAAyE,cAAc,CAAC,mBAAmB,OAAO,cAAc,CAAC,mBAAmB,GAAG,CACvJ,CAAA;YACD,MAAM,IAAI,CAAC,QAAQ,CAAC,cAAc,CACjC,8FAA8F,cAAc,CAAC,mBAAmB,SAAS,cAAc,CAAC,mBAAmB,wEAAwE,CACnP,CAAA;YACD,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,yBAAyB,EAAE,CAAA;YACxE,MAAM,IAAI,CAAC,iBAAiB,CAAC,cAAc,CAAC,gBAAgB,EAAE,IAAI,EAAE,iBAAiB,CAAC,CAAA;YACtF,OAAM;QACP,CAAC;QAED,IAAI,MAAM,CAAC,aAAa,IAAI,MAAM,CAAC,aAAa,KAAK,YAAY,EAAE,CAAC;YACnE,iBAAiB,CAAC;gBACjB,MAAM,EAAE,KAAK;gBACb,MAAM,EAAE,iDAAiD,MAAM,CAAC,aAAa,EAAE;aAC/E,CAAC,CAAA;YACF,OAAM;QACP,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;YACvG,MAAM,IAAI,KAAK,CAAC,+CAA+C,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAA;QAC1G,CAAC;QAED,MAAM,IAAI,KAAK,CAAC,6CAA6C,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAA;IAChG,CAAC;CACD"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ChatCompletionMessageParam } from 'openai/resources/chat/completions';
|
|
2
|
+
import { AiClient } from './client';
|
|
3
|
+
type InitialMessageParameters = {
|
|
4
|
+
systemPrompt: string;
|
|
5
|
+
userPrompt: string;
|
|
6
|
+
contextMessages?: ChatCompletionMessageParam[];
|
|
7
|
+
};
|
|
8
|
+
export declare class MessageHistory {
|
|
9
|
+
static readonly SNAPSHOT_IDENTIFIER = "this is a current page snapshot";
|
|
10
|
+
static readonly SCREENSHOT_IDENTIFIER = "this is a current screenshot of the page";
|
|
11
|
+
static readonly TOOL_EXECUTION_SUMMARY_IDENTIFIER = "tool execution summary";
|
|
12
|
+
buildInitialMessages(config: InitialMessageParameters): ChatCompletionMessageParam[];
|
|
13
|
+
createSnapshotMessage(snapshotContent: string | null): ChatCompletionMessageParam;
|
|
14
|
+
createScreenshotMessage(base64Data: string, mimeType?: string): ChatCompletionMessageParam;
|
|
15
|
+
removeEphemeralStateMessages(aiClient: AiClient): void;
|
|
16
|
+
private isEphemeralStateMessage;
|
|
17
|
+
}
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=message-history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-history.d.ts","sourceRoot":"","sources":["../../src/ai/message-history.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAA;AAC9E,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAEnC,KAAK,wBAAwB,GAAG;IAC/B,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,eAAe,CAAC,EAAE,0BAA0B,EAAE,CAAA;CAC9C,CAAA;AAED,qBAAa,cAAc;IAC1B,MAAM,CAAC,QAAQ,CAAC,mBAAmB,qCAAoC;IACvE,MAAM,CAAC,QAAQ,CAAC,qBAAqB,8CAA6C;IAClF,MAAM,CAAC,QAAQ,CAAC,iCAAiC,4BAA2B;IAE5E,oBAAoB,CAAC,MAAM,EAAE,wBAAwB,GAAG,0BAA0B,EAAE;IAcpF,qBAAqB,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,GAAG,0BAA0B;IAOjF,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAoB,GAAG,0BAA0B;IAUvG,4BAA4B,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAItD,OAAO,CAAC,uBAAuB;CAe/B"}
|