Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "3.6.0"
".": "3.7.0"
}
8 changes: 4 additions & 4 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 7
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-1c405024b4a17886e921871250a445362463b7ae6070cacc3d1927d59036730c.yml
openapi_spec_hash: c4ea3735257a48ed105002eb7aaa095a
config_hash: 85d56c7c196269badbd0b4a9dfb28d45
configured_endpoints: 8
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-089c8670f1d7c2e9fa8e5c97010db7c24b8f162eb7cfe76ffa41d70fa46efe2f.yml
openapi_spec_hash: 7a226aee8f3f2ab16febbe6bb35e1657
config_hash: 8e4ed6629c178aa0c8aaf575cb07c544
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## 3.7.0 (2026-01-22)

Full Changelog: [v3.6.0...v3.7.0](https://github.com/browserbase/stagehand-php/compare/v3.6.0...v3.7.0)

### Features

* Include replay endpoint in stainless spec so SDK clients can get run metrics ([7aa307a](https://github.com/browserbase/stagehand-php/commit/7aa307a606dab73325780ea7652ed649d5d4ab30))


### Chores

* **internal:** update phpstan comments ([544e99a](https://github.com/browserbase/stagehand-php/commit/544e99a2230737264bbd381c6d4b62974e4df5ed))

## 3.6.0 (2026-01-21)

Full Changelog: [v3.5.0...v3.6.0](https://github.com/browserbase/stagehand-php/compare/v3.5.0...v3.6.0)
Expand Down
13 changes: 11 additions & 2 deletions src/Core/BaseClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,17 @@ public function request(
?string $stream = null,
RequestOptions|array|null $options = [],
): BaseResponse {
// @phpstan-ignore-next-line
[$req, $opts] = $this->buildRequest(method: $method, path: $path, query: $query, headers: $headers, body: $body, opts: $options);
[$req, $opts] = $this->buildRequest(
method: $method,
// @phpstan-ignore argument.type
path: $path,
query: $query,
// @phpstan-ignore argument.type
headers: $headers,
body: $body,
// @phpstan-ignore argument.type
opts: $options,
);
['method' => $method, 'path' => $uri, 'headers' => $headers, 'body' => $data] = $req;
assert(!is_null($opts->requestFactory));

Expand Down
16 changes: 16 additions & 0 deletions src/ServiceContracts/SessionsContract.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Stagehand\Sessions\SessionExtractResponse;
use Stagehand\Sessions\SessionNavigateResponse;
use Stagehand\Sessions\SessionObserveResponse;
use Stagehand\Sessions\SessionReplayResponse;
use Stagehand\Sessions\SessionStartParams\Browser;
use Stagehand\Sessions\SessionStartParams\BrowserbaseSessionCreateParams;
use Stagehand\Sessions\SessionStartResponse;
Expand Down Expand Up @@ -259,6 +260,21 @@ public function observeStream(
RequestOptions|array|null $requestOptions = null,
): BaseStream;

/**
* @api
*
* @param string $id Unique session identifier
* @param \Stagehand\Sessions\SessionReplayParams\XStreamResponse|value-of<\Stagehand\Sessions\SessionReplayParams\XStreamResponse> $xStreamResponse Whether to stream the response via SSE
* @param RequestOpts|null $requestOptions
*
* @throws APIException
*/
public function replay(
string $id,
\Stagehand\Sessions\SessionReplayParams\XStreamResponse|string|null $xStreamResponse = null,
RequestOptions|array|null $requestOptions = null,
): SessionReplayResponse;

/**
* @api
*
Expand Down
19 changes: 19 additions & 0 deletions src/ServiceContracts/SessionsRawContract.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
use Stagehand\Sessions\SessionNavigateResponse;
use Stagehand\Sessions\SessionObserveParams;
use Stagehand\Sessions\SessionObserveResponse;
use Stagehand\Sessions\SessionReplayParams;
use Stagehand\Sessions\SessionReplayResponse;
use Stagehand\Sessions\SessionStartParams;
use Stagehand\Sessions\SessionStartResponse;
use Stagehand\Sessions\StreamEvent;
Expand Down Expand Up @@ -199,6 +201,23 @@ public function observeStream(
RequestOptions|array|null $requestOptions = null,
): BaseResponse;

/**
* @api
*
* @param string $id Unique session identifier
* @param array<string,mixed>|SessionReplayParams $params
* @param RequestOpts|null $requestOptions
*
* @return BaseResponse<SessionReplayResponse>
*
* @throws APIException
*/
public function replay(
string $id,
array|SessionReplayParams $params,
RequestOptions|array|null $requestOptions = null,
): BaseResponse;

/**
* @api
*
Expand Down
40 changes: 40 additions & 0 deletions src/Services/SessionsRawService.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
use Stagehand\Sessions\SessionNavigateResponse;
use Stagehand\Sessions\SessionObserveParams;
use Stagehand\Sessions\SessionObserveResponse;
use Stagehand\Sessions\SessionReplayParams;
use Stagehand\Sessions\SessionReplayResponse;
use Stagehand\Sessions\SessionStartParams;
use Stagehand\Sessions\SessionStartParams\Browser;
use Stagehand\Sessions\SessionStartParams\BrowserbaseSessionCreateParams;
Expand Down Expand Up @@ -535,6 +537,44 @@ public function observeStream(
);
}

/**
* @api
*
* Retrieves replay metrics for a session.
*
* @param string $id Unique session identifier
* @param array{
* xStreamResponse?: SessionReplayParams\XStreamResponse|value-of<SessionReplayParams\XStreamResponse>,
* }|SessionReplayParams $params
* @param RequestOpts|null $requestOptions
*
* @return BaseResponse<SessionReplayResponse>
*
* @throws APIException
*/
public function replay(
string $id,
array|SessionReplayParams $params,
RequestOptions|array|null $requestOptions = null,
): BaseResponse {
[$parsed, $options] = SessionReplayParams::parseRequest(
$params,
$requestOptions,
);

// @phpstan-ignore-next-line return.type
return $this->client->request(
method: 'get',
path: ['v1/sessions/%1$s/replay', $id],
headers: Util::array_transform_keys(
$parsed,
['xStreamResponse' => 'x-stream-response']
),
options: $options,
convert: SessionReplayResponse::class,
);
}

/**
* @api
*
Expand Down
25 changes: 25 additions & 0 deletions src/Services/SessionsService.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use Stagehand\Sessions\SessionExtractResponse;
use Stagehand\Sessions\SessionNavigateResponse;
use Stagehand\Sessions\SessionObserveResponse;
use Stagehand\Sessions\SessionReplayResponse;
use Stagehand\Sessions\SessionStartParams\Browser;
use Stagehand\Sessions\SessionStartParams\BrowserbaseSessionCreateParams;
use Stagehand\Sessions\SessionStartResponse;
Expand Down Expand Up @@ -425,6 +426,30 @@ public function observeStream(
return $response->parse();
}

/**
* @api
*
* Retrieves replay metrics for a session.
*
* @param string $id Unique session identifier
* @param \Stagehand\Sessions\SessionReplayParams\XStreamResponse|value-of<\Stagehand\Sessions\SessionReplayParams\XStreamResponse> $xStreamResponse Whether to stream the response via SSE
* @param RequestOpts|null $requestOptions
*
* @throws APIException
*/
public function replay(
string $id,
\Stagehand\Sessions\SessionReplayParams\XStreamResponse|string|null $xStreamResponse = null,
RequestOptions|array|null $requestOptions = null,
): SessionReplayResponse {
$params = Util::removeNulls(['xStreamResponse' => $xStreamResponse]);

// @phpstan-ignore-next-line argument.type
$response = $this->raw->replay($id, params: $params, requestOptions: $requestOptions);

return $response->parse();
}

/**
* @api
*
Expand Down
71 changes: 71 additions & 0 deletions src/Sessions/SessionReplayParams.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

declare(strict_types=1);

namespace Stagehand\Sessions;

use Stagehand\Core\Attributes\Optional;
use Stagehand\Core\Concerns\SdkModel;
use Stagehand\Core\Concerns\SdkParams;
use Stagehand\Core\Contracts\BaseModel;
use Stagehand\Sessions\SessionReplayParams\XStreamResponse;

/**
* Retrieves replay metrics for a session.
*
* @see Stagehand\Services\SessionsService::replay()
*
* @phpstan-type SessionReplayParamsShape = array{
* xStreamResponse?: null|XStreamResponse|value-of<XStreamResponse>
* }
*/
final class SessionReplayParams implements BaseModel
{
/** @use SdkModel<SessionReplayParamsShape> */
use SdkModel;
use SdkParams;

/**
* Whether to stream the response via SSE.
*
* @var value-of<XStreamResponse>|null $xStreamResponse
*/
#[Optional(enum: XStreamResponse::class)]
public ?string $xStreamResponse;

public function __construct()
{
$this->initialize();
}

/**
* Construct an instance from the required parameters.
*
* You must use named parameters to construct any parameters with a default value.
*
* @param XStreamResponse|value-of<XStreamResponse>|null $xStreamResponse
*/
public static function with(
XStreamResponse|string|null $xStreamResponse = null
): self {
$self = new self;

null !== $xStreamResponse && $self['xStreamResponse'] = $xStreamResponse;

return $self;
}

/**
* Whether to stream the response via SSE.
*
* @param XStreamResponse|value-of<XStreamResponse> $xStreamResponse
*/
public function withXStreamResponse(
XStreamResponse|string $xStreamResponse
): self {
$self = clone $this;
$self['xStreamResponse'] = $xStreamResponse;

return $self;
}
}
15 changes: 15 additions & 0 deletions src/Sessions/SessionReplayParams/XStreamResponse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Stagehand\Sessions\SessionReplayParams;

/**
* Whether to stream the response via SSE.
*/
enum XStreamResponse: string
{
case TRUE = 'true';

case FALSE = 'false';
}
90 changes: 90 additions & 0 deletions src/Sessions/SessionReplayResponse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php

declare(strict_types=1);

namespace Stagehand\Sessions;

use Stagehand\Core\Attributes\Required;
use Stagehand\Core\Concerns\SdkModel;
use Stagehand\Core\Contracts\BaseModel;
use Stagehand\Sessions\SessionReplayResponse\Data;

/**
* @phpstan-import-type DataShape from \Stagehand\Sessions\SessionReplayResponse\Data
*
* @phpstan-type SessionReplayResponseShape = array{
* data: Data|DataShape, success: bool
* }
*/
final class SessionReplayResponse implements BaseModel
{
/** @use SdkModel<SessionReplayResponseShape> */
use SdkModel;

#[Required]
public Data $data;

/**
* Indicates whether the request was successful.
*/
#[Required]
public bool $success;

/**
* `new SessionReplayResponse()` is missing required properties by the API.
*
* To enforce required parameters use
* ```
* SessionReplayResponse::with(data: ..., success: ...)
* ```
*
* Otherwise ensure the following setters are called
*
* ```
* (new SessionReplayResponse)->withData(...)->withSuccess(...)
* ```
*/
public function __construct()
{
$this->initialize();
}

/**
* Construct an instance from the required parameters.
*
* You must use named parameters to construct any parameters with a default value.
*
* @param Data|DataShape $data
*/
public static function with(Data|array $data, bool $success): self
{
$self = new self;

$self['data'] = $data;
$self['success'] = $success;

return $self;
}

/**
* @param Data|DataShape $data
*/
public function withData(Data|array $data): self
{
$self = clone $this;
$self['data'] = $data;

return $self;
}

/**
* Indicates whether the request was successful.
*/
public function withSuccess(bool $success): self
{
$self = clone $this;
$self['success'] = $success;

return $self;
}
}
Loading