Conversation
There was a problem hiding this comment.
Pull request overview
Adds an “observe → act” replay path to the SDKs, enabling deterministic browser actions by reusing a pre-resolved action object (rather than re-invoking an LLM).
Changes:
- Extend
observe()results to include suggestedmethodandargumentsto support replay. - Add
tab.act(action)overload (TypeScript) and broadenTab.act(...)to accept pre-resolved actions (Python async + generated sync). - Add/adjust tests and release notes (Python changelog + JS changeset).
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| packages/sdk/src/types.ts | Adds method/arguments to observe elements and exports BrowserAction union for replay. |
| packages/sdk/src/index.ts | Re-exports BrowserAction from the SDK entrypoint. |
| packages/sdk/src/client.ts | Adds Tab.act(...) overload to accept either an instruction string or a pre-resolved action body. |
| packages/sdk/src/tests/box-browser.test.ts | Adds coverage ensuring replay posts action (not instruction) and updates observe expectations. |
| packages/python-sdk/upstash_box/types.py | Extends BrowserObserveElement with method/arguments. |
| packages/python-sdk/upstash_box/_sync/client.py | Updates generated sync client act() to accept string or pre-resolved action models. |
| packages/python-sdk/upstash_box/_async/client.py | Updates async client act() to accept string or pre-resolved action models. |
| packages/python-sdk/tests/_async/test_box_browser.py | Adds an async unit test asserting replay posts action deterministically. |
| packages/python-sdk/CHANGELOG.md | Documents the new replay capability and the added observe fields. |
| .changeset/browser-act-replay.md | Adds a changeset entry describing the feature and new exported type. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 22 changed files in this pull request and generated no new comments.
Suppressed comments (5)
packages/sdk/src/client.ts:530
- Do not forward the
BrowserObserveElementverbatim. That public type permitsurl, while Stagehand v4 validates replay actions with a strict schema containing onlyselector,description,method, andarguments; an observed element carryingurlwill therefore make the advertisedobserve()→act(action)flow fail. Build the wire action from only those four fields.
: { action: instructionOrAction, tab: this.id };
packages/python-sdk/upstash_box/_async/client.py:611
- Restrict the serialized replay action to Stagehand v4's strict action fields.
BrowserObserveElementincludesurl, and_Modelalso allows arbitrary extra response fields, so dumping the whole model can send unsupported keys and cause an actualobserve()result to be rejected byact().
body = {"action": instruction.model_dump(exclude_none=True), "tab": self.id}
packages/sdk/src/types.ts:1184
- Keep accepting legacy
"run"markers when reading recording metadata. Recordings are retained for 14 days, so recordings created before this upgrade can still contain these markers; narrowing the type makes the mapper return values outside its declared type and breaks exhaustive consumers. Removingtab.run()only prevents new markers and does not invalidate stored recordings.
/** "tab_switch" (recorder-observed). */
type: "tab_switch";
packages/python-sdk/upstash_box/types.py:822
- Keep
"run"in the deserialization type for legacy recordings. Stored recordings remain available for 14 days, and_map_recording()validates server data through this model, so fetching a pre-upgrade recording containing a run marker will now raise a Pydantic validation error.
# "tab_switch" (recorder-observed).
type: Literal["tab_switch"] = "tab_switch"
packages/python-sdk/upstash_box/_sync/client.py:604
- The generated sync path has the same strict-schema issue: dumping a
BrowserObserveElementforwards its permittedurland any allowed extras, which Stagehand v4 rejects for replay actions. Filter to the four action fields in_async/client.py, then regenerate this file rather than editing it directly.
body = {"action": instruction.model_dump(exclude_none=True), "tab": self.id}
No description provided.