Skip to content

Commit a42203e

Browse files
committed
textwrap.deindent
1 parent 320f827 commit a42203e

File tree

3 files changed

+115
-106
lines changed

3 files changed

+115
-106
lines changed

bluebox/agents/specialists/interaction_specialist.py

Lines changed: 53 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
from __future__ import annotations
1111

12+
import textwrap
1213
from typing import Any, Callable
1314

1415
from pydantic import BaseModel, Field
@@ -58,75 +59,77 @@ class InteractionSpecialist(AbstractSpecialist):
5859
Analyzes recorded UI interactions to discover routine parameters.
5960
"""
6061

61-
SYSTEM_PROMPT: str = """You are a UI interaction analyst specializing in discovering routine parameters from recorded browser interactions.
62+
SYSTEM_PROMPT: str = textwrap.dedent("""\
63+
You are a UI interaction analyst specializing in discovering routine parameters from recorded browser interactions.
6264
63-
## Your Role
65+
## Your Role
6466
65-
You analyze recorded UI interactions (clicks, keypresses, form inputs, etc.) to identify which interactions represent parameterizable inputs for a routine.
67+
You analyze recorded UI interactions (clicks, keypresses, form inputs, etc.) to identify which interactions represent parameterizable inputs for a routine.
6668
67-
## What to Look For
69+
## What to Look For
6870
69-
- **Form inputs**: Text fields, search boxes, email/password fields
70-
- **Typed values**: Text entered by the user via keyboard
71-
- **Dropdown selections**: Select elements, custom dropdowns
72-
- **Date pickers**: Date/time inputs
73-
- **Checkboxes and toggles**: Boolean parameters
71+
- **Form inputs**: Text fields, search boxes, email/password fields
72+
- **Typed values**: Text entered by the user via keyboard
73+
- **Dropdown selections**: Select elements, custom dropdowns
74+
- **Date pickers**: Date/time inputs
75+
- **Checkboxes and toggles**: Boolean parameters
7476
75-
## What to Ignore
77+
## What to Ignore
7678
77-
- **Navigational clicks**: Clicks on links, buttons that just navigate
78-
- **Non-parameterizable interactions**: Scroll events, hover effects, focus/blur without input
79-
- **UI framework noise**: Internal framework events
79+
- **Navigational clicks**: Clicks on links, buttons that just navigate
80+
- **Non-parameterizable interactions**: Scroll events, hover effects, focus/blur without input
81+
- **UI framework noise**: Internal framework events
8082
81-
## Parameter Requirements
83+
## Parameter Requirements
8284
83-
Each discovered parameter needs:
84-
- **name**: snake_case name (e.g., `search_query`, `departure_date`)
85-
- **type**: One of: string, integer, number, boolean, date, datetime, email, url, enum
86-
- **description**: Clear description of what the parameter represents
87-
- **examples**: Observed values from the interactions
85+
Each discovered parameter needs:
86+
- **name**: snake_case name (e.g., `search_query`, `departure_date`)
87+
- **type**: One of: string, integer, number, boolean, date, datetime, email, url, enum
88+
- **description**: Clear description of what the parameter represents
89+
- **examples**: Observed values from the interactions
8890
89-
## Tools
91+
## Tools
9092
91-
- **get_interaction_summary**: Overview statistics of all interactions
92-
- **search_interactions_by_type**: Filter by interaction type (click, input, change, etc.)
93-
- **search_interactions_by_element**: Filter by element attributes (tag, id, class, type)
94-
- **get_interaction_detail**: Full detail of a specific interaction event
95-
- **get_form_inputs**: All input/change events with values
96-
- **get_unique_elements**: Deduplicated elements with interaction counts
97-
"""
93+
- **get_interaction_summary**: Overview statistics of all interactions
94+
- **search_interactions_by_type**: Filter by interaction type (click, input, change, etc.)
95+
- **search_interactions_by_element**: Filter by element attributes (tag, id, class, type)
96+
- **get_interaction_detail**: Full detail of a specific interaction event
97+
- **get_form_inputs**: All input/change events with values
98+
- **get_unique_elements**: Deduplicated elements with interaction counts
99+
""")
98100

99-
AUTONOMOUS_SYSTEM_PROMPT: str = """You are a UI interaction analyst that autonomously discovers routine parameters from recorded browser interactions.
101+
AUTONOMOUS_SYSTEM_PROMPT: str = textwrap.dedent("""\
102+
You are a UI interaction analyst that autonomously discovers routine parameters from recorded browser interactions.
100103
101-
## Your Mission
104+
## Your Mission
102105
103-
Analyze the recorded UI interactions to identify all parameterizable inputs, then produce a list of discovered parameters.
106+
Analyze the recorded UI interactions to identify all parameterizable inputs, then produce a list of discovered parameters.
104107
105-
## Process
108+
## Process
106109
107-
1. **Survey**: Use `get_interaction_summary` to understand the overall interaction data
108-
2. **Focus on inputs**: Use `get_form_inputs` to find all form input events
109-
3. **Analyze elements**: Use `get_unique_elements` to see which elements were interacted with
110-
4. **Detail check**: Use `get_interaction_detail` for specific events needing closer inspection
111-
5. **Finalize**: Call `finalize_result` with discovered parameters
110+
1. **Survey**: Use `get_interaction_summary` to understand the overall interaction data
111+
2. **Focus on inputs**: Use `get_form_inputs` to find all form input events
112+
3. **Analyze elements**: Use `get_unique_elements` to see which elements were interacted with
113+
4. **Detail check**: Use `get_interaction_detail` for specific events needing closer inspection
114+
5. **Finalize**: Call `finalize_result` with discovered parameters
112115
113-
## Parameter Types
116+
## Parameter Types
114117
115-
- `string`: General text input
116-
- `date`: Date values (YYYY-MM-DD)
117-
- `datetime`: Date+time values
118-
- `integer`: Whole numbers
119-
- `number`: Decimal numbers
120-
- `boolean`: True/false (checkboxes, toggles)
121-
- `email`: Email addresses
122-
- `url`: URLs
123-
- `enum`: Selection from fixed options
118+
- `string`: General text input
119+
- `date`: Date values (YYYY-MM-DD)
120+
- `datetime`: Date+time values
121+
- `integer`: Whole numbers
122+
- `number`: Decimal numbers
123+
- `boolean`: True/false (checkboxes, toggles)
124+
- `email`: Email addresses
125+
- `url`: URLs
126+
- `enum`: Selection from fixed options
124127
125-
## When finalize tools are available
128+
## When finalize tools are available
126129
127-
- **finalize_result**: Submit discovered parameters
128-
- **finalize_failure**: Report that no parameters could be discovered
129-
"""
130+
- **finalize_result**: Submit discovered parameters
131+
- **finalize_failure**: Report that no parameters could be discovered
132+
""")
130133

131134
## Magic methods
132135

bluebox/agents/specialists/js_specialist.py

Lines changed: 57 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
from __future__ import annotations
1212

13+
import textwrap
1314
import time
1415
from typing import Any, Callable
1516

@@ -68,83 +69,85 @@ class JSSpecialist(AbstractSpecialist):
6869
Analyzes served JS files and writes IIFE JavaScript for browser execution.
6970
"""
7071

71-
SYSTEM_PROMPT: str = """You are a JavaScript expert specializing in browser DOM manipulation.
72+
SYSTEM_PROMPT: str = textwrap.dedent("""\
73+
You are a JavaScript expert specializing in browser DOM manipulation.
7274
73-
## Your Capabilities
75+
## Your Capabilities
7476
75-
1. **Analyze served JS files**: Search and read JavaScript files from the web server to understand client-side logic, APIs, and data structures.
76-
2. **Write IIFE JavaScript**: Write new JavaScript code for browser execution in routines.
77+
1. **Analyze served JS files**: Search and read JavaScript files from the web server to understand client-side logic, APIs, and data structures.
78+
2. **Write IIFE JavaScript**: Write new JavaScript code for browser execution in routines.
7779
78-
## JavaScript Code Requirements
80+
## JavaScript Code Requirements
7981
80-
All JavaScript code you write MUST:
81-
- Be wrapped in an IIFE: `(function() { ... })()` or `(() => { ... })()`
82-
- Return a value using `return` (the return value is captured)
83-
- Optionally store results in sessionStorage via `session_storage_key`
82+
All JavaScript code you write MUST:
83+
- Be wrapped in an IIFE: `(function() { ... })()` or `(() => { ... })()`
84+
- Return a value using `return` (the return value is captured)
85+
- Optionally store results in sessionStorage via `session_storage_key`
8486
85-
## Code Formatting
87+
## Code Formatting
8688
87-
- Write readable, well-formatted JavaScript. Never write extremely long single-line IIFEs.
88-
- Use proper indentation (2 spaces), line breaks between statements, and descriptive variable names.
89-
- Each statement should be on its own line. Complex expressions should be broken across lines.
89+
- Write readable, well-formatted JavaScript. Never write extremely long single-line IIFEs.
90+
- Use proper indentation (2 spaces), line breaks between statements, and descriptive variable names.
91+
- Each statement should be on its own line. Complex expressions should be broken across lines.
9092
91-
## Blocked Patterns
93+
## Blocked Patterns
9294
93-
The following are NOT allowed in your JavaScript code:
94-
- `eval()`, `Function()` — no dynamic code generation
95-
- `fetch()`, `XMLHttpRequest`, `WebSocket`, `sendBeacon` — no network requests (use RoutineFetchOperation instead)
96-
- `addEventListener()`, `MutationObserver`, `IntersectionObserver` — no persistent event hooks
97-
- `window.close()` — no navigation/lifecycle control
95+
The following are NOT allowed in your JavaScript code:
96+
- `eval()`, `Function()` — no dynamic code generation
97+
- `fetch()`, `XMLHttpRequest`, `WebSocket`, `sendBeacon` — no network requests (use RoutineFetchOperation instead)
98+
- `addEventListener()`, `MutationObserver`, `IntersectionObserver` — no persistent event hooks
99+
- `window.close()` — no navigation/lifecycle control
98100
99-
## Tools
101+
## Tools
100102
101-
- **search_js_files**: Search JS file response bodies by terms
102-
- **get_js_file_detail**: Get full JS file content by request_id
103-
- **get_dom_snapshot**: Get DOM snapshot (latest by default)
104-
- **validate_js_code**: Dry-run validation of JS code
105-
- **submit_js_code**: Submit final validated JS code
106-
- **execute_js_in_browser**: Test your JavaScript code against the live website. Navigates to the URL and executes your IIFE, returning the result and any console output. Use this to verify your code works before submitting.
103+
- **search_js_files**: Search JS file response bodies by terms
104+
- **get_js_file_detail**: Get full JS file content by request_id
105+
- **get_dom_snapshot**: Get DOM snapshot (latest by default)
106+
- **validate_js_code**: Dry-run validation of JS code
107+
- **submit_js_code**: Submit final validated JS code
108+
- **execute_js_in_browser**: Test your JavaScript code against the live website. Navigates to the URL and executes your IIFE, returning the result and any console output. Use this to verify your code works before submitting.
107109
108-
## Guidelines
110+
## Guidelines
109111
110-
- Use `validate_js_code` before `submit_js_code` to catch errors early
111-
- Keep code concise and focused on the specific task
112-
- Use DOM APIs (querySelector, getElementById, etc.) for element interaction
113-
- Use sessionStorage for passing data between operations
114-
"""
112+
- Use `validate_js_code` before `submit_js_code` to catch errors early
113+
- Keep code concise and focused on the specific task
114+
- Use DOM APIs (querySelector, getElementById, etc.) for element interaction
115+
- Use sessionStorage for passing data between operations
116+
""")
115117

116-
AUTONOMOUS_SYSTEM_PROMPT: str = """You are a JavaScript expert that autonomously writes browser DOM manipulation code.
118+
AUTONOMOUS_SYSTEM_PROMPT: str = textwrap.dedent("""\
119+
You are a JavaScript expert that autonomously writes browser DOM manipulation code.
117120
118-
## Your Mission
121+
## Your Mission
119122
120-
Given a task, write IIFE JavaScript code that accomplishes it in the browser context.
123+
Given a task, write IIFE JavaScript code that accomplishes it in the browser context.
121124
122-
## Process
125+
## Process
123126
124-
1. **Understand**: Analyze the task and determine what DOM manipulation is needed
125-
2. **Research**: If JS files are available, search them for relevant APIs or data structures
126-
3. **Check DOM**: Use `get_dom_snapshot` to understand the current page structure
127-
4. **Write**: Write the JavaScript code, validate it, then submit
128-
5. **Finalize**: Call `submit_js_code` with your validated code
127+
1. **Understand**: Analyze the task and determine what DOM manipulation is needed
128+
2. **Research**: If JS files are available, search them for relevant APIs or data structures
129+
3. **Check DOM**: Use `get_dom_snapshot` to understand the current page structure
130+
4. **Write**: Write the JavaScript code, validate it, then submit
131+
5. **Finalize**: Call `submit_js_code` with your validated code
129132
130-
## Code Requirements
133+
## Code Requirements
131134
132-
- IIFE format: `(function() { ... })()` or `(() => { ... })()`
133-
- Blocked: eval, fetch, XMLHttpRequest, WebSocket, sendBeacon, addEventListener, MutationObserver, IntersectionObserver, window.close
134-
- Use `return` to produce output; optionally use `session_storage_key` for cross-operation data
135+
- IIFE format: `(function() { ... })()` or `(() => { ... })()`
136+
- Blocked: eval, fetch, XMLHttpRequest, WebSocket, sendBeacon, addEventListener, MutationObserver, IntersectionObserver, window.close
137+
- Use `return` to produce output; optionally use `session_storage_key` for cross-operation data
135138
136-
## Code Formatting
139+
## Code Formatting
137140
138-
- Write readable, well-formatted JavaScript. Never write extremely long single-line IIFEs.
139-
- Use proper indentation (2 spaces), line breaks between statements, and descriptive variable names.
140-
- Each statement should be on its own line. Complex expressions should be broken across lines.
141+
- Write readable, well-formatted JavaScript. Never write extremely long single-line IIFEs.
142+
- Use proper indentation (2 spaces), line breaks between statements, and descriptive variable names.
143+
- Each statement should be on its own line. Complex expressions should be broken across lines.
141144
142-
## When finalize tools are available
145+
## When finalize tools are available
143146
144-
- **submit_js_code**: Submit your final validated JavaScript code
145-
- **finalize_failure**: Report that the task cannot be accomplished with JS
146-
- **execute_js_in_browser**: Test your JavaScript code against the live website before submitting
147-
"""
147+
- **submit_js_code**: Submit your final validated JavaScript code
148+
- **finalize_failure**: Report that the task cannot be accomplished with JS
149+
- **execute_js_in_browser**: Test your JavaScript code against the live website before submitting
150+
""")
148151

149152
def __init__(
150153
self,

bluebox/llms/infra/js_data_store.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def __init__(self, jsonl_path: str) -> None:
7777
if not path.exists():
7878
raise ValueError(f"JSONL file does not exist: {jsonl_path}")
7979

80-
# Load all entries (no filtering the JS JSONL is already pre-filtered)
80+
# load all entries (no filtering; the JS JSONL is already pre-filtered)
8181
with open(path, mode="r", encoding="utf-8") as f:
8282
for line_num, line in enumerate(f):
8383
line = line.strip()
@@ -215,7 +215,10 @@ def search_by_url(self, pattern: str) -> list[NetworkTransactionEvent]:
215215
Returns:
216216
List of matching NetworkTransactionEvent entries.
217217
"""
218-
return [entry for entry in self._entries if fnmatch.fnmatch(entry.url, pattern)]
218+
return [
219+
entry for entry in self._entries
220+
if fnmatch.fnmatch(entry.url, pattern)
221+
]
219222

220223
def list_files(self) -> list[dict[str, Any]]:
221224
"""

0 commit comments

Comments
 (0)