testronaut 2.1.2 → 2.1.3
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/TODO.md +10 -0
- package/package.json +1 -1
- package/tests/toolsTests/chromeBrowserPressKey.test.js +39 -0
- package/tests/toolsTests/toolSchema.test.js +6 -0
- package/tools/chromeBrowser.js +13 -0
- package/tools/toolSchema.js +21 -0
- package/todo.md +0 -25
package/TODO.md
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
## Browser Automation Follow-Ups
|
|
13
13
|
|
|
14
14
|
- [x] Make `click_text` match exact text, prefer the innermost visible element, and fail quickly instead of clicking an ancestor or partial match.
|
|
15
|
+
- [ ] Complete `press_key` turn-loop integration: classify it as fire-and-forget, automatically inject the updated DOM after successful key presses, and test that Enter/Escape state changes are available to the next reasoning turn without an explicit `get_dom` call.
|
|
15
16
|
- [ ] Replace framework/vendor-specific DOM class stripping with a framework-agnostic classifier that removes generated hashes, styling utilities, variants, and arbitrary selectors while preserving semantic component classes. Reconsider broad prefix rules such as `/^cl-/`, cap retained class count and length, and add representative fixtures for Tailwind, MUI, Ant Design, Chakra, Clerk, CSS Modules, and CSS-in-JS.
|
|
16
17
|
|
|
17
18
|
## Session and Reporting Follow-Ups
|
|
@@ -27,9 +28,18 @@
|
|
|
27
28
|
|
|
28
29
|
## Optimization and Rate-Limit Follow-Ups
|
|
29
30
|
|
|
31
|
+
- [ ] Reduce redundant screenshot capture in focused missions without weakening evidence: clarify or enforce when starting, transition, and final screenshots materially differ, and measure the effect on turns, tokens, and report usefulness.
|
|
30
32
|
- [ ] Run a history-informed model-routing benchmark before expanding cross-provider routing. Give Jev versioned, per-model/per-mission-class reliability, token, latency, and price observations from prior runs; require a configurable reliability floor; compare against the best fixed-model-plus-guardrails control with blocked repetitions; keep selection at the mission boundary; record the evidence and reason for every choice; and define cold-start, stale-data, low-confidence, and provider-failure fallbacks. Do not retry a failed mission on another provider in the benchmark because that would confound routing quality with retry recovery.
|
|
31
33
|
- [ ] Add an opt-in CLI/config policy that reroutes an imminent throttled LLM request to a compatible model as an alternative to the default backoff behavior. Keep backoff as the default; use observed TPM/RPM headroom and projected request tokens; constrain failover to explicitly configured provider/model families; preserve tool/history compatibility; prevent routing loops; fall back safely when the alternate model is unavailable; and record the original model, routed model, trigger, token usage, latency, and outcome in reports.
|
|
32
34
|
|
|
35
|
+
## OpenAI Provider Follow-Ups
|
|
36
|
+
|
|
37
|
+
- [ ] Migrate the OpenAI adapter from Chat Completions to the Responses API in a dedicated change. Preserve Testronaut's provider-neutral message and tool-call contract, add response-ID/reasoning-state handling, normalize usage and raw headers, and cover multi-turn tool continuation with unit and API smoke tests. Once migrated, remove the GPT-5.6 Chat Completions compatibility override that sets `reasoning_effort` to `none` for function-tool requests.
|
|
38
|
+
- [ ] Add active context budgeting after its behavior is designed and tested. Use model context/output metadata to reserve response and reasoning capacity, then apply explicit history compaction or summarization rules. Do not silently truncate mission instructions, current DOM state, or unmatched tool calls.
|
|
39
|
+
- [ ] Learn effective OpenAI TPM/RPM limits from successful response headers and rate-limit errors. Prefer observed project/model limits over inferring a named account tier; retain the environment override and conservative startup values.
|
|
40
|
+
- [ ] Persist provider-observed rate limits in a separate, expiring local cache keyed by provider, API project/account, endpoint/region, model, and traffic type. Never rewrite user config or infer a named usage tier from a TPM value; expose configured, cached, and live sources distinctly and discard stale observations.
|
|
41
|
+
- [ ] After dynamic rate limits are established, make DOM injection quota-aware. Budget DOM tokens against both remaining TPM and the model context window, preserve mission instructions and actionable controls, and fall back to semantic sections plus on-demand DOM chunks instead of silent truncation.
|
|
42
|
+
|
|
33
43
|
## Automated MFA Follow-Ups
|
|
34
44
|
|
|
35
45
|
- [ ] Add an integration smoke test against a local or staging API fixture for `get_mfa_code`.
|
package/package.json
CHANGED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { CHROME_TOOL_MAP, ChromeBrowser } from '../../tools/chromeBrowser.js';
|
|
3
|
+
|
|
4
|
+
describe('ChromeBrowser.press_key', () => {
|
|
5
|
+
it('presses a key on the active page', async () => {
|
|
6
|
+
const browser = new ChromeBrowser();
|
|
7
|
+
browser.page = { keyboard: { press: vi.fn().mockResolvedValue(undefined) } };
|
|
8
|
+
|
|
9
|
+
await expect(browser.press_key({ key: 'Escape' })).resolves.toBe('pressed Escape');
|
|
10
|
+
expect(browser.page.keyboard.press).toHaveBeenCalledWith('Escape');
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('focuses a selected element before pressing Enter', async () => {
|
|
14
|
+
const browser = new ChromeBrowser();
|
|
15
|
+
const focus = vi.fn().mockResolvedValue(undefined);
|
|
16
|
+
const first = vi.fn().mockReturnValue({ focus });
|
|
17
|
+
browser.page = {
|
|
18
|
+
locator: vi.fn().mockReturnValue({ first }),
|
|
19
|
+
keyboard: { press: vi.fn().mockResolvedValue(undefined) },
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
await expect(browser.press_key({ key: 'Enter', selector: '#email' }))
|
|
23
|
+
.resolves.toBe('pressed Enter after focusing #email');
|
|
24
|
+
|
|
25
|
+
expect(browser.page.locator).toHaveBeenCalledWith('#email');
|
|
26
|
+
expect(first).toHaveBeenCalledOnce();
|
|
27
|
+
expect(focus).toHaveBeenCalledWith({ timeout: 3000 });
|
|
28
|
+
expect(browser.page.keyboard.press).toHaveBeenCalledWith('Enter');
|
|
29
|
+
expect(focus.mock.invocationCallOrder[0])
|
|
30
|
+
.toBeLessThan(browser.page.keyboard.press.mock.invocationCallOrder[0]);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('is exposed through the browser tool dispatcher', async () => {
|
|
34
|
+
const press_key = vi.fn().mockResolvedValue('pressed Control+B');
|
|
35
|
+
await expect(CHROME_TOOL_MAP.press_key({ press_key }, { key: 'Control+B' }))
|
|
36
|
+
.resolves.toBe('pressed Control+B');
|
|
37
|
+
expect(press_key).toHaveBeenCalledWith({ key: 'Control+B' });
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -21,6 +21,12 @@ describe('tools/toolSchema', () => {
|
|
|
21
21
|
const entry = toolsSchema.find(tool => tool.function.name === 'get_dom');
|
|
22
22
|
expect(entry.function.parameters.properties.selector.type).toBe('string');
|
|
23
23
|
});
|
|
24
|
+
it('includes press_key with a required key and optional selector', () => {
|
|
25
|
+
const entry = toolsSchema.find(tool => tool.function.name === 'press_key');
|
|
26
|
+
expect(entry?.function.parameters.required).toEqual(['key']);
|
|
27
|
+
expect(entry.function.parameters.properties.key.type).toBe('string');
|
|
28
|
+
expect(entry.function.parameters.properties.selector.type).toBe('string');
|
|
29
|
+
});
|
|
24
30
|
it('exposes iframe targeting and iframe text search', () => {
|
|
25
31
|
const fill = toolsSchema.find(tool => tool.function.name === 'fill');
|
|
26
32
|
const click = toolsSchema.find(tool => tool.function.name === 'click');
|
package/tools/chromeBrowser.js
CHANGED
|
@@ -771,6 +771,18 @@ export class ChromeBrowser {
|
|
|
771
771
|
}, { attempts: 3, baseMs: 250 });
|
|
772
772
|
}
|
|
773
773
|
|
|
774
|
+
async press_key({ key, selector }) {
|
|
775
|
+
if (selector) {
|
|
776
|
+
const target = this.page.locator(selector).first();
|
|
777
|
+
await target.focus({ timeout: 3000 });
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
await this.page.keyboard.press(key);
|
|
781
|
+
return selector
|
|
782
|
+
? `pressed ${key} after focusing ${selector}`
|
|
783
|
+
: `pressed ${key}`;
|
|
784
|
+
}
|
|
785
|
+
|
|
774
786
|
|
|
775
787
|
|
|
776
788
|
/**
|
|
@@ -1525,6 +1537,7 @@ export const CHROME_TOOL_MAP = {
|
|
|
1525
1537
|
reload: (b) => b.reload(),
|
|
1526
1538
|
fill: (b, args) => b.fill(args),
|
|
1527
1539
|
click: (b, args) => b.click(args),
|
|
1540
|
+
press_key: (b, args) => b.press_key(args),
|
|
1528
1541
|
get_dom: (b, args, agentMemory) => b.get_dom(args, agentMemory),
|
|
1529
1542
|
check_text: (b, args) => b.check_text(args),
|
|
1530
1543
|
click_text: async (browser, args, agentMemory) => {
|
package/tools/toolSchema.js
CHANGED
|
@@ -75,6 +75,27 @@ const toolsSchema = [
|
|
|
75
75
|
},
|
|
76
76
|
},
|
|
77
77
|
},
|
|
78
|
+
{
|
|
79
|
+
type: 'function',
|
|
80
|
+
function: {
|
|
81
|
+
name: 'press_key',
|
|
82
|
+
description: 'Press a keyboard key or shortcut, optionally focusing an element by CSS selector first',
|
|
83
|
+
parameters: {
|
|
84
|
+
type: 'object',
|
|
85
|
+
properties: {
|
|
86
|
+
key: {
|
|
87
|
+
type: 'string',
|
|
88
|
+
description: 'Playwright key or shortcut, such as Enter, Escape, Control+B, or Meta+B',
|
|
89
|
+
},
|
|
90
|
+
selector: {
|
|
91
|
+
type: 'string',
|
|
92
|
+
description: 'Optional CSS selector of the element to focus before pressing the key',
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
required: ['key'],
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
78
99
|
{
|
|
79
100
|
type: 'function',
|
|
80
101
|
function: {
|
package/todo.md
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# Testronaut CLI TODO
|
|
2
|
-
|
|
3
|
-
## OpenAI provider follow-ups
|
|
4
|
-
|
|
5
|
-
- Migrate the OpenAI adapter from Chat Completions to the Responses API in a
|
|
6
|
-
dedicated change. Preserve Testronaut's provider-neutral message and tool-call
|
|
7
|
-
contract, add response-ID/reasoning-state handling, normalize usage and raw
|
|
8
|
-
headers, and cover multi-turn tool continuation with unit and API smoke tests.
|
|
9
|
-
Once migrated, remove the GPT-5.6 Chat Completions compatibility override that
|
|
10
|
-
sets `reasoning_effort` to `none` for function-tool requests.
|
|
11
|
-
- Add active context budgeting after its behavior is designed and tested. Use
|
|
12
|
-
model context/output metadata to reserve response and reasoning capacity, then
|
|
13
|
-
apply explicit history compaction or summarization rules. Do not silently
|
|
14
|
-
truncate mission instructions, current DOM state, or unmatched tool calls.
|
|
15
|
-
- Learn effective OpenAI TPM/RPM limits from successful response headers and
|
|
16
|
-
rate-limit errors. Prefer observed project/model limits over inferring a named
|
|
17
|
-
account tier; retain the environment override and conservative startup values.
|
|
18
|
-
- Persist provider-observed rate limits in a separate, expiring local cache keyed
|
|
19
|
-
by provider, API project/account, endpoint/region, model, and traffic type.
|
|
20
|
-
Never rewrite user config or infer a named usage tier from a TPM value; expose
|
|
21
|
-
configured, cached, and live sources distinctly and discard stale observations.
|
|
22
|
-
- After dynamic rate limits are established, make DOM injection quota-aware.
|
|
23
|
-
Budget DOM tokens against both remaining TPM and the model context window,
|
|
24
|
-
preserve mission instructions and actionable controls, and fall back to
|
|
25
|
-
semantic sections plus on-demand DOM chunks instead of silent truncation.
|