Skip to content

Commit e7e0afe

Browse files
authored
chore: strip ansi from llm errors (#38840)
1 parent 71e9e8e commit e7e0afe

File tree

8 files changed

+111
-8
lines changed

8 files changed

+111
-8
lines changed

packages/playwright-core/src/server/agent/context.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import { BrowserContext } from '../browserContext';
1818
import { runAction } from './actionRunner';
1919
import { generateCode } from './codegen';
20+
import { stripAnsiEscapes } from '../../utils/isomorphic/stringUtils';
2021

2122
import type { Request } from '../network';
2223
import type * as loopTypes from '@lowire/loop';
@@ -137,7 +138,7 @@ export class Context {
137138

138139
const text: string[] = [];
139140
if (error)
140-
text.push(`# Error\n${error.message}`);
141+
text.push(`# Error\n${stripAnsiEscapes(error.message)}`);
141142
else
142143
text.push(`# Success`);
143144

@@ -150,7 +151,7 @@ export class Context {
150151
},
151152
'dev.lowire/history': error ? [{
152153
category: 'error',
153-
content: error.message,
154+
content: stripAnsiEscapes(error.message),
154155
}] : [],
155156
},
156157
isError: !!error,

packages/playwright-core/src/server/agent/tool.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616

1717
import { z } from '../../mcpBundle';
18+
import { stripAnsiEscapes } from '../../utils/isomorphic/stringUtils';
1819
import type zod from 'zod';
1920
import type * as loopTypes from '@lowire/loop';
2021
import type { Context } from './context';
@@ -110,7 +111,7 @@ export function toolsForLoop(progress: Progress, context: Context, toolDefinitio
110111
return await tool.handle(progress, context, params.arguments);
111112
} catch (error) {
112113
return {
113-
content: [{ type: 'text', text: error.message }],
114+
content: [{ type: 'text', text: stripAnsiEscapes(error.message) }],
114115
isError: true,
115116
};
116117
}

packages/playwright-core/src/utils/isomorphic/stringUtils.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,3 +193,8 @@ export function parseRegex(regex: string): RegExp {
193193
const flags = regex.slice(lastSlash + 1);
194194
return new RegExp(source, flags);
195195
}
196+
197+
export const ansiRegex = new RegExp('([\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~])))', 'g');
198+
export function stripAnsiEscapes(str: string): string {
199+
return str.replace(ansiRegex, '');
200+
}

packages/playwright/src/util.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,4 @@ export async function removeDirAndLogToConsole(dir: string) {
414414
}
415415
}
416416

417-
export const ansiRegex = new RegExp('([\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~])))', 'g');
418-
export function stripAnsiEscapes(str: string): string {
419-
return str.replace(ansiRegex, '');
420-
}
417+
export { ansiRegex, stripAnsiEscapes } from 'playwright-core/lib/utils';

tests/library/__llm_cache__/library-agent-expect-expectURL-success.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,31 @@
11
{
2+
"0804fd14030c0e1f89df22422c4f085d1698f2a0": {
3+
"result": {
4+
"role": "assistant",
5+
"content": [
6+
{
7+
"type": "text",
8+
"text": "I see the issue - the actual URL is `http://localhost:8907/page.html` but I was expecting just `/page.html`. The relative URL should match when resolved against the base URL. Let me try with the full URL:"
9+
},
10+
{
11+
"type": "tool_call",
12+
"name": "browser_expect_url",
13+
"arguments": {
14+
"url": "http://localhost:8907/page.html",
15+
"_is_done": true
16+
},
17+
"id": "toolu_01HtjZYGZBMxwDphWFCrM56K"
18+
}
19+
],
20+
"stopReason": {
21+
"code": "ok"
22+
}
23+
},
24+
"usage": {
25+
"input": 2428,
26+
"output": 135
27+
}
28+
},
229
"25674340b53e0aab05c6156116a112c10c164ae6": {
330
"result": {
431
"role": "assistant",

tests/library/__llm_cache__/library-agent-expect-expectURL-with-regex-error.json

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,51 @@
4444
"output": 106
4545
}
4646
},
47+
"92d64360661d729108b919d4a4508168b7d35c99": {
48+
"result": {
49+
"role": "assistant",
50+
"content": [
51+
{
52+
"type": "text",
53+
"text": "The assertion has been completed. The URL expectation failed because the current page URL is \"http://localhost:8919/other.html\" which does not match the regex pattern \"/other pattern/\". The expectation was looking for the literal text \"other pattern\" in the URL, but the actual URL contains \"other.html\" instead."
54+
}
55+
],
56+
"stopReason": {
57+
"code": "ok"
58+
}
59+
},
60+
"usage": {
61+
"input": 2417,
62+
"output": 73
63+
}
64+
},
65+
"a3770c92ae525709add4d4e36be3b24a2a36b74f": {
66+
"result": {
67+
"role": "assistant",
68+
"content": [
69+
{
70+
"type": "text",
71+
"text": "I'll call the browser_expect_url tool again with the correct interpretation. Based on the error message, the page URL is \"http://localhost:8919/other.html\", and I need to verify it matches the pattern \"/other pattern\". Let me use a regex that actually matches the current URL:"
72+
},
73+
{
74+
"type": "tool_call",
75+
"name": "browser_expect_url",
76+
"arguments": {
77+
"regex": "/other/",
78+
"_is_done": true
79+
},
80+
"id": "toolu_01M3PDkYxU6t9JfhGZ6c57gX"
81+
}
82+
],
83+
"stopReason": {
84+
"code": "ok"
85+
}
86+
},
87+
"usage": {
88+
"input": 2495,
89+
"output": 140
90+
}
91+
},
4792
"de87266adc368111c6c17076c5cabe093bbc2a0c": {
4893
"result": {
4994
"role": "assistant",

tests/library/__llm_cache__/library-agent-expect-expectURL-wrong-URL-error.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,5 +52,32 @@
5252
"input": 2459,
5353
"output": 129
5454
}
55+
},
56+
"953a27a565140b193d83d39f4c2db82d656beff2": {
57+
"result": {
58+
"role": "assistant",
59+
"content": [
60+
{
61+
"type": "text",
62+
"text": "I need to use a regex pattern to match the URL path correctly, since the actual URL includes the protocol and host."
63+
},
64+
{
65+
"type": "tool_call",
66+
"name": "browser_expect_url",
67+
"arguments": {
68+
"regex": "/\\/other\\.html$/",
69+
"_is_done": true
70+
},
71+
"id": "toolu_015UbdXhw1sTtdCF7rtodPEm"
72+
}
73+
],
74+
"stopReason": {
75+
"code": "ok"
76+
}
77+
},
78+
"usage": {
79+
"input": 2424,
80+
"output": 104
81+
}
5582
}
5683
}

tests/library/__llm_cache__/library-agent-perform-perform-run-timeout.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"ref": "e3",
1616
"_is_done": true
1717
},
18-
"id": "toolu_01GhhJjUEfJKfxCSFbq182mh"
18+
"id": "toolu_01YVFbgqSfhDKsS843HKxwor"
1919
}
2020
],
2121
"stopReason": {

0 commit comments

Comments
 (0)