diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 10f3091..6b7b74c 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.2.0" + ".": "0.3.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 36782ae..f4f95e8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-705638ac8966569986bd9ebb7c9761bf0016909e9f2753e77ceabb12c8049511.yml -openapi_spec_hash: a8fbbcaa38e91c7f97313620b42d8d62 -config_hash: a35b56eb05306a0f02e83c11d57f975f +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-39cd9547d16412cf0568f6ce2ad8d43805dffe65bde830beeff630b903ae3b38.yml +openapi_spec_hash: 9cd7c9fefa686f9711392782d948470f +config_hash: 1f709f8775e13029dc60064ef3a94355 diff --git a/CHANGELOG.md b/CHANGELOG.md index d4bfbb5..9c1d4fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,51 @@ # Changelog +## 0.3.0 (2026-01-07) + +Full Changelog: [v0.2.0...v0.3.0](https://github.com/browserbase/stagehand-php/compare/v0.2.0...v0.3.0) + +### ⚠ BREAKING CHANGES + +* use aliases for phpstan types + +### Features + +* [STG-1053] [server] Use fastify-zod-openapi + zod v4 for openapi generation ([3d7bdf5](https://github.com/browserbase/stagehand-php/commit/3d7bdf5f97754c73ae6eb48ea8349f2c8ffc66a8)) +* Added optional param to force empty object ([7405f84](https://github.com/browserbase/stagehand-php/commit/7405f84d11aec0e4d031da5cce447fe841c77ec3)) +* **api:** manual updates ([9cdfcfd](https://github.com/browserbase/stagehand-php/commit/9cdfcfd1bcbdce9a8c9320b5efac239e5ee8cf6c)) +* **api:** manual updates ([68fe598](https://github.com/browserbase/stagehand-php/commit/68fe598df0ac0f73aa8806ed4730bd4c479f54a6)) +* **api:** manual updates ([c1b5c85](https://github.com/browserbase/stagehand-php/commit/c1b5c857aa25cd839ce1ce448d7148e4eccdffe8)) +* **api:** manual updates ([bbf2825](https://github.com/browserbase/stagehand-php/commit/bbf28250640bcdeaf02f2a40ef93802d7630990d)) +* **api:** manual updates ([f5b7983](https://github.com/browserbase/stagehand-php/commit/f5b7983cab846df088bddc707aa1c8fdaf9d1952)) +* **api:** manual updates ([7d51568](https://github.com/browserbase/stagehand-php/commit/7d515687b0aca206c9124b270a4f1f0ab84fe467)) +* **api:** manual updates ([3aac7a3](https://github.com/browserbase/stagehand-php/commit/3aac7a31a6a32ef739f918fba6effb6081b7c10a)) +* **api:** manual updates ([0501932](https://github.com/browserbase/stagehand-php/commit/050193250e7e1092ba83b97d4735e80328492188)) +* **api:** manual updates ([2748aea](https://github.com/browserbase/stagehand-php/commit/2748aea3da35936913f4643a70fb2aff6f61a562)) +* **api:** manual updates ([7715406](https://github.com/browserbase/stagehand-php/commit/771540668a5d44d36d65b566b8c1cacfc1a0312d)) +* **api:** manual updates ([9c9d8f7](https://github.com/browserbase/stagehand-php/commit/9c9d8f74c362253e3494407a8de53713079ff3d9)) +* **api:** manual updates ([8dac4ee](https://github.com/browserbase/stagehand-php/commit/8dac4ee0f673830cc9f31e6c7971cd6bbf1f049f)) +* improved phpstan type annotations ([95004df](https://github.com/browserbase/stagehand-php/commit/95004df5bf286d7fc8942781a6e69a56e6cefe53)) +* use aliases for phpstan types ([7a4328b](https://github.com/browserbase/stagehand-php/commit/7a4328bfa32b6475cb2cbf1da56cb9d2d1fef514)) + + +### Bug Fixes + +* support arrays in query param construction ([4b195d7](https://github.com/browserbase/stagehand-php/commit/4b195d7ecfae72625b33ce440cd9bb83aa6deeea)) + + +### Chores + +* **internal:** codegen related update ([79b8f76](https://github.com/browserbase/stagehand-php/commit/79b8f76ee409f5a35cc742496109e803138554b1)) +* **internal:** codegen related update ([96c0813](https://github.com/browserbase/stagehand-php/commit/96c0813ae699b18ce127aa6f693009cc2f3d63b2)) +* **internal:** codegen related update ([3ce08d1](https://github.com/browserbase/stagehand-php/commit/3ce08d172eba2c771edcd7d7cd81fdc461547c8b)) +* **internal:** codegen related update ([8935e42](https://github.com/browserbase/stagehand-php/commit/8935e42bd30fb4d0a81a211b11c098181404e360)) +* **internal:** refactor auth by moving concern from base client into client ([ccced14](https://github.com/browserbase/stagehand-php/commit/ccced14ea53cfa8120ab9226eb84465703eb7f63)) + + +### Documentation + +* add more examples ([1a0904d](https://github.com/browserbase/stagehand-php/commit/1a0904d4498d41422c6a341ffdbcefcb9f5710c1)) + ## 0.2.0 (2025-12-16) Full Changelog: [v0.1.0...v0.2.0](https://github.com/browserbase/stagehand-php/compare/v0.1.0...v0.2.0) diff --git a/LICENSE b/LICENSE index 6b24314..d15d021 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2025 Stagehand + Copyright 2026 Stagehand Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index e045f4e..a345c11 100644 --- a/README.md +++ b/README.md @@ -60,15 +60,42 @@ $response = $client->sessions->act( input: 'click the first link on the page', ); -var_dump($response->actions); +var_dump($response->data); ``` ### Value Objects -It is recommended to use the static `with` constructor `Action::with(arguments: ['string'], ...)` +It is recommended to use the static `with` constructor `Action::with(description: 'Click the submit button', ...)` and named parameters to initialize value objects. -However, builders are also provided `(new Action)->withArguments(['string'])`. +However, builders are also provided `(new Action)->withDescription('Click the submit button')`. + +### Streaming + +We provide support for streaming responses using Server-Sent Events (SSE). + +```php +sessions->actStream( + '00000000-your-session-id-000000000000', + input: 'click the first link on the page', +); + +foreach ($stream as $response) { + var_dump($response); +} +``` ### Handling errors @@ -80,10 +107,7 @@ When the library is unable to connect to the API, or if the API returns a non-su use Stagehand\Core\Exceptions\APIConnectionException; try { - $response = $client->sessions->start( - browserbaseAPIKey: 'your Browserbase API key', - browserbaseProjectID: 'your Browserbase Project ID', - ); + $response = $client->sessions->start(modelName: 'openai/gpt-5-nano'); } catch (APIConnectionException $e) { echo "The server could not be reached", PHP_EOL; var_dump($e->getPrevious()); @@ -130,8 +154,7 @@ $client = new Client(maxRetries: 0); // Or, configure per-request: $result = $client->sessions->start( - browserbaseAPIKey: 'your Browserbase API key', - browserbaseProjectID: 'your Browserbase Project ID', + modelName: 'openai/gpt-5-nano', requestOptions: RequestOptions::with(maxRetries: 5), ); ``` @@ -152,8 +175,7 @@ Note: the `extra*` parameters of the same name overrides the documented paramete use Stagehand\RequestOptions; $response = $client->sessions->start( - browserbaseAPIKey: 'your Browserbase API key', - browserbaseProjectID: 'your Browserbase Project ID', + modelName: 'openai/gpt-5-nano', requestOptions: RequestOptions::with( extraQueryParams: ['my_query_parameter' => 'value'], extraBodyParams: ['my_body_parameter' => 'value'], diff --git a/src/Client.php b/src/Client.php index 2629b4d..6358a75 100644 --- a/src/Client.php +++ b/src/Client.php @@ -10,6 +10,10 @@ use Stagehand\Core\Util; use Stagehand\Services\SessionsService; +/** + * @phpstan-import-type NormalizedRequest from \Stagehand\Core\BaseClient + * @phpstan-import-type RequestOpts from \Stagehand\RequestOptions + */ class Client extends BaseClient { public string $browserbaseAPIKey; @@ -35,7 +39,7 @@ public function __construct( $baseUrl ??= getenv( 'STAGEHAND_BASE_URL' - ) ?: 'https://api.stagehand.browserbase.com/v1'; + ) ?: 'https://api.stagehand.browserbase.com'; $options = RequestOptions::with( uriFactory: Psr17FactoryDiscovery::findUriFactory(), @@ -63,6 +67,16 @@ public function __construct( $this->sessions = new SessionsService($this); } + /** @return array */ + protected function authHeaders(): array + { + return [ + ...$this->bbAPIKeyAuth(), + ...$this->bbProjectIDAuth(), + ...$this->llmModelAPIKeyAuth(), + ]; + } + /** @return array */ protected function bbAPIKeyAuth(): array { @@ -84,4 +98,32 @@ protected function llmModelAPIKeyAuth(): array { return $this->modelAPIKey ? ['x-model-api-key' => $this->modelAPIKey] : []; } + + /** + * @internal + * + * @param string|list $path + * @param array $query + * @param array|null> $headers + * @param RequestOpts|null $opts + * + * @return array{NormalizedRequest, RequestOptions} + */ + protected function buildRequest( + string $method, + string|array $path, + array $query, + array $headers, + mixed $body, + RequestOptions|array|null $opts, + ): array { + return parent::buildRequest( + method: $method, + path: $path, + query: $query, + headers: [...$this->authHeaders(), ...$headers], + body: $body, + opts: $opts, + ); + } } diff --git a/src/Core/BaseClient.php b/src/Core/BaseClient.php index 36371fb..eb7c6dd 100644 --- a/src/Core/BaseClient.php +++ b/src/Core/BaseClient.php @@ -5,12 +5,8 @@ namespace Stagehand\Core; use Psr\Http\Client\ClientExceptionInterface; -use Psr\Http\Client\ClientInterface; -use Psr\Http\Message\RequestFactoryInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; -use Psr\Http\Message\StreamFactoryInterface; -use Psr\Http\Message\UriFactoryInterface; use Psr\Http\Message\UriInterface; use Stagehand\Core\Contracts\BasePage; use Stagehand\Core\Contracts\BaseResponse; @@ -23,7 +19,9 @@ use Stagehand\RequestOptions; /** - * @phpstan-type normalized_request = array{ + * @phpstan-import-type RequestOpts from \Stagehand\RequestOptions + * + * @phpstan-type NormalizedRequest = array{ * method: string, * path: string, * query: array, @@ -80,6 +78,7 @@ public function request( $request = $opts->requestFactory->createRequest($method, uri: $uri); $request = Util::withSetHeaders($request, headers: $headers); + $request = $this->transformRequest($request); // @phpstan-ignore-next-line argument.type $rsp = $this->sendRequest($opts, req: $request, data: $data, redirectCount: 0, retryCount: 0); @@ -88,25 +87,6 @@ public function request( return new RawResponse(client: $this, request: $request, response: $rsp, options: $opts, requestInfo: $req, unwrap: $unwrap, stream: $stream, page: $page, convert: $convert ?? 'null'); } - /** @return array */ - protected function authHeaders(): array - { - return [ - ...$this->bbAPIKeyAuth(), - ...$this->bbProjectIDAuth(), - ...$this->llmModelAPIKeyAuth(), - ]; - } - - /** @return array */ - abstract protected function bbAPIKeyAuth(): array; - - /** @return array */ - abstract protected function bbProjectIDAuth(): array; - - /** @return array */ - abstract protected function llmModelAPIKeyAuth(): array; - /** * @internal */ @@ -123,21 +103,9 @@ protected function generateIdempotencyKey(): string * @param string|list $path * @param array $query * @param array|null> $headers - * @param array{ - * timeout?: float|null, - * maxRetries?: int|null, - * initialRetryDelay?: float|null, - * maxRetryDelay?: float|null, - * extraHeaders?: array|null>|null, - * extraQueryParams?: array|null, - * extraBodyParams?: mixed, - * transporter?: ClientInterface|null, - * uriFactory?: UriFactoryInterface|null, - * streamFactory?: StreamFactoryInterface|null, - * requestFactory?: RequestFactoryInterface|null, - * }|null $opts + * @param RequestOpts|null $opts * - * @return array{normalized_request, RequestOptions} + * @return array{NormalizedRequest, RequestOptions} */ protected function buildRequest( string $method, @@ -164,7 +132,6 @@ protected function buildRequest( /** @var array|null> $mergedHeaders */ $mergedHeaders = [ ...$this->headers, - ...$this->authHeaders(), ...$headers, ...($options->extraHeaders ?? []), ...$idempotencyHeaders, @@ -175,6 +142,12 @@ protected function buildRequest( return [$req, $options]; } + protected function transformRequest( + RequestInterface $request + ): RequestInterface { + return $request; + } + /** * @internal */ diff --git a/src/Core/Concerns/SdkModel.php b/src/Core/Concerns/SdkModel.php index 96f7f65..dc02763 100644 --- a/src/Core/Concerns/SdkModel.php +++ b/src/Core/Concerns/SdkModel.php @@ -75,8 +75,6 @@ public function __toString(): string * a native class property, indicating an omitted value, * or a property overridden with an incongruent type * - * @return value-of - * * @throws \Exception */ public function __get(string $key): mixed diff --git a/src/Core/Concerns/SdkPage.php b/src/Core/Concerns/SdkPage.php index 19bd4f2..9bdf711 100644 --- a/src/Core/Concerns/SdkPage.php +++ b/src/Core/Concerns/SdkPage.php @@ -12,6 +12,8 @@ use Stagehand\RequestOptions; /** + * @phpstan-import-type NormalizedRequest from \Stagehand\Core\BaseClient + * * @internal * * @template Item @@ -94,7 +96,7 @@ public function pagingEachItem(): \Generator /** * @internal * - * @return array{normalized_request, RequestOptions} + * @return array{NormalizedRequest, RequestOptions} */ abstract protected function nextRequest(): ?array; } diff --git a/src/Core/Concerns/SdkStream.php b/src/Core/Concerns/SdkStream.php new file mode 100644 index 0000000..4af482b --- /dev/null +++ b/src/Core/Concerns/SdkStream.php @@ -0,0 +1,57 @@ + + */ +trait SdkStream +{ + /** @var \Generator */ + protected \Generator $stream; + + /** @var \Generator */ + private \Generator $generator; + + public function __construct( + protected string|Converter|ConverterSource $convert, + protected RequestInterface $request, + protected ResponseInterface $response, + protected mixed $parsedBody, + ) { + // @phpstan-ignore-next-line + $this->stream = $parsedBody; + $this->generator = $this->parsedGenerator(); + } + + /** @return \Iterator */ + public function getIterator(): \Iterator + { + return $this->generator; + } + + public function close(): void + { + try { + $this->stream->throw(new IteratorExit); + } catch (IteratorExit $_) { + // IteratorExit shouldn't be noticed. + return; + } + } + + /** @return \Generator $stream */ + abstract private function parsedGenerator(): \Generator; +} diff --git a/src/Core/Contracts/BasePage.php b/src/Core/Contracts/BasePage.php index 2afa086..13e1301 100644 --- a/src/Core/Contracts/BasePage.php +++ b/src/Core/Contracts/BasePage.php @@ -5,9 +5,9 @@ namespace Stagehand\Core\Contracts; /** - * @internal + * @phpstan-import-type NormalizedRequest from \Stagehand\Core\BaseClient * - * @phpstan-import-type normalized_request from \Stagehand\Core\BaseClient + * @internal * * @template Item * diff --git a/src/Core/Implementation/IteratorExit.php b/src/Core/Implementation/IteratorExit.php new file mode 100644 index 0000000..483976e --- /dev/null +++ b/src/Core/Implementation/IteratorExit.php @@ -0,0 +1,5 @@ + - * - * @phpstan-import-type normalized_request from \Stagehand\Core\BaseClient */ class RawResponse implements BaseResponse { @@ -35,7 +35,7 @@ class RawResponse implements BaseResponse private bool $coerced = false; /** - * @param normalized_request $requestInfo + * @param NormalizedRequest $requestInfo * @param list|string|int|null $unwrap */ public function __construct( diff --git a/src/Core/Util.php b/src/Core/Util.php index f70edca..ccc5941 100644 --- a/src/Core/Util.php +++ b/src/Core/Util.php @@ -87,6 +87,20 @@ public static function array_filter_omit(array $arr): array return array_filter($arr, fn ($v, $_) => OMIT !== $v, mode: ARRAY_FILTER_USE_BOTH); } + public static function strVal(mixed $value): string + { + if (is_bool($value)) { + return $value ? 'true' : 'false'; + } + + if (is_object($value) && is_a($value, class: \DateTimeInterface::class)) { + return date_format($value, format: \DateTimeInterface::RFC3339); + } + + // @phpstan-ignore-next-line argument.type + return strval($value); + } + /** * @param callable $callback */ @@ -185,7 +199,12 @@ public static function joinUri( parse_str($parsed['query'] ?? '', $q2); $mergedQuery = array_merge_recursive($q1, $q2, $query); - $normalizedQuery = array_map(static fn ($v) => self::strVal($v), array: $mergedQuery); + + /** @var array */ + $normalizedQuery = self::mapRecursive( + static fn ($v) => is_bool($v) || is_numeric($v) ? self::strVal($v) : $v, + value: $mergedQuery + ); $qs = http_build_query($normalizedQuery, encoding_type: PHP_QUERY_RFC3986); return $base->withQuery($qs); @@ -409,20 +428,6 @@ public static function prettyEncodeJson(mixed $obj): string return json_encode($obj, flags: JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) ?: ''; } - private static function strVal(mixed $value): string - { - if (is_bool($value)) { - return $value ? 'true' : 'false'; - } - - if (is_object($value) && is_a($value, class: \DateTimeInterface::class)) { - return date_format($value, format: \DateTimeInterface::RFC3339); - } - - // @phpstan-ignore-next-line argument.type - return strval($value); - } - /** * @param list $closing * diff --git a/src/RequestOptions.php b/src/RequestOptions.php index 621af75..5b6dc2f 100644 --- a/src/RequestOptions.php +++ b/src/RequestOptions.php @@ -17,7 +17,7 @@ use const Stagehand\Core\OMIT as omit; /** - * @phpstan-type request_options = array{ + * @phpstan-type RequestOptionShape = array{ * timeout?: float|null, * maxRetries?: int|null, * initialRetryDelay?: float|null, @@ -30,11 +30,11 @@ * streamFactory?: StreamFactoryInterface|null, * requestFactory?: RequestFactoryInterface|null, * } - * @phpstan-type request_opts = null|RequestOptions|request_options + * @phpstan-type RequestOpts = null|RequestOptions|RequestOptionShape */ final class RequestOptions implements BaseModel { - /** @use SdkModel */ + /** @use SdkModel */ use SdkModel; #[Property] @@ -78,7 +78,7 @@ public function __construct() } /** - * @param request_opts|null $options + * @param RequestOpts|null $options */ public static function parse(RequestOptions|array|null ...$options): self { diff --git a/src/SSEStream.php b/src/SSEStream.php new file mode 100644 index 0000000..ee5b5a2 --- /dev/null +++ b/src/SSEStream.php @@ -0,0 +1,77 @@ + + */ +final class SSEStream implements BaseStream +{ + /** + * @use SdkStream + */ + use SdkStream; + + private function parsedGenerator(): \Generator + { + if (!$this->stream->valid()) { + return; + } + + $done = false; + foreach ($this->stream as $row) { + // @phpstan-ignore if.alwaysFalse + if ($done) { + // Iterate through the whole stream + continue; + } + + switch ($row['event'] ?? null) { + case null: + if ($data = $row['data'] ?? '') { + $decoded = Util::decodeJson($data); + + yield Conversion::coerce($this->convert, value: $decoded); + } + + break; + } + + if ($data = $row['data'] ?? '') { + if (str_starts_with($data, needle: 'finished')) { + $done = true; + + continue; + } + + if (str_starts_with($data, needle: 'error')) { + if ($data = $row['data'] ?? '') { + $json = Util::decodeJson($data); + $message = Util::prettyEncodeJson($json); + + $exn = APIStatusException::from( + request: $this->request, + response: $this->response, + message: $message, + ); + + throw $exn; + } + + continue; + } + } + } + } +} diff --git a/src/ServiceContracts/SessionsContract.php b/src/ServiceContracts/SessionsContract.php index c2f3698..aa6235e 100644 --- a/src/ServiceContracts/SessionsContract.php +++ b/src/ServiceContracts/SessionsContract.php @@ -4,207 +4,484 @@ namespace Stagehand\ServiceContracts; +use Stagehand\Core\Contracts\BaseStream; use Stagehand\Core\Exceptions\APIException; use Stagehand\RequestOptions; -use Stagehand\Sessions\Action; +use Stagehand\Sessions\ModelConfig\ModelConfigObject\Provider; +use Stagehand\Sessions\SessionActParams\XLanguage; use Stagehand\Sessions\SessionActParams\XStreamResponse; use Stagehand\Sessions\SessionActResponse; use Stagehand\Sessions\SessionEndResponse; -use Stagehand\Sessions\SessionExecuteAgentParams\AgentConfig\Provider; -use Stagehand\Sessions\SessionExecuteAgentResponse; -use Stagehand\Sessions\SessionExtractResponse\Extraction; +use Stagehand\Sessions\SessionExecuteResponse; +use Stagehand\Sessions\SessionExtractResponse; use Stagehand\Sessions\SessionNavigateParams\Options\WaitUntil; use Stagehand\Sessions\SessionNavigateResponse; +use Stagehand\Sessions\SessionObserveResponse; +use Stagehand\Sessions\SessionStartParams\Browser\Type; +use Stagehand\Sessions\SessionStartParams\BrowserbaseSessionCreateParams\BrowserSettings\Fingerprint\Browser; +use Stagehand\Sessions\SessionStartParams\BrowserbaseSessionCreateParams\BrowserSettings\Fingerprint\Device; +use Stagehand\Sessions\SessionStartParams\BrowserbaseSessionCreateParams\BrowserSettings\Fingerprint\HTTPVersion; +use Stagehand\Sessions\SessionStartParams\BrowserbaseSessionCreateParams\BrowserSettings\Fingerprint\OperatingSystem; +use Stagehand\Sessions\SessionStartParams\BrowserbaseSessionCreateParams\Region; use Stagehand\Sessions\SessionStartResponse; +use Stagehand\Sessions\StreamEvent; interface SessionsContract { /** * @api * - * @param string $sessionID Path param: The session ID returned by /sessions/start + * @param string $id Path param: Unique session identifier * @param string|array{ - * arguments: list, * description: string, - * method: string, * selector: string, - * backendNodeID?: int, - * }|Action $input Body param: Natural language instruction - * @param string $frameID Body param: Frame ID to act on (optional) + * arguments?: list, + * backendNodeID?: float, + * method?: string, + * } $input Body param: Natural language instruction or Action object + * @param string $frameID Body param: Target frame ID for the action * @param array{ - * model?: array{ + * model?: string|array{ + * modelName: string, * apiKey?: string, * baseURL?: string, - * model?: string, - * provider?: 'openai'|'anthropic'|'google'|\Stagehand\Sessions\ModelConfig\Provider, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|Provider, * }, - * timeout?: int, + * timeout?: float, * variables?: array, * } $options Body param: - * @param 'true'|'false'|XStreamResponse $xStreamResponse Header param: Enable Server-Sent Events streaming for real-time logs + * @param 'typescript'|'python'|'playground'|XLanguage $xLanguage Header param: Client SDK language + * @param string $xSDKVersion Header param: Version of the Stagehand SDK + * @param string|\DateTimeInterface $xSentAt Header param: ISO timestamp when request was sent + * @param 'true'|'false'|XStreamResponse $xStreamResponse Header param: Whether to stream the response via SSE * * @throws APIException */ public function act( - string $sessionID, - string|array|Action $input, + string $id, + string|array $input, ?string $frameID = null, ?array $options = null, - string|XStreamResponse $xStreamResponse = 'true', + string|XLanguage|null $xLanguage = null, + ?string $xSDKVersion = null, + string|\DateTimeInterface|null $xSentAt = null, + string|XStreamResponse|null $xStreamResponse = null, ?RequestOptions $requestOptions = null, ): SessionActResponse; /** * @api * - * @param string $sessionID The session ID returned by /sessions/start + * @param string $id Path param: Unique session identifier + * @param string|array{ + * description: string, + * selector: string, + * arguments?: list, + * backendNodeID?: float, + * method?: string, + * } $input Body param: Natural language instruction or Action object + * @param string $frameID Body param: Target frame ID for the action + * @param array{ + * model?: string|array{ + * modelName: string, + * apiKey?: string, + * baseURL?: string, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|Provider, + * }, + * timeout?: float, + * variables?: array, + * } $options Body param: + * @param 'typescript'|'python'|'playground'|XLanguage $xLanguage Header param: Client SDK language + * @param string $xSDKVersion Header param: Version of the Stagehand SDK + * @param string|\DateTimeInterface $xSentAt Header param: ISO timestamp when request was sent + * @param 'true'|'false'|XStreamResponse $xStreamResponse Header param: Whether to stream the response via SSE + * + * @return BaseStream + * + * @throws APIException + */ + public function actStream( + string $id, + string|array $input, + ?string $frameID = null, + ?array $options = null, + string|XLanguage|null $xLanguage = null, + ?string $xSDKVersion = null, + string|\DateTimeInterface|null $xSentAt = null, + string|XStreamResponse|null $xStreamResponse = null, + ?RequestOptions $requestOptions = null, + ): BaseStream; + + /** + * @api + * + * @param string $id Path param: Unique session identifier + * @param mixed $_forceBody Body param: + * @param 'typescript'|'python'|'playground'|\Stagehand\Sessions\SessionEndParams\XLanguage $xLanguage Header param: Client SDK language + * @param string $xSDKVersion Header param: Version of the Stagehand SDK + * @param string|\DateTimeInterface $xSentAt Header param: ISO timestamp when request was sent + * @param 'true'|'false'|\Stagehand\Sessions\SessionEndParams\XStreamResponse $xStreamResponse Header param: Whether to stream the response via SSE * * @throws APIException */ public function end( - string $sessionID, - ?RequestOptions $requestOptions = null + string $id, + mixed $_forceBody = null, + string|\Stagehand\Sessions\SessionEndParams\XLanguage|null $xLanguage = null, + ?string $xSDKVersion = null, + string|\DateTimeInterface|null $xSentAt = null, + string|\Stagehand\Sessions\SessionEndParams\XStreamResponse|null $xStreamResponse = null, + ?RequestOptions $requestOptions = null, ): SessionEndResponse; /** * @api * - * @param string $sessionID Path param: The session ID returned by /sessions/start + * @param string $id Path param: Unique session identifier * @param array{ * cua?: bool, * model?: string|array{ + * modelName: string, * apiKey?: string, * baseURL?: string, - * model?: string, - * provider?: 'openai'|'anthropic'|'google'|\Stagehand\Sessions\ModelConfig\Provider, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|Provider, * }, - * provider?: 'openai'|'anthropic'|'google'|Provider, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|\Stagehand\Sessions\SessionExecuteParams\AgentConfig\Provider, * systemPrompt?: string, * } $agentConfig Body param: * @param array{ - * instruction: string, highlightCursor?: bool, maxSteps?: int + * instruction: string, highlightCursor?: bool, maxSteps?: float * } $executeOptions Body param: - * @param string $frameID Body param: - * @param 'true'|'false'|\Stagehand\Sessions\SessionExecuteAgentParams\XStreamResponse $xStreamResponse Header param: Enable Server-Sent Events streaming for real-time logs + * @param string $frameID Body param: Target frame ID for the agent + * @param 'typescript'|'python'|'playground'|\Stagehand\Sessions\SessionExecuteParams\XLanguage $xLanguage Header param: Client SDK language + * @param string $xSDKVersion Header param: Version of the Stagehand SDK + * @param string|\DateTimeInterface $xSentAt Header param: ISO timestamp when request was sent + * @param 'true'|'false'|\Stagehand\Sessions\SessionExecuteParams\XStreamResponse $xStreamResponse Header param: Whether to stream the response via SSE * * @throws APIException */ - public function executeAgent( - string $sessionID, + public function execute( + string $id, array $agentConfig, array $executeOptions, ?string $frameID = null, - string|\Stagehand\Sessions\SessionExecuteAgentParams\XStreamResponse $xStreamResponse = 'true', + string|\Stagehand\Sessions\SessionExecuteParams\XLanguage|null $xLanguage = null, + ?string $xSDKVersion = null, + string|\DateTimeInterface|null $xSentAt = null, + string|\Stagehand\Sessions\SessionExecuteParams\XStreamResponse|null $xStreamResponse = null, + ?RequestOptions $requestOptions = null, + ): SessionExecuteResponse; + + /** + * @api + * + * @param string $id Path param: Unique session identifier + * @param array{ + * cua?: bool, + * model?: string|array{ + * modelName: string, + * apiKey?: string, + * baseURL?: string, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|Provider, + * }, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|\Stagehand\Sessions\SessionExecuteParams\AgentConfig\Provider, + * systemPrompt?: string, + * } $agentConfig Body param: + * @param array{ + * instruction: string, highlightCursor?: bool, maxSteps?: float + * } $executeOptions Body param: + * @param string $frameID Body param: Target frame ID for the agent + * @param 'typescript'|'python'|'playground'|\Stagehand\Sessions\SessionExecuteParams\XLanguage $xLanguage Header param: Client SDK language + * @param string $xSDKVersion Header param: Version of the Stagehand SDK + * @param string|\DateTimeInterface $xSentAt Header param: ISO timestamp when request was sent + * @param 'true'|'false'|\Stagehand\Sessions\SessionExecuteParams\XStreamResponse $xStreamResponse Header param: Whether to stream the response via SSE + * + * @return BaseStream + * + * @throws APIException + */ + public function executeStream( + string $id, + array $agentConfig, + array $executeOptions, + ?string $frameID = null, + string|\Stagehand\Sessions\SessionExecuteParams\XLanguage|null $xLanguage = null, + ?string $xSDKVersion = null, + string|\DateTimeInterface|null $xSentAt = null, + string|\Stagehand\Sessions\SessionExecuteParams\XStreamResponse|null $xStreamResponse = null, + ?RequestOptions $requestOptions = null, + ): BaseStream; + + /** + * @api + * + * @param string $id Path param: Unique session identifier + * @param string $frameID Body param: Target frame ID for the extraction + * @param string $instruction Body param: Natural language instruction for what to extract + * @param array{ + * model?: string|array{ + * modelName: string, + * apiKey?: string, + * baseURL?: string, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|Provider, + * }, + * selector?: string, + * timeout?: float, + * } $options Body param: + * @param array $schema Body param: JSON Schema defining the structure of data to extract + * @param 'typescript'|'python'|'playground'|\Stagehand\Sessions\SessionExtractParams\XLanguage $xLanguage Header param: Client SDK language + * @param string $xSDKVersion Header param: Version of the Stagehand SDK + * @param string|\DateTimeInterface $xSentAt Header param: ISO timestamp when request was sent + * @param 'true'|'false'|\Stagehand\Sessions\SessionExtractParams\XStreamResponse $xStreamResponse Header param: Whether to stream the response via SSE + * + * @throws APIException + */ + public function extract( + string $id, + ?string $frameID = null, + ?string $instruction = null, + ?array $options = null, + ?array $schema = null, + string|\Stagehand\Sessions\SessionExtractParams\XLanguage|null $xLanguage = null, + ?string $xSDKVersion = null, + string|\DateTimeInterface|null $xSentAt = null, + string|\Stagehand\Sessions\SessionExtractParams\XStreamResponse|null $xStreamResponse = null, ?RequestOptions $requestOptions = null, - ): SessionExecuteAgentResponse; + ): SessionExtractResponse; /** * @api * - * @param string $sessionID Path param: The session ID returned by /sessions/start - * @param string $frameID Body param: Frame ID to extract from - * @param string $instruction Body param: Natural language instruction for extraction + * @param string $id Path param: Unique session identifier + * @param string $frameID Body param: Target frame ID for the extraction + * @param string $instruction Body param: Natural language instruction for what to extract * @param array{ - * model?: array{ + * model?: string|array{ + * modelName: string, * apiKey?: string, * baseURL?: string, - * model?: string, - * provider?: 'openai'|'anthropic'|'google'|\Stagehand\Sessions\ModelConfig\Provider, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|Provider, * }, * selector?: string, - * timeout?: int, + * timeout?: float, * } $options Body param: - * @param array $schema Body param: JSON Schema for structured output - * @param 'true'|'false'|\Stagehand\Sessions\SessionExtractParams\XStreamResponse $xStreamResponse Header param: Enable Server-Sent Events streaming for real-time logs + * @param array $schema Body param: JSON Schema defining the structure of data to extract + * @param 'typescript'|'python'|'playground'|\Stagehand\Sessions\SessionExtractParams\XLanguage $xLanguage Header param: Client SDK language + * @param string $xSDKVersion Header param: Version of the Stagehand SDK + * @param string|\DateTimeInterface $xSentAt Header param: ISO timestamp when request was sent + * @param 'true'|'false'|\Stagehand\Sessions\SessionExtractParams\XStreamResponse $xStreamResponse Header param: Whether to stream the response via SSE * - * @return Extraction|array + * @return BaseStream * * @throws APIException */ - public function extract( - string $sessionID, + public function extractStream( + string $id, ?string $frameID = null, ?string $instruction = null, ?array $options = null, ?array $schema = null, - string|\Stagehand\Sessions\SessionExtractParams\XStreamResponse $xStreamResponse = 'true', + string|\Stagehand\Sessions\SessionExtractParams\XLanguage|null $xLanguage = null, + ?string $xSDKVersion = null, + string|\DateTimeInterface|null $xSentAt = null, + string|\Stagehand\Sessions\SessionExtractParams\XStreamResponse|null $xStreamResponse = null, ?RequestOptions $requestOptions = null, - ): Extraction|array; + ): BaseStream; /** * @api * - * @param string $sessionID Path param: The session ID returned by /sessions/start + * @param string $id Path param: Unique session identifier * @param string $url Body param: URL to navigate to - * @param string $frameID Body param: + * @param string $frameID Body param: Target frame ID for the navigation * @param array{ - * waitUntil?: 'load'|'domcontentloaded'|'networkidle'|WaitUntil + * referer?: string, + * timeout?: float, + * waitUntil?: 'load'|'domcontentloaded'|'networkidle'|WaitUntil, * } $options Body param: - * @param 'true'|'false'|\Stagehand\Sessions\SessionNavigateParams\XStreamResponse $xStreamResponse Header param: Enable Server-Sent Events streaming for real-time logs + * @param bool $streamResponse Body param: Whether to stream the response via SSE + * @param 'typescript'|'python'|'playground'|\Stagehand\Sessions\SessionNavigateParams\XLanguage $xLanguage Header param: Client SDK language + * @param string $xSDKVersion Header param: Version of the Stagehand SDK + * @param string|\DateTimeInterface $xSentAt Header param: ISO timestamp when request was sent + * @param 'true'|'false'|\Stagehand\Sessions\SessionNavigateParams\XStreamResponse $xStreamResponse Header param: Whether to stream the response via SSE * * @throws APIException */ public function navigate( - string $sessionID, + string $id, string $url, ?string $frameID = null, ?array $options = null, - string|\Stagehand\Sessions\SessionNavigateParams\XStreamResponse $xStreamResponse = 'true', + ?bool $streamResponse = null, + string|\Stagehand\Sessions\SessionNavigateParams\XLanguage|null $xLanguage = null, + ?string $xSDKVersion = null, + string|\DateTimeInterface|null $xSentAt = null, + string|\Stagehand\Sessions\SessionNavigateParams\XStreamResponse|null $xStreamResponse = null, ?RequestOptions $requestOptions = null, ): SessionNavigateResponse; /** * @api * - * @param string $sessionID Path param: The session ID returned by /sessions/start - * @param string $frameID Body param: Frame ID to observe - * @param string $instruction Body param: Natural language instruction to filter actions + * @param string $id Path param: Unique session identifier + * @param string $frameID Body param: Target frame ID for the observation + * @param string $instruction Body param: Natural language instruction for what actions to find * @param array{ - * model?: array{ + * model?: string|array{ + * modelName: string, * apiKey?: string, * baseURL?: string, - * model?: string, - * provider?: 'openai'|'anthropic'|'google'|\Stagehand\Sessions\ModelConfig\Provider, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|Provider, * }, * selector?: string, - * timeout?: int, + * timeout?: float, * } $options Body param: - * @param 'true'|'false'|\Stagehand\Sessions\SessionObserveParams\XStreamResponse $xStreamResponse Header param: Enable Server-Sent Events streaming for real-time logs - * - * @return list + * @param 'typescript'|'python'|'playground'|\Stagehand\Sessions\SessionObserveParams\XLanguage $xLanguage Header param: Client SDK language + * @param string $xSDKVersion Header param: Version of the Stagehand SDK + * @param string|\DateTimeInterface $xSentAt Header param: ISO timestamp when request was sent + * @param 'true'|'false'|\Stagehand\Sessions\SessionObserveParams\XStreamResponse $xStreamResponse Header param: Whether to stream the response via SSE * * @throws APIException */ public function observe( - string $sessionID, + string $id, ?string $frameID = null, ?string $instruction = null, ?array $options = null, - string|\Stagehand\Sessions\SessionObserveParams\XStreamResponse $xStreamResponse = 'true', + string|\Stagehand\Sessions\SessionObserveParams\XLanguage|null $xLanguage = null, + ?string $xSDKVersion = null, + string|\DateTimeInterface|null $xSentAt = null, + string|\Stagehand\Sessions\SessionObserveParams\XStreamResponse|null $xStreamResponse = null, ?RequestOptions $requestOptions = null, - ): array; + ): SessionObserveResponse; /** * @api * - * @param string $browserbaseAPIKey API key for Browserbase Cloud - * @param string $browserbaseProjectID Project ID for Browserbase - * @param int $domSettleTimeout Timeout in ms to wait for DOM to settle - * @param string $model AI model to use for actions (must be prefixed with provider/) - * @param bool $selfHeal Enable self-healing for failed actions - * @param string $systemPrompt Custom system prompt for AI actions - * @param int $verbose Logging verbosity level + * @param string $id Path param: Unique session identifier + * @param string $frameID Body param: Target frame ID for the observation + * @param string $instruction Body param: Natural language instruction for what actions to find + * @param array{ + * model?: string|array{ + * modelName: string, + * apiKey?: string, + * baseURL?: string, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|Provider, + * }, + * selector?: string, + * timeout?: float, + * } $options Body param: + * @param 'typescript'|'python'|'playground'|\Stagehand\Sessions\SessionObserveParams\XLanguage $xLanguage Header param: Client SDK language + * @param string $xSDKVersion Header param: Version of the Stagehand SDK + * @param string|\DateTimeInterface $xSentAt Header param: ISO timestamp when request was sent + * @param 'true'|'false'|\Stagehand\Sessions\SessionObserveParams\XStreamResponse $xStreamResponse Header param: Whether to stream the response via SSE + * + * @return BaseStream + * + * @throws APIException + */ + public function observeStream( + string $id, + ?string $frameID = null, + ?string $instruction = null, + ?array $options = null, + string|\Stagehand\Sessions\SessionObserveParams\XLanguage|null $xLanguage = null, + ?string $xSDKVersion = null, + string|\DateTimeInterface|null $xSentAt = null, + string|\Stagehand\Sessions\SessionObserveParams\XStreamResponse|null $xStreamResponse = null, + ?RequestOptions $requestOptions = null, + ): BaseStream; + + /** + * @api + * + * @param string $modelName Body param: Model name to use for AI operations + * @param float $actTimeoutMs Body param: Timeout in ms for act operations (deprecated, v2 only) + * @param array{ + * cdpURL?: string, + * launchOptions?: array{ + * acceptDownloads?: bool, + * args?: list, + * cdpURL?: string, + * chromiumSandbox?: bool, + * connectTimeoutMs?: float, + * deviceScaleFactor?: float, + * devtools?: bool, + * downloadsPath?: string, + * executablePath?: string, + * hasTouch?: bool, + * headless?: bool, + * ignoreDefaultArgs?: bool|list, + * ignoreHTTPSErrors?: bool, + * locale?: string, + * preserveUserDataDir?: bool, + * proxy?: array{ + * server: string, bypass?: string, password?: string, username?: string + * }, + * userDataDir?: string, + * viewport?: array{height: float, width: float}, + * }, + * type?: 'local'|'browserbase'|Type, + * } $browser Body param: + * @param array{ + * browserSettings?: array{ + * advancedStealth?: bool, + * blockAds?: bool, + * context?: array{id: string, persist?: bool}, + * extensionID?: string, + * fingerprint?: array{ + * browsers?: list<'chrome'|'edge'|'firefox'|'safari'|Browser>, + * devices?: list<'desktop'|'mobile'|Device>, + * httpVersion?: '1'|'2'|HTTPVersion, + * locales?: list, + * operatingSystems?: list<'android'|'ios'|'linux'|'macos'|'windows'|OperatingSystem>, + * screen?: array{ + * maxHeight?: float, maxWidth?: float, minHeight?: float, minWidth?: float + * }, + * }, + * logSession?: bool, + * recordSession?: bool, + * solveCaptchas?: bool, + * viewport?: array{height?: float, width?: float}, + * }, + * extensionID?: string, + * keepAlive?: bool, + * projectID?: string, + * proxies?: bool|list>, + * region?: 'us-west-2'|'us-east-1'|'eu-central-1'|'ap-southeast-1'|Region, + * timeout?: float, + * userMetadata?: array, + * } $browserbaseSessionCreateParams Body param: + * @param string $browserbaseSessionID Body param: Existing Browserbase session ID to resume + * @param float $domSettleTimeoutMs Body param: Timeout in ms to wait for DOM to settle + * @param bool $experimental Body param: + * @param bool $selfHeal Body param: Enable self-healing for failed actions + * @param string $systemPrompt Body param: Custom system prompt for AI operations + * @param float $verbose Body param: Logging verbosity level (0=quiet, 1=normal, 2=debug) + * @param bool $waitForCaptchaSolves Body param: Wait for captcha solves (deprecated, v2 only) + * @param 'typescript'|'python'|'playground'|\Stagehand\Sessions\SessionStartParams\XLanguage $xLanguage Header param: Client SDK language + * @param string $xSDKVersion Header param: Version of the Stagehand SDK + * @param string|\DateTimeInterface $xSentAt Header param: ISO timestamp when request was sent + * @param 'true'|'false'|\Stagehand\Sessions\SessionStartParams\XStreamResponse $xStreamResponse Header param: Whether to stream the response via SSE * * @throws APIException */ public function start( - string $browserbaseAPIKey, - string $browserbaseProjectID, - ?int $domSettleTimeout = null, - ?string $model = null, + string $modelName, + ?float $actTimeoutMs = null, + ?array $browser = null, + ?array $browserbaseSessionCreateParams = null, + ?string $browserbaseSessionID = null, + ?float $domSettleTimeoutMs = null, + ?bool $experimental = null, ?bool $selfHeal = null, ?string $systemPrompt = null, - int $verbose = 0, + ?float $verbose = null, + ?bool $waitForCaptchaSolves = null, + string|\Stagehand\Sessions\SessionStartParams\XLanguage|null $xLanguage = null, + ?string $xSDKVersion = null, + string|\DateTimeInterface|null $xSentAt = null, + string|\Stagehand\Sessions\SessionStartParams\XStreamResponse|null $xStreamResponse = null, ?RequestOptions $requestOptions = null, ): SessionStartResponse; } diff --git a/src/ServiceContracts/SessionsRawContract.php b/src/ServiceContracts/SessionsRawContract.php index c26faec..5b392d6 100644 --- a/src/ServiceContracts/SessionsRawContract.php +++ b/src/ServiceContracts/SessionsRawContract.php @@ -5,36 +5,39 @@ namespace Stagehand\ServiceContracts; use Stagehand\Core\Contracts\BaseResponse; +use Stagehand\Core\Contracts\BaseStream; use Stagehand\Core\Exceptions\APIException; use Stagehand\RequestOptions; -use Stagehand\Sessions\Action; use Stagehand\Sessions\SessionActParams; use Stagehand\Sessions\SessionActResponse; +use Stagehand\Sessions\SessionEndParams; use Stagehand\Sessions\SessionEndResponse; -use Stagehand\Sessions\SessionExecuteAgentParams; -use Stagehand\Sessions\SessionExecuteAgentResponse; +use Stagehand\Sessions\SessionExecuteParams; +use Stagehand\Sessions\SessionExecuteResponse; use Stagehand\Sessions\SessionExtractParams; -use Stagehand\Sessions\SessionExtractResponse\Extraction; +use Stagehand\Sessions\SessionExtractResponse; use Stagehand\Sessions\SessionNavigateParams; use Stagehand\Sessions\SessionNavigateResponse; use Stagehand\Sessions\SessionObserveParams; +use Stagehand\Sessions\SessionObserveResponse; use Stagehand\Sessions\SessionStartParams; use Stagehand\Sessions\SessionStartResponse; +use Stagehand\Sessions\StreamEvent; interface SessionsRawContract { /** * @api * - * @param string $sessionID Path param: The session ID returned by /sessions/start - * @param array|SessionActParams $params + * @param string $id Path param: Unique session identifier + * @param array|SessionActParams $params * * @return BaseResponse * * @throws APIException */ public function act( - string $sessionID, + string $id, array|SessionActParams $params, ?RequestOptions $requestOptions = null, ): BaseResponse; @@ -42,45 +45,79 @@ public function act( /** * @api * - * @param string $sessionID The session ID returned by /sessions/start + * @param string $id Path param: Unique session identifier + * @param array|SessionActParams $params + * + * @return BaseResponse> + * + * @throws APIException + */ + public function actStream( + string $id, + array|SessionActParams $params, + ?RequestOptions $requestOptions = null, + ): BaseResponse; + + /** + * @api + * + * @param string $id Path param: Unique session identifier + * @param array|SessionEndParams $params * * @return BaseResponse * * @throws APIException */ public function end( - string $sessionID, - ?RequestOptions $requestOptions = null + string $id, + array|SessionEndParams $params, + ?RequestOptions $requestOptions = null, + ): BaseResponse; + + /** + * @api + * + * @param string $id Path param: Unique session identifier + * @param array|SessionExecuteParams $params + * + * @return BaseResponse + * + * @throws APIException + */ + public function execute( + string $id, + array|SessionExecuteParams $params, + ?RequestOptions $requestOptions = null, ): BaseResponse; /** * @api * - * @param string $sessionID Path param: The session ID returned by /sessions/start - * @param array|SessionExecuteAgentParams $params + * @param string $id Path param: Unique session identifier + * @param array|SessionExecuteParams $params * - * @return BaseResponse + * @return BaseResponse> * * @throws APIException */ - public function executeAgent( - string $sessionID, - array|SessionExecuteAgentParams $params, + public function executeStream( + string $id, + array|SessionExecuteParams $params, ?RequestOptions $requestOptions = null, ): BaseResponse; /** * @api * - * @param string $sessionID Path param: The session ID returned by /sessions/start - * @param array|SessionExtractParams $params + * @param string $id Path param: Unique session identifier + * @param array|SessionExtractParams $params * - * @return BaseResponse> + * @return BaseResponse * * @throws APIException */ public function extract( - string $sessionID, + string $id, array|SessionExtractParams $params, ?RequestOptions $requestOptions = null, ): BaseResponse; @@ -88,15 +125,31 @@ public function extract( /** * @api * - * @param string $sessionID Path param: The session ID returned by /sessions/start - * @param array|SessionNavigateParams $params + * @param string $id Path param: Unique session identifier + * @param array|SessionExtractParams $params + * + * @return BaseResponse> + * + * @throws APIException + */ + public function extractStream( + string $id, + array|SessionExtractParams $params, + ?RequestOptions $requestOptions = null, + ): BaseResponse; + + /** + * @api + * + * @param string $id Path param: Unique session identifier + * @param array|SessionNavigateParams $params * * @return BaseResponse * * @throws APIException */ public function navigate( - string $sessionID, + string $id, array|SessionNavigateParams $params, ?RequestOptions $requestOptions = null, ): BaseResponse; @@ -104,15 +157,31 @@ public function navigate( /** * @api * - * @param string $sessionID Path param: The session ID returned by /sessions/start - * @param array|SessionObserveParams $params + * @param string $id Path param: Unique session identifier + * @param array|SessionObserveParams $params * - * @return BaseResponse> + * @return BaseResponse * * @throws APIException */ public function observe( - string $sessionID, + string $id, + array|SessionObserveParams $params, + ?RequestOptions $requestOptions = null, + ): BaseResponse; + + /** + * @api + * + * @param string $id Path param: Unique session identifier + * @param array|SessionObserveParams $params + * + * @return BaseResponse> + * + * @throws APIException + */ + public function observeStream( + string $id, array|SessionObserveParams $params, ?RequestOptions $requestOptions = null, ): BaseResponse; @@ -120,7 +189,7 @@ public function observe( /** * @api * - * @param array|SessionStartParams $params + * @param array|SessionStartParams $params * * @return BaseResponse * diff --git a/src/Services/SessionsRawService.php b/src/Services/SessionsRawService.php index 2056585..dc8437d 100644 --- a/src/Services/SessionsRawService.php +++ b/src/Services/SessionsRawService.php @@ -6,28 +6,34 @@ use Stagehand\Client; use Stagehand\Core\Contracts\BaseResponse; -use Stagehand\Core\Conversion\ListOf; +use Stagehand\Core\Contracts\BaseStream; use Stagehand\Core\Exceptions\APIException; use Stagehand\Core\Util; use Stagehand\RequestOptions; use Stagehand\ServiceContracts\SessionsRawContract; -use Stagehand\Sessions\Action; +use Stagehand\Sessions\ModelConfig\ModelConfigObject\Provider; use Stagehand\Sessions\SessionActParams; -use Stagehand\Sessions\SessionActParams\XStreamResponse; use Stagehand\Sessions\SessionActResponse; +use Stagehand\Sessions\SessionEndParams; +use Stagehand\Sessions\SessionEndParams\XLanguage; +use Stagehand\Sessions\SessionEndParams\XStreamResponse; use Stagehand\Sessions\SessionEndResponse; -use Stagehand\Sessions\SessionExecuteAgentParams; -use Stagehand\Sessions\SessionExecuteAgentParams\AgentConfig\Provider; -use Stagehand\Sessions\SessionExecuteAgentResponse; +use Stagehand\Sessions\SessionExecuteParams; +use Stagehand\Sessions\SessionExecuteResponse; use Stagehand\Sessions\SessionExtractParams; use Stagehand\Sessions\SessionExtractResponse; -use Stagehand\Sessions\SessionExtractResponse\Extraction; use Stagehand\Sessions\SessionNavigateParams; use Stagehand\Sessions\SessionNavigateParams\Options\WaitUntil; use Stagehand\Sessions\SessionNavigateResponse; use Stagehand\Sessions\SessionObserveParams; +use Stagehand\Sessions\SessionObserveResponse; use Stagehand\Sessions\SessionStartParams; +use Stagehand\Sessions\SessionStartParams\Browser\Type; +use Stagehand\Sessions\SessionStartParams\BrowserbaseSessionCreateParams\BrowserSettings\Fingerprint\HTTPVersion; +use Stagehand\Sessions\SessionStartParams\BrowserbaseSessionCreateParams\Region; use Stagehand\Sessions\SessionStartResponse; +use Stagehand\Sessions\StreamEvent; +use Stagehand\SSEStream; final class SessionsRawService implements SessionsRawContract { @@ -40,30 +46,32 @@ public function __construct(private Client $client) {} /** * @api * - * Performs a browser action based on natural language instruction or - * a specific action object returned by observe(). + * Executes a browser action using natural language instructions or a predefined Action object. * - * @param string $sessionID Path param: The session ID returned by /sessions/start + * @param string $id Path param: Unique session identifier * @param array{ * input: string|array{ - * arguments: list, * description: string, - * method: string, * selector: string, - * backendNodeID?: int, - * }|Action, + * arguments?: list, + * backendNodeID?: float, + * method?: string, + * }, * frameID?: string, * options?: array{ - * model?: array{ + * model?: string|array{ + * modelName: string, * apiKey?: string, * baseURL?: string, - * model?: string, - * provider?: 'openai'|'anthropic'|'google'|\Stagehand\Sessions\ModelConfig\Provider, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|Provider, * }, - * timeout?: int, + * timeout?: float, * variables?: array, * }, - * xStreamResponse?: 'true'|'false'|XStreamResponse, + * xLanguage?: 'typescript'|'python'|'playground'|SessionActParams\XLanguage, + * xSDKVersion?: string, + * xSentAt?: string|\DateTimeInterface, + * xStreamResponse?: 'true'|'false'|SessionActParams\XStreamResponse, * }|SessionActParams $params * * @return BaseResponse @@ -71,7 +79,7 @@ public function __construct(private Client $client) {} * @throws APIException */ public function act( - string $sessionID, + string $id, array|SessionActParams $params, ?RequestOptions $requestOptions = null, ): BaseResponse { @@ -79,12 +87,17 @@ public function act( $params, $requestOptions, ); - $header_params = ['xStreamResponse' => 'x-stream-response']; + $header_params = [ + 'xLanguage' => 'x-language', + 'xSDKVersion' => 'x-sdk-version', + 'xSentAt' => 'x-sent-at', + 'xStreamResponse' => 'x-stream-response', + ]; // @phpstan-ignore-next-line return.type return $this->client->request( method: 'post', - path: ['sessions/%1$s/act', $sessionID], + path: ['v1/sessions/%1$s/act', $id], headers: Util::array_transform_keys( array_intersect_key($parsed, array_flip(array_keys($header_params))), $header_params, @@ -101,23 +114,124 @@ public function act( /** * @api * - * Closes the browser and cleans up all resources associated with the session. + * @param string $id Path param: Unique session identifier + * @param array{ + * input: string|array{ + * description: string, + * selector: string, + * arguments?: list, + * backendNodeID?: float, + * method?: string, + * }, + * frameID?: string, + * options?: array{ + * model?: string|array{ + * modelName: string, + * apiKey?: string, + * baseURL?: string, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|Provider, + * }, + * timeout?: float, + * variables?: array, + * }, + * xLanguage?: 'typescript'|'python'|'playground'|SessionActParams\XLanguage, + * xSDKVersion?: string, + * xSentAt?: string|\DateTimeInterface, + * xStreamResponse?: 'true'|'false'|SessionActParams\XStreamResponse, + * }|SessionActParams $params + * + * @return BaseResponse> + * + * @throws APIException + */ + public function actStream( + string $id, + array|SessionActParams $params, + ?RequestOptions $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = SessionActParams::parseRequest( + $params, + $requestOptions, + ); + $parsed['streamResponse'] = true; + $header_params = [ + 'xLanguage' => 'x-language', + 'xSDKVersion' => 'x-sdk-version', + 'xSentAt' => 'x-sent-at', + 'xStreamResponse' => 'x-stream-response', + ]; + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: ['v1/sessions/%1$s/act', $id], + headers: Util::array_transform_keys( + [ + 'Accept' => 'text/event-stream', + ...array_intersect_key( + $parsed, + array_flip(array_keys($header_params)) + ), + ], + $header_params, + ), + body: (object) array_diff_key( + $parsed, + array_flip(array_keys($header_params)) + ), + options: $options, + convert: StreamEvent::class, + stream: SSEStream::class, + ); + } + + /** + * @api + * + * Terminates the browser session and releases all associated resources. * - * @param string $sessionID The session ID returned by /sessions/start + * @param string $id Path param: Unique session identifier + * @param array{ + * _forceBody?: mixed, + * xLanguage?: 'typescript'|'python'|'playground'|XLanguage, + * xSDKVersion?: string, + * xSentAt?: string|\DateTimeInterface, + * xStreamResponse?: 'true'|'false'|XStreamResponse, + * }|SessionEndParams $params * * @return BaseResponse * * @throws APIException */ public function end( - string $sessionID, - ?RequestOptions $requestOptions = null + string $id, + array|SessionEndParams $params, + ?RequestOptions $requestOptions = null, ): BaseResponse { + [$parsed, $options] = SessionEndParams::parseRequest( + $params, + $requestOptions, + ); + $header_params = [ + 'xLanguage' => 'x-language', + 'xSDKVersion' => 'x-sdk-version', + 'xSentAt' => 'x-sent-at', + 'xStreamResponse' => 'x-stream-response', + ]; + // @phpstan-ignore-next-line return.type return $this->client->request( method: 'post', - path: ['sessions/%1$s/end', $sessionID], - options: $requestOptions, + path: ['v1/sessions/%1$s/end', $id], + headers: Util::array_transform_keys( + array_intersect_key($parsed, array_flip(array_keys($header_params))), + $header_params, + ), + body: (object) array_diff_key( + $parsed, + array_flip(array_keys($header_params)) + ), + options: $options, convert: SessionEndResponse::class, ); } @@ -125,48 +239,55 @@ public function end( /** * @api * - * Runs an autonomous agent that can perform multiple actions to - * complete a complex task. + * Runs an autonomous AI agent that can perform complex multi-step browser tasks. * - * @param string $sessionID Path param: The session ID returned by /sessions/start + * @param string $id Path param: Unique session identifier * @param array{ * agentConfig: array{ * cua?: bool, * model?: string|array{ + * modelName: string, * apiKey?: string, * baseURL?: string, - * model?: string, - * provider?: 'openai'|'anthropic'|'google'|\Stagehand\Sessions\ModelConfig\Provider, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|Provider, * }, - * provider?: 'openai'|'anthropic'|'google'|Provider, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|SessionExecuteParams\AgentConfig\Provider, * systemPrompt?: string, * }, * executeOptions: array{ - * instruction: string, highlightCursor?: bool, maxSteps?: int + * instruction: string, highlightCursor?: bool, maxSteps?: float * }, * frameID?: string, - * xStreamResponse?: 'true'|'false'|SessionExecuteAgentParams\XStreamResponse, - * }|SessionExecuteAgentParams $params + * xLanguage?: 'typescript'|'python'|'playground'|SessionExecuteParams\XLanguage, + * xSDKVersion?: string, + * xSentAt?: string|\DateTimeInterface, + * xStreamResponse?: 'true'|'false'|SessionExecuteParams\XStreamResponse, + * }|SessionExecuteParams $params * - * @return BaseResponse + * @return BaseResponse * * @throws APIException */ - public function executeAgent( - string $sessionID, - array|SessionExecuteAgentParams $params, + public function execute( + string $id, + array|SessionExecuteParams $params, ?RequestOptions $requestOptions = null, ): BaseResponse { - [$parsed, $options] = SessionExecuteAgentParams::parseRequest( + [$parsed, $options] = SessionExecuteParams::parseRequest( $params, $requestOptions, ); - $header_params = ['xStreamResponse' => 'x-stream-response']; + $header_params = [ + 'xLanguage' => 'x-language', + 'xSDKVersion' => 'x-sdk-version', + 'xSentAt' => 'x-sent-at', + 'xStreamResponse' => 'x-stream-response', + ]; // @phpstan-ignore-next-line return.type return $this->client->request( method: 'post', - path: ['sessions/%1$s/agentExecute', $sessionID], + path: ['v1/sessions/%1$s/agentExecute', $id], headers: Util::array_transform_keys( array_intersect_key($parsed, array_flip(array_keys($header_params))), $header_params, @@ -176,40 +297,113 @@ public function executeAgent( array_flip(array_keys($header_params)) ), options: $options, - convert: SessionExecuteAgentResponse::class, + convert: SessionExecuteResponse::class, ); } /** * @api * - * Extracts data from the current page using natural language instructions - * and optional JSON schema for structured output. + * @param string $id Path param: Unique session identifier + * @param array{ + * agentConfig: array{ + * cua?: bool, + * model?: string|array{ + * modelName: string, + * apiKey?: string, + * baseURL?: string, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|Provider, + * }, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|SessionExecuteParams\AgentConfig\Provider, + * systemPrompt?: string, + * }, + * executeOptions: array{ + * instruction: string, highlightCursor?: bool, maxSteps?: float + * }, + * frameID?: string, + * xLanguage?: 'typescript'|'python'|'playground'|SessionExecuteParams\XLanguage, + * xSDKVersion?: string, + * xSentAt?: string|\DateTimeInterface, + * xStreamResponse?: 'true'|'false'|SessionExecuteParams\XStreamResponse, + * }|SessionExecuteParams $params + * + * @return BaseResponse> * - * @param string $sessionID Path param: The session ID returned by /sessions/start + * @throws APIException + */ + public function executeStream( + string $id, + array|SessionExecuteParams $params, + ?RequestOptions $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = SessionExecuteParams::parseRequest( + $params, + $requestOptions, + ); + $parsed['streamResponse'] = true; + $header_params = [ + 'xLanguage' => 'x-language', + 'xSDKVersion' => 'x-sdk-version', + 'xSentAt' => 'x-sent-at', + 'xStreamResponse' => 'x-stream-response', + ]; + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: ['v1/sessions/%1$s/agentExecute', $id], + headers: Util::array_transform_keys( + [ + 'Accept' => 'text/event-stream', + ...array_intersect_key( + $parsed, + array_flip(array_keys($header_params)) + ), + ], + $header_params, + ), + body: (object) array_diff_key( + $parsed, + array_flip(array_keys($header_params)) + ), + options: $options, + convert: StreamEvent::class, + stream: SSEStream::class, + ); + } + + /** + * @api + * + * Extracts structured data from the current page using AI-powered analysis. + * + * @param string $id Path param: Unique session identifier * @param array{ * frameID?: string, * instruction?: string, * options?: array{ - * model?: array{ + * model?: string|array{ + * modelName: string, * apiKey?: string, * baseURL?: string, - * model?: string, - * provider?: 'openai'|'anthropic'|'google'|\Stagehand\Sessions\ModelConfig\Provider, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|Provider, * }, * selector?: string, - * timeout?: int, + * timeout?: float, * }, * schema?: array, + * xLanguage?: 'typescript'|'python'|'playground'|SessionExtractParams\XLanguage, + * xSDKVersion?: string, + * xSentAt?: string|\DateTimeInterface, * xStreamResponse?: 'true'|'false'|SessionExtractParams\XStreamResponse, * }|SessionExtractParams $params * - * @return BaseResponse> + * @return BaseResponse * * @throws APIException */ public function extract( - string $sessionID, + string $id, array|SessionExtractParams $params, ?RequestOptions $requestOptions = null, ): BaseResponse { @@ -217,12 +411,17 @@ public function extract( $params, $requestOptions, ); - $header_params = ['xStreamResponse' => 'x-stream-response']; + $header_params = [ + 'xLanguage' => 'x-language', + 'xSDKVersion' => 'x-sdk-version', + 'xSentAt' => 'x-sent-at', + 'xStreamResponse' => 'x-stream-response', + ]; // @phpstan-ignore-next-line return.type return $this->client->request( method: 'post', - path: ['sessions/%1$s/extract', $sessionID], + path: ['v1/sessions/%1$s/extract', $id], headers: Util::array_transform_keys( array_intersect_key($parsed, array_flip(array_keys($header_params))), $header_params, @@ -239,15 +438,90 @@ public function extract( /** * @api * - * Navigates the browser to the specified URL and waits for page load. + * @param string $id Path param: Unique session identifier + * @param array{ + * frameID?: string, + * instruction?: string, + * options?: array{ + * model?: string|array{ + * modelName: string, + * apiKey?: string, + * baseURL?: string, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|Provider, + * }, + * selector?: string, + * timeout?: float, + * }, + * schema?: array, + * xLanguage?: 'typescript'|'python'|'playground'|SessionExtractParams\XLanguage, + * xSDKVersion?: string, + * xSentAt?: string|\DateTimeInterface, + * xStreamResponse?: 'true'|'false'|SessionExtractParams\XStreamResponse, + * }|SessionExtractParams $params + * + * @return BaseResponse> + * + * @throws APIException + */ + public function extractStream( + string $id, + array|SessionExtractParams $params, + ?RequestOptions $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = SessionExtractParams::parseRequest( + $params, + $requestOptions, + ); + $parsed['streamResponse'] = true; + $header_params = [ + 'xLanguage' => 'x-language', + 'xSDKVersion' => 'x-sdk-version', + 'xSentAt' => 'x-sent-at', + 'xStreamResponse' => 'x-stream-response', + ]; + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: ['v1/sessions/%1$s/extract', $id], + headers: Util::array_transform_keys( + [ + 'Accept' => 'text/event-stream', + ...array_intersect_key( + $parsed, + array_flip(array_keys($header_params)) + ), + ], + $header_params, + ), + body: (object) array_diff_key( + $parsed, + array_flip(array_keys($header_params)) + ), + options: $options, + convert: StreamEvent::class, + stream: SSEStream::class, + ); + } + + /** + * @api + * + * Navigates the browser to the specified URL. * - * @param string $sessionID Path param: The session ID returned by /sessions/start + * @param string $id Path param: Unique session identifier * @param array{ * url: string, * frameID?: string, * options?: array{ - * waitUntil?: 'load'|'domcontentloaded'|'networkidle'|WaitUntil + * referer?: string, + * timeout?: float, + * waitUntil?: 'load'|'domcontentloaded'|'networkidle'|WaitUntil, * }, + * streamResponse?: bool, + * xLanguage?: 'typescript'|'python'|'playground'|SessionNavigateParams\XLanguage, + * xSDKVersion?: string, + * xSentAt?: string|\DateTimeInterface, * xStreamResponse?: 'true'|'false'|SessionNavigateParams\XStreamResponse, * }|SessionNavigateParams $params * @@ -256,7 +530,7 @@ public function extract( * @throws APIException */ public function navigate( - string $sessionID, + string $id, array|SessionNavigateParams $params, ?RequestOptions $requestOptions = null, ): BaseResponse { @@ -264,12 +538,17 @@ public function navigate( $params, $requestOptions, ); - $header_params = ['xStreamResponse' => 'x-stream-response']; + $header_params = [ + 'xLanguage' => 'x-language', + 'xSDKVersion' => 'x-sdk-version', + 'xSentAt' => 'x-sent-at', + 'xStreamResponse' => 'x-stream-response', + ]; // @phpstan-ignore-next-line return.type return $this->client->request( method: 'post', - path: ['sessions/%1$s/navigate', $sessionID], + path: ['v1/sessions/%1$s/navigate', $id], headers: Util::array_transform_keys( array_intersect_key($parsed, array_flip(array_keys($header_params))), $header_params, @@ -286,32 +565,34 @@ public function navigate( /** * @api * - * Returns a list of candidate actions that can be performed on the page, - * optionally filtered by natural language instruction. + * Identifies and returns available actions on the current page that match the given instruction. * - * @param string $sessionID Path param: The session ID returned by /sessions/start + * @param string $id Path param: Unique session identifier * @param array{ * frameID?: string, * instruction?: string, * options?: array{ - * model?: array{ + * model?: string|array{ + * modelName: string, * apiKey?: string, * baseURL?: string, - * model?: string, - * provider?: 'openai'|'anthropic'|'google'|\Stagehand\Sessions\ModelConfig\Provider, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|Provider, * }, * selector?: string, - * timeout?: int, + * timeout?: float, * }, + * xLanguage?: 'typescript'|'python'|'playground'|SessionObserveParams\XLanguage, + * xSDKVersion?: string, + * xSentAt?: string|\DateTimeInterface, * xStreamResponse?: 'true'|'false'|SessionObserveParams\XStreamResponse, * }|SessionObserveParams $params * - * @return BaseResponse> + * @return BaseResponse * * @throws APIException */ public function observe( - string $sessionID, + string $id, array|SessionObserveParams $params, ?RequestOptions $requestOptions = null, ): BaseResponse { @@ -319,12 +600,17 @@ public function observe( $params, $requestOptions, ); - $header_params = ['xStreamResponse' => 'x-stream-response']; + $header_params = [ + 'xLanguage' => 'x-language', + 'xSDKVersion' => 'x-sdk-version', + 'xSentAt' => 'x-sent-at', + 'xStreamResponse' => 'x-stream-response', + ]; // @phpstan-ignore-next-line return.type return $this->client->request( method: 'post', - path: ['sessions/%1$s/observe', $sessionID], + path: ['v1/sessions/%1$s/observe', $id], headers: Util::array_transform_keys( array_intersect_key($parsed, array_flip(array_keys($header_params))), $header_params, @@ -334,24 +620,150 @@ public function observe( array_flip(array_keys($header_params)) ), options: $options, - convert: new ListOf(Action::class), + convert: SessionObserveResponse::class, ); } /** * @api * - * Initializes a new Stagehand session with a browser instance. - * Returns a session ID that must be used for all subsequent requests. + * @param string $id Path param: Unique session identifier + * @param array{ + * frameID?: string, + * instruction?: string, + * options?: array{ + * model?: string|array{ + * modelName: string, + * apiKey?: string, + * baseURL?: string, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|Provider, + * }, + * selector?: string, + * timeout?: float, + * }, + * xLanguage?: 'typescript'|'python'|'playground'|SessionObserveParams\XLanguage, + * xSDKVersion?: string, + * xSentAt?: string|\DateTimeInterface, + * xStreamResponse?: 'true'|'false'|SessionObserveParams\XStreamResponse, + * }|SessionObserveParams $params + * + * @return BaseResponse> + * + * @throws APIException + */ + public function observeStream( + string $id, + array|SessionObserveParams $params, + ?RequestOptions $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = SessionObserveParams::parseRequest( + $params, + $requestOptions, + ); + $parsed['streamResponse'] = true; + $header_params = [ + 'xLanguage' => 'x-language', + 'xSDKVersion' => 'x-sdk-version', + 'xSentAt' => 'x-sent-at', + 'xStreamResponse' => 'x-stream-response', + ]; + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: ['v1/sessions/%1$s/observe', $id], + headers: Util::array_transform_keys( + [ + 'Accept' => 'text/event-stream', + ...array_intersect_key( + $parsed, + array_flip(array_keys($header_params)) + ), + ], + $header_params, + ), + body: (object) array_diff_key( + $parsed, + array_flip(array_keys($header_params)) + ), + options: $options, + convert: StreamEvent::class, + stream: SSEStream::class, + ); + } + + /** + * @api + * + * Creates a new browser session with the specified configuration. Returns a session ID used for all subsequent operations. * * @param array{ - * browserbaseAPIKey: string, - * browserbaseProjectID: string, - * domSettleTimeout?: int, - * model?: string, + * modelName: string, + * actTimeoutMs?: float, + * browser?: array{ + * cdpURL?: string, + * launchOptions?: array{ + * acceptDownloads?: bool, + * args?: list, + * cdpURL?: string, + * chromiumSandbox?: bool, + * connectTimeoutMs?: float, + * deviceScaleFactor?: float, + * devtools?: bool, + * downloadsPath?: string, + * executablePath?: string, + * hasTouch?: bool, + * headless?: bool, + * ignoreDefaultArgs?: bool|list, + * ignoreHTTPSErrors?: bool, + * locale?: string, + * preserveUserDataDir?: bool, + * proxy?: array{ + * server: string, bypass?: string, password?: string, username?: string + * }, + * userDataDir?: string, + * viewport?: array{height: float, width: float}, + * }, + * type?: 'local'|'browserbase'|Type, + * }, + * browserbaseSessionCreateParams?: array{ + * browserSettings?: array{ + * advancedStealth?: bool, + * blockAds?: bool, + * context?: array{id: string, persist?: bool}, + * extensionID?: string, + * fingerprint?: array{ + * browsers?: list, + * devices?: list, + * httpVersion?: '1'|'2'|HTTPVersion, + * locales?: list, + * operatingSystems?: list, + * screen?: array, + * }, + * logSession?: bool, + * recordSession?: bool, + * solveCaptchas?: bool, + * viewport?: array{height?: float, width?: float}, + * }, + * extensionID?: string, + * keepAlive?: bool, + * projectID?: string, + * proxies?: bool|list>, + * region?: 'us-west-2'|'us-east-1'|'eu-central-1'|'ap-southeast-1'|Region, + * timeout?: float, + * userMetadata?: array, + * }, + * browserbaseSessionID?: string, + * domSettleTimeoutMs?: float, + * experimental?: bool, * selfHeal?: bool, * systemPrompt?: string, - * verbose?: int, + * verbose?: float, + * waitForCaptchaSolves?: bool, + * xLanguage?: 'typescript'|'python'|'playground'|SessionStartParams\XLanguage, + * xSDKVersion?: string, + * xSentAt?: string|\DateTimeInterface, + * xStreamResponse?: 'true'|'false'|SessionStartParams\XStreamResponse, * }|SessionStartParams $params * * @return BaseResponse @@ -366,12 +778,25 @@ public function start( $params, $requestOptions, ); + $header_params = [ + 'xLanguage' => 'x-language', + 'xSDKVersion' => 'x-sdk-version', + 'xSentAt' => 'x-sent-at', + 'xStreamResponse' => 'x-stream-response', + ]; // @phpstan-ignore-next-line return.type return $this->client->request( method: 'post', - path: 'sessions/start', - body: (object) $parsed, + path: 'v1/sessions/start', + headers: Util::array_transform_keys( + array_intersect_key($parsed, array_flip(array_keys($header_params))), + $header_params, + ), + body: (object) array_diff_key( + $parsed, + array_flip(array_keys($header_params)) + ), options: $options, convert: SessionStartResponse::class, ); diff --git a/src/Services/SessionsService.php b/src/Services/SessionsService.php index ed6dfc0..3128614 100644 --- a/src/Services/SessionsService.php +++ b/src/Services/SessionsService.php @@ -5,20 +5,29 @@ namespace Stagehand\Services; use Stagehand\Client; +use Stagehand\Core\Contracts\BaseStream; use Stagehand\Core\Exceptions\APIException; use Stagehand\Core\Util; use Stagehand\RequestOptions; use Stagehand\ServiceContracts\SessionsContract; -use Stagehand\Sessions\Action; +use Stagehand\Sessions\ModelConfig\ModelConfigObject\Provider; +use Stagehand\Sessions\SessionActParams\XLanguage; use Stagehand\Sessions\SessionActParams\XStreamResponse; use Stagehand\Sessions\SessionActResponse; use Stagehand\Sessions\SessionEndResponse; -use Stagehand\Sessions\SessionExecuteAgentParams\AgentConfig\Provider; -use Stagehand\Sessions\SessionExecuteAgentResponse; -use Stagehand\Sessions\SessionExtractResponse\Extraction; +use Stagehand\Sessions\SessionExecuteResponse; +use Stagehand\Sessions\SessionExtractResponse; use Stagehand\Sessions\SessionNavigateParams\Options\WaitUntil; use Stagehand\Sessions\SessionNavigateResponse; +use Stagehand\Sessions\SessionObserveResponse; +use Stagehand\Sessions\SessionStartParams\Browser\Type; +use Stagehand\Sessions\SessionStartParams\BrowserbaseSessionCreateParams\BrowserSettings\Fingerprint\Browser; +use Stagehand\Sessions\SessionStartParams\BrowserbaseSessionCreateParams\BrowserSettings\Fingerprint\Device; +use Stagehand\Sessions\SessionStartParams\BrowserbaseSessionCreateParams\BrowserSettings\Fingerprint\HTTPVersion; +use Stagehand\Sessions\SessionStartParams\BrowserbaseSessionCreateParams\BrowserSettings\Fingerprint\OperatingSystem; +use Stagehand\Sessions\SessionStartParams\BrowserbaseSessionCreateParams\Region; use Stagehand\Sessions\SessionStartResponse; +use Stagehand\Sessions\StreamEvent; final class SessionsService implements SessionsContract { @@ -38,38 +47,43 @@ public function __construct(private Client $client) /** * @api * - * Performs a browser action based on natural language instruction or - * a specific action object returned by observe(). + * Executes a browser action using natural language instructions or a predefined Action object. * - * @param string $sessionID Path param: The session ID returned by /sessions/start + * @param string $id Path param: Unique session identifier * @param string|array{ - * arguments: list, * description: string, - * method: string, * selector: string, - * backendNodeID?: int, - * }|Action $input Body param: Natural language instruction - * @param string $frameID Body param: Frame ID to act on (optional) + * arguments?: list, + * backendNodeID?: float, + * method?: string, + * } $input Body param: Natural language instruction or Action object + * @param string $frameID Body param: Target frame ID for the action * @param array{ - * model?: array{ + * model?: string|array{ + * modelName: string, * apiKey?: string, * baseURL?: string, - * model?: string, - * provider?: 'openai'|'anthropic'|'google'|\Stagehand\Sessions\ModelConfig\Provider, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|Provider, * }, - * timeout?: int, + * timeout?: float, * variables?: array, * } $options Body param: - * @param 'true'|'false'|XStreamResponse $xStreamResponse Header param: Enable Server-Sent Events streaming for real-time logs + * @param 'typescript'|'python'|'playground'|XLanguage $xLanguage Header param: Client SDK language + * @param string $xSDKVersion Header param: Version of the Stagehand SDK + * @param string|\DateTimeInterface $xSentAt Header param: ISO timestamp when request was sent + * @param 'true'|'false'|XStreamResponse $xStreamResponse Header param: Whether to stream the response via SSE * * @throws APIException */ public function act( - string $sessionID, - string|array|Action $input, + string $id, + string|array $input, ?string $frameID = null, ?array $options = null, - string|XStreamResponse $xStreamResponse = 'true', + string|XLanguage|null $xLanguage = null, + ?string $xSDKVersion = null, + string|\DateTimeInterface|null $xSentAt = null, + string|XStreamResponse|null $xStreamResponse = null, ?RequestOptions $requestOptions = null, ): SessionActResponse { $params = Util::removeNulls( @@ -77,12 +91,75 @@ public function act( 'input' => $input, 'frameID' => $frameID, 'options' => $options, + 'xLanguage' => $xLanguage, + 'xSDKVersion' => $xSDKVersion, + 'xSentAt' => $xSentAt, + 'xStreamResponse' => $xStreamResponse, + ], + ); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->act($id, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * @param string $id Path param: Unique session identifier + * @param string|array{ + * description: string, + * selector: string, + * arguments?: list, + * backendNodeID?: float, + * method?: string, + * } $input Body param: Natural language instruction or Action object + * @param string $frameID Body param: Target frame ID for the action + * @param array{ + * model?: string|array{ + * modelName: string, + * apiKey?: string, + * baseURL?: string, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|Provider, + * }, + * timeout?: float, + * variables?: array, + * } $options Body param: + * @param 'typescript'|'python'|'playground'|XLanguage $xLanguage Header param: Client SDK language + * @param string $xSDKVersion Header param: Version of the Stagehand SDK + * @param string|\DateTimeInterface $xSentAt Header param: ISO timestamp when request was sent + * @param 'true'|'false'|XStreamResponse $xStreamResponse Header param: Whether to stream the response via SSE + * + * @return BaseStream + * + * @throws APIException + */ + public function actStream( + string $id, + string|array $input, + ?string $frameID = null, + ?array $options = null, + string|XLanguage|null $xLanguage = null, + ?string $xSDKVersion = null, + string|\DateTimeInterface|null $xSentAt = null, + string|XStreamResponse|null $xStreamResponse = null, + ?RequestOptions $requestOptions = null, + ): BaseStream { + $params = Util::removeNulls( + [ + 'input' => $input, + 'frameID' => $frameID, + 'options' => $options, + 'xLanguage' => $xLanguage, + 'xSDKVersion' => $xSDKVersion, + 'xSentAt' => $xSentAt, 'xStreamResponse' => $xStreamResponse, ], ); // @phpstan-ignore-next-line argument.type - $response = $this->raw->act($sessionID, params: $params, requestOptions: $requestOptions); + $response = $this->raw->actStream($id, params: $params, requestOptions: $requestOptions); return $response->parse(); } @@ -90,18 +167,38 @@ public function act( /** * @api * - * Closes the browser and cleans up all resources associated with the session. + * Terminates the browser session and releases all associated resources. * - * @param string $sessionID The session ID returned by /sessions/start + * @param string $id Path param: Unique session identifier + * @param mixed $_forceBody Body param: + * @param 'typescript'|'python'|'playground'|\Stagehand\Sessions\SessionEndParams\XLanguage $xLanguage Header param: Client SDK language + * @param string $xSDKVersion Header param: Version of the Stagehand SDK + * @param string|\DateTimeInterface $xSentAt Header param: ISO timestamp when request was sent + * @param 'true'|'false'|\Stagehand\Sessions\SessionEndParams\XStreamResponse $xStreamResponse Header param: Whether to stream the response via SSE * * @throws APIException */ public function end( - string $sessionID, - ?RequestOptions $requestOptions = null + string $id, + mixed $_forceBody = null, + string|\Stagehand\Sessions\SessionEndParams\XLanguage|null $xLanguage = null, + ?string $xSDKVersion = null, + string|\DateTimeInterface|null $xSentAt = null, + string|\Stagehand\Sessions\SessionEndParams\XStreamResponse|null $xStreamResponse = null, + ?RequestOptions $requestOptions = null, ): SessionEndResponse { + $params = Util::removeNulls( + [ + '_forceBody' => $_forceBody, + 'xLanguage' => $xLanguage, + 'xSDKVersion' => $xSDKVersion, + 'xSentAt' => $xSentAt, + 'xStreamResponse' => $xStreamResponse, + ], + ); + // @phpstan-ignore-next-line argument.type - $response = $this->raw->end($sessionID, requestOptions: $requestOptions); + $response = $this->raw->end($id, params: $params, requestOptions: $requestOptions); return $response->parse(); } @@ -109,48 +206,113 @@ public function end( /** * @api * - * Runs an autonomous agent that can perform multiple actions to - * complete a complex task. + * Runs an autonomous AI agent that can perform complex multi-step browser tasks. + * + * @param string $id Path param: Unique session identifier + * @param array{ + * cua?: bool, + * model?: string|array{ + * modelName: string, + * apiKey?: string, + * baseURL?: string, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|Provider, + * }, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|\Stagehand\Sessions\SessionExecuteParams\AgentConfig\Provider, + * systemPrompt?: string, + * } $agentConfig Body param: + * @param array{ + * instruction: string, highlightCursor?: bool, maxSteps?: float + * } $executeOptions Body param: + * @param string $frameID Body param: Target frame ID for the agent + * @param 'typescript'|'python'|'playground'|\Stagehand\Sessions\SessionExecuteParams\XLanguage $xLanguage Header param: Client SDK language + * @param string $xSDKVersion Header param: Version of the Stagehand SDK + * @param string|\DateTimeInterface $xSentAt Header param: ISO timestamp when request was sent + * @param 'true'|'false'|\Stagehand\Sessions\SessionExecuteParams\XStreamResponse $xStreamResponse Header param: Whether to stream the response via SSE + * + * @throws APIException + */ + public function execute( + string $id, + array $agentConfig, + array $executeOptions, + ?string $frameID = null, + string|\Stagehand\Sessions\SessionExecuteParams\XLanguage|null $xLanguage = null, + ?string $xSDKVersion = null, + string|\DateTimeInterface|null $xSentAt = null, + string|\Stagehand\Sessions\SessionExecuteParams\XStreamResponse|null $xStreamResponse = null, + ?RequestOptions $requestOptions = null, + ): SessionExecuteResponse { + $params = Util::removeNulls( + [ + 'agentConfig' => $agentConfig, + 'executeOptions' => $executeOptions, + 'frameID' => $frameID, + 'xLanguage' => $xLanguage, + 'xSDKVersion' => $xSDKVersion, + 'xSentAt' => $xSentAt, + 'xStreamResponse' => $xStreamResponse, + ], + ); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->execute($id, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api * - * @param string $sessionID Path param: The session ID returned by /sessions/start + * @param string $id Path param: Unique session identifier * @param array{ * cua?: bool, * model?: string|array{ + * modelName: string, * apiKey?: string, * baseURL?: string, - * model?: string, - * provider?: 'openai'|'anthropic'|'google'|\Stagehand\Sessions\ModelConfig\Provider, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|Provider, * }, - * provider?: 'openai'|'anthropic'|'google'|Provider, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|\Stagehand\Sessions\SessionExecuteParams\AgentConfig\Provider, * systemPrompt?: string, * } $agentConfig Body param: * @param array{ - * instruction: string, highlightCursor?: bool, maxSteps?: int + * instruction: string, highlightCursor?: bool, maxSteps?: float * } $executeOptions Body param: - * @param string $frameID Body param: - * @param 'true'|'false'|\Stagehand\Sessions\SessionExecuteAgentParams\XStreamResponse $xStreamResponse Header param: Enable Server-Sent Events streaming for real-time logs + * @param string $frameID Body param: Target frame ID for the agent + * @param 'typescript'|'python'|'playground'|\Stagehand\Sessions\SessionExecuteParams\XLanguage $xLanguage Header param: Client SDK language + * @param string $xSDKVersion Header param: Version of the Stagehand SDK + * @param string|\DateTimeInterface $xSentAt Header param: ISO timestamp when request was sent + * @param 'true'|'false'|\Stagehand\Sessions\SessionExecuteParams\XStreamResponse $xStreamResponse Header param: Whether to stream the response via SSE + * + * @return BaseStream * * @throws APIException */ - public function executeAgent( - string $sessionID, + public function executeStream( + string $id, array $agentConfig, array $executeOptions, ?string $frameID = null, - string|\Stagehand\Sessions\SessionExecuteAgentParams\XStreamResponse $xStreamResponse = 'true', + string|\Stagehand\Sessions\SessionExecuteParams\XLanguage|null $xLanguage = null, + ?string $xSDKVersion = null, + string|\DateTimeInterface|null $xSentAt = null, + string|\Stagehand\Sessions\SessionExecuteParams\XStreamResponse|null $xStreamResponse = null, ?RequestOptions $requestOptions = null, - ): SessionExecuteAgentResponse { + ): BaseStream { $params = Util::removeNulls( [ 'agentConfig' => $agentConfig, 'executeOptions' => $executeOptions, 'frameID' => $frameID, + 'xLanguage' => $xLanguage, + 'xSDKVersion' => $xSDKVersion, + 'xSentAt' => $xSentAt, 'xStreamResponse' => $xStreamResponse, ], ); // @phpstan-ignore-next-line argument.type - $response = $this->raw->executeAgent($sessionID, params: $params, requestOptions: $requestOptions); + $response = $this->raw->executeStream($id, params: $params, requestOptions: $requestOptions); return $response->parse(); } @@ -158,50 +320,113 @@ public function executeAgent( /** * @api * - * Extracts data from the current page using natural language instructions - * and optional JSON schema for structured output. + * Extracts structured data from the current page using AI-powered analysis. * - * @param string $sessionID Path param: The session ID returned by /sessions/start - * @param string $frameID Body param: Frame ID to extract from - * @param string $instruction Body param: Natural language instruction for extraction + * @param string $id Path param: Unique session identifier + * @param string $frameID Body param: Target frame ID for the extraction + * @param string $instruction Body param: Natural language instruction for what to extract * @param array{ - * model?: array{ + * model?: string|array{ + * modelName: string, * apiKey?: string, * baseURL?: string, - * model?: string, - * provider?: 'openai'|'anthropic'|'google'|\Stagehand\Sessions\ModelConfig\Provider, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|Provider, * }, * selector?: string, - * timeout?: int, + * timeout?: float, * } $options Body param: - * @param array $schema Body param: JSON Schema for structured output - * @param 'true'|'false'|\Stagehand\Sessions\SessionExtractParams\XStreamResponse $xStreamResponse Header param: Enable Server-Sent Events streaming for real-time logs - * - * @return Extraction|array + * @param array $schema Body param: JSON Schema defining the structure of data to extract + * @param 'typescript'|'python'|'playground'|\Stagehand\Sessions\SessionExtractParams\XLanguage $xLanguage Header param: Client SDK language + * @param string $xSDKVersion Header param: Version of the Stagehand SDK + * @param string|\DateTimeInterface $xSentAt Header param: ISO timestamp when request was sent + * @param 'true'|'false'|\Stagehand\Sessions\SessionExtractParams\XStreamResponse $xStreamResponse Header param: Whether to stream the response via SSE * * @throws APIException */ public function extract( - string $sessionID, + string $id, + ?string $frameID = null, + ?string $instruction = null, + ?array $options = null, + ?array $schema = null, + string|\Stagehand\Sessions\SessionExtractParams\XLanguage|null $xLanguage = null, + ?string $xSDKVersion = null, + string|\DateTimeInterface|null $xSentAt = null, + string|\Stagehand\Sessions\SessionExtractParams\XStreamResponse|null $xStreamResponse = null, + ?RequestOptions $requestOptions = null, + ): SessionExtractResponse { + $params = Util::removeNulls( + [ + 'frameID' => $frameID, + 'instruction' => $instruction, + 'options' => $options, + 'schema' => $schema, + 'xLanguage' => $xLanguage, + 'xSDKVersion' => $xSDKVersion, + 'xSentAt' => $xSentAt, + 'xStreamResponse' => $xStreamResponse, + ], + ); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->extract($id, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * @param string $id Path param: Unique session identifier + * @param string $frameID Body param: Target frame ID for the extraction + * @param string $instruction Body param: Natural language instruction for what to extract + * @param array{ + * model?: string|array{ + * modelName: string, + * apiKey?: string, + * baseURL?: string, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|Provider, + * }, + * selector?: string, + * timeout?: float, + * } $options Body param: + * @param array $schema Body param: JSON Schema defining the structure of data to extract + * @param 'typescript'|'python'|'playground'|\Stagehand\Sessions\SessionExtractParams\XLanguage $xLanguage Header param: Client SDK language + * @param string $xSDKVersion Header param: Version of the Stagehand SDK + * @param string|\DateTimeInterface $xSentAt Header param: ISO timestamp when request was sent + * @param 'true'|'false'|\Stagehand\Sessions\SessionExtractParams\XStreamResponse $xStreamResponse Header param: Whether to stream the response via SSE + * + * @return BaseStream + * + * @throws APIException + */ + public function extractStream( + string $id, ?string $frameID = null, ?string $instruction = null, ?array $options = null, ?array $schema = null, - string|\Stagehand\Sessions\SessionExtractParams\XStreamResponse $xStreamResponse = 'true', + string|\Stagehand\Sessions\SessionExtractParams\XLanguage|null $xLanguage = null, + ?string $xSDKVersion = null, + string|\DateTimeInterface|null $xSentAt = null, + string|\Stagehand\Sessions\SessionExtractParams\XStreamResponse|null $xStreamResponse = null, ?RequestOptions $requestOptions = null, - ): Extraction|array { + ): BaseStream { $params = Util::removeNulls( [ 'frameID' => $frameID, 'instruction' => $instruction, 'options' => $options, 'schema' => $schema, + 'xLanguage' => $xLanguage, + 'xSDKVersion' => $xSDKVersion, + 'xSentAt' => $xSentAt, 'xStreamResponse' => $xStreamResponse, ], ); // @phpstan-ignore-next-line argument.type - $response = $this->raw->extract($sessionID, params: $params, requestOptions: $requestOptions); + $response = $this->raw->extractStream($id, params: $params, requestOptions: $requestOptions); return $response->parse(); } @@ -209,24 +434,34 @@ public function extract( /** * @api * - * Navigates the browser to the specified URL and waits for page load. + * Navigates the browser to the specified URL. * - * @param string $sessionID Path param: The session ID returned by /sessions/start + * @param string $id Path param: Unique session identifier * @param string $url Body param: URL to navigate to - * @param string $frameID Body param: + * @param string $frameID Body param: Target frame ID for the navigation * @param array{ - * waitUntil?: 'load'|'domcontentloaded'|'networkidle'|WaitUntil + * referer?: string, + * timeout?: float, + * waitUntil?: 'load'|'domcontentloaded'|'networkidle'|WaitUntil, * } $options Body param: - * @param 'true'|'false'|\Stagehand\Sessions\SessionNavigateParams\XStreamResponse $xStreamResponse Header param: Enable Server-Sent Events streaming for real-time logs + * @param bool $streamResponse Body param: Whether to stream the response via SSE + * @param 'typescript'|'python'|'playground'|\Stagehand\Sessions\SessionNavigateParams\XLanguage $xLanguage Header param: Client SDK language + * @param string $xSDKVersion Header param: Version of the Stagehand SDK + * @param string|\DateTimeInterface $xSentAt Header param: ISO timestamp when request was sent + * @param 'true'|'false'|\Stagehand\Sessions\SessionNavigateParams\XStreamResponse $xStreamResponse Header param: Whether to stream the response via SSE * * @throws APIException */ public function navigate( - string $sessionID, + string $id, string $url, ?string $frameID = null, ?array $options = null, - string|\Stagehand\Sessions\SessionNavigateParams\XStreamResponse $xStreamResponse = 'true', + ?bool $streamResponse = null, + string|\Stagehand\Sessions\SessionNavigateParams\XLanguage|null $xLanguage = null, + ?string $xSDKVersion = null, + string|\DateTimeInterface|null $xSentAt = null, + string|\Stagehand\Sessions\SessionNavigateParams\XStreamResponse|null $xStreamResponse = null, ?RequestOptions $requestOptions = null, ): SessionNavigateResponse { $params = Util::removeNulls( @@ -234,12 +469,16 @@ public function navigate( 'url' => $url, 'frameID' => $frameID, 'options' => $options, + 'streamResponse' => $streamResponse, + 'xLanguage' => $xLanguage, + 'xSDKVersion' => $xSDKVersion, + 'xSentAt' => $xSentAt, 'xStreamResponse' => $xStreamResponse, ], ); // @phpstan-ignore-next-line argument.type - $response = $this->raw->navigate($sessionID, params: $params, requestOptions: $requestOptions); + $response = $this->raw->navigate($id, params: $params, requestOptions: $requestOptions); return $response->parse(); } @@ -247,47 +486,107 @@ public function navigate( /** * @api * - * Returns a list of candidate actions that can be performed on the page, - * optionally filtered by natural language instruction. + * Identifies and returns available actions on the current page that match the given instruction. + * + * @param string $id Path param: Unique session identifier + * @param string $frameID Body param: Target frame ID for the observation + * @param string $instruction Body param: Natural language instruction for what actions to find + * @param array{ + * model?: string|array{ + * modelName: string, + * apiKey?: string, + * baseURL?: string, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|Provider, + * }, + * selector?: string, + * timeout?: float, + * } $options Body param: + * @param 'typescript'|'python'|'playground'|\Stagehand\Sessions\SessionObserveParams\XLanguage $xLanguage Header param: Client SDK language + * @param string $xSDKVersion Header param: Version of the Stagehand SDK + * @param string|\DateTimeInterface $xSentAt Header param: ISO timestamp when request was sent + * @param 'true'|'false'|\Stagehand\Sessions\SessionObserveParams\XStreamResponse $xStreamResponse Header param: Whether to stream the response via SSE + * + * @throws APIException + */ + public function observe( + string $id, + ?string $frameID = null, + ?string $instruction = null, + ?array $options = null, + string|\Stagehand\Sessions\SessionObserveParams\XLanguage|null $xLanguage = null, + ?string $xSDKVersion = null, + string|\DateTimeInterface|null $xSentAt = null, + string|\Stagehand\Sessions\SessionObserveParams\XStreamResponse|null $xStreamResponse = null, + ?RequestOptions $requestOptions = null, + ): SessionObserveResponse { + $params = Util::removeNulls( + [ + 'frameID' => $frameID, + 'instruction' => $instruction, + 'options' => $options, + 'xLanguage' => $xLanguage, + 'xSDKVersion' => $xSDKVersion, + 'xSentAt' => $xSentAt, + 'xStreamResponse' => $xStreamResponse, + ], + ); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->observe($id, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api * - * @param string $sessionID Path param: The session ID returned by /sessions/start - * @param string $frameID Body param: Frame ID to observe - * @param string $instruction Body param: Natural language instruction to filter actions + * @param string $id Path param: Unique session identifier + * @param string $frameID Body param: Target frame ID for the observation + * @param string $instruction Body param: Natural language instruction for what actions to find * @param array{ - * model?: array{ + * model?: string|array{ + * modelName: string, * apiKey?: string, * baseURL?: string, - * model?: string, - * provider?: 'openai'|'anthropic'|'google'|\Stagehand\Sessions\ModelConfig\Provider, + * provider?: 'openai'|'anthropic'|'google'|'microsoft'|Provider, * }, * selector?: string, - * timeout?: int, + * timeout?: float, * } $options Body param: - * @param 'true'|'false'|\Stagehand\Sessions\SessionObserveParams\XStreamResponse $xStreamResponse Header param: Enable Server-Sent Events streaming for real-time logs + * @param 'typescript'|'python'|'playground'|\Stagehand\Sessions\SessionObserveParams\XLanguage $xLanguage Header param: Client SDK language + * @param string $xSDKVersion Header param: Version of the Stagehand SDK + * @param string|\DateTimeInterface $xSentAt Header param: ISO timestamp when request was sent + * @param 'true'|'false'|\Stagehand\Sessions\SessionObserveParams\XStreamResponse $xStreamResponse Header param: Whether to stream the response via SSE * - * @return list + * @return BaseStream * * @throws APIException */ - public function observe( - string $sessionID, + public function observeStream( + string $id, ?string $frameID = null, ?string $instruction = null, ?array $options = null, - string|\Stagehand\Sessions\SessionObserveParams\XStreamResponse $xStreamResponse = 'true', + string|\Stagehand\Sessions\SessionObserveParams\XLanguage|null $xLanguage = null, + ?string $xSDKVersion = null, + string|\DateTimeInterface|null $xSentAt = null, + string|\Stagehand\Sessions\SessionObserveParams\XStreamResponse|null $xStreamResponse = null, ?RequestOptions $requestOptions = null, - ): array { + ): BaseStream { $params = Util::removeNulls( [ 'frameID' => $frameID, 'instruction' => $instruction, 'options' => $options, + 'xLanguage' => $xLanguage, + 'xSDKVersion' => $xSDKVersion, + 'xSentAt' => $xSentAt, 'xStreamResponse' => $xStreamResponse, ], ); // @phpstan-ignore-next-line argument.type - $response = $this->raw->observe($sessionID, params: $params, requestOptions: $requestOptions); + $response = $this->raw->observeStream($id, params: $params, requestOptions: $requestOptions); return $response->parse(); } @@ -295,38 +594,114 @@ public function observe( /** * @api * - * Initializes a new Stagehand session with a browser instance. - * Returns a session ID that must be used for all subsequent requests. + * Creates a new browser session with the specified configuration. Returns a session ID used for all subsequent operations. * - * @param string $browserbaseAPIKey API key for Browserbase Cloud - * @param string $browserbaseProjectID Project ID for Browserbase - * @param int $domSettleTimeout Timeout in ms to wait for DOM to settle - * @param string $model AI model to use for actions (must be prefixed with provider/) - * @param bool $selfHeal Enable self-healing for failed actions - * @param string $systemPrompt Custom system prompt for AI actions - * @param int $verbose Logging verbosity level + * @param string $modelName Body param: Model name to use for AI operations + * @param float $actTimeoutMs Body param: Timeout in ms for act operations (deprecated, v2 only) + * @param array{ + * cdpURL?: string, + * launchOptions?: array{ + * acceptDownloads?: bool, + * args?: list, + * cdpURL?: string, + * chromiumSandbox?: bool, + * connectTimeoutMs?: float, + * deviceScaleFactor?: float, + * devtools?: bool, + * downloadsPath?: string, + * executablePath?: string, + * hasTouch?: bool, + * headless?: bool, + * ignoreDefaultArgs?: bool|list, + * ignoreHTTPSErrors?: bool, + * locale?: string, + * preserveUserDataDir?: bool, + * proxy?: array{ + * server: string, bypass?: string, password?: string, username?: string + * }, + * userDataDir?: string, + * viewport?: array{height: float, width: float}, + * }, + * type?: 'local'|'browserbase'|Type, + * } $browser Body param: + * @param array{ + * browserSettings?: array{ + * advancedStealth?: bool, + * blockAds?: bool, + * context?: array{id: string, persist?: bool}, + * extensionID?: string, + * fingerprint?: array{ + * browsers?: list<'chrome'|'edge'|'firefox'|'safari'|Browser>, + * devices?: list<'desktop'|'mobile'|Device>, + * httpVersion?: '1'|'2'|HTTPVersion, + * locales?: list, + * operatingSystems?: list<'android'|'ios'|'linux'|'macos'|'windows'|OperatingSystem>, + * screen?: array{ + * maxHeight?: float, maxWidth?: float, minHeight?: float, minWidth?: float + * }, + * }, + * logSession?: bool, + * recordSession?: bool, + * solveCaptchas?: bool, + * viewport?: array{height?: float, width?: float}, + * }, + * extensionID?: string, + * keepAlive?: bool, + * projectID?: string, + * proxies?: bool|list>, + * region?: 'us-west-2'|'us-east-1'|'eu-central-1'|'ap-southeast-1'|Region, + * timeout?: float, + * userMetadata?: array, + * } $browserbaseSessionCreateParams Body param: + * @param string $browserbaseSessionID Body param: Existing Browserbase session ID to resume + * @param float $domSettleTimeoutMs Body param: Timeout in ms to wait for DOM to settle + * @param bool $experimental Body param: + * @param bool $selfHeal Body param: Enable self-healing for failed actions + * @param string $systemPrompt Body param: Custom system prompt for AI operations + * @param float $verbose Body param: Logging verbosity level (0=quiet, 1=normal, 2=debug) + * @param bool $waitForCaptchaSolves Body param: Wait for captcha solves (deprecated, v2 only) + * @param 'typescript'|'python'|'playground'|\Stagehand\Sessions\SessionStartParams\XLanguage $xLanguage Header param: Client SDK language + * @param string $xSDKVersion Header param: Version of the Stagehand SDK + * @param string|\DateTimeInterface $xSentAt Header param: ISO timestamp when request was sent + * @param 'true'|'false'|\Stagehand\Sessions\SessionStartParams\XStreamResponse $xStreamResponse Header param: Whether to stream the response via SSE * * @throws APIException */ public function start( - string $browserbaseAPIKey, - string $browserbaseProjectID, - ?int $domSettleTimeout = null, - ?string $model = null, + string $modelName, + ?float $actTimeoutMs = null, + ?array $browser = null, + ?array $browserbaseSessionCreateParams = null, + ?string $browserbaseSessionID = null, + ?float $domSettleTimeoutMs = null, + ?bool $experimental = null, ?bool $selfHeal = null, ?string $systemPrompt = null, - int $verbose = 0, + ?float $verbose = null, + ?bool $waitForCaptchaSolves = null, + string|\Stagehand\Sessions\SessionStartParams\XLanguage|null $xLanguage = null, + ?string $xSDKVersion = null, + string|\DateTimeInterface|null $xSentAt = null, + string|\Stagehand\Sessions\SessionStartParams\XStreamResponse|null $xStreamResponse = null, ?RequestOptions $requestOptions = null, ): SessionStartResponse { $params = Util::removeNulls( [ - 'browserbaseAPIKey' => $browserbaseAPIKey, - 'browserbaseProjectID' => $browserbaseProjectID, - 'domSettleTimeout' => $domSettleTimeout, - 'model' => $model, + 'modelName' => $modelName, + 'actTimeoutMs' => $actTimeoutMs, + 'browser' => $browser, + 'browserbaseSessionCreateParams' => $browserbaseSessionCreateParams, + 'browserbaseSessionID' => $browserbaseSessionID, + 'domSettleTimeoutMs' => $domSettleTimeoutMs, + 'experimental' => $experimental, 'selfHeal' => $selfHeal, 'systemPrompt' => $systemPrompt, 'verbose' => $verbose, + 'waitForCaptchaSolves' => $waitForCaptchaSolves, + 'xLanguage' => $xLanguage, + 'xSDKVersion' => $xSDKVersion, + 'xSentAt' => $xSentAt, + 'xStreamResponse' => $xStreamResponse, ], ); diff --git a/src/Sessions/Action.php b/src/Sessions/Action.php index acd24fb..3696c48 100644 --- a/src/Sessions/Action.php +++ b/src/Sessions/Action.php @@ -10,12 +10,14 @@ use Stagehand\Core\Contracts\BaseModel; /** + * Action object returned by observe and used by act. + * * @phpstan-type ActionShape = array{ - * arguments: list, * description: string, - * method: string, * selector: string, - * backendNodeID?: int|null, + * arguments?: list|null, + * backendNodeID?: float|null, + * method?: string|null, * } */ final class Action implements BaseModel @@ -23,14 +25,6 @@ final class Action implements BaseModel /** @use SdkModel */ use SdkModel; - /** - * Arguments for the method. - * - * @var list $arguments - */ - #[Required(list: 'string')] - public array $arguments; - /** * Human-readable description of the action. */ @@ -38,39 +32,43 @@ final class Action implements BaseModel public string $description; /** - * Method to execute (e.g., "click", "fill"). + * CSS selector or XPath for the element. */ #[Required] - public string $method; + public string $selector; /** - * CSS or XPath selector for the element. + * Arguments to pass to the method. + * + * @var list|null $arguments */ - #[Required] - public string $selector; + #[Optional(list: 'string')] + public ?array $arguments; /** - * CDP backend node ID. + * Backend node ID for the element. */ #[Optional('backendNodeId')] - public ?int $backendNodeID; + public ?float $backendNodeID; + + /** + * The method to execute (click, fill, etc.). + */ + #[Optional] + public ?string $method; /** * `new Action()` is missing required properties by the API. * * To enforce required parameters use * ``` - * Action::with(arguments: ..., description: ..., method: ..., selector: ...) + * Action::with(description: ..., selector: ...) * ``` * * Otherwise ensure the following setters are called * * ``` - * (new Action) - * ->withArguments(...) - * ->withDescription(...) - * ->withMethod(...) - * ->withSelector(...) + * (new Action)->withDescription(...)->withSelector(...) * ``` */ public function __construct() @@ -83,80 +81,80 @@ public function __construct() * * You must use named parameters to construct any parameters with a default value. * - * @param list $arguments + * @param list|null $arguments */ public static function with( - array $arguments, string $description, - string $method, string $selector, - ?int $backendNodeID = null, + ?array $arguments = null, + ?float $backendNodeID = null, + ?string $method = null, ): self { $self = new self; - $self['arguments'] = $arguments; $self['description'] = $description; - $self['method'] = $method; $self['selector'] = $selector; + null !== $arguments && $self['arguments'] = $arguments; null !== $backendNodeID && $self['backendNodeID'] = $backendNodeID; + null !== $method && $self['method'] = $method; return $self; } /** - * Arguments for the method. - * - * @param list $arguments + * Human-readable description of the action. */ - public function withArguments(array $arguments): self + public function withDescription(string $description): self { $self = clone $this; - $self['arguments'] = $arguments; + $self['description'] = $description; return $self; } /** - * Human-readable description of the action. + * CSS selector or XPath for the element. */ - public function withDescription(string $description): self + public function withSelector(string $selector): self { $self = clone $this; - $self['description'] = $description; + $self['selector'] = $selector; return $self; } /** - * Method to execute (e.g., "click", "fill"). + * Arguments to pass to the method. + * + * @param list $arguments */ - public function withMethod(string $method): self + public function withArguments(array $arguments): self { $self = clone $this; - $self['method'] = $method; + $self['arguments'] = $arguments; return $self; } /** - * CSS or XPath selector for the element. + * Backend node ID for the element. */ - public function withSelector(string $selector): self + public function withBackendNodeID(float $backendNodeID): self { $self = clone $this; - $self['selector'] = $selector; + $self['backendNodeID'] = $backendNodeID; return $self; } /** - * CDP backend node ID. + * The method to execute (click, fill, etc.). */ - public function withBackendNodeID(int $backendNodeID): self + public function withMethod(string $method): self { $self = clone $this; - $self['backendNodeID'] = $backendNodeID; + $self['method'] = $method; return $self; } diff --git a/src/Sessions/ModelConfig.php b/src/Sessions/ModelConfig.php index 3f5a2e8..86c9dfd 100644 --- a/src/Sessions/ModelConfig.php +++ b/src/Sessions/ModelConfig.php @@ -4,115 +4,27 @@ namespace Stagehand\Sessions; -use Stagehand\Core\Attributes\Optional; -use Stagehand\Core\Concerns\SdkModel; -use Stagehand\Core\Contracts\BaseModel; -use Stagehand\Sessions\ModelConfig\Provider; +use Stagehand\Core\Concerns\SdkUnion; +use Stagehand\Core\Conversion\Contracts\Converter; +use Stagehand\Core\Conversion\Contracts\ConverterSource; +use Stagehand\Sessions\ModelConfig\ModelConfigObject; /** - * @phpstan-type ModelConfigShape = array{ - * apiKey?: string|null, - * baseURL?: string|null, - * model?: string|null, - * provider?: value-of|null, - * } + * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', 'anthropic/claude-4.5-opus'). + * + * @phpstan-import-type ModelConfigObjectShape from \Stagehand\Sessions\ModelConfig\ModelConfigObject + * + * @phpstan-type ModelConfigShape = string|ModelConfigObjectShape */ -final class ModelConfig implements BaseModel +final class ModelConfig implements ConverterSource { - /** @use SdkModel */ - use SdkModel; + use SdkUnion; /** - * API key for the model provider. + * @return list|array */ - #[Optional] - public ?string $apiKey; - - /** - * Custom base URL for API. - */ - #[Optional] - public ?string $baseURL; - - /** - * Model name. - */ - #[Optional] - public ?string $model; - - /** @var value-of|null $provider */ - #[Optional(enum: Provider::class)] - public ?string $provider; - - 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 Provider|value-of $provider - */ - public static function with( - ?string $apiKey = null, - ?string $baseURL = null, - ?string $model = null, - Provider|string|null $provider = null, - ): self { - $self = new self; - - null !== $apiKey && $self['apiKey'] = $apiKey; - null !== $baseURL && $self['baseURL'] = $baseURL; - null !== $model && $self['model'] = $model; - null !== $provider && $self['provider'] = $provider; - - return $self; - } - - /** - * API key for the model provider. - */ - public function withAPIKey(string $apiKey): self + public static function variants(): array { - $self = clone $this; - $self['apiKey'] = $apiKey; - - return $self; - } - - /** - * Custom base URL for API. - */ - public function withBaseURL(string $baseURL): self - { - $self = clone $this; - $self['baseURL'] = $baseURL; - - return $self; - } - - /** - * Model name. - */ - public function withModel(string $model): self - { - $self = clone $this; - $self['model'] = $model; - - return $self; - } - - /** - * @param Provider|value-of $provider - */ - public function withProvider(Provider|string $provider): self - { - $self = clone $this; - $self['provider'] = $provider; - - return $self; + return ['string', ModelConfigObject::class]; } } diff --git a/src/Sessions/ModelConfig/ModelConfigObject.php b/src/Sessions/ModelConfig/ModelConfigObject.php new file mode 100644 index 0000000..5e0eb11 --- /dev/null +++ b/src/Sessions/ModelConfig/ModelConfigObject.php @@ -0,0 +1,140 @@ +, + * } + */ +final class ModelConfigObject implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Model name string without prefix (e.g., 'gpt-5-nano', 'claude-4.5-opus'). + */ + #[Required] + public string $modelName; + + /** + * API key for the model provider. + */ + #[Optional] + public ?string $apiKey; + + /** + * Base URL for the model provider. + */ + #[Optional] + public ?string $baseURL; + + /** + * AI provider for the model (or provide a baseURL endpoint instead). + * + * @var value-of|null $provider + */ + #[Optional(enum: Provider::class)] + public ?string $provider; + + /** + * `new ModelConfigObject()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * ModelConfigObject::with(modelName: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new ModelConfigObject)->withModelName(...) + * ``` + */ + 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 Provider|value-of|null $provider + */ + public static function with( + string $modelName, + ?string $apiKey = null, + ?string $baseURL = null, + Provider|string|null $provider = null, + ): self { + $self = new self; + + $self['modelName'] = $modelName; + + null !== $apiKey && $self['apiKey'] = $apiKey; + null !== $baseURL && $self['baseURL'] = $baseURL; + null !== $provider && $self['provider'] = $provider; + + return $self; + } + + /** + * Model name string without prefix (e.g., 'gpt-5-nano', 'claude-4.5-opus'). + */ + public function withModelName(string $modelName): self + { + $self = clone $this; + $self['modelName'] = $modelName; + + return $self; + } + + /** + * API key for the model provider. + */ + public function withAPIKey(string $apiKey): self + { + $self = clone $this; + $self['apiKey'] = $apiKey; + + return $self; + } + + /** + * Base URL for the model provider. + */ + public function withBaseURL(string $baseURL): self + { + $self = clone $this; + $self['baseURL'] = $baseURL; + + return $self; + } + + /** + * AI provider for the model (or provide a baseURL endpoint instead). + * + * @param Provider|value-of $provider + */ + public function withProvider(Provider|string $provider): self + { + $self = clone $this; + $self['provider'] = $provider; + + return $self; + } +} diff --git a/src/Sessions/ModelConfig/ModelConfigObject/Provider.php b/src/Sessions/ModelConfig/ModelConfigObject/Provider.php new file mode 100644 index 0000000..fb1ced7 --- /dev/null +++ b/src/Sessions/ModelConfig/ModelConfigObject/Provider.php @@ -0,0 +1,19 @@ +, - * description: string, - * method: string, - * selector: string, - * backendNodeID?: int|null, - * }, - * frameID?: string, - * options?: Options|array{ - * model?: ModelConfig|null, - * timeout?: int|null, - * variables?: array|null, - * }, - * xStreamResponse?: XStreamResponse|value-of, + * input: InputShape, + * frameID?: string|null, + * options?: null|Options|OptionsShape, + * xLanguage?: null|XLanguage|value-of, + * xSDKVersion?: string|null, + * xSentAt?: \DateTimeInterface|null, + * xStreamResponse?: null|XStreamResponse|value-of, * } */ final class SessionActParams implements BaseModel @@ -42,13 +38,13 @@ final class SessionActParams implements BaseModel use SdkParams; /** - * Natural language instruction. + * Natural language instruction or Action object. */ #[Required] public string|Action $input; /** - * Frame ID to act on (optional). + * Target frame ID for the action. */ #[Optional('frameId')] public ?string $frameID; @@ -56,7 +52,31 @@ final class SessionActParams implements BaseModel #[Optional] public ?Options $options; - /** @var value-of|null $xStreamResponse */ + /** + * Client SDK language. + * + * @var value-of|null $xLanguage + */ + #[Optional(enum: XLanguage::class)] + public ?string $xLanguage; + + /** + * Version of the Stagehand SDK. + */ + #[Optional] + public ?string $xSDKVersion; + + /** + * ISO timestamp when request was sent. + */ + #[Optional] + public ?\DateTimeInterface $xSentAt; + + /** + * Whether to stream the response via SSE. + * + * @var value-of|null $xStreamResponse + */ #[Optional(enum: XStreamResponse::class)] public ?string $xStreamResponse; @@ -84,24 +104,18 @@ public function __construct() * * You must use named parameters to construct any parameters with a default value. * - * @param string|Action|array{ - * arguments: list, - * description: string, - * method: string, - * selector: string, - * backendNodeID?: int|null, - * } $input - * @param Options|array{ - * model?: ModelConfig|null, - * timeout?: int|null, - * variables?: array|null, - * } $options - * @param XStreamResponse|value-of $xStreamResponse + * @param InputShape $input + * @param Options|OptionsShape|null $options + * @param XLanguage|value-of|null $xLanguage + * @param XStreamResponse|value-of|null $xStreamResponse */ public static function with( string|Action|array $input, ?string $frameID = null, Options|array|null $options = null, + XLanguage|string|null $xLanguage = null, + ?string $xSDKVersion = null, + ?\DateTimeInterface $xSentAt = null, XStreamResponse|string|null $xStreamResponse = null, ): self { $self = new self; @@ -110,21 +124,18 @@ public static function with( null !== $frameID && $self['frameID'] = $frameID; null !== $options && $self['options'] = $options; + null !== $xLanguage && $self['xLanguage'] = $xLanguage; + null !== $xSDKVersion && $self['xSDKVersion'] = $xSDKVersion; + null !== $xSentAt && $self['xSentAt'] = $xSentAt; null !== $xStreamResponse && $self['xStreamResponse'] = $xStreamResponse; return $self; } /** - * Natural language instruction. + * Natural language instruction or Action object. * - * @param string|Action|array{ - * arguments: list, - * description: string, - * method: string, - * selector: string, - * backendNodeID?: int|null, - * } $input + * @param InputShape $input */ public function withInput(string|Action|array $input): self { @@ -135,7 +146,7 @@ public function withInput(string|Action|array $input): self } /** - * Frame ID to act on (optional). + * Target frame ID for the action. */ public function withFrameID(string $frameID): self { @@ -146,11 +157,7 @@ public function withFrameID(string $frameID): self } /** - * @param Options|array{ - * model?: ModelConfig|null, - * timeout?: int|null, - * variables?: array|null, - * } $options + * @param Options|OptionsShape $options */ public function withOptions(Options|array $options): self { @@ -161,6 +168,43 @@ public function withOptions(Options|array $options): self } /** + * Client SDK language. + * + * @param XLanguage|value-of $xLanguage + */ + public function withXLanguage(XLanguage|string $xLanguage): self + { + $self = clone $this; + $self['xLanguage'] = $xLanguage; + + return $self; + } + + /** + * Version of the Stagehand SDK. + */ + public function withXSDKVersion(string $xSDKVersion): self + { + $self = clone $this; + $self['xSDKVersion'] = $xSDKVersion; + + return $self; + } + + /** + * ISO timestamp when request was sent. + */ + public function withXSentAt(\DateTimeInterface $xSentAt): self + { + $self = clone $this; + $self['xSentAt'] = $xSentAt; + + return $self; + } + + /** + * Whether to stream the response via SSE. + * * @param XStreamResponse|value-of $xStreamResponse */ public function withXStreamResponse( diff --git a/src/Sessions/SessionActParams/Input.php b/src/Sessions/SessionActParams/Input.php index fe1645f..8e6a27e 100644 --- a/src/Sessions/SessionActParams/Input.php +++ b/src/Sessions/SessionActParams/Input.php @@ -10,7 +10,11 @@ use Stagehand\Sessions\Action; /** - * Natural language instruction. + * Natural language instruction or Action object. + * + * @phpstan-import-type ActionShape from \Stagehand\Sessions\Action + * + * @phpstan-type InputShape = string|ActionShape */ final class Input implements ConverterSource { diff --git a/src/Sessions/SessionActParams/Options.php b/src/Sessions/SessionActParams/Options.php index 37a97d6..1cae53a 100644 --- a/src/Sessions/SessionActParams/Options.php +++ b/src/Sessions/SessionActParams/Options.php @@ -7,13 +7,14 @@ use Stagehand\Core\Attributes\Optional; use Stagehand\Core\Concerns\SdkModel; use Stagehand\Core\Contracts\BaseModel; -use Stagehand\Sessions\ModelConfig; -use Stagehand\Sessions\ModelConfig\Provider; +use Stagehand\Sessions\ModelConfig\ModelConfigObject; /** + * @phpstan-import-type ModelConfigShape from \Stagehand\Sessions\ModelConfig + * * @phpstan-type OptionsShape = array{ - * model?: ModelConfig|null, - * timeout?: int|null, + * model?: ModelConfigShape|null, + * timeout?: float|null, * variables?: array|null, * } */ @@ -22,17 +23,20 @@ final class Options implements BaseModel /** @use SdkModel */ use SdkModel; + /** + * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', 'anthropic/claude-4.5-opus'). + */ #[Optional] - public ?ModelConfig $model; + public string|ModelConfigObject|null $model; /** - * Timeout in milliseconds. + * Timeout in ms for the action. */ #[Optional] - public ?int $timeout; + public ?float $timeout; /** - * Template variables for instruction. + * Variables to substitute in the action instruction. * * @var array|null $variables */ @@ -49,17 +53,12 @@ public function __construct() * * You must use named parameters to construct any parameters with a default value. * - * @param ModelConfig|array{ - * apiKey?: string|null, - * baseURL?: string|null, - * model?: string|null, - * provider?: value-of|null, - * } $model - * @param array $variables + * @param ModelConfigShape|null $model + * @param array|null $variables */ public static function with( - ModelConfig|array|null $model = null, - ?int $timeout = null, + string|ModelConfigObject|array|null $model = null, + ?float $timeout = null, ?array $variables = null, ): self { $self = new self; @@ -72,14 +71,11 @@ public static function with( } /** - * @param ModelConfig|array{ - * apiKey?: string|null, - * baseURL?: string|null, - * model?: string|null, - * provider?: value-of|null, - * } $model + * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', 'anthropic/claude-4.5-opus'). + * + * @param ModelConfigShape $model */ - public function withModel(ModelConfig|array $model): self + public function withModel(string|ModelConfigObject|array $model): self { $self = clone $this; $self['model'] = $model; @@ -88,9 +84,9 @@ public function withModel(ModelConfig|array $model): self } /** - * Timeout in milliseconds. + * Timeout in ms for the action. */ - public function withTimeout(int $timeout): self + public function withTimeout(float $timeout): self { $self = clone $this; $self['timeout'] = $timeout; @@ -99,7 +95,7 @@ public function withTimeout(int $timeout): self } /** - * Template variables for instruction. + * Variables to substitute in the action instruction. * * @param array $variables */ diff --git a/src/Sessions/SessionActParams/XLanguage.php b/src/Sessions/SessionActParams/XLanguage.php new file mode 100644 index 0000000..a13d848 --- /dev/null +++ b/src/Sessions/SessionActParams/XLanguage.php @@ -0,0 +1,17 @@ +, message: string, success: bool + * data: Data|DataShape, success: bool * } */ final class SessionActResponse implements BaseModel @@ -18,22 +21,11 @@ final class SessionActResponse implements BaseModel /** @use SdkModel */ use SdkModel; - /** - * Actions that were executed. - * - * @var list $actions - */ - #[Required(list: Action::class)] - public array $actions; - - /** - * Result message. - */ #[Required] - public string $message; + public Data $data; /** - * Whether the action succeeded. + * Indicates whether the request was successful. */ #[Required] public bool $success; @@ -43,13 +35,13 @@ final class SessionActResponse implements BaseModel * * To enforce required parameters use * ``` - * SessionActResponse::with(actions: ..., message: ..., success: ...) + * SessionActResponse::with(data: ..., success: ...) * ``` * * Otherwise ensure the following setters are called * * ``` - * (new SessionActResponse)->withActions(...)->withMessage(...)->withSuccess(...) + * (new SessionActResponse)->withData(...)->withSuccess(...) * ``` */ public function __construct() @@ -62,60 +54,31 @@ public function __construct() * * You must use named parameters to construct any parameters with a default value. * - * @param list, - * description: string, - * method: string, - * selector: string, - * backendNodeID?: int|null, - * }> $actions + * @param Data|DataShape $data */ - public static function with( - array $actions, - string $message, - bool $success - ): self { + public static function with(Data|array $data, bool $success): self + { $self = new self; - $self['actions'] = $actions; - $self['message'] = $message; + $self['data'] = $data; $self['success'] = $success; return $self; } /** - * Actions that were executed. - * - * @param list, - * description: string, - * method: string, - * selector: string, - * backendNodeID?: int|null, - * }> $actions - */ - public function withActions(array $actions): self - { - $self = clone $this; - $self['actions'] = $actions; - - return $self; - } - - /** - * Result message. + * @param Data|DataShape $data */ - public function withMessage(string $message): self + public function withData(Data|array $data): self { $self = clone $this; - $self['message'] = $message; + $self['data'] = $data; return $self; } /** - * Whether the action succeeded. + * Indicates whether the request was successful. */ public function withSuccess(bool $success): self { diff --git a/src/Sessions/SessionActResponse/Data.php b/src/Sessions/SessionActResponse/Data.php new file mode 100644 index 0000000..73af7f4 --- /dev/null +++ b/src/Sessions/SessionActResponse/Data.php @@ -0,0 +1,94 @@ + */ + use SdkModel; + + #[Required] + public Result $result; + + /** + * Action ID for tracking. + */ + #[Optional('actionId')] + public ?string $actionID; + + /** + * `new Data()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Data::with(result: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Data)->withResult(...) + * ``` + */ + 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 Result|ResultShape $result + */ + public static function with( + Result|array $result, + ?string $actionID = null + ): self { + $self = new self; + + $self['result'] = $result; + + null !== $actionID && $self['actionID'] = $actionID; + + return $self; + } + + /** + * @param Result|ResultShape $result + */ + public function withResult(Result|array $result): self + { + $self = clone $this; + $self['result'] = $result; + + return $self; + } + + /** + * Action ID for tracking. + */ + public function withActionID(string $actionID): self + { + $self = clone $this; + $self['actionID'] = $actionID; + + return $self; + } +} diff --git a/src/Sessions/SessionActResponse/Data/Result.php b/src/Sessions/SessionActResponse/Data/Result.php new file mode 100644 index 0000000..e2c375c --- /dev/null +++ b/src/Sessions/SessionActResponse/Data/Result.php @@ -0,0 +1,144 @@ +, + * message: string, + * success: bool, + * } + */ +final class Result implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Description of the action that was performed. + */ + #[Required] + public string $actionDescription; + + /** + * List of actions that were executed. + * + * @var list $actions + */ + #[Required(list: Action::class)] + public array $actions; + + /** + * Human-readable result message. + */ + #[Required] + public string $message; + + /** + * Whether the action completed successfully. + */ + #[Required] + public bool $success; + + /** + * `new Result()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Result::with(actionDescription: ..., actions: ..., message: ..., success: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Result) + * ->withActionDescription(...) + * ->withActions(...) + * ->withMessage(...) + * ->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 list $actions + */ + public static function with( + string $actionDescription, + array $actions, + string $message, + bool $success + ): self { + $self = new self; + + $self['actionDescription'] = $actionDescription; + $self['actions'] = $actions; + $self['message'] = $message; + $self['success'] = $success; + + return $self; + } + + /** + * Description of the action that was performed. + */ + public function withActionDescription(string $actionDescription): self + { + $self = clone $this; + $self['actionDescription'] = $actionDescription; + + return $self; + } + + /** + * List of actions that were executed. + * + * @param list $actions + */ + public function withActions(array $actions): self + { + $self = clone $this; + $self['actions'] = $actions; + + return $self; + } + + /** + * Human-readable result message. + */ + public function withMessage(string $message): self + { + $self = clone $this; + $self['message'] = $message; + + return $self; + } + + /** + * Whether the action completed successfully. + */ + public function withSuccess(bool $success): self + { + $self = clone $this; + $self['success'] = $success; + + return $self; + } +} diff --git a/src/Sessions/SessionActResponse/Data/Result/Action.php b/src/Sessions/SessionActResponse/Data/Result/Action.php new file mode 100644 index 0000000..9e4e3e9 --- /dev/null +++ b/src/Sessions/SessionActResponse/Data/Result/Action.php @@ -0,0 +1,161 @@ +|null, + * backendNodeID?: float|null, + * method?: string|null, + * } + */ +final class Action implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Human-readable description of the action. + */ + #[Required] + public string $description; + + /** + * CSS selector or XPath for the element. + */ + #[Required] + public string $selector; + + /** + * Arguments to pass to the method. + * + * @var list|null $arguments + */ + #[Optional(list: 'string')] + public ?array $arguments; + + /** + * Backend node ID for the element. + */ + #[Optional('backendNodeId')] + public ?float $backendNodeID; + + /** + * The method to execute (click, fill, etc.). + */ + #[Optional] + public ?string $method; + + /** + * `new Action()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Action::with(description: ..., selector: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Action)->withDescription(...)->withSelector(...) + * ``` + */ + 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 list|null $arguments + */ + public static function with( + string $description, + string $selector, + ?array $arguments = null, + ?float $backendNodeID = null, + ?string $method = null, + ): self { + $self = new self; + + $self['description'] = $description; + $self['selector'] = $selector; + + null !== $arguments && $self['arguments'] = $arguments; + null !== $backendNodeID && $self['backendNodeID'] = $backendNodeID; + null !== $method && $self['method'] = $method; + + return $self; + } + + /** + * Human-readable description of the action. + */ + public function withDescription(string $description): self + { + $self = clone $this; + $self['description'] = $description; + + return $self; + } + + /** + * CSS selector or XPath for the element. + */ + public function withSelector(string $selector): self + { + $self = clone $this; + $self['selector'] = $selector; + + return $self; + } + + /** + * Arguments to pass to the method. + * + * @param list $arguments + */ + public function withArguments(array $arguments): self + { + $self = clone $this; + $self['arguments'] = $arguments; + + return $self; + } + + /** + * Backend node ID for the element. + */ + public function withBackendNodeID(float $backendNodeID): self + { + $self = clone $this; + $self['backendNodeID'] = $backendNodeID; + + return $self; + } + + /** + * The method to execute (click, fill, etc.). + */ + public function withMethod(string $method): self + { + $self = clone $this; + $self['method'] = $method; + + return $self; + } +} diff --git a/src/Sessions/SessionEndParams.php b/src/Sessions/SessionEndParams.php new file mode 100644 index 0000000..56ba309 --- /dev/null +++ b/src/Sessions/SessionEndParams.php @@ -0,0 +1,151 @@ +, + * xSDKVersion?: string|null, + * xSentAt?: \DateTimeInterface|null, + * xStreamResponse?: null|XStreamResponse|value-of, + * } + */ +final class SessionEndParams implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + use SdkParams; + + #[Optional] + public mixed $_forceBody; + + /** + * Client SDK language. + * + * @var value-of|null $xLanguage + */ + #[Optional(enum: XLanguage::class)] + public ?string $xLanguage; + + /** + * Version of the Stagehand SDK. + */ + #[Optional] + public ?string $xSDKVersion; + + /** + * ISO timestamp when request was sent. + */ + #[Optional] + public ?\DateTimeInterface $xSentAt; + + /** + * Whether to stream the response via SSE. + * + * @var value-of|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 XLanguage|value-of|null $xLanguage + * @param XStreamResponse|value-of|null $xStreamResponse + */ + public static function with( + mixed $_forceBody = null, + XLanguage|string|null $xLanguage = null, + ?string $xSDKVersion = null, + ?\DateTimeInterface $xSentAt = null, + XStreamResponse|string|null $xStreamResponse = null, + ): self { + $self = new self; + + null !== $_forceBody && $self['_forceBody'] = $_forceBody; + null !== $xLanguage && $self['xLanguage'] = $xLanguage; + null !== $xSDKVersion && $self['xSDKVersion'] = $xSDKVersion; + null !== $xSentAt && $self['xSentAt'] = $xSentAt; + null !== $xStreamResponse && $self['xStreamResponse'] = $xStreamResponse; + + return $self; + } + + public function withForceBody(mixed $_forceBody): self + { + $self = clone $this; + $self['_forceBody'] = $_forceBody; + + return $self; + } + + /** + * Client SDK language. + * + * @param XLanguage|value-of $xLanguage + */ + public function withXLanguage(XLanguage|string $xLanguage): self + { + $self = clone $this; + $self['xLanguage'] = $xLanguage; + + return $self; + } + + /** + * Version of the Stagehand SDK. + */ + public function withXSDKVersion(string $xSDKVersion): self + { + $self = clone $this; + $self['xSDKVersion'] = $xSDKVersion; + + return $self; + } + + /** + * ISO timestamp when request was sent. + */ + public function withXSentAt(\DateTimeInterface $xSentAt): self + { + $self = clone $this; + $self['xSentAt'] = $xSentAt; + + return $self; + } + + /** + * Whether to stream the response via SSE. + * + * @param XStreamResponse|value-of $xStreamResponse + */ + public function withXStreamResponse( + XStreamResponse|string $xStreamResponse + ): self { + $self = clone $this; + $self['xStreamResponse'] = $xStreamResponse; + + return $self; + } +} diff --git a/src/Sessions/SessionEndParams/XLanguage.php b/src/Sessions/SessionEndParams/XLanguage.php new file mode 100644 index 0000000..0857a8f --- /dev/null +++ b/src/Sessions/SessionEndParams/XLanguage.php @@ -0,0 +1,17 @@ + */ use SdkModel; - #[Optional] - public ?bool $success; + /** + * Indicates whether the request was successful. + */ + #[Required] + public bool $success; + /** + * `new SessionEndResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * SessionEndResponse::with(success: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new SessionEndResponse)->withSuccess(...) + * ``` + */ public function __construct() { $this->initialize(); @@ -29,15 +46,18 @@ public function __construct() * * You must use named parameters to construct any parameters with a default value. */ - public static function with(?bool $success = null): self + public static function with(bool $success): self { $self = new self; - null !== $success && $self['success'] = $success; + $self['success'] = $success; return $self; } + /** + * Indicates whether the request was successful. + */ public function withSuccess(bool $success): self { $self = clone $this; diff --git a/src/Sessions/SessionExecuteAgentParams.php b/src/Sessions/SessionExecuteAgentParams.php deleted file mode 100644 index fc541ff..0000000 --- a/src/Sessions/SessionExecuteAgentParams.php +++ /dev/null @@ -1,157 +0,0 @@ -|null, - * systemPrompt?: string|null, - * }, - * executeOptions: ExecuteOptions|array{ - * instruction: string, highlightCursor?: bool|null, maxSteps?: int|null - * }, - * frameID?: string, - * xStreamResponse?: XStreamResponse|value-of, - * } - */ -final class SessionExecuteAgentParams implements BaseModel -{ - /** @use SdkModel */ - use SdkModel; - use SdkParams; - - #[Required] - public AgentConfig $agentConfig; - - #[Required] - public ExecuteOptions $executeOptions; - - #[Optional('frameId')] - public ?string $frameID; - - /** @var value-of|null $xStreamResponse */ - #[Optional(enum: XStreamResponse::class)] - public ?string $xStreamResponse; - - /** - * `new SessionExecuteAgentParams()` is missing required properties by the API. - * - * To enforce required parameters use - * ``` - * SessionExecuteAgentParams::with(agentConfig: ..., executeOptions: ...) - * ``` - * - * Otherwise ensure the following setters are called - * - * ``` - * (new SessionExecuteAgentParams)->withAgentConfig(...)->withExecuteOptions(...) - * ``` - */ - 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 AgentConfig|array{ - * cua?: bool|null, - * model?: string|ModelConfig|null, - * provider?: value-of|null, - * systemPrompt?: string|null, - * } $agentConfig - * @param ExecuteOptions|array{ - * instruction: string, highlightCursor?: bool|null, maxSteps?: int|null - * } $executeOptions - * @param XStreamResponse|value-of $xStreamResponse - */ - public static function with( - AgentConfig|array $agentConfig, - ExecuteOptions|array $executeOptions, - ?string $frameID = null, - XStreamResponse|string|null $xStreamResponse = null, - ): self { - $self = new self; - - $self['agentConfig'] = $agentConfig; - $self['executeOptions'] = $executeOptions; - - null !== $frameID && $self['frameID'] = $frameID; - null !== $xStreamResponse && $self['xStreamResponse'] = $xStreamResponse; - - return $self; - } - - /** - * @param AgentConfig|array{ - * cua?: bool|null, - * model?: string|ModelConfig|null, - * provider?: value-of|null, - * systemPrompt?: string|null, - * } $agentConfig - */ - public function withAgentConfig(AgentConfig|array $agentConfig): self - { - $self = clone $this; - $self['agentConfig'] = $agentConfig; - - return $self; - } - - /** - * @param ExecuteOptions|array{ - * instruction: string, highlightCursor?: bool|null, maxSteps?: int|null - * } $executeOptions - */ - public function withExecuteOptions( - ExecuteOptions|array $executeOptions - ): self { - $self = clone $this; - $self['executeOptions'] = $executeOptions; - - return $self; - } - - public function withFrameID(string $frameID): self - { - $self = clone $this; - $self['frameID'] = $frameID; - - return $self; - } - - /** - * @param XStreamResponse|value-of $xStreamResponse - */ - public function withXStreamResponse( - XStreamResponse|string $xStreamResponse - ): self { - $self = clone $this; - $self['xStreamResponse'] = $xStreamResponse; - - return $self; - } -} diff --git a/src/Sessions/SessionExecuteAgentParams/AgentConfig/Provider.php b/src/Sessions/SessionExecuteAgentParams/AgentConfig/Provider.php deleted file mode 100644 index 9d22eb5..0000000 --- a/src/Sessions/SessionExecuteAgentParams/AgentConfig/Provider.php +++ /dev/null @@ -1,14 +0,0 @@ - */ - use SdkModel; - - /** - * Final message from the agent. - */ - #[Optional] - public ?string $message; - - 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. - */ - public static function with(?string $message = null): self - { - $self = new self; - - null !== $message && $self['message'] = $message; - - return $self; - } - - /** - * Final message from the agent. - */ - public function withMessage(string $message): self - { - $self = clone $this; - $self['message'] = $message; - - return $self; - } -} diff --git a/src/Sessions/SessionExecuteParams.php b/src/Sessions/SessionExecuteParams.php new file mode 100644 index 0000000..c7e5e88 --- /dev/null +++ b/src/Sessions/SessionExecuteParams.php @@ -0,0 +1,215 @@ +, + * xSDKVersion?: string|null, + * xSentAt?: \DateTimeInterface|null, + * xStreamResponse?: null|XStreamResponse|value-of, + * } + */ +final class SessionExecuteParams implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + use SdkParams; + + #[Required] + public AgentConfig $agentConfig; + + #[Required] + public ExecuteOptions $executeOptions; + + /** + * Target frame ID for the agent. + */ + #[Optional('frameId')] + public ?string $frameID; + + /** + * Client SDK language. + * + * @var value-of|null $xLanguage + */ + #[Optional(enum: XLanguage::class)] + public ?string $xLanguage; + + /** + * Version of the Stagehand SDK. + */ + #[Optional] + public ?string $xSDKVersion; + + /** + * ISO timestamp when request was sent. + */ + #[Optional] + public ?\DateTimeInterface $xSentAt; + + /** + * Whether to stream the response via SSE. + * + * @var value-of|null $xStreamResponse + */ + #[Optional(enum: XStreamResponse::class)] + public ?string $xStreamResponse; + + /** + * `new SessionExecuteParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * SessionExecuteParams::with(agentConfig: ..., executeOptions: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new SessionExecuteParams)->withAgentConfig(...)->withExecuteOptions(...) + * ``` + */ + 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 AgentConfig|AgentConfigShape $agentConfig + * @param ExecuteOptions|ExecuteOptionsShape $executeOptions + * @param XLanguage|value-of|null $xLanguage + * @param XStreamResponse|value-of|null $xStreamResponse + */ + public static function with( + AgentConfig|array $agentConfig, + ExecuteOptions|array $executeOptions, + ?string $frameID = null, + XLanguage|string|null $xLanguage = null, + ?string $xSDKVersion = null, + ?\DateTimeInterface $xSentAt = null, + XStreamResponse|string|null $xStreamResponse = null, + ): self { + $self = new self; + + $self['agentConfig'] = $agentConfig; + $self['executeOptions'] = $executeOptions; + + null !== $frameID && $self['frameID'] = $frameID; + null !== $xLanguage && $self['xLanguage'] = $xLanguage; + null !== $xSDKVersion && $self['xSDKVersion'] = $xSDKVersion; + null !== $xSentAt && $self['xSentAt'] = $xSentAt; + null !== $xStreamResponse && $self['xStreamResponse'] = $xStreamResponse; + + return $self; + } + + /** + * @param AgentConfig|AgentConfigShape $agentConfig + */ + public function withAgentConfig(AgentConfig|array $agentConfig): self + { + $self = clone $this; + $self['agentConfig'] = $agentConfig; + + return $self; + } + + /** + * @param ExecuteOptions|ExecuteOptionsShape $executeOptions + */ + public function withExecuteOptions( + ExecuteOptions|array $executeOptions + ): self { + $self = clone $this; + $self['executeOptions'] = $executeOptions; + + return $self; + } + + /** + * Target frame ID for the agent. + */ + public function withFrameID(string $frameID): self + { + $self = clone $this; + $self['frameID'] = $frameID; + + return $self; + } + + /** + * Client SDK language. + * + * @param XLanguage|value-of $xLanguage + */ + public function withXLanguage(XLanguage|string $xLanguage): self + { + $self = clone $this; + $self['xLanguage'] = $xLanguage; + + return $self; + } + + /** + * Version of the Stagehand SDK. + */ + public function withXSDKVersion(string $xSDKVersion): self + { + $self = clone $this; + $self['xSDKVersion'] = $xSDKVersion; + + return $self; + } + + /** + * ISO timestamp when request was sent. + */ + public function withXSentAt(\DateTimeInterface $xSentAt): self + { + $self = clone $this; + $self['xSentAt'] = $xSentAt; + + return $self; + } + + /** + * Whether to stream the response via SSE. + * + * @param XStreamResponse|value-of $xStreamResponse + */ + public function withXStreamResponse( + XStreamResponse|string $xStreamResponse + ): self { + $self = clone $this; + $self['xStreamResponse'] = $xStreamResponse; + + return $self; + } +} diff --git a/src/Sessions/SessionExecuteAgentParams/AgentConfig.php b/src/Sessions/SessionExecuteParams/AgentConfig.php similarity index 61% rename from src/Sessions/SessionExecuteAgentParams/AgentConfig.php rename to src/Sessions/SessionExecuteParams/AgentConfig.php index d052c16..fefd2cf 100644 --- a/src/Sessions/SessionExecuteAgentParams/AgentConfig.php +++ b/src/Sessions/SessionExecuteParams/AgentConfig.php @@ -2,19 +2,21 @@ declare(strict_types=1); -namespace Stagehand\Sessions\SessionExecuteAgentParams; +namespace Stagehand\Sessions\SessionExecuteParams; use Stagehand\Core\Attributes\Optional; use Stagehand\Core\Concerns\SdkModel; use Stagehand\Core\Contracts\BaseModel; -use Stagehand\Sessions\ModelConfig; -use Stagehand\Sessions\SessionExecuteAgentParams\AgentConfig\Provider; +use Stagehand\Sessions\ModelConfig\ModelConfigObject; +use Stagehand\Sessions\SessionExecuteParams\AgentConfig\Provider; /** + * @phpstan-import-type ModelConfigShape from \Stagehand\Sessions\ModelConfig + * * @phpstan-type AgentConfigShape = array{ * cua?: bool|null, - * model?: string|null|ModelConfig, - * provider?: value-of|null, + * model?: ModelConfigShape|null, + * provider?: null|Provider|value-of, * systemPrompt?: string|null, * } */ @@ -29,13 +31,23 @@ final class AgentConfig implements BaseModel #[Optional] public ?bool $cua; + /** + * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', 'anthropic/claude-4.5-opus'). + */ #[Optional] - public string|ModelConfig|null $model; + public string|ModelConfigObject|null $model; - /** @var value-of|null $provider */ + /** + * AI provider for the agent (legacy, use model: openai/gpt-5-nano instead). + * + * @var value-of|null $provider + */ #[Optional(enum: Provider::class)] public ?string $provider; + /** + * Custom system prompt for the agent. + */ #[Optional] public ?string $systemPrompt; @@ -49,17 +61,12 @@ public function __construct() * * You must use named parameters to construct any parameters with a default value. * - * @param string|ModelConfig|array{ - * apiKey?: string|null, - * baseURL?: string|null, - * model?: string|null, - * provider?: value-of|null, - * } $model - * @param Provider|value-of $provider + * @param ModelConfigShape|null $model + * @param Provider|value-of|null $provider */ public static function with( ?bool $cua = null, - string|ModelConfig|array|null $model = null, + string|ModelConfigObject|array|null $model = null, Provider|string|null $provider = null, ?string $systemPrompt = null, ): self { @@ -85,14 +92,11 @@ public function withCua(bool $cua): self } /** - * @param string|ModelConfig|array{ - * apiKey?: string|null, - * baseURL?: string|null, - * model?: string|null, - * provider?: value-of|null, - * } $model + * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', 'anthropic/claude-4.5-opus'). + * + * @param ModelConfigShape $model */ - public function withModel(string|ModelConfig|array $model): self + public function withModel(string|ModelConfigObject|array $model): self { $self = clone $this; $self['model'] = $model; @@ -101,6 +105,8 @@ public function withModel(string|ModelConfig|array $model): self } /** + * AI provider for the agent (legacy, use model: openai/gpt-5-nano instead). + * * @param Provider|value-of $provider */ public function withProvider(Provider|string $provider): self @@ -111,6 +117,9 @@ public function withProvider(Provider|string $provider): self return $self; } + /** + * Custom system prompt for the agent. + */ public function withSystemPrompt(string $systemPrompt): self { $self = clone $this; diff --git a/src/Sessions/SessionExecuteParams/AgentConfig/Provider.php b/src/Sessions/SessionExecuteParams/AgentConfig/Provider.php new file mode 100644 index 0000000..53a8864 --- /dev/null +++ b/src/Sessions/SessionExecuteParams/AgentConfig/Provider.php @@ -0,0 +1,19 @@ + */ + use SdkModel; + + #[Required] + public Data $data; + + /** + * Indicates whether the request was successful. + */ + #[Required] + public bool $success; + + /** + * `new SessionExecuteResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * SessionExecuteResponse::with(data: ..., success: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new SessionExecuteResponse)->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; + } +} diff --git a/src/Sessions/SessionExecuteResponse/Data.php b/src/Sessions/SessionExecuteResponse/Data.php new file mode 100644 index 0000000..1e26019 --- /dev/null +++ b/src/Sessions/SessionExecuteResponse/Data.php @@ -0,0 +1,70 @@ + */ + use SdkModel; + + #[Required] + public Result $result; + + /** + * `new Data()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Data::with(result: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Data)->withResult(...) + * ``` + */ + 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 Result|ResultShape $result + */ + public static function with(Result|array $result): self + { + $self = new self; + + $self['result'] = $result; + + return $self; + } + + /** + * @param Result|ResultShape $result + */ + public function withResult(Result|array $result): self + { + $self = clone $this; + $self['result'] = $result; + + return $self; + } +} diff --git a/src/Sessions/SessionExecuteResponse/Data/Result.php b/src/Sessions/SessionExecuteResponse/Data/Result.php new file mode 100644 index 0000000..4efeb99 --- /dev/null +++ b/src/Sessions/SessionExecuteResponse/Data/Result.php @@ -0,0 +1,179 @@ +, + * completed: bool, + * message: string, + * success: bool, + * metadata?: array|null, + * usage?: null|Usage|UsageShape, + * } + */ +final class Result implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** @var list $actions */ + #[Required(list: Action::class)] + public array $actions; + + /** + * Whether the agent finished its task. + */ + #[Required] + public bool $completed; + + /** + * Summary of what the agent accomplished. + */ + #[Required] + public string $message; + + /** + * Whether the agent completed successfully. + */ + #[Required] + public bool $success; + + /** @var array|null $metadata */ + #[Optional(map: 'mixed')] + public ?array $metadata; + + #[Optional] + public ?Usage $usage; + + /** + * `new Result()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Result::with(actions: ..., completed: ..., message: ..., success: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Result) + * ->withActions(...) + * ->withCompleted(...) + * ->withMessage(...) + * ->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 list $actions + * @param array|null $metadata + * @param Usage|UsageShape|null $usage + */ + public static function with( + array $actions, + bool $completed, + string $message, + bool $success, + ?array $metadata = null, + Usage|array|null $usage = null, + ): self { + $self = new self; + + $self['actions'] = $actions; + $self['completed'] = $completed; + $self['message'] = $message; + $self['success'] = $success; + + null !== $metadata && $self['metadata'] = $metadata; + null !== $usage && $self['usage'] = $usage; + + return $self; + } + + /** + * @param list $actions + */ + public function withActions(array $actions): self + { + $self = clone $this; + $self['actions'] = $actions; + + return $self; + } + + /** + * Whether the agent finished its task. + */ + public function withCompleted(bool $completed): self + { + $self = clone $this; + $self['completed'] = $completed; + + return $self; + } + + /** + * Summary of what the agent accomplished. + */ + public function withMessage(string $message): self + { + $self = clone $this; + $self['message'] = $message; + + return $self; + } + + /** + * Whether the agent completed successfully. + */ + public function withSuccess(bool $success): self + { + $self = clone $this; + $self['success'] = $success; + + return $self; + } + + /** + * @param array $metadata + */ + public function withMetadata(array $metadata): self + { + $self = clone $this; + $self['metadata'] = $metadata; + + return $self; + } + + /** + * @param Usage|UsageShape $usage + */ + public function withUsage(Usage|array $usage): self + { + $self = clone $this; + $self['usage'] = $usage; + + return $self; + } +} diff --git a/src/Sessions/SessionExecuteResponse/Data/Result/Action.php b/src/Sessions/SessionExecuteResponse/Data/Result/Action.php new file mode 100644 index 0000000..042697d --- /dev/null +++ b/src/Sessions/SessionExecuteResponse/Data/Result/Action.php @@ -0,0 +1,183 @@ + */ + use SdkModel; + + /** + * Type of action taken. + */ + #[Required] + public string $type; + + #[Optional] + public ?string $action; + + #[Optional] + public ?string $instruction; + + #[Optional] + public ?string $pageText; + + #[Optional('pageUrl')] + public ?string $pageURL; + + /** + * Agent's reasoning for taking this action. + */ + #[Optional] + public ?string $reasoning; + + #[Optional] + public ?bool $taskCompleted; + + /** + * Time taken for this action in ms. + */ + #[Optional] + public ?float $timeMs; + + /** + * `new Action()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Action::with(type: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Action)->withType(...) + * ``` + */ + 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. + */ + public static function with( + string $type, + ?string $action = null, + ?string $instruction = null, + ?string $pageText = null, + ?string $pageURL = null, + ?string $reasoning = null, + ?bool $taskCompleted = null, + ?float $timeMs = null, + ): self { + $self = new self; + + $self['type'] = $type; + + null !== $action && $self['action'] = $action; + null !== $instruction && $self['instruction'] = $instruction; + null !== $pageText && $self['pageText'] = $pageText; + null !== $pageURL && $self['pageURL'] = $pageURL; + null !== $reasoning && $self['reasoning'] = $reasoning; + null !== $taskCompleted && $self['taskCompleted'] = $taskCompleted; + null !== $timeMs && $self['timeMs'] = $timeMs; + + return $self; + } + + /** + * Type of action taken. + */ + public function withType(string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + public function withAction(string $action): self + { + $self = clone $this; + $self['action'] = $action; + + return $self; + } + + public function withInstruction(string $instruction): self + { + $self = clone $this; + $self['instruction'] = $instruction; + + return $self; + } + + public function withPageText(string $pageText): self + { + $self = clone $this; + $self['pageText'] = $pageText; + + return $self; + } + + public function withPageURL(string $pageURL): self + { + $self = clone $this; + $self['pageURL'] = $pageURL; + + return $self; + } + + /** + * Agent's reasoning for taking this action. + */ + public function withReasoning(string $reasoning): self + { + $self = clone $this; + $self['reasoning'] = $reasoning; + + return $self; + } + + public function withTaskCompleted(bool $taskCompleted): self + { + $self = clone $this; + $self['taskCompleted'] = $taskCompleted; + + return $self; + } + + /** + * Time taken for this action in ms. + */ + public function withTimeMs(float $timeMs): self + { + $self = clone $this; + $self['timeMs'] = $timeMs; + + return $self; + } +} diff --git a/src/Sessions/SessionExecuteResponse/Data/Result/Usage.php b/src/Sessions/SessionExecuteResponse/Data/Result/Usage.php new file mode 100644 index 0000000..500be83 --- /dev/null +++ b/src/Sessions/SessionExecuteResponse/Data/Result/Usage.php @@ -0,0 +1,126 @@ + */ + use SdkModel; + + #[Required('inference_time_ms')] + public float $inferenceTimeMs; + + #[Required('input_tokens')] + public float $inputTokens; + + #[Required('output_tokens')] + public float $outputTokens; + + #[Optional('cached_input_tokens')] + public ?float $cachedInputTokens; + + #[Optional('reasoning_tokens')] + public ?float $reasoningTokens; + + /** + * `new Usage()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Usage::with(inferenceTimeMs: ..., inputTokens: ..., outputTokens: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Usage) + * ->withInferenceTimeMs(...) + * ->withInputTokens(...) + * ->withOutputTokens(...) + * ``` + */ + 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. + */ + public static function with( + float $inferenceTimeMs, + float $inputTokens, + float $outputTokens, + ?float $cachedInputTokens = null, + ?float $reasoningTokens = null, + ): self { + $self = new self; + + $self['inferenceTimeMs'] = $inferenceTimeMs; + $self['inputTokens'] = $inputTokens; + $self['outputTokens'] = $outputTokens; + + null !== $cachedInputTokens && $self['cachedInputTokens'] = $cachedInputTokens; + null !== $reasoningTokens && $self['reasoningTokens'] = $reasoningTokens; + + return $self; + } + + public function withInferenceTimeMs(float $inferenceTimeMs): self + { + $self = clone $this; + $self['inferenceTimeMs'] = $inferenceTimeMs; + + return $self; + } + + public function withInputTokens(float $inputTokens): self + { + $self = clone $this; + $self['inputTokens'] = $inputTokens; + + return $self; + } + + public function withOutputTokens(float $outputTokens): self + { + $self = clone $this; + $self['outputTokens'] = $outputTokens; + + return $self; + } + + public function withCachedInputTokens(float $cachedInputTokens): self + { + $self = clone $this; + $self['cachedInputTokens'] = $cachedInputTokens; + + return $self; + } + + public function withReasoningTokens(float $reasoningTokens): self + { + $self = clone $this; + $self['reasoningTokens'] = $reasoningTokens; + + return $self; + } +} diff --git a/src/Sessions/SessionExtractParams.php b/src/Sessions/SessionExtractParams.php index 78fecbd..7c840bd 100644 --- a/src/Sessions/SessionExtractParams.php +++ b/src/Sessions/SessionExtractParams.php @@ -9,22 +9,25 @@ use Stagehand\Core\Concerns\SdkParams; use Stagehand\Core\Contracts\BaseModel; use Stagehand\Sessions\SessionExtractParams\Options; +use Stagehand\Sessions\SessionExtractParams\XLanguage; use Stagehand\Sessions\SessionExtractParams\XStreamResponse; /** - * Extracts data from the current page using natural language instructions - * and optional JSON schema for structured output. + * Extracts structured data from the current page using AI-powered analysis. * * @see Stagehand\Services\SessionsService::extract() * + * @phpstan-import-type OptionsShape from \Stagehand\Sessions\SessionExtractParams\Options + * * @phpstan-type SessionExtractParamsShape = array{ - * frameID?: string, - * instruction?: string, - * options?: Options|array{ - * model?: ModelConfig|null, selector?: string|null, timeout?: int|null - * }, - * schema?: array, - * xStreamResponse?: XStreamResponse|value-of, + * frameID?: string|null, + * instruction?: string|null, + * options?: null|Options|OptionsShape, + * schema?: array|null, + * xLanguage?: null|XLanguage|value-of, + * xSDKVersion?: string|null, + * xSentAt?: \DateTimeInterface|null, + * xStreamResponse?: null|XStreamResponse|value-of, * } */ final class SessionExtractParams implements BaseModel @@ -34,13 +37,13 @@ final class SessionExtractParams implements BaseModel use SdkParams; /** - * Frame ID to extract from. + * Target frame ID for the extraction. */ #[Optional('frameId')] public ?string $frameID; /** - * Natural language instruction for extraction. + * Natural language instruction for what to extract. */ #[Optional] public ?string $instruction; @@ -49,14 +52,38 @@ final class SessionExtractParams implements BaseModel public ?Options $options; /** - * JSON Schema for structured output. + * JSON Schema defining the structure of data to extract. * * @var array|null $schema */ #[Optional(map: 'mixed')] public ?array $schema; - /** @var value-of|null $xStreamResponse */ + /** + * Client SDK language. + * + * @var value-of|null $xLanguage + */ + #[Optional(enum: XLanguage::class)] + public ?string $xLanguage; + + /** + * Version of the Stagehand SDK. + */ + #[Optional] + public ?string $xSDKVersion; + + /** + * ISO timestamp when request was sent. + */ + #[Optional] + public ?\DateTimeInterface $xSentAt; + + /** + * Whether to stream the response via SSE. + * + * @var value-of|null $xStreamResponse + */ #[Optional(enum: XStreamResponse::class)] public ?string $xStreamResponse; @@ -70,17 +97,19 @@ public function __construct() * * You must use named parameters to construct any parameters with a default value. * - * @param Options|array{ - * model?: ModelConfig|null, selector?: string|null, timeout?: int|null - * } $options - * @param array $schema - * @param XStreamResponse|value-of $xStreamResponse + * @param Options|OptionsShape|null $options + * @param array|null $schema + * @param XLanguage|value-of|null $xLanguage + * @param XStreamResponse|value-of|null $xStreamResponse */ public static function with( ?string $frameID = null, ?string $instruction = null, Options|array|null $options = null, ?array $schema = null, + XLanguage|string|null $xLanguage = null, + ?string $xSDKVersion = null, + ?\DateTimeInterface $xSentAt = null, XStreamResponse|string|null $xStreamResponse = null, ): self { $self = new self; @@ -89,13 +118,16 @@ public static function with( null !== $instruction && $self['instruction'] = $instruction; null !== $options && $self['options'] = $options; null !== $schema && $self['schema'] = $schema; + null !== $xLanguage && $self['xLanguage'] = $xLanguage; + null !== $xSDKVersion && $self['xSDKVersion'] = $xSDKVersion; + null !== $xSentAt && $self['xSentAt'] = $xSentAt; null !== $xStreamResponse && $self['xStreamResponse'] = $xStreamResponse; return $self; } /** - * Frame ID to extract from. + * Target frame ID for the extraction. */ public function withFrameID(string $frameID): self { @@ -106,7 +138,7 @@ public function withFrameID(string $frameID): self } /** - * Natural language instruction for extraction. + * Natural language instruction for what to extract. */ public function withInstruction(string $instruction): self { @@ -117,9 +149,7 @@ public function withInstruction(string $instruction): self } /** - * @param Options|array{ - * model?: ModelConfig|null, selector?: string|null, timeout?: int|null - * } $options + * @param Options|OptionsShape $options */ public function withOptions(Options|array $options): self { @@ -130,7 +160,7 @@ public function withOptions(Options|array $options): self } /** - * JSON Schema for structured output. + * JSON Schema defining the structure of data to extract. * * @param array $schema */ @@ -143,6 +173,43 @@ public function withSchema(array $schema): self } /** + * Client SDK language. + * + * @param XLanguage|value-of $xLanguage + */ + public function withXLanguage(XLanguage|string $xLanguage): self + { + $self = clone $this; + $self['xLanguage'] = $xLanguage; + + return $self; + } + + /** + * Version of the Stagehand SDK. + */ + public function withXSDKVersion(string $xSDKVersion): self + { + $self = clone $this; + $self['xSDKVersion'] = $xSDKVersion; + + return $self; + } + + /** + * ISO timestamp when request was sent. + */ + public function withXSentAt(\DateTimeInterface $xSentAt): self + { + $self = clone $this; + $self['xSentAt'] = $xSentAt; + + return $self; + } + + /** + * Whether to stream the response via SSE. + * * @param XStreamResponse|value-of $xStreamResponse */ public function withXStreamResponse( diff --git a/src/Sessions/SessionExtractParams/Options.php b/src/Sessions/SessionExtractParams/Options.php index 5c8ac6d..b7946aa 100644 --- a/src/Sessions/SessionExtractParams/Options.php +++ b/src/Sessions/SessionExtractParams/Options.php @@ -7,12 +7,13 @@ use Stagehand\Core\Attributes\Optional; use Stagehand\Core\Concerns\SdkModel; use Stagehand\Core\Contracts\BaseModel; -use Stagehand\Sessions\ModelConfig; -use Stagehand\Sessions\ModelConfig\Provider; +use Stagehand\Sessions\ModelConfig\ModelConfigObject; /** + * @phpstan-import-type ModelConfigShape from \Stagehand\Sessions\ModelConfig + * * @phpstan-type OptionsShape = array{ - * model?: ModelConfig|null, selector?: string|null, timeout?: int|null + * model?: ModelConfigShape|null, selector?: string|null, timeout?: float|null * } */ final class Options implements BaseModel @@ -20,17 +21,23 @@ final class Options implements BaseModel /** @use SdkModel */ use SdkModel; + /** + * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', 'anthropic/claude-4.5-opus'). + */ #[Optional] - public ?ModelConfig $model; + public string|ModelConfigObject|null $model; /** - * Extract only from elements matching this selector. + * CSS selector to scope extraction to a specific element. */ #[Optional] public ?string $selector; + /** + * Timeout in ms for the extraction. + */ #[Optional] - public ?int $timeout; + public ?float $timeout; public function __construct() { @@ -42,17 +49,12 @@ public function __construct() * * You must use named parameters to construct any parameters with a default value. * - * @param ModelConfig|array{ - * apiKey?: string|null, - * baseURL?: string|null, - * model?: string|null, - * provider?: value-of|null, - * } $model + * @param ModelConfigShape|null $model */ public static function with( - ModelConfig|array|null $model = null, + string|ModelConfigObject|array|null $model = null, ?string $selector = null, - ?int $timeout = null, + ?float $timeout = null, ): self { $self = new self; @@ -64,14 +66,11 @@ public static function with( } /** - * @param ModelConfig|array{ - * apiKey?: string|null, - * baseURL?: string|null, - * model?: string|null, - * provider?: value-of|null, - * } $model + * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', 'anthropic/claude-4.5-opus'). + * + * @param ModelConfigShape $model */ - public function withModel(ModelConfig|array $model): self + public function withModel(string|ModelConfigObject|array $model): self { $self = clone $this; $self['model'] = $model; @@ -80,7 +79,7 @@ public function withModel(ModelConfig|array $model): self } /** - * Extract only from elements matching this selector. + * CSS selector to scope extraction to a specific element. */ public function withSelector(string $selector): self { @@ -90,7 +89,10 @@ public function withSelector(string $selector): self return $self; } - public function withTimeout(int $timeout): self + /** + * Timeout in ms for the extraction. + */ + public function withTimeout(float $timeout): self { $self = clone $this; $self['timeout'] = $timeout; diff --git a/src/Sessions/SessionExtractParams/XLanguage.php b/src/Sessions/SessionExtractParams/XLanguage.php new file mode 100644 index 0000000..677e218 --- /dev/null +++ b/src/Sessions/SessionExtractParams/XLanguage.php @@ -0,0 +1,17 @@ + */ + use SdkModel; + + #[Required] + public Data $data; + + /** + * Indicates whether the request was successful. + */ + #[Required] + public bool $success; + + /** + * `new SessionExtractResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * SessionExtractResponse::with(data: ..., success: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new SessionExtractResponse)->withData(...)->withSuccess(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } /** - * @return list|array + * 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 variants(): array + public static function with(Data|array $data, bool $success): self { - return [Extraction::class, new MapOf('mixed')]; + $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; } } diff --git a/src/Sessions/SessionExtractResponse/Data.php b/src/Sessions/SessionExtractResponse/Data.php new file mode 100644 index 0000000..e80c821 --- /dev/null +++ b/src/Sessions/SessionExtractResponse/Data.php @@ -0,0 +1,88 @@ + */ + use SdkModel; + + /** + * Extracted data matching the requested schema. + */ + #[Required] + public mixed $result; + + /** + * Action ID for tracking. + */ + #[Optional('actionId')] + public ?string $actionID; + + /** + * `new Data()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Data::with(result: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Data)->withResult(...) + * ``` + */ + 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. + */ + public static function with(mixed $result, ?string $actionID = null): self + { + $self = new self; + + $self['result'] = $result; + + null !== $actionID && $self['actionID'] = $actionID; + + return $self; + } + + /** + * Extracted data matching the requested schema. + */ + public function withResult(mixed $result): self + { + $self = clone $this; + $self['result'] = $result; + + return $self; + } + + /** + * Action ID for tracking. + */ + public function withActionID(string $actionID): self + { + $self = clone $this; + $self['actionID'] = $actionID; + + return $self; + } +} diff --git a/src/Sessions/SessionExtractResponse/Extraction.php b/src/Sessions/SessionExtractResponse/Extraction.php deleted file mode 100644 index 22a6f95..0000000 --- a/src/Sessions/SessionExtractResponse/Extraction.php +++ /dev/null @@ -1,50 +0,0 @@ - */ - use SdkModel; - - #[Optional] - public ?string $extraction; - - 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. - */ - public static function with(?string $extraction = null): self - { - $self = new self; - - null !== $extraction && $self['extraction'] = $extraction; - - return $self; - } - - public function withExtraction(string $extraction): self - { - $self = clone $this; - $self['extraction'] = $extraction; - - return $self; - } -} diff --git a/src/Sessions/SessionNavigateParams.php b/src/Sessions/SessionNavigateParams.php index f3cd37d..97fb1a5 100644 --- a/src/Sessions/SessionNavigateParams.php +++ b/src/Sessions/SessionNavigateParams.php @@ -10,19 +10,25 @@ use Stagehand\Core\Concerns\SdkParams; use Stagehand\Core\Contracts\BaseModel; use Stagehand\Sessions\SessionNavigateParams\Options; -use Stagehand\Sessions\SessionNavigateParams\Options\WaitUntil; +use Stagehand\Sessions\SessionNavigateParams\XLanguage; use Stagehand\Sessions\SessionNavigateParams\XStreamResponse; /** - * Navigates the browser to the specified URL and waits for page load. + * Navigates the browser to the specified URL. * * @see Stagehand\Services\SessionsService::navigate() * + * @phpstan-import-type OptionsShape from \Stagehand\Sessions\SessionNavigateParams\Options + * * @phpstan-type SessionNavigateParamsShape = array{ * url: string, - * frameID?: string, - * options?: Options|array{waitUntil?: value-of|null}, - * xStreamResponse?: XStreamResponse|value-of, + * frameID?: string|null, + * options?: null|Options|OptionsShape, + * streamResponse?: bool|null, + * xLanguage?: null|XLanguage|value-of, + * xSDKVersion?: string|null, + * xSentAt?: \DateTimeInterface|null, + * xStreamResponse?: null|XStreamResponse|value-of, * } */ final class SessionNavigateParams implements BaseModel @@ -37,13 +43,46 @@ final class SessionNavigateParams implements BaseModel #[Required] public string $url; + /** + * Target frame ID for the navigation. + */ #[Optional('frameId')] public ?string $frameID; #[Optional] public ?Options $options; - /** @var value-of|null $xStreamResponse */ + /** + * Whether to stream the response via SSE. + */ + #[Optional] + public ?bool $streamResponse; + + /** + * Client SDK language. + * + * @var value-of|null $xLanguage + */ + #[Optional(enum: XLanguage::class)] + public ?string $xLanguage; + + /** + * Version of the Stagehand SDK. + */ + #[Optional] + public ?string $xSDKVersion; + + /** + * ISO timestamp when request was sent. + */ + #[Optional] + public ?\DateTimeInterface $xSentAt; + + /** + * Whether to stream the response via SSE. + * + * @var value-of|null $xStreamResponse + */ #[Optional(enum: XStreamResponse::class)] public ?string $xStreamResponse; @@ -71,13 +110,18 @@ public function __construct() * * You must use named parameters to construct any parameters with a default value. * - * @param Options|array{waitUntil?: value-of|null} $options - * @param XStreamResponse|value-of $xStreamResponse + * @param Options|OptionsShape|null $options + * @param XLanguage|value-of|null $xLanguage + * @param XStreamResponse|value-of|null $xStreamResponse */ public static function with( string $url, ?string $frameID = null, Options|array|null $options = null, + ?bool $streamResponse = null, + XLanguage|string|null $xLanguage = null, + ?string $xSDKVersion = null, + ?\DateTimeInterface $xSentAt = null, XStreamResponse|string|null $xStreamResponse = null, ): self { $self = new self; @@ -86,6 +130,10 @@ public static function with( null !== $frameID && $self['frameID'] = $frameID; null !== $options && $self['options'] = $options; + null !== $streamResponse && $self['streamResponse'] = $streamResponse; + null !== $xLanguage && $self['xLanguage'] = $xLanguage; + null !== $xSDKVersion && $self['xSDKVersion'] = $xSDKVersion; + null !== $xSentAt && $self['xSentAt'] = $xSentAt; null !== $xStreamResponse && $self['xStreamResponse'] = $xStreamResponse; return $self; @@ -102,6 +150,9 @@ public function withURL(string $url): self return $self; } + /** + * Target frame ID for the navigation. + */ public function withFrameID(string $frameID): self { $self = clone $this; @@ -111,7 +162,7 @@ public function withFrameID(string $frameID): self } /** - * @param Options|array{waitUntil?: value-of|null} $options + * @param Options|OptionsShape $options */ public function withOptions(Options|array $options): self { @@ -122,6 +173,54 @@ public function withOptions(Options|array $options): self } /** + * Whether to stream the response via SSE. + */ + public function withStreamResponse(bool $streamResponse): self + { + $self = clone $this; + $self['streamResponse'] = $streamResponse; + + return $self; + } + + /** + * Client SDK language. + * + * @param XLanguage|value-of $xLanguage + */ + public function withXLanguage(XLanguage|string $xLanguage): self + { + $self = clone $this; + $self['xLanguage'] = $xLanguage; + + return $self; + } + + /** + * Version of the Stagehand SDK. + */ + public function withXSDKVersion(string $xSDKVersion): self + { + $self = clone $this; + $self['xSDKVersion'] = $xSDKVersion; + + return $self; + } + + /** + * ISO timestamp when request was sent. + */ + public function withXSentAt(\DateTimeInterface $xSentAt): self + { + $self = clone $this; + $self['xSentAt'] = $xSentAt; + + return $self; + } + + /** + * Whether to stream the response via SSE. + * * @param XStreamResponse|value-of $xStreamResponse */ public function withXStreamResponse( diff --git a/src/Sessions/SessionNavigateParams/Options.php b/src/Sessions/SessionNavigateParams/Options.php index d8cfc0c..be4e190 100644 --- a/src/Sessions/SessionNavigateParams/Options.php +++ b/src/Sessions/SessionNavigateParams/Options.php @@ -10,13 +10,29 @@ use Stagehand\Sessions\SessionNavigateParams\Options\WaitUntil; /** - * @phpstan-type OptionsShape = array{waitUntil?: value-of|null} + * @phpstan-type OptionsShape = array{ + * referer?: string|null, + * timeout?: float|null, + * waitUntil?: null|WaitUntil|value-of, + * } */ final class Options implements BaseModel { /** @use SdkModel */ use SdkModel; + /** + * Referer header to send with the request. + */ + #[Optional] + public ?string $referer; + + /** + * Timeout in ms for the navigation. + */ + #[Optional] + public ?float $timeout; + /** * When to consider navigation complete. * @@ -35,17 +51,44 @@ public function __construct() * * You must use named parameters to construct any parameters with a default value. * - * @param WaitUntil|value-of $waitUntil + * @param WaitUntil|value-of|null $waitUntil */ - public static function with(WaitUntil|string|null $waitUntil = null): self - { + public static function with( + ?string $referer = null, + ?float $timeout = null, + WaitUntil|string|null $waitUntil = null, + ): self { $self = new self; + null !== $referer && $self['referer'] = $referer; + null !== $timeout && $self['timeout'] = $timeout; null !== $waitUntil && $self['waitUntil'] = $waitUntil; return $self; } + /** + * Referer header to send with the request. + */ + public function withReferer(string $referer): self + { + $self = clone $this; + $self['referer'] = $referer; + + return $self; + } + + /** + * Timeout in ms for the navigation. + */ + public function withTimeout(float $timeout): self + { + $self = clone $this; + $self['timeout'] = $timeout; + + return $self; + } + /** * When to consider navigation complete. * diff --git a/src/Sessions/SessionNavigateParams/XLanguage.php b/src/Sessions/SessionNavigateParams/XLanguage.php new file mode 100644 index 0000000..9a1416b --- /dev/null +++ b/src/Sessions/SessionNavigateParams/XLanguage.php @@ -0,0 +1,17 @@ + */ use SdkModel; - #[Optional] - public ?bool $ok; + #[Required] + public Data $data; - #[Optional] - public ?int $status; - - #[Optional] - public ?string $url; + /** + * Indicates whether the request was successful. + */ + #[Required] + public bool $success; + /** + * `new SessionNavigateResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * SessionNavigateResponse::with(data: ..., success: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new SessionNavigateResponse)->withData(...)->withSuccess(...) + * ``` + */ public function __construct() { $this->initialize(); @@ -38,41 +53,37 @@ public function __construct() * 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( - ?bool $ok = null, - ?int $status = null, - ?string $url = null - ): self { + public static function with(Data|array $data, bool $success): self + { $self = new self; - null !== $ok && $self['ok'] = $ok; - null !== $status && $self['status'] = $status; - null !== $url && $self['url'] = $url; + $self['data'] = $data; + $self['success'] = $success; return $self; } - public function withOk(bool $ok): self - { - $self = clone $this; - $self['ok'] = $ok; - - return $self; - } - - public function withStatus(int $status): self + /** + * @param Data|DataShape $data + */ + public function withData(Data|array $data): self { $self = clone $this; - $self['status'] = $status; + $self['data'] = $data; return $self; } - public function withURL(string $url): self + /** + * Indicates whether the request was successful. + */ + public function withSuccess(bool $success): self { $self = clone $this; - $self['url'] = $url; + $self['success'] = $success; return $self; } diff --git a/src/Sessions/SessionNavigateResponse/Data.php b/src/Sessions/SessionNavigateResponse/Data.php new file mode 100644 index 0000000..cf584bc --- /dev/null +++ b/src/Sessions/SessionNavigateResponse/Data.php @@ -0,0 +1,88 @@ + */ + use SdkModel; + + /** + * Navigation response (Playwright Response object or null). + */ + #[Required] + public mixed $result; + + /** + * Action ID for tracking. + */ + #[Optional('actionId')] + public ?string $actionID; + + /** + * `new Data()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Data::with(result: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Data)->withResult(...) + * ``` + */ + 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. + */ + public static function with(mixed $result, ?string $actionID = null): self + { + $self = new self; + + $self['result'] = $result; + + null !== $actionID && $self['actionID'] = $actionID; + + return $self; + } + + /** + * Navigation response (Playwright Response object or null). + */ + public function withResult(mixed $result): self + { + $self = clone $this; + $self['result'] = $result; + + return $self; + } + + /** + * Action ID for tracking. + */ + public function withActionID(string $actionID): self + { + $self = clone $this; + $self['actionID'] = $actionID; + + return $self; + } +} diff --git a/src/Sessions/SessionObserveParams.php b/src/Sessions/SessionObserveParams.php index 6846de0..c344597 100644 --- a/src/Sessions/SessionObserveParams.php +++ b/src/Sessions/SessionObserveParams.php @@ -9,21 +9,24 @@ use Stagehand\Core\Concerns\SdkParams; use Stagehand\Core\Contracts\BaseModel; use Stagehand\Sessions\SessionObserveParams\Options; +use Stagehand\Sessions\SessionObserveParams\XLanguage; use Stagehand\Sessions\SessionObserveParams\XStreamResponse; /** - * Returns a list of candidate actions that can be performed on the page, - * optionally filtered by natural language instruction. + * Identifies and returns available actions on the current page that match the given instruction. * * @see Stagehand\Services\SessionsService::observe() * + * @phpstan-import-type OptionsShape from \Stagehand\Sessions\SessionObserveParams\Options + * * @phpstan-type SessionObserveParamsShape = array{ - * frameID?: string, - * instruction?: string, - * options?: Options|array{ - * model?: ModelConfig|null, selector?: string|null, timeout?: int|null - * }, - * xStreamResponse?: XStreamResponse|value-of, + * frameID?: string|null, + * instruction?: string|null, + * options?: null|Options|OptionsShape, + * xLanguage?: null|XLanguage|value-of, + * xSDKVersion?: string|null, + * xSentAt?: \DateTimeInterface|null, + * xStreamResponse?: null|XStreamResponse|value-of, * } */ final class SessionObserveParams implements BaseModel @@ -33,13 +36,13 @@ final class SessionObserveParams implements BaseModel use SdkParams; /** - * Frame ID to observe. + * Target frame ID for the observation. */ #[Optional('frameId')] public ?string $frameID; /** - * Natural language instruction to filter actions. + * Natural language instruction for what actions to find. */ #[Optional] public ?string $instruction; @@ -47,7 +50,31 @@ final class SessionObserveParams implements BaseModel #[Optional] public ?Options $options; - /** @var value-of|null $xStreamResponse */ + /** + * Client SDK language. + * + * @var value-of|null $xLanguage + */ + #[Optional(enum: XLanguage::class)] + public ?string $xLanguage; + + /** + * Version of the Stagehand SDK. + */ + #[Optional] + public ?string $xSDKVersion; + + /** + * ISO timestamp when request was sent. + */ + #[Optional] + public ?\DateTimeInterface $xSentAt; + + /** + * Whether to stream the response via SSE. + * + * @var value-of|null $xStreamResponse + */ #[Optional(enum: XStreamResponse::class)] public ?string $xStreamResponse; @@ -61,15 +88,17 @@ public function __construct() * * You must use named parameters to construct any parameters with a default value. * - * @param Options|array{ - * model?: ModelConfig|null, selector?: string|null, timeout?: int|null - * } $options - * @param XStreamResponse|value-of $xStreamResponse + * @param Options|OptionsShape|null $options + * @param XLanguage|value-of|null $xLanguage + * @param XStreamResponse|value-of|null $xStreamResponse */ public static function with( ?string $frameID = null, ?string $instruction = null, Options|array|null $options = null, + XLanguage|string|null $xLanguage = null, + ?string $xSDKVersion = null, + ?\DateTimeInterface $xSentAt = null, XStreamResponse|string|null $xStreamResponse = null, ): self { $self = new self; @@ -77,13 +106,16 @@ public static function with( null !== $frameID && $self['frameID'] = $frameID; null !== $instruction && $self['instruction'] = $instruction; null !== $options && $self['options'] = $options; + null !== $xLanguage && $self['xLanguage'] = $xLanguage; + null !== $xSDKVersion && $self['xSDKVersion'] = $xSDKVersion; + null !== $xSentAt && $self['xSentAt'] = $xSentAt; null !== $xStreamResponse && $self['xStreamResponse'] = $xStreamResponse; return $self; } /** - * Frame ID to observe. + * Target frame ID for the observation. */ public function withFrameID(string $frameID): self { @@ -94,7 +126,7 @@ public function withFrameID(string $frameID): self } /** - * Natural language instruction to filter actions. + * Natural language instruction for what actions to find. */ public function withInstruction(string $instruction): self { @@ -105,9 +137,7 @@ public function withInstruction(string $instruction): self } /** - * @param Options|array{ - * model?: ModelConfig|null, selector?: string|null, timeout?: int|null - * } $options + * @param Options|OptionsShape $options */ public function withOptions(Options|array $options): self { @@ -118,6 +148,43 @@ public function withOptions(Options|array $options): self } /** + * Client SDK language. + * + * @param XLanguage|value-of $xLanguage + */ + public function withXLanguage(XLanguage|string $xLanguage): self + { + $self = clone $this; + $self['xLanguage'] = $xLanguage; + + return $self; + } + + /** + * Version of the Stagehand SDK. + */ + public function withXSDKVersion(string $xSDKVersion): self + { + $self = clone $this; + $self['xSDKVersion'] = $xSDKVersion; + + return $self; + } + + /** + * ISO timestamp when request was sent. + */ + public function withXSentAt(\DateTimeInterface $xSentAt): self + { + $self = clone $this; + $self['xSentAt'] = $xSentAt; + + return $self; + } + + /** + * Whether to stream the response via SSE. + * * @param XStreamResponse|value-of $xStreamResponse */ public function withXStreamResponse( diff --git a/src/Sessions/SessionObserveParams/Options.php b/src/Sessions/SessionObserveParams/Options.php index edf0b99..19644b3 100644 --- a/src/Sessions/SessionObserveParams/Options.php +++ b/src/Sessions/SessionObserveParams/Options.php @@ -7,12 +7,13 @@ use Stagehand\Core\Attributes\Optional; use Stagehand\Core\Concerns\SdkModel; use Stagehand\Core\Contracts\BaseModel; -use Stagehand\Sessions\ModelConfig; -use Stagehand\Sessions\ModelConfig\Provider; +use Stagehand\Sessions\ModelConfig\ModelConfigObject; /** + * @phpstan-import-type ModelConfigShape from \Stagehand\Sessions\ModelConfig + * * @phpstan-type OptionsShape = array{ - * model?: ModelConfig|null, selector?: string|null, timeout?: int|null + * model?: ModelConfigShape|null, selector?: string|null, timeout?: float|null * } */ final class Options implements BaseModel @@ -20,17 +21,23 @@ final class Options implements BaseModel /** @use SdkModel */ use SdkModel; + /** + * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', 'anthropic/claude-4.5-opus'). + */ #[Optional] - public ?ModelConfig $model; + public string|ModelConfigObject|null $model; /** - * Observe only elements matching this selector. + * CSS selector to scope observation to a specific element. */ #[Optional] public ?string $selector; + /** + * Timeout in ms for the observation. + */ #[Optional] - public ?int $timeout; + public ?float $timeout; public function __construct() { @@ -42,17 +49,12 @@ public function __construct() * * You must use named parameters to construct any parameters with a default value. * - * @param ModelConfig|array{ - * apiKey?: string|null, - * baseURL?: string|null, - * model?: string|null, - * provider?: value-of|null, - * } $model + * @param ModelConfigShape|null $model */ public static function with( - ModelConfig|array|null $model = null, + string|ModelConfigObject|array|null $model = null, ?string $selector = null, - ?int $timeout = null, + ?float $timeout = null, ): self { $self = new self; @@ -64,14 +66,11 @@ public static function with( } /** - * @param ModelConfig|array{ - * apiKey?: string|null, - * baseURL?: string|null, - * model?: string|null, - * provider?: value-of|null, - * } $model + * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', 'anthropic/claude-4.5-opus'). + * + * @param ModelConfigShape $model */ - public function withModel(ModelConfig|array $model): self + public function withModel(string|ModelConfigObject|array $model): self { $self = clone $this; $self['model'] = $model; @@ -80,7 +79,7 @@ public function withModel(ModelConfig|array $model): self } /** - * Observe only elements matching this selector. + * CSS selector to scope observation to a specific element. */ public function withSelector(string $selector): self { @@ -90,7 +89,10 @@ public function withSelector(string $selector): self return $self; } - public function withTimeout(int $timeout): self + /** + * Timeout in ms for the observation. + */ + public function withTimeout(float $timeout): self { $self = clone $this; $self['timeout'] = $timeout; diff --git a/src/Sessions/SessionObserveParams/XLanguage.php b/src/Sessions/SessionObserveParams/XLanguage.php new file mode 100644 index 0000000..a6afb44 --- /dev/null +++ b/src/Sessions/SessionObserveParams/XLanguage.php @@ -0,0 +1,17 @@ + */ + use SdkModel; + + #[Required] + public Data $data; + + /** + * Indicates whether the request was successful. + */ + #[Required] + public bool $success; + + /** + * `new SessionObserveResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * SessionObserveResponse::with(data: ..., success: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new SessionObserveResponse)->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; + } +} diff --git a/src/Sessions/SessionObserveResponse/Data.php b/src/Sessions/SessionObserveResponse/Data.php new file mode 100644 index 0000000..1d247eb --- /dev/null +++ b/src/Sessions/SessionObserveResponse/Data.php @@ -0,0 +1,93 @@ +, actionID?: string|null + * } + */ +final class Data implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** @var list $result */ + #[Required(list: Result::class)] + public array $result; + + /** + * Action ID for tracking. + */ + #[Optional('actionId')] + public ?string $actionID; + + /** + * `new Data()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Data::with(result: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Data)->withResult(...) + * ``` + */ + 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 list $result + */ + public static function with(array $result, ?string $actionID = null): self + { + $self = new self; + + $self['result'] = $result; + + null !== $actionID && $self['actionID'] = $actionID; + + return $self; + } + + /** + * @param list $result + */ + public function withResult(array $result): self + { + $self = clone $this; + $self['result'] = $result; + + return $self; + } + + /** + * Action ID for tracking. + */ + public function withActionID(string $actionID): self + { + $self = clone $this; + $self['actionID'] = $actionID; + + return $self; + } +} diff --git a/src/Sessions/SessionObserveResponse/Data/Result.php b/src/Sessions/SessionObserveResponse/Data/Result.php new file mode 100644 index 0000000..1bc17e4 --- /dev/null +++ b/src/Sessions/SessionObserveResponse/Data/Result.php @@ -0,0 +1,161 @@ +|null, + * backendNodeID?: float|null, + * method?: string|null, + * } + */ +final class Result implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Human-readable description of the action. + */ + #[Required] + public string $description; + + /** + * CSS selector or XPath for the element. + */ + #[Required] + public string $selector; + + /** + * Arguments to pass to the method. + * + * @var list|null $arguments + */ + #[Optional(list: 'string')] + public ?array $arguments; + + /** + * Backend node ID for the element. + */ + #[Optional('backendNodeId')] + public ?float $backendNodeID; + + /** + * The method to execute (click, fill, etc.). + */ + #[Optional] + public ?string $method; + + /** + * `new Result()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Result::with(description: ..., selector: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Result)->withDescription(...)->withSelector(...) + * ``` + */ + 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 list|null $arguments + */ + public static function with( + string $description, + string $selector, + ?array $arguments = null, + ?float $backendNodeID = null, + ?string $method = null, + ): self { + $self = new self; + + $self['description'] = $description; + $self['selector'] = $selector; + + null !== $arguments && $self['arguments'] = $arguments; + null !== $backendNodeID && $self['backendNodeID'] = $backendNodeID; + null !== $method && $self['method'] = $method; + + return $self; + } + + /** + * Human-readable description of the action. + */ + public function withDescription(string $description): self + { + $self = clone $this; + $self['description'] = $description; + + return $self; + } + + /** + * CSS selector or XPath for the element. + */ + public function withSelector(string $selector): self + { + $self = clone $this; + $self['selector'] = $selector; + + return $self; + } + + /** + * Arguments to pass to the method. + * + * @param list $arguments + */ + public function withArguments(array $arguments): self + { + $self = clone $this; + $self['arguments'] = $arguments; + + return $self; + } + + /** + * Backend node ID for the element. + */ + public function withBackendNodeID(float $backendNodeID): self + { + $self = clone $this; + $self['backendNodeID'] = $backendNodeID; + + return $self; + } + + /** + * The method to execute (click, fill, etc.). + */ + public function withMethod(string $method): self + { + $self = clone $this; + $self['method'] = $method; + + return $self; + } +} diff --git a/src/Sessions/SessionStartParams.php b/src/Sessions/SessionStartParams.php index 9c67425..0950eea 100644 --- a/src/Sessions/SessionStartParams.php +++ b/src/Sessions/SessionStartParams.php @@ -9,21 +9,35 @@ use Stagehand\Core\Concerns\SdkModel; use Stagehand\Core\Concerns\SdkParams; use Stagehand\Core\Contracts\BaseModel; +use Stagehand\Sessions\SessionStartParams\Browser; +use Stagehand\Sessions\SessionStartParams\BrowserbaseSessionCreateParams; +use Stagehand\Sessions\SessionStartParams\XLanguage; +use Stagehand\Sessions\SessionStartParams\XStreamResponse; /** - * Initializes a new Stagehand session with a browser instance. - * Returns a session ID that must be used for all subsequent requests. + * Creates a new browser session with the specified configuration. Returns a session ID used for all subsequent operations. * * @see Stagehand\Services\SessionsService::start() * + * @phpstan-import-type BrowserShape from \Stagehand\Sessions\SessionStartParams\Browser + * @phpstan-import-type BrowserbaseSessionCreateParamsShape from \Stagehand\Sessions\SessionStartParams\BrowserbaseSessionCreateParams + * * @phpstan-type SessionStartParamsShape = array{ - * browserbaseAPIKey: string, - * browserbaseProjectID: string, - * domSettleTimeout?: int, - * model?: string, - * selfHeal?: bool, - * systemPrompt?: string, - * verbose?: int, + * modelName: string, + * actTimeoutMs?: float|null, + * browser?: null|Browser|BrowserShape, + * browserbaseSessionCreateParams?: null|BrowserbaseSessionCreateParams|BrowserbaseSessionCreateParamsShape, + * browserbaseSessionID?: string|null, + * domSettleTimeoutMs?: float|null, + * experimental?: bool|null, + * selfHeal?: bool|null, + * systemPrompt?: string|null, + * verbose?: float|null, + * waitForCaptchaSolves?: bool|null, + * xLanguage?: null|XLanguage|value-of, + * xSDKVersion?: string|null, + * xSentAt?: \DateTimeInterface|null, + * xStreamResponse?: null|XStreamResponse|value-of, * } */ final class SessionStartParams implements BaseModel @@ -33,28 +47,37 @@ final class SessionStartParams implements BaseModel use SdkParams; /** - * API key for Browserbase Cloud. + * Model name to use for AI operations. */ - #[Required('BROWSERBASE_API_KEY')] - public string $browserbaseAPIKey; + #[Required] + public string $modelName; /** - * Project ID for Browserbase. + * Timeout in ms for act operations (deprecated, v2 only). */ - #[Required('BROWSERBASE_PROJECT_ID')] - public string $browserbaseProjectID; + #[Optional] + public ?float $actTimeoutMs; + + #[Optional] + public ?Browser $browser; + + #[Optional] + public ?BrowserbaseSessionCreateParams $browserbaseSessionCreateParams; /** - * Timeout in ms to wait for DOM to settle. + * Existing Browserbase session ID to resume. */ #[Optional] - public ?int $domSettleTimeout; + public ?string $browserbaseSessionID; /** - * AI model to use for actions (must be prefixed with provider/). + * Timeout in ms to wait for DOM to settle. */ #[Optional] - public ?string $model; + public ?float $domSettleTimeoutMs; + + #[Optional] + public ?bool $experimental; /** * Enable self-healing for failed actions. @@ -63,31 +86,63 @@ final class SessionStartParams implements BaseModel public ?bool $selfHeal; /** - * Custom system prompt for AI actions. + * Custom system prompt for AI operations. */ #[Optional] public ?string $systemPrompt; /** - * Logging verbosity level. + * Logging verbosity level (0=quiet, 1=normal, 2=debug). */ #[Optional] - public ?int $verbose; + public ?float $verbose; + + /** + * Wait for captcha solves (deprecated, v2 only). + */ + #[Optional] + public ?bool $waitForCaptchaSolves; + + /** + * Client SDK language. + * + * @var value-of|null $xLanguage + */ + #[Optional(enum: XLanguage::class)] + public ?string $xLanguage; + + /** + * Version of the Stagehand SDK. + */ + #[Optional] + public ?string $xSDKVersion; + + /** + * ISO timestamp when request was sent. + */ + #[Optional] + public ?\DateTimeInterface $xSentAt; + + /** + * Whether to stream the response via SSE. + * + * @var value-of|null $xStreamResponse + */ + #[Optional(enum: XStreamResponse::class)] + public ?string $xStreamResponse; /** * `new SessionStartParams()` is missing required properties by the API. * * To enforce required parameters use * ``` - * SessionStartParams::with(browserbaseAPIKey: ..., browserbaseProjectID: ...) + * SessionStartParams::with(modelName: ...) * ``` * * Otherwise ensure the following setters are called * * ``` - * (new SessionStartParams) - * ->withBrowserbaseAPIKey(...) - * ->withBrowserbaseProjectID(...) + * (new SessionStartParams)->withModelName(...) * ``` */ public function __construct() @@ -99,70 +154,122 @@ public function __construct() * Construct an instance from the required parameters. * * You must use named parameters to construct any parameters with a default value. + * + * @param Browser|BrowserShape|null $browser + * @param BrowserbaseSessionCreateParams|BrowserbaseSessionCreateParamsShape|null $browserbaseSessionCreateParams + * @param XLanguage|value-of|null $xLanguage + * @param XStreamResponse|value-of|null $xStreamResponse */ public static function with( - string $browserbaseAPIKey, - string $browserbaseProjectID, - ?int $domSettleTimeout = null, - ?string $model = null, + string $modelName, + ?float $actTimeoutMs = null, + Browser|array|null $browser = null, + BrowserbaseSessionCreateParams|array|null $browserbaseSessionCreateParams = null, + ?string $browserbaseSessionID = null, + ?float $domSettleTimeoutMs = null, + ?bool $experimental = null, ?bool $selfHeal = null, ?string $systemPrompt = null, - ?int $verbose = null, + ?float $verbose = null, + ?bool $waitForCaptchaSolves = null, + XLanguage|string|null $xLanguage = null, + ?string $xSDKVersion = null, + ?\DateTimeInterface $xSentAt = null, + XStreamResponse|string|null $xStreamResponse = null, ): self { $self = new self; - $self['browserbaseAPIKey'] = $browserbaseAPIKey; - $self['browserbaseProjectID'] = $browserbaseProjectID; + $self['modelName'] = $modelName; - null !== $domSettleTimeout && $self['domSettleTimeout'] = $domSettleTimeout; - null !== $model && $self['model'] = $model; + null !== $actTimeoutMs && $self['actTimeoutMs'] = $actTimeoutMs; + null !== $browser && $self['browser'] = $browser; + null !== $browserbaseSessionCreateParams && $self['browserbaseSessionCreateParams'] = $browserbaseSessionCreateParams; + null !== $browserbaseSessionID && $self['browserbaseSessionID'] = $browserbaseSessionID; + null !== $domSettleTimeoutMs && $self['domSettleTimeoutMs'] = $domSettleTimeoutMs; + null !== $experimental && $self['experimental'] = $experimental; null !== $selfHeal && $self['selfHeal'] = $selfHeal; null !== $systemPrompt && $self['systemPrompt'] = $systemPrompt; null !== $verbose && $self['verbose'] = $verbose; + null !== $waitForCaptchaSolves && $self['waitForCaptchaSolves'] = $waitForCaptchaSolves; + null !== $xLanguage && $self['xLanguage'] = $xLanguage; + null !== $xSDKVersion && $self['xSDKVersion'] = $xSDKVersion; + null !== $xSentAt && $self['xSentAt'] = $xSentAt; + null !== $xStreamResponse && $self['xStreamResponse'] = $xStreamResponse; return $self; } /** - * API key for Browserbase Cloud. + * Model name to use for AI operations. */ - public function withBrowserbaseAPIKey(string $browserbaseAPIKey): self + public function withModelName(string $modelName): self { $self = clone $this; - $self['browserbaseAPIKey'] = $browserbaseAPIKey; + $self['modelName'] = $modelName; return $self; } /** - * Project ID for Browserbase. + * Timeout in ms for act operations (deprecated, v2 only). */ - public function withBrowserbaseProjectID(string $browserbaseProjectID): self + public function withActTimeoutMs(float $actTimeoutMs): self { $self = clone $this; - $self['browserbaseProjectID'] = $browserbaseProjectID; + $self['actTimeoutMs'] = $actTimeoutMs; return $self; } /** - * Timeout in ms to wait for DOM to settle. + * @param Browser|BrowserShape $browser */ - public function withDomSettleTimeout(int $domSettleTimeout): self + public function withBrowser(Browser|array $browser): self { $self = clone $this; - $self['domSettleTimeout'] = $domSettleTimeout; + $self['browser'] = $browser; + + return $self; + } + + /** + * @param BrowserbaseSessionCreateParams|BrowserbaseSessionCreateParamsShape $browserbaseSessionCreateParams + */ + public function withBrowserbaseSessionCreateParams( + BrowserbaseSessionCreateParams|array $browserbaseSessionCreateParams + ): self { + $self = clone $this; + $self['browserbaseSessionCreateParams'] = $browserbaseSessionCreateParams; return $self; } /** - * AI model to use for actions (must be prefixed with provider/). + * Existing Browserbase session ID to resume. */ - public function withModel(string $model): self + public function withBrowserbaseSessionID(string $browserbaseSessionID): self { $self = clone $this; - $self['model'] = $model; + $self['browserbaseSessionID'] = $browserbaseSessionID; + + return $self; + } + + /** + * Timeout in ms to wait for DOM to settle. + */ + public function withDomSettleTimeoutMs(float $domSettleTimeoutMs): self + { + $self = clone $this; + $self['domSettleTimeoutMs'] = $domSettleTimeoutMs; + + return $self; + } + + public function withExperimental(bool $experimental): self + { + $self = clone $this; + $self['experimental'] = $experimental; return $self; } @@ -179,7 +286,7 @@ public function withSelfHeal(bool $selfHeal): self } /** - * Custom system prompt for AI actions. + * Custom system prompt for AI operations. */ public function withSystemPrompt(string $systemPrompt): self { @@ -190,13 +297,73 @@ public function withSystemPrompt(string $systemPrompt): self } /** - * Logging verbosity level. + * Logging verbosity level (0=quiet, 1=normal, 2=debug). */ - public function withVerbose(int $verbose): self + public function withVerbose(float $verbose): self { $self = clone $this; $self['verbose'] = $verbose; return $self; } + + /** + * Wait for captcha solves (deprecated, v2 only). + */ + public function withWaitForCaptchaSolves(bool $waitForCaptchaSolves): self + { + $self = clone $this; + $self['waitForCaptchaSolves'] = $waitForCaptchaSolves; + + return $self; + } + + /** + * Client SDK language. + * + * @param XLanguage|value-of $xLanguage + */ + public function withXLanguage(XLanguage|string $xLanguage): self + { + $self = clone $this; + $self['xLanguage'] = $xLanguage; + + return $self; + } + + /** + * Version of the Stagehand SDK. + */ + public function withXSDKVersion(string $xSDKVersion): self + { + $self = clone $this; + $self['xSDKVersion'] = $xSDKVersion; + + return $self; + } + + /** + * ISO timestamp when request was sent. + */ + public function withXSentAt(\DateTimeInterface $xSentAt): self + { + $self = clone $this; + $self['xSentAt'] = $xSentAt; + + return $self; + } + + /** + * Whether to stream the response via SSE. + * + * @param XStreamResponse|value-of $xStreamResponse + */ + public function withXStreamResponse( + XStreamResponse|string $xStreamResponse + ): self { + $self = clone $this; + $self['xStreamResponse'] = $xStreamResponse; + + return $self; + } } diff --git a/src/Sessions/SessionStartParams/Browser.php b/src/Sessions/SessionStartParams/Browser.php new file mode 100644 index 0000000..b4ab955 --- /dev/null +++ b/src/Sessions/SessionStartParams/Browser.php @@ -0,0 +1,105 @@ +, + * } + */ +final class Browser implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Chrome DevTools Protocol URL for connecting to existing browser. + */ + #[Optional('cdpUrl')] + public ?string $cdpURL; + + #[Optional] + public ?LaunchOptions $launchOptions; + + /** + * Browser type to use. + * + * @var value-of|null $type + */ + #[Optional(enum: Type::class)] + public ?string $type; + + 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 LaunchOptions|LaunchOptionsShape|null $launchOptions + * @param Type|value-of|null $type + */ + public static function with( + ?string $cdpURL = null, + LaunchOptions|array|null $launchOptions = null, + Type|string|null $type = null, + ): self { + $self = new self; + + null !== $cdpURL && $self['cdpURL'] = $cdpURL; + null !== $launchOptions && $self['launchOptions'] = $launchOptions; + null !== $type && $self['type'] = $type; + + return $self; + } + + /** + * Chrome DevTools Protocol URL for connecting to existing browser. + */ + public function withCdpURL(string $cdpURL): self + { + $self = clone $this; + $self['cdpURL'] = $cdpURL; + + return $self; + } + + /** + * @param LaunchOptions|LaunchOptionsShape $launchOptions + */ + public function withLaunchOptions(LaunchOptions|array $launchOptions): self + { + $self = clone $this; + $self['launchOptions'] = $launchOptions; + + return $self; + } + + /** + * Browser type to use. + * + * @param Type|value-of $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } +} diff --git a/src/Sessions/SessionStartParams/Browser/LaunchOptions.php b/src/Sessions/SessionStartParams/Browser/LaunchOptions.php new file mode 100644 index 0000000..d2fb2b7 --- /dev/null +++ b/src/Sessions/SessionStartParams/Browser/LaunchOptions.php @@ -0,0 +1,315 @@ +|null, + * cdpURL?: string|null, + * chromiumSandbox?: bool|null, + * connectTimeoutMs?: float|null, + * deviceScaleFactor?: float|null, + * devtools?: bool|null, + * downloadsPath?: string|null, + * executablePath?: string|null, + * hasTouch?: bool|null, + * headless?: bool|null, + * ignoreDefaultArgs?: IgnoreDefaultArgsShape|null, + * ignoreHTTPSErrors?: bool|null, + * locale?: string|null, + * preserveUserDataDir?: bool|null, + * proxy?: null|Proxy|ProxyShape, + * userDataDir?: string|null, + * viewport?: null|Viewport|ViewportShape, + * } + */ +final class LaunchOptions implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + #[Optional] + public ?bool $acceptDownloads; + + /** @var list|null $args */ + #[Optional(list: 'string')] + public ?array $args; + + #[Optional('cdpUrl')] + public ?string $cdpURL; + + #[Optional] + public ?bool $chromiumSandbox; + + #[Optional] + public ?float $connectTimeoutMs; + + #[Optional] + public ?float $deviceScaleFactor; + + #[Optional] + public ?bool $devtools; + + #[Optional] + public ?string $downloadsPath; + + #[Optional] + public ?string $executablePath; + + #[Optional] + public ?bool $hasTouch; + + #[Optional] + public ?bool $headless; + + /** @var bool|list|null $ignoreDefaultArgs */ + #[Optional(union: IgnoreDefaultArgs::class)] + public bool|array|null $ignoreDefaultArgs; + + #[Optional] + public ?bool $ignoreHTTPSErrors; + + #[Optional] + public ?string $locale; + + #[Optional] + public ?bool $preserveUserDataDir; + + #[Optional] + public ?Proxy $proxy; + + #[Optional] + public ?string $userDataDir; + + #[Optional] + public ?Viewport $viewport; + + 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 list|null $args + * @param IgnoreDefaultArgsShape|null $ignoreDefaultArgs + * @param Proxy|ProxyShape|null $proxy + * @param Viewport|ViewportShape|null $viewport + */ + public static function with( + ?bool $acceptDownloads = null, + ?array $args = null, + ?string $cdpURL = null, + ?bool $chromiumSandbox = null, + ?float $connectTimeoutMs = null, + ?float $deviceScaleFactor = null, + ?bool $devtools = null, + ?string $downloadsPath = null, + ?string $executablePath = null, + ?bool $hasTouch = null, + ?bool $headless = null, + bool|array|null $ignoreDefaultArgs = null, + ?bool $ignoreHTTPSErrors = null, + ?string $locale = null, + ?bool $preserveUserDataDir = null, + Proxy|array|null $proxy = null, + ?string $userDataDir = null, + Viewport|array|null $viewport = null, + ): self { + $self = new self; + + null !== $acceptDownloads && $self['acceptDownloads'] = $acceptDownloads; + null !== $args && $self['args'] = $args; + null !== $cdpURL && $self['cdpURL'] = $cdpURL; + null !== $chromiumSandbox && $self['chromiumSandbox'] = $chromiumSandbox; + null !== $connectTimeoutMs && $self['connectTimeoutMs'] = $connectTimeoutMs; + null !== $deviceScaleFactor && $self['deviceScaleFactor'] = $deviceScaleFactor; + null !== $devtools && $self['devtools'] = $devtools; + null !== $downloadsPath && $self['downloadsPath'] = $downloadsPath; + null !== $executablePath && $self['executablePath'] = $executablePath; + null !== $hasTouch && $self['hasTouch'] = $hasTouch; + null !== $headless && $self['headless'] = $headless; + null !== $ignoreDefaultArgs && $self['ignoreDefaultArgs'] = $ignoreDefaultArgs; + null !== $ignoreHTTPSErrors && $self['ignoreHTTPSErrors'] = $ignoreHTTPSErrors; + null !== $locale && $self['locale'] = $locale; + null !== $preserveUserDataDir && $self['preserveUserDataDir'] = $preserveUserDataDir; + null !== $proxy && $self['proxy'] = $proxy; + null !== $userDataDir && $self['userDataDir'] = $userDataDir; + null !== $viewport && $self['viewport'] = $viewport; + + return $self; + } + + public function withAcceptDownloads(bool $acceptDownloads): self + { + $self = clone $this; + $self['acceptDownloads'] = $acceptDownloads; + + return $self; + } + + /** + * @param list $args + */ + public function withArgs(array $args): self + { + $self = clone $this; + $self['args'] = $args; + + return $self; + } + + public function withCdpURL(string $cdpURL): self + { + $self = clone $this; + $self['cdpURL'] = $cdpURL; + + return $self; + } + + public function withChromiumSandbox(bool $chromiumSandbox): self + { + $self = clone $this; + $self['chromiumSandbox'] = $chromiumSandbox; + + return $self; + } + + public function withConnectTimeoutMs(float $connectTimeoutMs): self + { + $self = clone $this; + $self['connectTimeoutMs'] = $connectTimeoutMs; + + return $self; + } + + public function withDeviceScaleFactor(float $deviceScaleFactor): self + { + $self = clone $this; + $self['deviceScaleFactor'] = $deviceScaleFactor; + + return $self; + } + + public function withDevtools(bool $devtools): self + { + $self = clone $this; + $self['devtools'] = $devtools; + + return $self; + } + + public function withDownloadsPath(string $downloadsPath): self + { + $self = clone $this; + $self['downloadsPath'] = $downloadsPath; + + return $self; + } + + public function withExecutablePath(string $executablePath): self + { + $self = clone $this; + $self['executablePath'] = $executablePath; + + return $self; + } + + public function withHasTouch(bool $hasTouch): self + { + $self = clone $this; + $self['hasTouch'] = $hasTouch; + + return $self; + } + + public function withHeadless(bool $headless): self + { + $self = clone $this; + $self['headless'] = $headless; + + return $self; + } + + /** + * @param IgnoreDefaultArgsShape $ignoreDefaultArgs + */ + public function withIgnoreDefaultArgs(bool|array $ignoreDefaultArgs): self + { + $self = clone $this; + $self['ignoreDefaultArgs'] = $ignoreDefaultArgs; + + return $self; + } + + public function withIgnoreHTTPSErrors(bool $ignoreHTTPSErrors): self + { + $self = clone $this; + $self['ignoreHTTPSErrors'] = $ignoreHTTPSErrors; + + return $self; + } + + public function withLocale(string $locale): self + { + $self = clone $this; + $self['locale'] = $locale; + + return $self; + } + + public function withPreserveUserDataDir(bool $preserveUserDataDir): self + { + $self = clone $this; + $self['preserveUserDataDir'] = $preserveUserDataDir; + + return $self; + } + + /** + * @param Proxy|ProxyShape $proxy + */ + public function withProxy(Proxy|array $proxy): self + { + $self = clone $this; + $self['proxy'] = $proxy; + + return $self; + } + + public function withUserDataDir(string $userDataDir): self + { + $self = clone $this; + $self['userDataDir'] = $userDataDir; + + return $self; + } + + /** + * @param Viewport|ViewportShape $viewport + */ + public function withViewport(Viewport|array $viewport): self + { + $self = clone $this; + $self['viewport'] = $viewport; + + return $self; + } +} diff --git a/src/Sessions/SessionExecuteAgentParams/AgentConfig/Model.php b/src/Sessions/SessionStartParams/Browser/LaunchOptions/IgnoreDefaultArgs.php similarity index 57% rename from src/Sessions/SessionExecuteAgentParams/AgentConfig/Model.php rename to src/Sessions/SessionStartParams/Browser/LaunchOptions/IgnoreDefaultArgs.php index 8f5d33a..453660a 100644 --- a/src/Sessions/SessionExecuteAgentParams/AgentConfig/Model.php +++ b/src/Sessions/SessionStartParams/Browser/LaunchOptions/IgnoreDefaultArgs.php @@ -2,14 +2,17 @@ declare(strict_types=1); -namespace Stagehand\Sessions\SessionExecuteAgentParams\AgentConfig; +namespace Stagehand\Sessions\SessionStartParams\Browser\LaunchOptions; use Stagehand\Core\Concerns\SdkUnion; use Stagehand\Core\Conversion\Contracts\Converter; use Stagehand\Core\Conversion\Contracts\ConverterSource; -use Stagehand\Sessions\ModelConfig; +use Stagehand\Core\Conversion\ListOf; -final class Model implements ConverterSource +/** + * @phpstan-type IgnoreDefaultArgsShape = bool|list + */ +final class IgnoreDefaultArgs implements ConverterSource { use SdkUnion; @@ -18,6 +21,6 @@ final class Model implements ConverterSource */ public static function variants(): array { - return ['string', ModelConfig::class]; + return ['bool', new ListOf('string')]; } } diff --git a/src/Sessions/SessionStartParams/Browser/LaunchOptions/Proxy.php b/src/Sessions/SessionStartParams/Browser/LaunchOptions/Proxy.php new file mode 100644 index 0000000..ac3b76f --- /dev/null +++ b/src/Sessions/SessionStartParams/Browser/LaunchOptions/Proxy.php @@ -0,0 +1,109 @@ + */ + use SdkModel; + + #[Required] + public string $server; + + #[Optional] + public ?string $bypass; + + #[Optional] + public ?string $password; + + #[Optional] + public ?string $username; + + /** + * `new Proxy()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Proxy::with(server: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Proxy)->withServer(...) + * ``` + */ + 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. + */ + public static function with( + string $server, + ?string $bypass = null, + ?string $password = null, + ?string $username = null, + ): self { + $self = new self; + + $self['server'] = $server; + + null !== $bypass && $self['bypass'] = $bypass; + null !== $password && $self['password'] = $password; + null !== $username && $self['username'] = $username; + + return $self; + } + + public function withServer(string $server): self + { + $self = clone $this; + $self['server'] = $server; + + return $self; + } + + public function withBypass(string $bypass): self + { + $self = clone $this; + $self['bypass'] = $bypass; + + return $self; + } + + public function withPassword(string $password): self + { + $self = clone $this; + $self['password'] = $password; + + return $self; + } + + public function withUsername(string $username): self + { + $self = clone $this; + $self['username'] = $username; + + return $self; + } +} diff --git a/src/Sessions/SessionStartParams/Browser/LaunchOptions/Viewport.php b/src/Sessions/SessionStartParams/Browser/LaunchOptions/Viewport.php new file mode 100644 index 0000000..7536799 --- /dev/null +++ b/src/Sessions/SessionStartParams/Browser/LaunchOptions/Viewport.php @@ -0,0 +1,74 @@ + */ + use SdkModel; + + #[Required] + public float $height; + + #[Required] + public float $width; + + /** + * `new Viewport()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Viewport::with(height: ..., width: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Viewport)->withHeight(...)->withWidth(...) + * ``` + */ + 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. + */ + public static function with(float $height, float $width): self + { + $self = new self; + + $self['height'] = $height; + $self['width'] = $width; + + return $self; + } + + public function withHeight(float $height): self + { + $self = clone $this; + $self['height'] = $height; + + return $self; + } + + public function withWidth(float $width): self + { + $self = clone $this; + $self['width'] = $width; + + return $self; + } +} diff --git a/src/Sessions/SessionStartParams/Browser/Type.php b/src/Sessions/SessionStartParams/Browser/Type.php new file mode 100644 index 0000000..c6baf44 --- /dev/null +++ b/src/Sessions/SessionStartParams/Browser/Type.php @@ -0,0 +1,15 @@ +, + * timeout?: float|null, + * userMetadata?: array|null, + * } + */ +final class BrowserbaseSessionCreateParams implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + #[Optional] + public ?BrowserSettings $browserSettings; + + #[Optional('extensionId')] + public ?string $extensionID; + + #[Optional] + public ?bool $keepAlive; + + #[Optional('projectId')] + public ?string $projectID; + + /** @var bool|list|null $proxies */ + #[Optional(union: Proxies::class)] + public bool|array|null $proxies; + + /** @var value-of|null $region */ + #[Optional(enum: Region::class)] + public ?string $region; + + #[Optional] + public ?float $timeout; + + /** @var array|null $userMetadata */ + #[Optional(map: 'mixed')] + public ?array $userMetadata; + + 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 BrowserSettings|BrowserSettingsShape|null $browserSettings + * @param ProxiesShape|null $proxies + * @param Region|value-of|null $region + * @param array|null $userMetadata + */ + public static function with( + BrowserSettings|array|null $browserSettings = null, + ?string $extensionID = null, + ?bool $keepAlive = null, + ?string $projectID = null, + bool|array|null $proxies = null, + Region|string|null $region = null, + ?float $timeout = null, + ?array $userMetadata = null, + ): self { + $self = new self; + + null !== $browserSettings && $self['browserSettings'] = $browserSettings; + null !== $extensionID && $self['extensionID'] = $extensionID; + null !== $keepAlive && $self['keepAlive'] = $keepAlive; + null !== $projectID && $self['projectID'] = $projectID; + null !== $proxies && $self['proxies'] = $proxies; + null !== $region && $self['region'] = $region; + null !== $timeout && $self['timeout'] = $timeout; + null !== $userMetadata && $self['userMetadata'] = $userMetadata; + + return $self; + } + + /** + * @param BrowserSettings|BrowserSettingsShape $browserSettings + */ + public function withBrowserSettings( + BrowserSettings|array $browserSettings + ): self { + $self = clone $this; + $self['browserSettings'] = $browserSettings; + + return $self; + } + + public function withExtensionID(string $extensionID): self + { + $self = clone $this; + $self['extensionID'] = $extensionID; + + return $self; + } + + public function withKeepAlive(bool $keepAlive): self + { + $self = clone $this; + $self['keepAlive'] = $keepAlive; + + return $self; + } + + public function withProjectID(string $projectID): self + { + $self = clone $this; + $self['projectID'] = $projectID; + + return $self; + } + + /** + * @param ProxiesShape $proxies + */ + public function withProxies(bool|array $proxies): self + { + $self = clone $this; + $self['proxies'] = $proxies; + + return $self; + } + + /** + * @param Region|value-of $region + */ + public function withRegion(Region|string $region): self + { + $self = clone $this; + $self['region'] = $region; + + return $self; + } + + public function withTimeout(float $timeout): self + { + $self = clone $this; + $self['timeout'] = $timeout; + + return $self; + } + + /** + * @param array $userMetadata + */ + public function withUserMetadata(array $userMetadata): self + { + $self = clone $this; + $self['userMetadata'] = $userMetadata; + + return $self; + } +} diff --git a/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/BrowserSettings.php b/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/BrowserSettings.php new file mode 100644 index 0000000..6014c60 --- /dev/null +++ b/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/BrowserSettings.php @@ -0,0 +1,183 @@ + */ + use SdkModel; + + #[Optional] + public ?bool $advancedStealth; + + #[Optional] + public ?bool $blockAds; + + #[Optional] + public ?Context $context; + + #[Optional('extensionId')] + public ?string $extensionID; + + #[Optional] + public ?Fingerprint $fingerprint; + + #[Optional] + public ?bool $logSession; + + #[Optional] + public ?bool $recordSession; + + #[Optional] + public ?bool $solveCaptchas; + + #[Optional] + public ?Viewport $viewport; + + 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 Context|ContextShape|null $context + * @param Fingerprint|FingerprintShape|null $fingerprint + * @param Viewport|ViewportShape|null $viewport + */ + public static function with( + ?bool $advancedStealth = null, + ?bool $blockAds = null, + Context|array|null $context = null, + ?string $extensionID = null, + Fingerprint|array|null $fingerprint = null, + ?bool $logSession = null, + ?bool $recordSession = null, + ?bool $solveCaptchas = null, + Viewport|array|null $viewport = null, + ): self { + $self = new self; + + null !== $advancedStealth && $self['advancedStealth'] = $advancedStealth; + null !== $blockAds && $self['blockAds'] = $blockAds; + null !== $context && $self['context'] = $context; + null !== $extensionID && $self['extensionID'] = $extensionID; + null !== $fingerprint && $self['fingerprint'] = $fingerprint; + null !== $logSession && $self['logSession'] = $logSession; + null !== $recordSession && $self['recordSession'] = $recordSession; + null !== $solveCaptchas && $self['solveCaptchas'] = $solveCaptchas; + null !== $viewport && $self['viewport'] = $viewport; + + return $self; + } + + public function withAdvancedStealth(bool $advancedStealth): self + { + $self = clone $this; + $self['advancedStealth'] = $advancedStealth; + + return $self; + } + + public function withBlockAds(bool $blockAds): self + { + $self = clone $this; + $self['blockAds'] = $blockAds; + + return $self; + } + + /** + * @param Context|ContextShape $context + */ + public function withContext(Context|array $context): self + { + $self = clone $this; + $self['context'] = $context; + + return $self; + } + + public function withExtensionID(string $extensionID): self + { + $self = clone $this; + $self['extensionID'] = $extensionID; + + return $self; + } + + /** + * @param Fingerprint|FingerprintShape $fingerprint + */ + public function withFingerprint(Fingerprint|array $fingerprint): self + { + $self = clone $this; + $self['fingerprint'] = $fingerprint; + + return $self; + } + + public function withLogSession(bool $logSession): self + { + $self = clone $this; + $self['logSession'] = $logSession; + + return $self; + } + + public function withRecordSession(bool $recordSession): self + { + $self = clone $this; + $self['recordSession'] = $recordSession; + + return $self; + } + + public function withSolveCaptchas(bool $solveCaptchas): self + { + $self = clone $this; + $self['solveCaptchas'] = $solveCaptchas; + + return $self; + } + + /** + * @param Viewport|ViewportShape $viewport + */ + public function withViewport(Viewport|array $viewport): self + { + $self = clone $this; + $self['viewport'] = $viewport; + + return $self; + } +} diff --git a/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/BrowserSettings/Context.php b/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/BrowserSettings/Context.php new file mode 100644 index 0000000..b270035 --- /dev/null +++ b/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/BrowserSettings/Context.php @@ -0,0 +1,76 @@ + */ + use SdkModel; + + #[Required] + public string $id; + + #[Optional] + public ?bool $persist; + + /** + * `new Context()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Context::with(id: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Context)->withID(...) + * ``` + */ + 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. + */ + public static function with(string $id, ?bool $persist = null): self + { + $self = new self; + + $self['id'] = $id; + + null !== $persist && $self['persist'] = $persist; + + return $self; + } + + public function withID(string $id): self + { + $self = clone $this; + $self['id'] = $id; + + return $self; + } + + public function withPersist(bool $persist): self + { + $self = clone $this; + $self['persist'] = $persist; + + return $self; + } +} diff --git a/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/BrowserSettings/Fingerprint.php b/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/BrowserSettings/Fingerprint.php new file mode 100644 index 0000000..e757711 --- /dev/null +++ b/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/BrowserSettings/Fingerprint.php @@ -0,0 +1,158 @@ +>|null, + * devices?: list>|null, + * httpVersion?: null|HTTPVersion|value-of, + * locales?: list|null, + * operatingSystems?: list>|null, + * screen?: null|Screen|ScreenShape, + * } + */ +final class Fingerprint implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** @var list>|null $browsers */ + #[Optional(list: Browser::class)] + public ?array $browsers; + + /** @var list>|null $devices */ + #[Optional(list: Device::class)] + public ?array $devices; + + /** @var value-of|null $httpVersion */ + #[Optional(enum: HTTPVersion::class)] + public ?string $httpVersion; + + /** @var list|null $locales */ + #[Optional(list: 'string')] + public ?array $locales; + + /** @var list>|null $operatingSystems */ + #[Optional(list: OperatingSystem::class)] + public ?array $operatingSystems; + + #[Optional] + public ?Screen $screen; + + 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 list>|null $browsers + * @param list>|null $devices + * @param HTTPVersion|value-of|null $httpVersion + * @param list|null $locales + * @param list>|null $operatingSystems + * @param Screen|ScreenShape|null $screen + */ + public static function with( + ?array $browsers = null, + ?array $devices = null, + HTTPVersion|string|null $httpVersion = null, + ?array $locales = null, + ?array $operatingSystems = null, + Screen|array|null $screen = null, + ): self { + $self = new self; + + null !== $browsers && $self['browsers'] = $browsers; + null !== $devices && $self['devices'] = $devices; + null !== $httpVersion && $self['httpVersion'] = $httpVersion; + null !== $locales && $self['locales'] = $locales; + null !== $operatingSystems && $self['operatingSystems'] = $operatingSystems; + null !== $screen && $self['screen'] = $screen; + + return $self; + } + + /** + * @param list> $browsers + */ + public function withBrowsers(array $browsers): self + { + $self = clone $this; + $self['browsers'] = $browsers; + + return $self; + } + + /** + * @param list> $devices + */ + public function withDevices(array $devices): self + { + $self = clone $this; + $self['devices'] = $devices; + + return $self; + } + + /** + * @param HTTPVersion|value-of $httpVersion + */ + public function withHTTPVersion(HTTPVersion|string $httpVersion): self + { + $self = clone $this; + $self['httpVersion'] = $httpVersion; + + return $self; + } + + /** + * @param list $locales + */ + public function withLocales(array $locales): self + { + $self = clone $this; + $self['locales'] = $locales; + + return $self; + } + + /** + * @param list> $operatingSystems + */ + public function withOperatingSystems(array $operatingSystems): self + { + $self = clone $this; + $self['operatingSystems'] = $operatingSystems; + + return $self; + } + + /** + * @param Screen|ScreenShape $screen + */ + public function withScreen(Screen|array $screen): self + { + $self = clone $this; + $self['screen'] = $screen; + + return $self; + } +} diff --git a/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/BrowserSettings/Fingerprint/Browser.php b/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/BrowserSettings/Fingerprint/Browser.php new file mode 100644 index 0000000..54a65f2 --- /dev/null +++ b/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/BrowserSettings/Fingerprint/Browser.php @@ -0,0 +1,16 @@ + */ + use SdkModel; + + #[Optional] + public ?float $maxHeight; + + #[Optional] + public ?float $maxWidth; + + #[Optional] + public ?float $minHeight; + + #[Optional] + public ?float $minWidth; + + 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. + */ + public static function with( + ?float $maxHeight = null, + ?float $maxWidth = null, + ?float $minHeight = null, + ?float $minWidth = null, + ): self { + $self = new self; + + null !== $maxHeight && $self['maxHeight'] = $maxHeight; + null !== $maxWidth && $self['maxWidth'] = $maxWidth; + null !== $minHeight && $self['minHeight'] = $minHeight; + null !== $minWidth && $self['minWidth'] = $minWidth; + + return $self; + } + + public function withMaxHeight(float $maxHeight): self + { + $self = clone $this; + $self['maxHeight'] = $maxHeight; + + return $self; + } + + public function withMaxWidth(float $maxWidth): self + { + $self = clone $this; + $self['maxWidth'] = $maxWidth; + + return $self; + } + + public function withMinHeight(float $minHeight): self + { + $self = clone $this; + $self['minHeight'] = $minHeight; + + return $self; + } + + public function withMinWidth(float $minWidth): self + { + $self = clone $this; + $self['minWidth'] = $minWidth; + + return $self; + } +} diff --git a/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/BrowserSettings/Viewport.php b/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/BrowserSettings/Viewport.php new file mode 100644 index 0000000..020cca8 --- /dev/null +++ b/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/BrowserSettings/Viewport.php @@ -0,0 +1,60 @@ + */ + use SdkModel; + + #[Optional] + public ?float $height; + + #[Optional] + public ?float $width; + + 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. + */ + public static function with(?float $height = null, ?float $width = null): self + { + $self = new self; + + null !== $height && $self['height'] = $height; + null !== $width && $self['width'] = $width; + + return $self; + } + + public function withHeight(float $height): self + { + $self = clone $this; + $self['height'] = $height; + + return $self; + } + + public function withWidth(float $width): self + { + $self = clone $this; + $self['width'] = $width; + + return $self; + } +} diff --git a/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/Proxies.php b/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/Proxies.php new file mode 100644 index 0000000..2b16438 --- /dev/null +++ b/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/Proxies.php @@ -0,0 +1,29 @@ + + */ +final class Proxies implements ConverterSource +{ + use SdkUnion; + + /** + * @return list|array + */ + public static function variants(): array + { + return ['bool', new ListOf(ProxyConfigList::class)]; + } +} diff --git a/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/Proxies/ProxyConfigList.php b/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/Proxies/ProxyConfigList.php new file mode 100644 index 0000000..6462c66 --- /dev/null +++ b/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/Proxies/ProxyConfigList.php @@ -0,0 +1,38 @@ +|array + */ + public static function variants(): array + { + return [ + 'browserbase' => BrowserbaseProxyConfig::class, + 'external' => ExternalProxyConfig::class, + ]; + } +} diff --git a/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/Proxies/ProxyConfigList/BrowserbaseProxyConfig.php b/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/Proxies/ProxyConfigList/BrowserbaseProxyConfig.php new file mode 100644 index 0000000..3aa53a2 --- /dev/null +++ b/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/Proxies/ProxyConfigList/BrowserbaseProxyConfig.php @@ -0,0 +1,79 @@ + */ + use SdkModel; + + /** @var 'browserbase' $type */ + #[Required] + public string $type = 'browserbase'; + + #[Optional] + public ?string $domainPattern; + + #[Optional] + public ?Geolocation $geolocation; + + 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 Geolocation|GeolocationShape|null $geolocation + */ + public static function with( + ?string $domainPattern = null, + Geolocation|array|null $geolocation = null + ): self { + $self = new self; + + null !== $domainPattern && $self['domainPattern'] = $domainPattern; + null !== $geolocation && $self['geolocation'] = $geolocation; + + return $self; + } + + public function withDomainPattern(string $domainPattern): self + { + $self = clone $this; + $self['domainPattern'] = $domainPattern; + + return $self; + } + + /** + * @param Geolocation|GeolocationShape $geolocation + */ + public function withGeolocation(Geolocation|array $geolocation): self + { + $self = clone $this; + $self['geolocation'] = $geolocation; + + return $self; + } +} diff --git a/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/Proxies/ProxyConfigList/BrowserbaseProxyConfig/Geolocation.php b/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/Proxies/ProxyConfigList/BrowserbaseProxyConfig/Geolocation.php new file mode 100644 index 0000000..0bfd18e --- /dev/null +++ b/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/Proxies/ProxyConfigList/BrowserbaseProxyConfig/Geolocation.php @@ -0,0 +1,93 @@ + */ + use SdkModel; + + #[Required] + public string $country; + + #[Optional] + public ?string $city; + + #[Optional] + public ?string $state; + + /** + * `new Geolocation()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Geolocation::with(country: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Geolocation)->withCountry(...) + * ``` + */ + 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. + */ + public static function with( + string $country, + ?string $city = null, + ?string $state = null + ): self { + $self = new self; + + $self['country'] = $country; + + null !== $city && $self['city'] = $city; + null !== $state && $self['state'] = $state; + + return $self; + } + + public function withCountry(string $country): self + { + $self = clone $this; + $self['country'] = $country; + + return $self; + } + + public function withCity(string $city): self + { + $self = clone $this; + $self['city'] = $city; + + return $self; + } + + public function withState(string $state): self + { + $self = clone $this; + $self['state'] = $state; + + return $self; + } +} diff --git a/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/Proxies/ProxyConfigList/ExternalProxyConfig.php b/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/Proxies/ProxyConfigList/ExternalProxyConfig.php new file mode 100644 index 0000000..a203e40 --- /dev/null +++ b/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/Proxies/ProxyConfigList/ExternalProxyConfig.php @@ -0,0 +1,114 @@ + */ + use SdkModel; + + /** @var 'external' $type */ + #[Required] + public string $type = 'external'; + + #[Required] + public string $server; + + #[Optional] + public ?string $domainPattern; + + #[Optional] + public ?string $password; + + #[Optional] + public ?string $username; + + /** + * `new ExternalProxyConfig()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * ExternalProxyConfig::with(server: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new ExternalProxyConfig)->withServer(...) + * ``` + */ + 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. + */ + public static function with( + string $server, + ?string $domainPattern = null, + ?string $password = null, + ?string $username = null, + ): self { + $self = new self; + + $self['server'] = $server; + + null !== $domainPattern && $self['domainPattern'] = $domainPattern; + null !== $password && $self['password'] = $password; + null !== $username && $self['username'] = $username; + + return $self; + } + + public function withServer(string $server): self + { + $self = clone $this; + $self['server'] = $server; + + return $self; + } + + public function withDomainPattern(string $domainPattern): self + { + $self = clone $this; + $self['domainPattern'] = $domainPattern; + + return $self; + } + + public function withPassword(string $password): self + { + $self = clone $this; + $self['password'] = $password; + + return $self; + } + + public function withUsername(string $username): self + { + $self = clone $this; + $self['username'] = $username; + + return $self; + } +} diff --git a/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/Region.php b/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/Region.php new file mode 100644 index 0000000..0262878 --- /dev/null +++ b/src/Sessions/SessionStartParams/BrowserbaseSessionCreateParams/Region.php @@ -0,0 +1,16 @@ + */ use SdkModel; - /** - * Whether the session is ready to use. - */ #[Required] - public bool $available; + public Data $data; /** - * Unique identifier for the session. + * Indicates whether the request was successful. */ - #[Required('sessionId')] - public string $sessionID; + #[Required] + public bool $success; /** * `new SessionStartResponse()` is missing required properties by the API. * * To enforce required parameters use * ``` - * SessionStartResponse::with(available: ..., sessionID: ...) + * SessionStartResponse::with(data: ..., success: ...) * ``` * * Otherwise ensure the following setters are called * * ``` - * (new SessionStartResponse)->withAvailable(...)->withSessionID(...) + * (new SessionStartResponse)->withData(...)->withSuccess(...) * ``` */ public function __construct() @@ -53,35 +53,37 @@ public function __construct() * 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(bool $available, string $sessionID): self + public static function with(Data|array $data, bool $success): self { $self = new self; - $self['available'] = $available; - $self['sessionID'] = $sessionID; + $self['data'] = $data; + $self['success'] = $success; return $self; } /** - * Whether the session is ready to use. + * @param Data|DataShape $data */ - public function withAvailable(bool $available): self + public function withData(Data|array $data): self { $self = clone $this; - $self['available'] = $available; + $self['data'] = $data; return $self; } /** - * Unique identifier for the session. + * Indicates whether the request was successful. */ - public function withSessionID(string $sessionID): self + public function withSuccess(bool $success): self { $self = clone $this; - $self['sessionID'] = $sessionID; + $self['success'] = $success; return $self; } diff --git a/src/Sessions/SessionStartResponse/Data.php b/src/Sessions/SessionStartResponse/Data.php new file mode 100644 index 0000000..c220cea --- /dev/null +++ b/src/Sessions/SessionStartResponse/Data.php @@ -0,0 +1,105 @@ + */ + use SdkModel; + + #[Required] + public bool $available; + + /** + * Unique Browserbase session identifier. + */ + #[Required('sessionId')] + public string $sessionID; + + /** + * CDP WebSocket URL for connecting to the Browserbase cloud browser (present when available). + */ + #[Optional('cdpUrl', nullable: true)] + public ?string $cdpURL; + + /** + * `new Data()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Data::with(available: ..., sessionID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Data)->withAvailable(...)->withSessionID(...) + * ``` + */ + 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. + */ + public static function with( + bool $available, + string $sessionID, + ?string $cdpURL = null + ): self { + $self = new self; + + $self['available'] = $available; + $self['sessionID'] = $sessionID; + + null !== $cdpURL && $self['cdpURL'] = $cdpURL; + + return $self; + } + + public function withAvailable(bool $available): self + { + $self = clone $this; + $self['available'] = $available; + + return $self; + } + + /** + * Unique Browserbase session identifier. + */ + public function withSessionID(string $sessionID): self + { + $self = clone $this; + $self['sessionID'] = $sessionID; + + return $self; + } + + /** + * CDP WebSocket URL for connecting to the Browserbase cloud browser (present when available). + */ + public function withCdpURL(?string $cdpURL): self + { + $self = clone $this; + $self['cdpURL'] = $cdpURL; + + return $self; + } +} diff --git a/src/Sessions/StreamEvent.php b/src/Sessions/StreamEvent.php new file mode 100644 index 0000000..f75321a --- /dev/null +++ b/src/Sessions/StreamEvent.php @@ -0,0 +1,121 @@ +\n\n`. Key order: data (with status first), type, id. + * + * @phpstan-import-type DataShape from \Stagehand\Sessions\StreamEvent\Data + * + * @phpstan-type StreamEventShape = array{ + * id: string, data: DataShape, type: Type|value-of + * } + */ +final class StreamEvent implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Unique identifier for this event. + */ + #[Required] + public string $id; + + #[Required] + public StreamEventSystemDataOutput|StreamEventLogDataOutput $data; + + /** + * Type of stream event - system events or log messages. + * + * @var value-of $type + */ + #[Required(enum: Type::class)] + public string $type; + + /** + * `new StreamEvent()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * StreamEvent::with(id: ..., data: ..., type: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new StreamEvent)->withID(...)->withData(...)->withType(...) + * ``` + */ + 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 DataShape $data + * @param Type|value-of $type + */ + public static function with( + string $id, + StreamEventSystemDataOutput|array|StreamEventLogDataOutput $data, + Type|string $type, + ): self { + $self = new self; + + $self['id'] = $id; + $self['data'] = $data; + $self['type'] = $type; + + return $self; + } + + /** + * Unique identifier for this event. + */ + public function withID(string $id): self + { + $self = clone $this; + $self['id'] = $id; + + return $self; + } + + /** + * @param DataShape $data + */ + public function withData( + StreamEventSystemDataOutput|array|StreamEventLogDataOutput $data + ): self { + $self = clone $this; + $self['data'] = $data; + + return $self; + } + + /** + * Type of stream event - system events or log messages. + * + * @param Type|value-of $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } +} diff --git a/src/Sessions/StreamEvent/Data.php b/src/Sessions/StreamEvent/Data.php new file mode 100644 index 0000000..7f95224 --- /dev/null +++ b/src/Sessions/StreamEvent/Data.php @@ -0,0 +1,32 @@ +|array + */ + public static function variants(): array + { + return [ + StreamEventSystemDataOutput::class, StreamEventLogDataOutput::class, + ]; + } +} diff --git a/src/Sessions/StreamEvent/Data/StreamEventLogDataOutput.php b/src/Sessions/StreamEvent/Data/StreamEventLogDataOutput.php new file mode 100644 index 0000000..5477691 --- /dev/null +++ b/src/Sessions/StreamEvent/Data/StreamEventLogDataOutput.php @@ -0,0 +1,74 @@ + */ + use SdkModel; + + /** @var 'running' $status */ + #[Required] + public string $status = 'running'; + + /** + * Log message from the operation. + */ + #[Required] + public string $message; + + /** + * `new StreamEventLogDataOutput()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * StreamEventLogDataOutput::with(message: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new StreamEventLogDataOutput)->withMessage(...) + * ``` + */ + 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. + */ + public static function with(string $message): self + { + $self = new self; + + $self['message'] = $message; + + return $self; + } + + /** + * Log message from the operation. + */ + public function withMessage(string $message): self + { + $self = clone $this; + $self['message'] = $message; + + return $self; + } +} diff --git a/src/Sessions/StreamEvent/Data/StreamEventSystemDataOutput.php b/src/Sessions/StreamEvent/Data/StreamEventSystemDataOutput.php new file mode 100644 index 0000000..1d6cbef --- /dev/null +++ b/src/Sessions/StreamEvent/Data/StreamEventSystemDataOutput.php @@ -0,0 +1,118 @@ +, error?: string|null, result?: mixed + * } + */ +final class StreamEventSystemDataOutput implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Current status of the streaming operation. + * + * @var value-of $status + */ + #[Required(enum: Status::class)] + public string $status; + + /** + * Error message (present when status is 'error'). + */ + #[Optional] + public ?string $error; + + /** + * Operation result (present when status is 'finished'). + */ + #[Optional] + public mixed $result; + + /** + * `new StreamEventSystemDataOutput()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * StreamEventSystemDataOutput::with(status: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new StreamEventSystemDataOutput)->withStatus(...) + * ``` + */ + 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 Status|value-of $status + */ + public static function with( + Status|string $status, + ?string $error = null, + mixed $result = null + ): self { + $self = new self; + + $self['status'] = $status; + + null !== $error && $self['error'] = $error; + null !== $result && $self['result'] = $result; + + return $self; + } + + /** + * Current status of the streaming operation. + * + * @param Status|value-of $status + */ + public function withStatus(Status|string $status): self + { + $self = clone $this; + $self['status'] = $status; + + return $self; + } + + /** + * Error message (present when status is 'error'). + */ + public function withError(string $error): self + { + $self = clone $this; + $self['error'] = $error; + + return $self; + } + + /** + * Operation result (present when status is 'finished'). + */ + public function withResult(mixed $result): self + { + $self = clone $this; + $self['result'] = $result; + + return $self; + } +} diff --git a/src/Sessions/StreamEvent/Data/StreamEventSystemDataOutput/Status.php b/src/Sessions/StreamEvent/Data/StreamEventSystemDataOutput/Status.php new file mode 100644 index 0000000..4c30706 --- /dev/null +++ b/src/Sessions/StreamEvent/Data/StreamEventSystemDataOutput/Status.php @@ -0,0 +1,21 @@ +> */ use SdkModel; @@ -43,7 +43,7 @@ public function __construct( $this->ageYears = $ageYears; $this->owner = $owner; - null != $friends && $this->friends = $friends; + null !== $friends && $this['friends'] = $friends; } } @@ -58,11 +58,7 @@ class ModelTest extends TestCase #[Test] public function testBasicGetAndSet(): void { - $model = new Model( - name: 'Bob', - ageYears: 12, - owner: null, - ); + $model = new Dog(name: 'Bob', ageYears: 12, owner: null); $this->assertEquals(12, $model->ageYears); ++$model->ageYears; @@ -72,11 +68,7 @@ public function testBasicGetAndSet(): void #[Test] public function testNullAccess(): void { - $model = new Model( - name: 'Bob', - ageYears: 12, - owner: null, - ); + $model = new Dog(name: 'Bob', ageYears: 12, owner: null); $this->assertNull($model->owner); $this->assertNull($model->friends); } @@ -84,11 +76,7 @@ public function testNullAccess(): void #[Test] public function testArrayGetAndSet(): void { - $model = new Model( - name: 'Bob', - ageYears: 12, - owner: null, - ); + $model = new Dog(name: 'Bob', ageYears: 12, owner: null); $model->friends ??= []; $this->assertEquals([], $model->friends); $model->friends[] = 'Alice'; @@ -98,16 +86,8 @@ public function testArrayGetAndSet(): void #[Test] public function testDiscernsBetweenNullAndUnset(): void { - $modelUnsetFriends = new Model( - name: 'Bob', - ageYears: 12, - owner: null, - ); - $modelNullFriends = new Model( - name: 'bob', - ageYears: 12, - owner: null, - ); + $modelUnsetFriends = new Dog(name: 'Bob', ageYears: 12, owner: null); + $modelNullFriends = new Dog(name: 'bob', ageYears: 12, owner: null); $modelNullFriends->friends = null; $this->assertEquals(12, $modelUnsetFriends->ageYears); @@ -126,11 +106,7 @@ public function testDiscernsBetweenNullAndUnset(): void #[Test] public function testIssetOnOmittedProperties(): void { - $model = new Model( - name: 'Bob', - ageYears: 12, - owner: null, - ); + $model = new Dog(name: 'Bob', ageYears: 12, owner: null); $this->assertFalse(isset($model->owner)); $this->assertFalse(isset($model->friends)); } @@ -138,12 +114,7 @@ public function testIssetOnOmittedProperties(): void #[Test] public function testSerializeBasicModel(): void { - $model = new Model( - name: 'Bob', - ageYears: 12, - owner: 'Eve', - friends: ['Alice', 'Charlie'], - ); + $model = new Dog(name: 'Bob', ageYears: 12, owner: 'Eve', friends: ['Alice', 'Charlie']); $this->assertEquals( '{"name":"Bob","age_years":12,"friends":["Alice","Charlie"],"owner":"Eve"}', json_encode($model) @@ -153,11 +124,7 @@ public function testSerializeBasicModel(): void #[Test] public function testSerializeModelWithOmittedProperties(): void { - $model = new Model( - name: 'Bob', - ageYears: 12, - owner: null, - ); + $model = new Dog(name: 'Bob', ageYears: 12, owner: null); $this->assertEquals( '{"name":"Bob","age_years":12,"owner":null}', json_encode($model) @@ -167,11 +134,7 @@ public function testSerializeModelWithOmittedProperties(): void #[Test] public function testSerializeModelWithExplicitNull(): void { - $model = new Model( - name: 'Bob', - ageYears: 12, - owner: null, - ); + $model = new Dog(name: 'Bob', ageYears: 12, owner: null); $model->friends = null; $this->assertEquals( '{"name":"Bob","age_years":12,"friends":null,"owner":null}', diff --git a/tests/Core/UtilTest.php b/tests/Core/UtilTest.php index d4cd0ac..63fd6fb 100644 --- a/tests/Core/UtilTest.php +++ b/tests/Core/UtilTest.php @@ -2,6 +2,7 @@ namespace Tests\Core; +use Http\Discovery\Psr17FactoryDiscovery; use PHPUnit\Framework\Attributes\CoversNothing; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; @@ -29,11 +30,61 @@ public function testMapRecursive(): void ['b' => [null, null], 'c' => ['e' => 0], 'f' => []], static fn ($vs) => is_array($vs) && !array_is_list($vs) ? array_filter($vs, callback: static fn ($v) => !is_null($v)) : $vs, ], + [ + ['a' => null, 'b' => 2, 'c' => true, 'd' => [1, 2]], + ['a' => null, 'b' => '2', 'c' => true, 'd' => ['1', '2']], + static fn ($v) => is_bool($v) || is_numeric($v) ? Util::strVal($v) : $v, + ], + ]; + + foreach ($cases as [$input, $expected, $xform]) { + $actual = Util::mapRecursive($xform, value: $input); + $this->assertEquals($expected, $actual); + } + } + + #[Test] + public function testJoinUri(): void + { + $factory = Psr17FactoryDiscovery::findUriFactory(); + $base = $factory->createUri('http://localhost'); + $cases = [ + [ + '', + [], + 'http://localhost', + ], + [ + 'dog', + [], + 'http://localhost/dog', + ], + [ + '', + ['dog' => 'dog'], + 'http://localhost?dog=dog', + ], + [ + '', + ['dog' => ['dog']], + 'http://localhost?dog[0]=dog', + ], + [ + '', + ['dog' => [true, false]], + 'http://localhost?dog[0]=true&dog[1]=false', + ], + [ + '', + ['dog' => ['dog' => ['dog']]], + 'http://localhost?dog[dog][0]=dog', + ], ]; - foreach ($cases as [$input, $output, $xform]) { - $mapped = Util::mapRecursive($xform, value: $input); - $this->assertEquals($mapped, $output); + foreach ($cases as [$path, $query, $output]) { + $expected = $factory->createUri($output); + $actual = Util::joinUri($base, path: $path, query: $query); + $this->assertEquals($expected, $actual); } } } diff --git a/tests/Services/SessionsTest.php b/tests/Services/SessionsTest.php index 684dd57..7a86423 100644 --- a/tests/Services/SessionsTest.php +++ b/tests/Services/SessionsTest.php @@ -8,8 +8,10 @@ use Stagehand\Client; use Stagehand\Sessions\SessionActResponse; use Stagehand\Sessions\SessionEndResponse; -use Stagehand\Sessions\SessionExecuteAgentResponse; +use Stagehand\Sessions\SessionExecuteResponse; +use Stagehand\Sessions\SessionExtractResponse; use Stagehand\Sessions\SessionNavigateResponse; +use Stagehand\Sessions\SessionObserveResponse; use Stagehand\Sessions\SessionStartResponse; use Tests\UnsupportedMockTests; @@ -44,8 +46,8 @@ public function testAct(): void } $result = $this->client->sessions->act( - '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', - input: 'click the sign in button' + 'c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123', + input: 'Click the login button' ); // @phpstan-ignore-next-line method.alreadyNarrowedType @@ -60,19 +62,17 @@ public function testActWithOptionalParams(): void } $result = $this->client->sessions->act( - '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', - input: 'click the sign in button', + 'c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123', + input: 'Click the login button', frameID: 'frameId', options: [ - 'model' => [ - 'apiKey' => 'apiKey', - 'baseURL' => 'https://example.com', - 'model' => 'model', - 'provider' => 'openai', - ], - 'timeout' => 0, - 'variables' => ['foo' => 'string'], + 'model' => 'openai/gpt-5-nano', + 'timeout' => 30000, + 'variables' => ['username' => 'john_doe'], ], + xLanguage: 'typescript', + xSDKVersion: '3.0.6', + xSentAt: new \DateTimeImmutable('2025-01-15T10:30:00Z'), xStreamResponse: 'true', ); @@ -88,7 +88,7 @@ public function testEnd(): void } $result = $this->client->sessions->end( - '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e' + 'c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123' ); // @phpstan-ignore-next-line method.alreadyNarrowedType @@ -96,48 +96,53 @@ public function testEnd(): void } #[Test] - public function testExecuteAgent(): void + public function testExecute(): void { if (UnsupportedMockTests::$skip) { $this->markTestSkipped('Prism tests are disabled'); } - $result = $this->client->sessions->executeAgent( - '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + $result = $this->client->sessions->execute( + 'c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123', agentConfig: [], - executeOptions: ['instruction' => 'Find and click the first product'], + executeOptions: [ + 'instruction' => 'Log in with username \'demo\' and password \'test123\', then navigate to settings', + ], ); // @phpstan-ignore-next-line method.alreadyNarrowedType - $this->assertInstanceOf(SessionExecuteAgentResponse::class, $result); + $this->assertInstanceOf(SessionExecuteResponse::class, $result); } #[Test] - public function testExecuteAgentWithOptionalParams(): void + public function testExecuteWithOptionalParams(): void { if (UnsupportedMockTests::$skip) { $this->markTestSkipped('Prism tests are disabled'); } - $result = $this->client->sessions->executeAgent( - '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + $result = $this->client->sessions->execute( + 'c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123', agentConfig: [ 'cua' => true, - 'model' => 'openai/gpt-4o', + 'model' => 'openai/gpt-5-nano', 'provider' => 'openai', 'systemPrompt' => 'systemPrompt', ], executeOptions: [ - 'instruction' => 'Find and click the first product', + 'instruction' => 'Log in with username \'demo\' and password \'test123\', then navigate to settings', 'highlightCursor' => true, - 'maxSteps' => 10, + 'maxSteps' => 20, ], frameID: 'frameId', + xLanguage: 'typescript', + xSDKVersion: '3.0.6', + xSentAt: new \DateTimeImmutable('2025-01-15T10:30:00Z'), xStreamResponse: 'true', ); // @phpstan-ignore-next-line method.alreadyNarrowedType - $this->assertInstanceOf(SessionExecuteAgentResponse::class, $result); + $this->assertInstanceOf(SessionExecuteResponse::class, $result); } #[Test] @@ -148,11 +153,11 @@ public function testExtract(): void } $result = $this->client->sessions->extract( - '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e' + 'c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123' ); // @phpstan-ignore-next-line method.alreadyNarrowedType - $this->assertNotNull($result); + $this->assertInstanceOf(SessionExtractResponse::class, $result); } #[Test] @@ -163,7 +168,7 @@ public function testNavigate(): void } $result = $this->client->sessions->navigate( - '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + 'c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123', url: 'https://example.com' ); @@ -179,10 +184,16 @@ public function testNavigateWithOptionalParams(): void } $result = $this->client->sessions->navigate( - '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + 'c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123', url: 'https://example.com', frameID: 'frameId', - options: ['waitUntil' => 'load'], + options: [ + 'referer' => 'referer', 'timeout' => 30000, 'waitUntil' => 'networkidle', + ], + streamResponse: true, + xLanguage: 'typescript', + xSDKVersion: '3.0.6', + xSentAt: new \DateTimeImmutable('2025-01-15T10:30:00Z'), xStreamResponse: 'true', ); @@ -198,11 +209,11 @@ public function testObserve(): void } $result = $this->client->sessions->observe( - '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e' + 'c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123' ); // @phpstan-ignore-next-line method.alreadyNarrowedType - $this->assertIsList($result); + $this->assertInstanceOf(SessionObserveResponse::class, $result); } #[Test] @@ -212,10 +223,7 @@ public function testStart(): void $this->markTestSkipped('Prism tests are disabled'); } - $result = $this->client->sessions->start( - browserbaseAPIKey: 'BROWSERBASE_API_KEY', - browserbaseProjectID: 'BROWSERBASE_PROJECT_ID', - ); + $result = $this->client->sessions->start(modelName: 'gpt-4o'); // @phpstan-ignore-next-line method.alreadyNarrowedType $this->assertInstanceOf(SessionStartResponse::class, $result); @@ -229,13 +237,80 @@ public function testStartWithOptionalParams(): void } $result = $this->client->sessions->start( - browserbaseAPIKey: 'BROWSERBASE_API_KEY', - browserbaseProjectID: 'BROWSERBASE_PROJECT_ID', - domSettleTimeout: 0, - model: 'openai/gpt-4o', + modelName: 'gpt-4o', + actTimeoutMs: 0, + browser: [ + 'cdpURL' => 'ws://localhost:9222', + 'launchOptions' => [ + 'acceptDownloads' => true, + 'args' => ['string'], + 'cdpURL' => 'cdpUrl', + 'chromiumSandbox' => true, + 'connectTimeoutMs' => 0, + 'deviceScaleFactor' => 0, + 'devtools' => true, + 'downloadsPath' => 'downloadsPath', + 'executablePath' => 'executablePath', + 'hasTouch' => true, + 'headless' => true, + 'ignoreDefaultArgs' => true, + 'ignoreHTTPSErrors' => true, + 'locale' => 'locale', + 'preserveUserDataDir' => true, + 'proxy' => [ + 'server' => 'server', + 'bypass' => 'bypass', + 'password' => 'password', + 'username' => 'username', + ], + 'userDataDir' => 'userDataDir', + 'viewport' => ['height' => 0, 'width' => 0], + ], + 'type' => 'local', + ], + browserbaseSessionCreateParams: [ + 'browserSettings' => [ + 'advancedStealth' => true, + 'blockAds' => true, + 'context' => ['id' => 'id', 'persist' => true], + 'extensionID' => 'extensionId', + 'fingerprint' => [ + 'browsers' => ['chrome'], + 'devices' => ['desktop'], + 'httpVersion' => '1', + 'locales' => ['string'], + 'operatingSystems' => ['android'], + 'screen' => [ + 'maxHeight' => 0, + 'maxWidth' => 0, + 'minHeight' => 0, + 'minWidth' => 0, + ], + ], + 'logSession' => true, + 'recordSession' => true, + 'solveCaptchas' => true, + 'viewport' => ['height' => 0, 'width' => 0], + ], + 'extensionID' => 'extensionId', + 'keepAlive' => true, + 'projectID' => 'projectId', + 'proxies' => true, + 'region' => 'us-west-2', + 'timeout' => 0, + 'userMetadata' => ['foo' => 'bar'], + ], + browserbaseSessionID: 'browserbaseSessionID', + domSettleTimeoutMs: 5000, + experimental: true, selfHeal: true, systemPrompt: 'systemPrompt', verbose: 1, + waitForCaptchaSolves: true, + xLanguage: 'typescript', + xSDKVersion: '3.0.6', + xSentAt: new \DateTimeImmutable('2025-01-15T10:30:00Z'), + xStreamResponse: 'true', ); // @phpstan-ignore-next-line method.alreadyNarrowedType