diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0273714..5721b93 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,12 +1,14 @@ name: CI on: push: - branches-ignore: - - 'generated' - - 'codegen/**' - - 'integrated/**' - - 'stl-preview-head/**' - - 'stl-preview-base/**' + branches: + - '**' + - '!integrated/**' + - '!stl-preview-head/**' + - '!stl-preview-base/**' + - '!generated' + - '!codegen/**' + - 'codegen/stl/**' pull_request: branches-ignore: - 'stl-preview-head/**' diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 2c220f1..df3292b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "3.16.0" + ".": "3.18.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index c61740e..129faad 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-a4e672f457dd99336f4b2a113fd7c7c6c9db0941b38d57cff6e3641549a6c4ed.yml -openapi_spec_hash: eae9c8561e420db8e4d238c1e59617fb -config_hash: 2a565ad6662259a2e90fa5f1f5095525 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-bc309fd00fe0507f4cbe3bc77fa27d0fbffeaa6e71998778da34de42608a67e8.yml +openapi_spec_hash: 1db1af5c1b068bba1d652102f4454668 +config_hash: d6c6f623d03971bdba921650e5eb7e5f diff --git a/CHANGELOG.md b/CHANGELOG.md index d3679b8..e2302ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Changelog +## 3.18.0 (2026-03-24) + +Full Changelog: [v3.16.0...v3.18.0](https://github.com/browserbase/stagehand-php/compare/v3.16.0...v3.18.0) + +### Features + +* [fix]: add `useSearch` & `toolTimeout` to stainless types ([b192d02](https://github.com/browserbase/stagehand-php/commit/b192d027f259557655a980b8b013033726c70038)) +* [STG-1607] Yield finished SSE event instead of silently dropping it ([bcbd0d1](https://github.com/browserbase/stagehand-php/commit/bcbd0d1b1a07c26b372e01dee544ef0b4d2bb50d)) +* Add explicit SSE event names for local v3 streaming ([a9777b9](https://github.com/browserbase/stagehand-php/commit/a9777b9389adbaf2c2f9dfdc34ce41f3004b9085)) +* Add missing cdpHeaders field to v3 server openapi spec ([07f2358](https://github.com/browserbase/stagehand-php/commit/07f23586505243db4dc86414a3d5c381b26fd22d)) +* Include LLM headers in ModelConfig ([879642a](https://github.com/browserbase/stagehand-php/commit/879642a0677170a48904a52f339c0403f2b16203)) +* Revert broken finished SSE yield config ([7910a59](https://github.com/browserbase/stagehand-php/commit/7910a59b8374edd635c968ecd57548b1c6826f20)) +* variables for observe ([9187d2e](https://github.com/browserbase/stagehand-php/commit/9187d2ec460a547a9463a395175482cd1bd72c18)) + + +### Chores + +* **internal:** codegen related update ([20b3106](https://github.com/browserbase/stagehand-php/commit/20b3106f3919092115a690e43bb4641dccd91aad)) +* **internal:** tweak CI branches ([5c0e28e](https://github.com/browserbase/stagehand-php/commit/5c0e28e04a565c53dbd42f01fd920ba65ffea9e6)) +* **internal:** upgrade phpunit ([b09b7ff](https://github.com/browserbase/stagehand-php/commit/b09b7ffb3644b16039aa400ed430deeb993e18ce)) + ## 3.16.0 (2026-02-25) Full Changelog: [v3.15.0...v3.16.0](https://github.com/browserbase/stagehand-php/compare/v3.15.0...v3.16.0) diff --git a/README.md b/README.md index 93e8674..417917d 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ The REST API documentation can be found on [docs.stagehand.dev](https://docs.sta ``` -composer require "browserbase/stagehand 3.16.0" +composer require "browserbase/stagehand 3.18.0" ``` diff --git a/composer.lock b/composer.lock index 3f6c209..7a5e63d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5fc63f7c84d94b42416689723c547f69", + "content-hash": "ffa287ea8babf60e021f37e62c6c207a", "packages": [ { "name": "php-http/discovery", @@ -194,16 +194,16 @@ "packages-dev": [ { "name": "brianium/paratest", - "version": "v7.8.4", + "version": "v7.8.5", "source": { "type": "git", "url": "https://github.com/paratestphp/paratest.git", - "reference": "130a9bf0e269ee5f5b320108f794ad03e275cad4" + "reference": "9b324c8fc319cf9728b581c7a90e1c8f6361c5e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paratestphp/paratest/zipball/130a9bf0e269ee5f5b320108f794ad03e275cad4", - "reference": "130a9bf0e269ee5f5b320108f794ad03e275cad4", + "url": "https://api.github.com/repos/paratestphp/paratest/zipball/9b324c8fc319cf9728b581c7a90e1c8f6361c5e5", + "reference": "9b324c8fc319cf9728b581c7a90e1c8f6361c5e5", "shasum": "" }, "require": { @@ -211,27 +211,27 @@ "ext-pcre": "*", "ext-reflection": "*", "ext-simplexml": "*", - "fidry/cpu-core-counter": "^1.2.0", + "fidry/cpu-core-counter": "^1.3.0", "jean85/pretty-package-versions": "^2.1.1", - "php": "~8.2.0 || ~8.3.0 || ~8.4.0", - "phpunit/php-code-coverage": "^11.0.10", + "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "phpunit/php-code-coverage": "^11.0.12", "phpunit/php-file-iterator": "^5.1.0", "phpunit/php-timer": "^7.0.1", - "phpunit/phpunit": "^11.5.24", + "phpunit/phpunit": "^11.5.46", "sebastian/environment": "^7.2.1", - "symfony/console": "^6.4.22 || ^7.3.0", - "symfony/process": "^6.4.20 || ^7.3.0" + "symfony/console": "^6.4.22 || ^7.3.4 || ^8.0.3", + "symfony/process": "^6.4.20 || ^7.3.4 || ^8.0.3" }, "require-dev": { "doctrine/coding-standard": "^12.0.0", "ext-pcov": "*", "ext-posix": "*", - "phpstan/phpstan": "^2.1.17", + "phpstan/phpstan": "^2.1.33", "phpstan/phpstan-deprecation-rules": "^2.0.3", - "phpstan/phpstan-phpunit": "^2.0.6", - "phpstan/phpstan-strict-rules": "^2.0.4", - "squizlabs/php_codesniffer": "^3.13.2", - "symfony/filesystem": "^6.4.13 || ^7.3.0" + "phpstan/phpstan-phpunit": "^2.0.11", + "phpstan/phpstan-strict-rules": "^2.0.7", + "squizlabs/php_codesniffer": "^3.13.5", + "symfony/filesystem": "^6.4.13 || ^7.3.2 || ^8.0.1" }, "bin": [ "bin/paratest", @@ -271,7 +271,7 @@ ], "support": { "issues": "https://github.com/paratestphp/paratest/issues", - "source": "https://github.com/paratestphp/paratest/tree/v7.8.4" + "source": "https://github.com/paratestphp/paratest/tree/v7.8.5" }, "funding": [ { @@ -283,7 +283,7 @@ "type": "paypal" } ], - "time": "2025-06-23T06:07:21+00:00" + "time": "2026-01-08T08:02:38+00:00" }, { "name": "clue/ndjson-react", @@ -1412,38 +1412,38 @@ }, { "name": "pestphp/pest", - "version": "v3.8.4", + "version": "v3.8.5", "source": { "type": "git", "url": "https://github.com/pestphp/pest.git", - "reference": "72cf695554420e21858cda831d5db193db102574" + "reference": "7796630eafcfd1c02660cecdde3bc6984fbf01f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest/zipball/72cf695554420e21858cda831d5db193db102574", - "reference": "72cf695554420e21858cda831d5db193db102574", + "url": "https://api.github.com/repos/pestphp/pest/zipball/7796630eafcfd1c02660cecdde3bc6984fbf01f4", + "reference": "7796630eafcfd1c02660cecdde3bc6984fbf01f4", "shasum": "" }, "require": { - "brianium/paratest": "^7.8.4", - "nunomaduro/collision": "^8.8.2", - "nunomaduro/termwind": "^2.3.1", + "brianium/paratest": "^7.8.5", + "nunomaduro/collision": "^8.8.3", + "nunomaduro/termwind": "^2.3.3", "pestphp/pest-plugin": "^3.0.0", "pestphp/pest-plugin-arch": "^3.1.1", "pestphp/pest-plugin-mutate": "^3.0.5", "php": "^8.2.0", - "phpunit/phpunit": "^11.5.33" + "phpunit/phpunit": "^11.5.50" }, "conflict": { "filp/whoops": "<2.16.0", - "phpunit/phpunit": ">11.5.33", + "phpunit/phpunit": ">11.5.50", "sebastian/exporter": "<6.0.0", "webmozart/assert": "<1.11.0" }, "require-dev": { "pestphp/pest-dev-tools": "^3.4.0", "pestphp/pest-plugin-type-coverage": "^3.6.1", - "symfony/process": "^7.3.0" + "symfony/process": "^7.4.4" }, "bin": [ "bin/pest" @@ -1508,7 +1508,7 @@ ], "support": { "issues": "https://github.com/pestphp/pest/issues", - "source": "https://github.com/pestphp/pest/tree/v3.8.4" + "source": "https://github.com/pestphp/pest/tree/v3.8.5" }, "funding": [ { @@ -1520,7 +1520,7 @@ "type": "github" } ], - "time": "2025-08-20T19:12:42+00:00" + "time": "2026-01-28T01:33:45+00:00" }, { "name": "pestphp/pest-plugin", @@ -2627,28 +2627,28 @@ }, { "name": "phpunit/php-file-iterator", - "version": "5.1.0", + "version": "5.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6" + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/118cfaaa8bc5aef3287bf315b6060b1174754af6", - "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/2f3a64888c814fc235386b7387dd5b5ed92ad903", + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903", "shasum": "" }, "require": { "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^11.3" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "5.1-dev" } }, "autoload": { @@ -2676,15 +2676,27 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.0" + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.1" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-file-iterator", + "type": "tidelift" } ], - "time": "2024-08-27T05:02:59+00:00" + "time": "2026-02-02T13:52:54+00:00" }, { "name": "phpunit/php-invoker", @@ -2872,16 +2884,16 @@ }, { "name": "phpunit/phpunit", - "version": "11.5.33", + "version": "11.5.50", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "5965e9ff57546cb9137c0ff6aa78cb7442b05cf6" + "reference": "fdfc727f0fcacfeb8fcb30c7e5da173125b58be3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/5965e9ff57546cb9137c0ff6aa78cb7442b05cf6", - "reference": "5965e9ff57546cb9137c0ff6aa78cb7442b05cf6", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fdfc727f0fcacfeb8fcb30c7e5da173125b58be3", + "reference": "fdfc727f0fcacfeb8fcb30c7e5da173125b58be3", "shasum": "" }, "require": { @@ -2895,17 +2907,17 @@ "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=8.2", - "phpunit/php-code-coverage": "^11.0.10", + "phpunit/php-code-coverage": "^11.0.12", "phpunit/php-file-iterator": "^5.1.0", "phpunit/php-invoker": "^5.0.1", "phpunit/php-text-template": "^4.0.1", "phpunit/php-timer": "^7.0.1", "sebastian/cli-parser": "^3.0.2", "sebastian/code-unit": "^3.0.3", - "sebastian/comparator": "^6.3.2", + "sebastian/comparator": "^6.3.3", "sebastian/diff": "^6.0.2", "sebastian/environment": "^7.2.1", - "sebastian/exporter": "^6.3.0", + "sebastian/exporter": "^6.3.2", "sebastian/global-state": "^7.0.2", "sebastian/object-enumerator": "^6.0.1", "sebastian/type": "^5.1.3", @@ -2953,7 +2965,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.33" + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.50" }, "funding": [ { @@ -2977,7 +2989,7 @@ "type": "tidelift" } ], - "time": "2025-08-16T05:19:02+00:00" + "time": "2026-01-27T05:59:18+00:00" }, { "name": "psr/container", @@ -3936,16 +3948,16 @@ }, { "name": "sebastian/comparator", - "version": "6.3.2", + "version": "6.3.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "85c77556683e6eee4323e4c5468641ca0237e2e8" + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/85c77556683e6eee4323e4c5468641ca0237e2e8", - "reference": "85c77556683e6eee4323e4c5468641ca0237e2e8", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", "shasum": "" }, "require": { @@ -4004,7 +4016,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.2" + "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.3" }, "funding": [ { @@ -4024,7 +4036,7 @@ "type": "tidelift" } ], - "time": "2025-08-10T08:07:46+00:00" + "time": "2026-01-24T09:26:40+00:00" }, { "name": "sebastian/complexity", @@ -6668,5 +6680,5 @@ "platform-overrides": { "php": "8.3" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } diff --git a/src/Core/Conversion.php b/src/Core/Conversion.php index b682229..1942914 100644 --- a/src/Core/Conversion.php +++ b/src/Core/Conversion.php @@ -170,6 +170,37 @@ private static function tryConvert(Converter|ConverterSource|string $target, mix return $value; + case 'DateTimeInterface': + case 'DateTimeImmutable': + if (is_string($value)) { + try { + ++$state->maybe; + + return new \DateTimeImmutable($value); + } catch (\Exception) { + --$state->maybe; + } + } + + ++$state->no; + + return $value; + + case 'DateTime': + if (is_string($value)) { + try { + ++$state->maybe; + + return new \DateTime($value); + } catch (\Exception) { + --$state->maybe; + } + } + + ++$state->no; + + return $value; + default: ++$state->no; diff --git a/src/SSEStream.php b/src/SSEStream.php index db4b673..a5229af 100644 --- a/src/SSEStream.php +++ b/src/SSEStream.php @@ -29,33 +29,9 @@ private function parsedGenerator(): \Generator 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: '{"data":{"status":"finished"')) { - $done = true; - - continue; - } - - if (str_starts_with($data, needle: 'error')) { + case 'error': if ($data = $row['data'] ?? '') { $json = Util::decodeJson($data); $message = Util::prettyEncodeJson($json); @@ -69,8 +45,19 @@ private function parsedGenerator(): \Generator throw $exn; } - continue; - } + break; + + case 'starting': + case 'connected': + case 'running': + case 'finished': + if ($data = $row['data'] ?? '') { + $decoded = Util::decodeJson($data); + + yield Conversion::coerce($this->convert, value: $decoded); + } + + break; } } } diff --git a/src/Sessions/ModelConfig.php b/src/Sessions/ModelConfig.php index 1a7a6a0..c03b239 100644 --- a/src/Sessions/ModelConfig.php +++ b/src/Sessions/ModelConfig.php @@ -15,6 +15,7 @@ * modelName: string, * apiKey?: string|null, * baseURL?: string|null, + * headers?: array|null, * provider?: null|Provider|value-of, * } */ @@ -41,6 +42,14 @@ final class ModelConfig implements BaseModel #[Optional] public ?string $baseURL; + /** + * Custom headers sent with every request to the model provider. + * + * @var array|null $headers + */ + #[Optional(map: 'string')] + public ?array $headers; + /** * AI provider for the model (or provide a baseURL endpoint instead). * @@ -73,12 +82,14 @@ public function __construct() * * You must use named parameters to construct any parameters with a default value. * + * @param array|null $headers * @param Provider|value-of|null $provider */ public static function with( string $modelName, ?string $apiKey = null, ?string $baseURL = null, + ?array $headers = null, Provider|string|null $provider = null, ): self { $self = new self; @@ -87,6 +98,7 @@ public static function with( null !== $apiKey && $self['apiKey'] = $apiKey; null !== $baseURL && $self['baseURL'] = $baseURL; + null !== $headers && $self['headers'] = $headers; null !== $provider && $self['provider'] = $provider; return $self; @@ -125,6 +137,19 @@ public function withBaseURL(string $baseURL): self return $self; } + /** + * Custom headers sent with every request to the model provider. + * + * @param array $headers + */ + public function withHeaders(array $headers): self + { + $self = clone $this; + $self['headers'] = $headers; + + return $self; + } + /** * AI provider for the model (or provide a baseURL endpoint instead). * diff --git a/src/Sessions/SessionActParams/Options.php b/src/Sessions/SessionActParams/Options.php index 587c413..a127767 100644 --- a/src/Sessions/SessionActParams/Options.php +++ b/src/Sessions/SessionActParams/Options.php @@ -8,15 +8,18 @@ use Stagehand\Core\Concerns\SdkModel; use Stagehand\Core\Contracts\BaseModel; use Stagehand\Sessions\ModelConfig; +use Stagehand\Sessions\SessionActParams\Options\Variable; /** * @phpstan-import-type ModelVariants from \Stagehand\Sessions\SessionActParams\Options\Model + * @phpstan-import-type VariableVariants from \Stagehand\Sessions\SessionActParams\Options\Variable * @phpstan-import-type ModelShape from \Stagehand\Sessions\SessionActParams\Options\Model + * @phpstan-import-type VariableShape from \Stagehand\Sessions\SessionActParams\Options\Variable * * @phpstan-type OptionsShape = array{ * model?: ModelShape|null, * timeout?: float|null, - * variables?: array|null, + * variables?: array|null, * } */ final class Options implements BaseModel @@ -39,11 +42,11 @@ final class Options implements BaseModel public ?float $timeout; /** - * Variables to substitute in the action instruction. + * Variables to substitute in the action instruction. Accepts flat primitives or { value, description? } objects. * - * @var array|null $variables + * @var array|null $variables */ - #[Optional(map: 'string')] + #[Optional(map: Variable::class)] public ?array $variables; public function __construct() @@ -57,7 +60,7 @@ public function __construct() * You must use named parameters to construct any parameters with a default value. * * @param ModelShape|null $model - * @param array|null $variables + * @param array|null $variables */ public static function with( string|ModelConfig|array|null $model = null, @@ -98,9 +101,9 @@ public function withTimeout(float $timeout): self } /** - * Variables to substitute in the action instruction. + * Variables to substitute in the action instruction. Accepts flat primitives or { value, description? } objects. * - * @param array $variables + * @param array $variables */ public function withVariables(array $variables): self { diff --git a/src/Sessions/SessionActParams/Options/Variable.php b/src/Sessions/SessionActParams/Options/Variable.php new file mode 100644 index 0000000..2bc0140 --- /dev/null +++ b/src/Sessions/SessionActParams/Options/Variable.php @@ -0,0 +1,29 @@ +|array + */ + public static function variants(): array + { + return ['string', 'float', 'bool', UnionMember3::class]; + } +} diff --git a/src/Sessions/SessionActParams/Options/Variable/UnionMember3.php b/src/Sessions/SessionActParams/Options/Variable/UnionMember3.php new file mode 100644 index 0000000..ba57a6a --- /dev/null +++ b/src/Sessions/SessionActParams/Options/Variable/UnionMember3.php @@ -0,0 +1,89 @@ + */ + use SdkModel; + + /** @var ValueVariants $value */ + #[Required] + public string|float|bool $value; + + #[Optional] + public ?string $description; + + /** + * `new UnionMember3()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UnionMember3::with(value: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UnionMember3)->withValue(...) + * ``` + */ + 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 ValueShape $value + */ + public static function with( + string|float|bool $value, + ?string $description = null + ): self { + $self = new self; + + $self['value'] = $value; + + null !== $description && $self['description'] = $description; + + return $self; + } + + /** + * @param ValueShape $value + */ + public function withValue(string|float|bool $value): self + { + $self = clone $this; + $self['value'] = $value; + + return $self; + } + + public function withDescription(string $description): self + { + $self = clone $this; + $self['description'] = $description; + + return $self; + } +} diff --git a/src/Sessions/SessionActParams/Options/Variable/UnionMember3/Value.php b/src/Sessions/SessionActParams/Options/Variable/UnionMember3/Value.php new file mode 100644 index 0000000..b671515 --- /dev/null +++ b/src/Sessions/SessionActParams/Options/Variable/UnionMember3/Value.php @@ -0,0 +1,26 @@ +|array + */ + public static function variants(): array + { + return ['string', 'float', 'bool']; + } +} diff --git a/src/Sessions/SessionExecuteParams/ExecuteOptions.php b/src/Sessions/SessionExecuteParams/ExecuteOptions.php index c5e676f..be26904 100644 --- a/src/Sessions/SessionExecuteParams/ExecuteOptions.php +++ b/src/Sessions/SessionExecuteParams/ExecuteOptions.php @@ -11,7 +11,11 @@ /** * @phpstan-type ExecuteOptionsShape = array{ - * instruction: string, highlightCursor?: bool|null, maxSteps?: float|null + * instruction: string, + * highlightCursor?: bool|null, + * maxSteps?: float|null, + * toolTimeout?: float|null, + * useSearch?: bool|null, * } */ final class ExecuteOptions implements BaseModel @@ -37,6 +41,18 @@ final class ExecuteOptions implements BaseModel #[Optional] public ?float $maxSteps; + /** + * Timeout in milliseconds for each agent tool call. + */ + #[Optional] + public ?float $toolTimeout; + + /** + * Whether to enable the web search tool powered by Browserbase Search API. + */ + #[Optional] + public ?bool $useSearch; + /** * `new ExecuteOptions()` is missing required properties by the API. * @@ -64,7 +80,9 @@ public function __construct() public static function with( string $instruction, ?bool $highlightCursor = null, - ?float $maxSteps = null + ?float $maxSteps = null, + ?float $toolTimeout = null, + ?bool $useSearch = null, ): self { $self = new self; @@ -72,6 +90,8 @@ public static function with( null !== $highlightCursor && $self['highlightCursor'] = $highlightCursor; null !== $maxSteps && $self['maxSteps'] = $maxSteps; + null !== $toolTimeout && $self['toolTimeout'] = $toolTimeout; + null !== $useSearch && $self['useSearch'] = $useSearch; return $self; } @@ -108,4 +128,26 @@ public function withMaxSteps(float $maxSteps): self return $self; } + + /** + * Timeout in milliseconds for each agent tool call. + */ + public function withToolTimeout(float $toolTimeout): self + { + $self = clone $this; + $self['toolTimeout'] = $toolTimeout; + + return $self; + } + + /** + * Whether to enable the web search tool powered by Browserbase Search API. + */ + public function withUseSearch(bool $useSearch): self + { + $self = clone $this; + $self['useSearch'] = $useSearch; + + return $self; + } } diff --git a/src/Sessions/SessionObserveParams/Options.php b/src/Sessions/SessionObserveParams/Options.php index cf545e9..02bc11c 100644 --- a/src/Sessions/SessionObserveParams/Options.php +++ b/src/Sessions/SessionObserveParams/Options.php @@ -8,13 +8,19 @@ use Stagehand\Core\Concerns\SdkModel; use Stagehand\Core\Contracts\BaseModel; use Stagehand\Sessions\ModelConfig; +use Stagehand\Sessions\SessionObserveParams\Options\Variable; /** * @phpstan-import-type ModelVariants from \Stagehand\Sessions\SessionObserveParams\Options\Model + * @phpstan-import-type VariableVariants from \Stagehand\Sessions\SessionObserveParams\Options\Variable * @phpstan-import-type ModelShape from \Stagehand\Sessions\SessionObserveParams\Options\Model + * @phpstan-import-type VariableShape from \Stagehand\Sessions\SessionObserveParams\Options\Variable * * @phpstan-type OptionsShape = array{ - * model?: ModelShape|null, selector?: string|null, timeout?: float|null + * model?: ModelShape|null, + * selector?: string|null, + * timeout?: float|null, + * variables?: array|null, * } */ final class Options implements BaseModel @@ -42,6 +48,14 @@ final class Options implements BaseModel #[Optional] public ?float $timeout; + /** + * Variables whose names are exposed to the model so observe() returns %variableName% placeholders in suggested action arguments instead of literal values. Accepts flat primitives or { value, description? } objects. + * + * @var array|null $variables + */ + #[Optional(map: Variable::class)] + public ?array $variables; + public function __construct() { $this->initialize(); @@ -53,17 +67,20 @@ public function __construct() * You must use named parameters to construct any parameters with a default value. * * @param ModelShape|null $model + * @param array|null $variables */ public static function with( string|ModelConfig|array|null $model = null, ?string $selector = null, ?float $timeout = null, + ?array $variables = null, ): self { $self = new self; null !== $model && $self['model'] = $model; null !== $selector && $self['selector'] = $selector; null !== $timeout && $self['timeout'] = $timeout; + null !== $variables && $self['variables'] = $variables; return $self; } @@ -102,4 +119,17 @@ public function withTimeout(float $timeout): self return $self; } + + /** + * Variables whose names are exposed to the model so observe() returns %variableName% placeholders in suggested action arguments instead of literal values. Accepts flat primitives or { value, description? } objects. + * + * @param array $variables + */ + public function withVariables(array $variables): self + { + $self = clone $this; + $self['variables'] = $variables; + + return $self; + } } diff --git a/src/Sessions/SessionObserveParams/Options/Variable.php b/src/Sessions/SessionObserveParams/Options/Variable.php new file mode 100644 index 0000000..a296e7d --- /dev/null +++ b/src/Sessions/SessionObserveParams/Options/Variable.php @@ -0,0 +1,29 @@ +|array + */ + public static function variants(): array + { + return ['string', 'float', 'bool', UnionMember3::class]; + } +} diff --git a/src/Sessions/SessionObserveParams/Options/Variable/UnionMember3.php b/src/Sessions/SessionObserveParams/Options/Variable/UnionMember3.php new file mode 100644 index 0000000..d69bcad --- /dev/null +++ b/src/Sessions/SessionObserveParams/Options/Variable/UnionMember3.php @@ -0,0 +1,89 @@ + */ + use SdkModel; + + /** @var ValueVariants $value */ + #[Required] + public string|float|bool $value; + + #[Optional] + public ?string $description; + + /** + * `new UnionMember3()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UnionMember3::with(value: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UnionMember3)->withValue(...) + * ``` + */ + 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 ValueShape $value + */ + public static function with( + string|float|bool $value, + ?string $description = null + ): self { + $self = new self; + + $self['value'] = $value; + + null !== $description && $self['description'] = $description; + + return $self; + } + + /** + * @param ValueShape $value + */ + public function withValue(string|float|bool $value): self + { + $self = clone $this; + $self['value'] = $value; + + return $self; + } + + public function withDescription(string $description): self + { + $self = clone $this; + $self['description'] = $description; + + return $self; + } +} diff --git a/src/Sessions/SessionObserveParams/Options/Variable/UnionMember3/Value.php b/src/Sessions/SessionObserveParams/Options/Variable/UnionMember3/Value.php new file mode 100644 index 0000000..e82d01d --- /dev/null +++ b/src/Sessions/SessionObserveParams/Options/Variable/UnionMember3/Value.php @@ -0,0 +1,26 @@ +|array + */ + public static function variants(): array + { + return ['string', 'float', 'bool']; + } +} diff --git a/src/Sessions/SessionStartParams/Browser/LaunchOptions.php b/src/Sessions/SessionStartParams/Browser/LaunchOptions.php index ce410ab..29c88b9 100644 --- a/src/Sessions/SessionStartParams/Browser/LaunchOptions.php +++ b/src/Sessions/SessionStartParams/Browser/LaunchOptions.php @@ -20,6 +20,7 @@ * @phpstan-type LaunchOptionsShape = array{ * acceptDownloads?: bool|null, * args?: list|null, + * cdpHeaders?: array|null, * cdpURL?: string|null, * chromiumSandbox?: bool|null, * connectTimeoutMs?: float|null, @@ -51,6 +52,10 @@ final class LaunchOptions implements BaseModel #[Optional(list: 'string')] public ?array $args; + /** @var array|null $cdpHeaders */ + #[Optional(map: 'string')] + public ?array $cdpHeaders; + #[Optional('cdpUrl')] public ?string $cdpURL; @@ -114,6 +119,7 @@ public function __construct() * You must use named parameters to construct any parameters with a default value. * * @param list|null $args + * @param array|null $cdpHeaders * @param IgnoreDefaultArgsShape|null $ignoreDefaultArgs * @param Proxy|ProxyShape|null $proxy * @param Viewport|ViewportShape|null $viewport @@ -121,6 +127,7 @@ public function __construct() public static function with( ?bool $acceptDownloads = null, ?array $args = null, + ?array $cdpHeaders = null, ?string $cdpURL = null, ?bool $chromiumSandbox = null, ?float $connectTimeoutMs = null, @@ -143,6 +150,7 @@ public static function with( null !== $acceptDownloads && $self['acceptDownloads'] = $acceptDownloads; null !== $args && $self['args'] = $args; + null !== $cdpHeaders && $self['cdpHeaders'] = $cdpHeaders; null !== $cdpURL && $self['cdpURL'] = $cdpURL; null !== $chromiumSandbox && $self['chromiumSandbox'] = $chromiumSandbox; null !== $connectTimeoutMs && $self['connectTimeoutMs'] = $connectTimeoutMs; @@ -183,6 +191,17 @@ public function withArgs(array $args): self return $self; } + /** + * @param array $cdpHeaders + */ + public function withCdpHeaders(array $cdpHeaders): self + { + $self = clone $this; + $self['cdpHeaders'] = $cdpHeaders; + + return $self; + } + public function withCdpURL(string $cdpURL): self { $self = clone $this; diff --git a/src/Sessions/StreamEvent.php b/src/Sessions/StreamEvent.php index 2c9a1c3..ec577de 100644 --- a/src/Sessions/StreamEvent.php +++ b/src/Sessions/StreamEvent.php @@ -12,7 +12,7 @@ use Stagehand\Sessions\StreamEvent\Type; /** - * Server-Sent Event emitted during streaming responses. Events are sent as `data: \n\n`. Key order: data (with status first), type, id. + * Server-Sent Event emitted during streaming responses. Events are sent as `event: \ndata: \n\n`, where the JSON payload has the shape `{ data, type, id }`. * * @phpstan-import-type DataVariants from \Stagehand\Sessions\StreamEvent\Data * @phpstan-import-type DataShape from \Stagehand\Sessions\StreamEvent\Data diff --git a/src/Version.php b/src/Version.php index c2d8cf4..c3e4a22 100644 --- a/src/Version.php +++ b/src/Version.php @@ -5,5 +5,5 @@ namespace Stagehand; // x-release-please-start-version -const VERSION = '3.16.0'; +const VERSION = '3.18.0'; // x-release-please-end diff --git a/tests/Services/SessionsTest.php b/tests/Services/SessionsTest.php index 14abf28..076d524 100644 --- a/tests/Services/SessionsTest.php +++ b/tests/Services/SessionsTest.php @@ -72,10 +72,16 @@ public function testActWithOptionalParams(): void 'modelName' => 'openai/gpt-5-nano', 'apiKey' => 'sk-some-openai-api-key', 'baseURL' => 'https://api.openai.com/v1', + 'headers' => ['foo' => 'string'], 'provider' => 'openai', ], 'timeout' => 30000, - 'variables' => ['username' => 'john_doe'], + 'variables' => [ + 'username' => 'john_doe', + 'password' => [ + 'value' => 'secret123', 'description' => 'The login password', + ], + ], ], xStreamResponse: 'true', ); @@ -133,6 +139,7 @@ public function testExecuteWithOptionalParams(): void 'modelName' => 'openai/gpt-5-nano', 'apiKey' => 'sk-some-openai-api-key', 'baseURL' => 'https://api.openai.com/v1', + 'headers' => ['foo' => 'string'], 'provider' => 'openai', ], 'mode' => 'cua', @@ -140,6 +147,7 @@ public function testExecuteWithOptionalParams(): void 'modelName' => 'openai/gpt-5-nano', 'apiKey' => 'sk-some-openai-api-key', 'baseURL' => 'https://api.openai.com/v1', + 'headers' => ['foo' => 'string'], 'provider' => 'openai', ], 'provider' => 'openai', @@ -149,6 +157,8 @@ public function testExecuteWithOptionalParams(): void 'instruction' => 'Log in with username \'demo\' and password \'test123\', then navigate to settings', 'highlightCursor' => true, 'maxSteps' => 20, + 'toolTimeout' => 30000, + 'useSearch' => true, ], frameID: 'frameId', shouldCache: true, @@ -270,6 +280,7 @@ public function testStartWithOptionalParams(): void 'launchOptions' => [ 'acceptDownloads' => true, 'args' => ['string'], + 'cdpHeaders' => ['foo' => 'string'], 'cdpURL' => 'cdpUrl', 'chromiumSandbox' => true, 'connectTimeoutMs' => 0,