|
1 | 1 | import { tool } from "ai"; |
2 | 2 | import { z } from "zod"; |
3 | 3 | import type { V3 } from "../../v3.js"; |
| 4 | +import { TimeoutError } from "../../types/public/sdkErrors.js"; |
4 | 5 |
|
5 | | -export const ariaTreeTool = (v3: V3) => |
| 6 | +export const ariaTreeTool = (v3: V3, toolTimeout?: number) => |
6 | 7 | tool({ |
7 | 8 | description: |
8 | 9 | "gets the accessibility (ARIA) hybrid tree text for the current page. use this to understand structure and content.", |
9 | 10 | inputSchema: z.object({}), |
10 | 11 | execute: async () => { |
11 | | - v3.logger({ |
12 | | - category: "agent", |
13 | | - message: `Agent calling tool: ariaTree`, |
14 | | - level: 1, |
15 | | - }); |
16 | | - const page = await v3.context.awaitActivePage(); |
17 | | - const { pageText } = (await v3.extract()) as { pageText: string }; |
18 | | - const pageUrl = page.url(); |
| 12 | + try { |
| 13 | + v3.logger({ |
| 14 | + category: "agent", |
| 15 | + message: `Agent calling tool: ariaTree`, |
| 16 | + level: 1, |
| 17 | + }); |
| 18 | + const page = await v3.context.awaitActivePage(); |
| 19 | + const extractOptions = toolTimeout |
| 20 | + ? { timeout: toolTimeout } |
| 21 | + : undefined; |
| 22 | + const { pageText } = (await v3.extract(extractOptions)) as { |
| 23 | + pageText: string; |
| 24 | + }; |
| 25 | + const pageUrl = page.url(); |
19 | 26 |
|
20 | | - let content = pageText; |
21 | | - const MAX_TOKENS = 70000; // rough cap, assume ~4 chars per token for conservative truncation |
22 | | - const estimatedTokens = Math.ceil(content.length / 4); |
23 | | - if (estimatedTokens > MAX_TOKENS) { |
24 | | - const maxChars = MAX_TOKENS * 4; |
25 | | - content = |
26 | | - content.substring(0, maxChars) + |
27 | | - "\n\n[CONTENT TRUNCATED: Exceeded 70,000 token limit]"; |
| 27 | + let content = pageText; |
| 28 | + const MAX_TOKENS = 70000; // rough cap, assume ~4 chars per token for conservative truncation |
| 29 | + const estimatedTokens = Math.ceil(content.length / 4); |
| 30 | + if (estimatedTokens > MAX_TOKENS) { |
| 31 | + const maxChars = MAX_TOKENS * 4; |
| 32 | + content = |
| 33 | + content.substring(0, maxChars) + |
| 34 | + "\n\n[CONTENT TRUNCATED: Exceeded 70,000 token limit]"; |
| 35 | + } |
| 36 | + |
| 37 | + return { success: true, content, pageUrl }; |
| 38 | + } catch (error) { |
| 39 | + if (error instanceof TimeoutError) { |
| 40 | + const timeoutMessage = `TimeoutError: ariaTree() timed out — the page may be too large`; |
| 41 | + v3.logger({ |
| 42 | + category: "agent", |
| 43 | + message: timeoutMessage, |
| 44 | + level: 0, |
| 45 | + }); |
| 46 | + return { |
| 47 | + content: "", |
| 48 | + error: timeoutMessage, |
| 49 | + success: false, |
| 50 | + pageUrl: "", |
| 51 | + }; |
| 52 | + } |
| 53 | + return { |
| 54 | + content: "", |
| 55 | + error: error?.message ?? String(error), |
| 56 | + success: false, |
| 57 | + pageUrl: "", |
| 58 | + }; |
| 59 | + } |
| 60 | + }, |
| 61 | + toModelOutput: (result) => { |
| 62 | + if (result.success === false || result.error !== undefined) { |
| 63 | + return { |
| 64 | + type: "content", |
| 65 | + value: [{ type: "text", text: JSON.stringify(result) }], |
| 66 | + }; |
28 | 67 | } |
29 | 68 |
|
30 | | - return { content, pageUrl }; |
| 69 | + return { |
| 70 | + type: "content", |
| 71 | + value: [ |
| 72 | + { type: "text", text: `Accessibility Tree:\n${result.content}` }, |
| 73 | + ], |
| 74 | + }; |
31 | 75 | }, |
32 | | - toModelOutput: (result) => ({ |
33 | | - type: "content", |
34 | | - value: [{ type: "text", text: `Accessibility Tree:\n${result.content}` }], |
35 | | - }), |
36 | 76 | }); |
0 commit comments