speqs 0.6.0 → 0.7.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/dist/commands/simulation.js +66 -1
- package/dist/lib/api-client.d.ts +30 -0
- package/dist/lib/api-client.js +16 -0
- package/dist/lib/local-sim/actions.d.ts +22 -0
- package/dist/lib/local-sim/actions.js +379 -0
- package/dist/lib/local-sim/browser.d.ts +63 -0
- package/dist/lib/local-sim/browser.js +332 -0
- package/dist/lib/local-sim/debug-report.d.ts +21 -0
- package/dist/lib/local-sim/debug-report.js +186 -0
- package/dist/lib/local-sim/debug.d.ts +44 -0
- package/dist/lib/local-sim/debug.js +103 -0
- package/dist/lib/local-sim/install.d.ts +25 -0
- package/dist/lib/local-sim/install.js +72 -0
- package/dist/lib/local-sim/loop.d.ts +60 -0
- package/dist/lib/local-sim/loop.js +526 -0
- package/dist/lib/local-sim/types.d.ts +232 -0
- package/dist/lib/local-sim/types.js +8 -0
- package/dist/lib/local-sim/upload.d.ts +6 -0
- package/dist/lib/local-sim/upload.js +24 -0
- package/package.json +3 -2
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for local browser simulation protocol.
|
|
3
|
+
*
|
|
4
|
+
* Aligned with backend contract (app/api/simulation/local/models.py).
|
|
5
|
+
* CLI captures observations locally, sends to Speqs API for LLM reasoning,
|
|
6
|
+
* receives actions with node_ids, resolves elements locally via CDP.
|
|
7
|
+
*/
|
|
8
|
+
export interface LocalSimInitRequest {
|
|
9
|
+
tester_id: string;
|
|
10
|
+
study_id: string;
|
|
11
|
+
product_id: string;
|
|
12
|
+
iteration_id: string;
|
|
13
|
+
}
|
|
14
|
+
export interface IterationDetails {
|
|
15
|
+
url: string;
|
|
16
|
+
platform: string;
|
|
17
|
+
screen_format: "desktop" | "mobile_portrait";
|
|
18
|
+
locale?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface LocalSimInitResponse {
|
|
21
|
+
tester_id: string;
|
|
22
|
+
study_id: string;
|
|
23
|
+
product_id: string;
|
|
24
|
+
assignments: LocalSimAssignment[];
|
|
25
|
+
tester_background: Record<string, unknown> | null;
|
|
26
|
+
tester_language: string | null;
|
|
27
|
+
config: Record<string, unknown>;
|
|
28
|
+
context_values: ContextValue[];
|
|
29
|
+
max_interactions: number;
|
|
30
|
+
agent_model: string;
|
|
31
|
+
dom_model: string;
|
|
32
|
+
llm_provider: string;
|
|
33
|
+
iteration_details: IterationDetails | null;
|
|
34
|
+
}
|
|
35
|
+
export interface LocalSimAssignment {
|
|
36
|
+
id: string;
|
|
37
|
+
name: string;
|
|
38
|
+
instructions: string;
|
|
39
|
+
sequence: number;
|
|
40
|
+
}
|
|
41
|
+
export interface ContextValue {
|
|
42
|
+
name: string;
|
|
43
|
+
type: "var" | "secret";
|
|
44
|
+
value: string | null;
|
|
45
|
+
description?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface HistoryEntry {
|
|
48
|
+
comment: string;
|
|
49
|
+
action_description: string;
|
|
50
|
+
location: string;
|
|
51
|
+
sentiment: string;
|
|
52
|
+
interacted_with: string | null;
|
|
53
|
+
is_user_instruction?: boolean;
|
|
54
|
+
}
|
|
55
|
+
export interface ForwardEntry {
|
|
56
|
+
type: string;
|
|
57
|
+
content: string;
|
|
58
|
+
}
|
|
59
|
+
export interface LocalSimStepRequest {
|
|
60
|
+
tester_id: string;
|
|
61
|
+
product_id: string;
|
|
62
|
+
assignment_name: string;
|
|
63
|
+
assignment_instructions: string;
|
|
64
|
+
screenshot: string;
|
|
65
|
+
accessibility_tree: string;
|
|
66
|
+
current_url: string;
|
|
67
|
+
screen_width: number;
|
|
68
|
+
screen_height: number;
|
|
69
|
+
interaction_count: number;
|
|
70
|
+
history: HistoryEntry[];
|
|
71
|
+
forwards: ForwardEntry[];
|
|
72
|
+
tester_background: Record<string, unknown> | null;
|
|
73
|
+
tester_language: string | null;
|
|
74
|
+
context_values: ContextValue[];
|
|
75
|
+
agent_model: string | null;
|
|
76
|
+
dom_model: string | null;
|
|
77
|
+
llm_provider: string | null;
|
|
78
|
+
user_instruction?: string | null;
|
|
79
|
+
}
|
|
80
|
+
export interface LocalStepAction {
|
|
81
|
+
type: string;
|
|
82
|
+
element_name: string | null;
|
|
83
|
+
element_description: string | null;
|
|
84
|
+
element_type: string | null;
|
|
85
|
+
node_id: string | null;
|
|
86
|
+
node_description: string | null;
|
|
87
|
+
value: string | null;
|
|
88
|
+
value_type: string | null;
|
|
89
|
+
mode: string | null;
|
|
90
|
+
submit: boolean | null;
|
|
91
|
+
direction: string | null;
|
|
92
|
+
amount: string | null;
|
|
93
|
+
count: number | null;
|
|
94
|
+
duration_ms: number | null;
|
|
95
|
+
thoughts: string | null;
|
|
96
|
+
}
|
|
97
|
+
/** Raw backend step response — output is nested, actions are separate. */
|
|
98
|
+
export interface LocalSimStepResponseRaw {
|
|
99
|
+
output: {
|
|
100
|
+
comment: string;
|
|
101
|
+
sentiment: string;
|
|
102
|
+
sentiment_valence?: number;
|
|
103
|
+
sentiment_intensity?: number;
|
|
104
|
+
current_location: string;
|
|
105
|
+
effort_seconds: number;
|
|
106
|
+
assignment_completed: boolean;
|
|
107
|
+
action: {
|
|
108
|
+
actions: Array<{
|
|
109
|
+
type: string;
|
|
110
|
+
element?: {
|
|
111
|
+
name: string;
|
|
112
|
+
type?: string;
|
|
113
|
+
description?: string;
|
|
114
|
+
};
|
|
115
|
+
value?: string;
|
|
116
|
+
value_type?: string;
|
|
117
|
+
mode?: string;
|
|
118
|
+
submit?: boolean;
|
|
119
|
+
direction?: string;
|
|
120
|
+
amount?: string;
|
|
121
|
+
count?: number;
|
|
122
|
+
duration_ms?: number;
|
|
123
|
+
thoughts?: string;
|
|
124
|
+
}>;
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
resolved_actions: LocalStepAction[];
|
|
128
|
+
loop_detected: boolean;
|
|
129
|
+
}
|
|
130
|
+
/** Normalized step response used by the loop. */
|
|
131
|
+
export interface LocalSimStepResponse {
|
|
132
|
+
comment: string;
|
|
133
|
+
sentiment: string;
|
|
134
|
+
sentiment_valence: number;
|
|
135
|
+
sentiment_intensity: number;
|
|
136
|
+
current_location: string;
|
|
137
|
+
effort_seconds: number;
|
|
138
|
+
assignment_completed: boolean;
|
|
139
|
+
actions: LocalStepAction[];
|
|
140
|
+
loop_detected: boolean;
|
|
141
|
+
}
|
|
142
|
+
export interface SentimentData {
|
|
143
|
+
label: string;
|
|
144
|
+
valence: number;
|
|
145
|
+
intensity: number;
|
|
146
|
+
}
|
|
147
|
+
export interface ActionData {
|
|
148
|
+
action_type: string;
|
|
149
|
+
element_label: string | null;
|
|
150
|
+
element_type: string | null;
|
|
151
|
+
coordinates: {
|
|
152
|
+
x: number;
|
|
153
|
+
y: number;
|
|
154
|
+
} | null;
|
|
155
|
+
data: Record<string, unknown> | null;
|
|
156
|
+
order: number;
|
|
157
|
+
}
|
|
158
|
+
export interface RecordInteraction {
|
|
159
|
+
step: number;
|
|
160
|
+
assignment_id: string;
|
|
161
|
+
screenshot_base64?: string;
|
|
162
|
+
screenshot_url?: string;
|
|
163
|
+
frame_version_id?: string;
|
|
164
|
+
timestamp_ms: number;
|
|
165
|
+
comment: string | null;
|
|
166
|
+
url: string | null;
|
|
167
|
+
sentiment: SentimentData;
|
|
168
|
+
actions: ActionData[];
|
|
169
|
+
current_location: string | null;
|
|
170
|
+
assignment_completed: boolean;
|
|
171
|
+
}
|
|
172
|
+
export interface AssignmentStatusUpdate {
|
|
173
|
+
assignment_id: string;
|
|
174
|
+
status: string;
|
|
175
|
+
step_count: number;
|
|
176
|
+
}
|
|
177
|
+
export interface LocalSimRecordRequest {
|
|
178
|
+
tester_id: string;
|
|
179
|
+
product_id: string;
|
|
180
|
+
interactions: RecordInteraction[];
|
|
181
|
+
final_status: string;
|
|
182
|
+
assignment_statuses: AssignmentStatusUpdate[];
|
|
183
|
+
}
|
|
184
|
+
export interface LocalSimRecordResponse {
|
|
185
|
+
tester_id: string;
|
|
186
|
+
interactions_created: number;
|
|
187
|
+
credits_consumed: number;
|
|
188
|
+
}
|
|
189
|
+
export interface ActionResult {
|
|
190
|
+
success: boolean;
|
|
191
|
+
elementName: string | null;
|
|
192
|
+
coordinates: {
|
|
193
|
+
x: number;
|
|
194
|
+
y: number;
|
|
195
|
+
} | null;
|
|
196
|
+
}
|
|
197
|
+
export interface LocalSimBrowserOptions {
|
|
198
|
+
headed: boolean;
|
|
199
|
+
slowMo?: number;
|
|
200
|
+
devtools?: boolean;
|
|
201
|
+
viewport: {
|
|
202
|
+
width: number;
|
|
203
|
+
height: number;
|
|
204
|
+
};
|
|
205
|
+
locale?: string;
|
|
206
|
+
screenFormat: "desktop" | "mobile_portrait";
|
|
207
|
+
}
|
|
208
|
+
/** Raw accessibility tree data stored for CDP node resolution. */
|
|
209
|
+
export interface TreeData {
|
|
210
|
+
simplified: string;
|
|
211
|
+
nodeMap: Map<string, {
|
|
212
|
+
backendNodeId: number;
|
|
213
|
+
frameIndex: number;
|
|
214
|
+
}>;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Session state cached from init, passed per step.
|
|
218
|
+
* Avoids DB lookups on the backend hot path.
|
|
219
|
+
*/
|
|
220
|
+
export interface SessionState {
|
|
221
|
+
tester_id: string;
|
|
222
|
+
study_id: string;
|
|
223
|
+
product_id: string;
|
|
224
|
+
assignments: LocalSimAssignment[];
|
|
225
|
+
tester_background: Record<string, unknown> | null;
|
|
226
|
+
tester_language: string | null;
|
|
227
|
+
context_values: ContextValue[];
|
|
228
|
+
max_interactions: number;
|
|
229
|
+
agent_model: string;
|
|
230
|
+
dom_model: string;
|
|
231
|
+
llm_provider: string;
|
|
232
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for local browser simulation protocol.
|
|
3
|
+
*
|
|
4
|
+
* Aligned with backend contract (app/api/simulation/local/models.py).
|
|
5
|
+
* CLI captures observations locally, sends to Speqs API for LLM reasoning,
|
|
6
|
+
* receives actions with node_ids, resolves elements locally via CDP.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ApiClient } from "../api-client.js";
|
|
2
|
+
export interface ScreenshotUploadResult {
|
|
3
|
+
screenshotUrl: string;
|
|
4
|
+
screenshotId: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function uploadScreenshot(client: ApiClient, productId: string, jpegBuffer: Buffer): Promise<ScreenshotUploadResult>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
export async function uploadScreenshot(client, productId, jpegBuffer) {
|
|
3
|
+
const screenshotId = randomUUID();
|
|
4
|
+
// Step 1: Get signed URL from backend
|
|
5
|
+
const resp = await client.localSimScreenshotUpload({
|
|
6
|
+
product_id: productId,
|
|
7
|
+
screenshot_id: screenshotId,
|
|
8
|
+
content_type: "image/jpeg",
|
|
9
|
+
});
|
|
10
|
+
// Step 2: PUT raw JPEG bytes directly to Supabase Storage
|
|
11
|
+
const putResp = await fetch(resp.upload_info.signed_upload_url, {
|
|
12
|
+
method: "PUT",
|
|
13
|
+
headers: {
|
|
14
|
+
"Content-Type": "image/jpeg",
|
|
15
|
+
"Content-Length": String(jpegBuffer.byteLength),
|
|
16
|
+
},
|
|
17
|
+
body: jpegBuffer,
|
|
18
|
+
signal: AbortSignal.timeout(30_000),
|
|
19
|
+
});
|
|
20
|
+
if (!putResp.ok) {
|
|
21
|
+
throw new Error(`Screenshot upload failed (HTTP ${putResp.status})`);
|
|
22
|
+
}
|
|
23
|
+
return { screenshotUrl: resp.screenshot_url, screenshotId };
|
|
24
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "speqs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "The command-line interface for Speqs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -33,7 +33,8 @@
|
|
|
33
33
|
"email": "support@speqs.io"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"commander": "^13.0.0"
|
|
36
|
+
"commander": "^13.0.0",
|
|
37
|
+
"playwright-core": "^1.58.2"
|
|
37
38
|
},
|
|
38
39
|
"devDependencies": {
|
|
39
40
|
"@types/node": "^22.0.0",
|