Skip to content

Commit ad64eeb

Browse files
shnpdcursoragent
andcommitted
fix(protocol): align Trace v2/v3 classification and hover steps
Require Trace v3 version const 3, reject mixed pages/states payloads, and align TypeScript selection optionality with the generated schema. Trace v2 on main already records hover steps, so the frozen v2 schema must accept them instead of dropping them during reduction. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 28b8a57 commit ad64eeb

9 files changed

Lines changed: 234 additions & 31 deletions

File tree

apps/extension/src/lib/__tests__/trace-reducer.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ describe("reduceTraceSteps", () => {
130130
});
131131
});
132132

133-
it("drops hover steps unsupported by historical v2 clients", () => {
133+
it("keeps hover steps before menu clicks", () => {
134134
const { steps } = reduceTraceSteps(
135135
[
136136
{
@@ -146,11 +146,11 @@ describe("reduceTraceSteps", () => {
146146
],
147147
"https://example.com/app",
148148
);
149-
expect(steps.map((s) => s.op)).toEqual(["click"]);
149+
expect(steps.map((s) => s.op)).toEqual(["hover", "click"]);
150150
expect(steps[0]).toMatchObject({
151-
op: "click",
151+
op: "hover",
152152
page: "p1",
153-
target: { name: "Profile" },
153+
target: { name: "Account" },
154154
});
155155
});
156156

apps/extension/src/lib/trace-reducer.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ export function shouldRecordPress(
1818
}
1919

2020
function shouldIncludeDraft(step: DraftTraceStep): boolean {
21-
if (step.op === "hover") return false;
2221
if (step.op === "fill" && !(step.value ?? "").trim() && !step.redacted) return false;
2322
if (step.op === "press" && !shouldRecordPress(step.key, step.modifiers)) return false;
2423
return true;
@@ -141,7 +140,12 @@ function toV2Step(
141140
effectForNavigation(step.navigated_to, urlToId),
142141
);
143142
case "hover":
144-
return null;
143+
return {
144+
op: "hover",
145+
id,
146+
page,
147+
target: step.target,
148+
};
145149
case "fill":
146150
return {
147151
op: "fill",

apps/extension/src/transport/types.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,7 @@ export type DraftTraceStep =
793793
export type Step =
794794
| ({ op: "navigate" } & StepCommon & { to: string })
795795
| ({ op: "click" } & StepCommon & { target: TargetDescriptor })
796+
| ({ op: "hover" } & StepCommon & { target: TargetDescriptor })
796797
| ({ op: "fill" } & StepCommon & {
797798
target: TargetDescriptor;
798799
value: string;
@@ -834,7 +835,7 @@ export type StepV3 =
834835
})
835836
| ({ op: "select" } & StepCommonV3 & {
836837
target: TargetDescriptorV3;
837-
selection: SelectedOption[];
838+
selection?: SelectedOption[];
838839
})
839840
| ({ op: "press" } & StepCommonV3 & {
840841
key: string;
@@ -844,7 +845,7 @@ export type StepV3 =
844845
| ({ op: "scroll" } & StepCommonV3);
845846

846847
export interface TraceV3 {
847-
version: number;
848+
version: 3;
848849
recorded_at: string;
849850
started_at?: string;
850851
purpose?: string;

crates/bsk-protocol/schema/tool_record_await_result.json

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,46 @@
512512
}
513513
}
514514
},
515+
{
516+
"description": "Fields shared by every v2 step variant (flattened in JSON).",
517+
"type": "object",
518+
"required": [
519+
"id",
520+
"op",
521+
"page",
522+
"target"
523+
],
524+
"properties": {
525+
"effect": {
526+
"anyOf": [
527+
{
528+
"$ref": "#/definitions/StepEffectV2"
529+
},
530+
{
531+
"type": "null"
532+
}
533+
]
534+
},
535+
"id": {
536+
"type": "integer",
537+
"format": "uint32",
538+
"minimum": 0.0
539+
},
540+
"op": {
541+
"type": "string",
542+
"enum": [
543+
"hover"
544+
]
545+
},
546+
"page": {
547+
"description": "Reference into `pages[]`.",
548+
"type": "string"
549+
},
550+
"target": {
551+
"$ref": "#/definitions/TargetDescriptorV2"
552+
}
553+
}
554+
},
515555
{
516556
"description": "Fields shared by every v2 step variant (flattened in JSON).",
517557
"type": "object",
@@ -803,10 +843,10 @@
803843
},
804844
"version": {
805845
"type": "integer",
806-
"format": "uint32",
807-
"minimum": 0.0
846+
"const": 3
808847
}
809-
}
848+
},
849+
"additionalProperties": false
810850
},
811851
"TraceEntry": {
812852
"description": "Recording entry point — first URL the flow starts from.",
@@ -900,7 +940,8 @@
900940
"$ref": "#/definitions/StepV2"
901941
}
902942
}
903-
}
943+
},
944+
"additionalProperties": false
904945
}
905946
}
906947
}

crates/bsk-protocol/schema/tool_record_stop_result.json

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,46 @@
512512
}
513513
}
514514
},
515+
{
516+
"description": "Fields shared by every v2 step variant (flattened in JSON).",
517+
"type": "object",
518+
"required": [
519+
"id",
520+
"op",
521+
"page",
522+
"target"
523+
],
524+
"properties": {
525+
"effect": {
526+
"anyOf": [
527+
{
528+
"$ref": "#/definitions/StepEffectV2"
529+
},
530+
{
531+
"type": "null"
532+
}
533+
]
534+
},
535+
"id": {
536+
"type": "integer",
537+
"format": "uint32",
538+
"minimum": 0.0
539+
},
540+
"op": {
541+
"type": "string",
542+
"enum": [
543+
"hover"
544+
]
545+
},
546+
"page": {
547+
"description": "Reference into `pages[]`.",
548+
"type": "string"
549+
},
550+
"target": {
551+
"$ref": "#/definitions/TargetDescriptorV2"
552+
}
553+
}
554+
},
515555
{
516556
"description": "Fields shared by every v2 step variant (flattened in JSON).",
517557
"type": "object",
@@ -803,10 +843,10 @@
803843
},
804844
"version": {
805845
"type": "integer",
806-
"format": "uint32",
807-
"minimum": 0.0
846+
"const": 3
808847
}
809-
}
848+
},
849+
"additionalProperties": false
810850
},
811851
"TraceEntry": {
812852
"description": "Recording entry point — first URL the flow starts from.",
@@ -900,7 +940,8 @@
900940
"$ref": "#/definitions/StepV2"
901941
}
902942
}
903-
}
943+
},
944+
"additionalProperties": false
904945
}
905946
}
906947
}

crates/bsk-protocol/schema/trace.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@
5151
},
5252
"version": {
5353
"type": "integer",
54-
"format": "uint32",
55-
"minimum": 0.0
54+
"const": 3
5655
}
5756
},
57+
"additionalProperties": false,
5858
"definitions": {
5959
"FillCommit": {
6060
"type": "string",

crates/bsk-protocol/schema/trace_v2.json

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
}
4343
}
4444
},
45+
"additionalProperties": false,
4546
"definitions": {
4647
"KeyModifier": {
4748
"description": "Keyboard modifier flags. Multiple flags may be combined; the extension folds them into CDP's bitfield (`alt=1, ctrl=2, meta=4, shift=8`).",
@@ -189,6 +190,46 @@
189190
}
190191
}
191192
},
193+
{
194+
"description": "Fields shared by every v2 step variant (flattened in JSON).",
195+
"type": "object",
196+
"required": [
197+
"id",
198+
"op",
199+
"page",
200+
"target"
201+
],
202+
"properties": {
203+
"effect": {
204+
"anyOf": [
205+
{
206+
"$ref": "#/definitions/StepEffectV2"
207+
},
208+
{
209+
"type": "null"
210+
}
211+
]
212+
},
213+
"id": {
214+
"type": "integer",
215+
"format": "uint32",
216+
"minimum": 0.0
217+
},
218+
"op": {
219+
"type": "string",
220+
"enum": [
221+
"hover"
222+
]
223+
},
224+
"page": {
225+
"description": "Reference into `pages[]`.",
226+
"type": "string"
227+
},
228+
"target": {
229+
"$ref": "#/definitions/TargetDescriptorV2"
230+
}
231+
}
232+
},
192233
{
193234
"description": "Fields shared by every v2 step variant (flattened in JSON).",
194235
"type": "object",

0 commit comments

Comments
 (0)