From 64805ae68f0978264fb77801e8e94a470a039e94 Mon Sep 17 00:00:00 2001 From: "kernel-internal[bot]" <260533166+kernel-internal[bot]@users.noreply.github.com> Date: Fri, 18 Sep 2026 23:28:11 +0000 Subject: [PATCH 1/7] feat: Publish restricted_route_unavailable and unknown proxy_error codes Stainless-Generated-From: 30b8dbda88df8b8b5d482c48532d5826e1ce35a4 --- .../browsers/browser_proxy_error_event.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/kernel/types/browsers/browser_proxy_error_event.py b/src/kernel/types/browsers/browser_proxy_error_event.py index d8c9dd93..5d40f9ed 100644 --- a/src/kernel/types/browsers/browser_proxy_error_event.py +++ b/src/kernel/types/browsers/browser_proxy_error_event.py @@ -22,18 +22,23 @@ class Data(BrowserEventContext): "provider_unreachable", "provider_rejected", "origin_tls_timeout", + "origin_response_incomplete", "proxy_unavailable", + "restricted_route_unavailable", "upstream_timeout", "upstream_dns_failure", "upstream_connect_failed", + "unknown", ] """ Proxy-layer error code: the X-Kernel-Proxy-Error response header value from a branded 5xx error page served by the metro egress host-proxy. Values mirror what the proxy emits: destination_blocked, provider_blacklisted, - provider_unreachable, provider_rejected, origin_tls_timeout, proxy_unavailable, - upstream_timeout, upstream_dns_failure, upstream_connect_failed. Unknown header - values are dropped. + provider_unreachable, provider_rejected, origin_tls_timeout, + origin_response_incomplete, proxy_unavailable, restricted_route_unavailable, + upstream_timeout, upstream_dns_failure, upstream_connect_failed. A header value + the browser image does not recognize is reported as unknown, with the header + value in raw_code. """ request_id: str @@ -45,6 +50,14 @@ class Data(BrowserEventContext): method: Optional[str] = None """HTTP method of the failed request, when known.""" + raw_code: Optional[str] = None + """Sanitized X-Kernel-Proxy-Error header value, present only when code is unknown. + + Surrounding whitespace is removed, the value is lowercased, characters outside + [a-z0-9_] are replaced with \\__, and the result is truncated to at most 64 + characters. + """ + resource_type: Optional[str] = None """CDP Network.ResourceType for the request, when known.""" From 5f2df0a4170aa146eabb23f576195d1a06621925 Mon Sep 17 00:00:00 2001 From: "kernel-internal[bot]" <260533166+kernel-internal[bot]@users.noreply.github.com> Date: Mon, 21 Sep 2026 15:57:52 +0000 Subject: [PATCH 2/7] feat: Support native prepared Adyen Sessions checkout Stainless-Generated-From: 1c59aa3eefd9ebe82d2a948a4b96dfe9903207a1 --- src/kernel/resources/vaults/items.py | 4 ++-- .../types/vaults/agentcard_checkout_preparation.py | 2 +- .../types/vaults/agentcard_prepared_processor.py | 2 +- src/kernel/types/vaults/card_vault_item_state.py | 6 ++++-- .../types/vaults/item_perform_operation_params.py | 2 +- ..._checkout_vault_item_operation_request_param.py | 4 ++-- .../types/vaults/vault_checkout_context_param.py | 14 ++++++++------ 7 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/kernel/resources/vaults/items.py b/src/kernel/resources/vaults/items.py index a9058c09..acaf0315 100644 --- a/src/kernel/resources/vaults/items.py +++ b/src/kernel/resources/vaults/items.py @@ -517,7 +517,7 @@ def perform_operation( leave the outcome unknown; do not automatically retry. Args: - checkout: Required when preparing an unused AgentCard card for a supported tokenization + checkout: Required when preparing an unused AgentCard card for a supported checkout processor. Consent is bound to this browser and declared merchant origin, not a tab. Wait for the item's ready_to_submit status before native Pay and submit within its readiness deadline. Unused preparations expire automatically; every @@ -1290,7 +1290,7 @@ async def perform_operation( leave the outcome unknown; do not automatically retry. Args: - checkout: Required when preparing an unused AgentCard card for a supported tokenization + checkout: Required when preparing an unused AgentCard card for a supported checkout processor. Consent is bound to this browser and declared merchant origin, not a tab. Wait for the item's ready_to_submit status before native Pay and submit within its readiness deadline. Unused preparations expire automatically; every diff --git a/src/kernel/types/vaults/agentcard_checkout_preparation.py b/src/kernel/types/vaults/agentcard_checkout_preparation.py index 7f9da71f..419f3fdd 100644 --- a/src/kernel/types/vaults/agentcard_checkout_preparation.py +++ b/src/kernel/types/vaults/agentcard_checkout_preparation.py @@ -13,7 +13,7 @@ class AgentcardCheckoutPreparation(BaseModel): """One-use processor-bound checkout preparation. - Keep the approval page open through token handoff. The amount is display-only and does not constrain the merchant's eventual charge. + Keep the approval page open through device handoff, including Adyen encryption. The amount is declared by the caller and does not constrain the merchant's eventual charge. Adyen device approval and browser Authorised responses are not capture or fulfillment evidence. """ browser_id: str diff --git a/src/kernel/types/vaults/agentcard_prepared_processor.py b/src/kernel/types/vaults/agentcard_prepared_processor.py index ebf94c86..41c3c7c2 100644 --- a/src/kernel/types/vaults/agentcard_prepared_processor.py +++ b/src/kernel/types/vaults/agentcard_prepared_processor.py @@ -4,4 +4,4 @@ __all__ = ["AgentcardPreparedProcessor"] -AgentcardPreparedProcessor: TypeAlias = Literal["square", "braintree", "worldpay", "bambora", "mercado_pago"] +AgentcardPreparedProcessor: TypeAlias = Literal["square", "braintree", "worldpay", "bambora", "mercado_pago", "adyen"] diff --git a/src/kernel/types/vaults/card_vault_item_state.py b/src/kernel/types/vaults/card_vault_item_state.py index a1cb0b68..df7a4306 100644 --- a/src/kernel/types/vaults/card_vault_item_state.py +++ b/src/kernel/types/vaults/card_vault_item_state.py @@ -117,8 +117,10 @@ class AgentCardCardState(BaseModel): preparation: Optional[AgentcardCheckoutPreparation] = None """One-use processor-bound checkout preparation. - Keep the approval page open through token handoff. The amount is display-only - and does not constrain the merchant's eventual charge. + Keep the approval page open through device handoff, including Adyen encryption. + The amount is declared by the caller and does not constrain the merchant's + eventual charge. Adyen device approval and browser Authorised responses are not + capture or fulfillment evidence. """ status_reason: Optional[str] = None diff --git a/src/kernel/types/vaults/item_perform_operation_params.py b/src/kernel/types/vaults/item_perform_operation_params.py index c1fb80c9..7e866ff3 100644 --- a/src/kernel/types/vaults/item_perform_operation_params.py +++ b/src/kernel/types/vaults/item_perform_operation_params.py @@ -34,7 +34,7 @@ class PrepareCheckoutVaultItemOperationRequest(TypedDict, total=False): checkout: Required[VaultCheckoutContextParam] """ - Required when preparing an unused AgentCard card for a supported tokenization + Required when preparing an unused AgentCard card for a supported checkout processor. Consent is bound to this browser and declared merchant origin, not a tab. Wait for the item's ready_to_submit status before native Pay and submit within its readiness deadline. Unused preparations expire automatically; every diff --git a/src/kernel/types/vaults/prepare_checkout_vault_item_operation_request_param.py b/src/kernel/types/vaults/prepare_checkout_vault_item_operation_request_param.py index 72fdb4d2..73d92e08 100644 --- a/src/kernel/types/vaults/prepare_checkout_vault_item_operation_request_param.py +++ b/src/kernel/types/vaults/prepare_checkout_vault_item_operation_request_param.py @@ -10,14 +10,14 @@ class PrepareCheckoutVaultItemOperationRequestParam(TypedDict, total=False): - """Prepare an unused AgentCard card for a supported tokenization checkout. + """Prepare an unused AgentCard card for a supported checkout. Deliver the returned approval URL and keep the approval page open. Poll the item until ready_to_submit, then submit native Pay before preparation.expires_at. Readiness lasts at most 30 seconds. Unused preparations expire automatically. Preparations are single-use even after failure or expiry; do not automatically retry and reconcile uncertain outcomes with the merchant. """ checkout: Required[VaultCheckoutContextParam] """ - Required when preparing an unused AgentCard card for a supported tokenization + Required when preparing an unused AgentCard card for a supported checkout processor. Consent is bound to this browser and declared merchant origin, not a tab. Wait for the item's ready_to_submit status before native Pay and submit within its readiness deadline. Unused preparations expire automatically; every diff --git a/src/kernel/types/vaults/vault_checkout_context_param.py b/src/kernel/types/vaults/vault_checkout_context_param.py index f5fda5db..545f2dff 100644 --- a/src/kernel/types/vaults/vault_checkout_context_param.py +++ b/src/kernel/types/vaults/vault_checkout_context_param.py @@ -11,7 +11,7 @@ class VaultCheckoutContextParam(TypedDict, total=False): """ - Required when preparing an unused AgentCard card for a supported tokenization processor. Consent is bound to this browser and declared merchant origin, not a tab. Wait for the item's ready_to_submit status before native Pay and submit within its readiness deadline. Unused preparations expire automatically; every preparation is single-use, including after failure or expiry. + Required when preparing an unused AgentCard card for a supported checkout processor. Consent is bound to this browser and declared merchant origin, not a tab. Wait for the item's ready_to_submit status before native Pay and submit within its readiness deadline. Unused preparations expire automatically; every preparation is single-use, including after failure or expiry. """ browser_id: Required[str] @@ -19,8 +19,8 @@ class VaultCheckoutContextParam(TypedDict, total=False): environment: Required[Literal["production", "sandbox", "shared"]] """ - Use production or sandbox for Square, Braintree and Worldpay; shared for Bambora - and Mercado Pago. Shared endpoints do not establish test mode. Merchant + Use production or sandbox for Square, Braintree, Worldpay and Adyen; shared for + Bambora and Mercado Pago. Shared endpoints do not establish test mode. Merchant credentials/configuration determine processor test mode, independently of the AgentCard credential mode. """ @@ -32,8 +32,10 @@ class VaultCheckoutContextParam(TypedDict, total=False): """ psp: AgentcardPreparedProcessor - """Tokenization processor. + """Checkout processor. - Omit for Square compatibility. Non-Square processors require multi-processor - preparation enablement. + Omit for Square compatibility. Adyen supports fresh-card Sessions requests on + Adyen hosts only. Use public dummy card fields, not vault aliases. The unique + armed preparation is associated with the subsequent eligible request from this + browser and declared merchant origin; competing preparations are rejected. """ From 41059ae6d345b924d7e508e43a8b1d0842c58556 Mon Sep 17 00:00:00 2001 From: "kernel-internal[bot]" <260533166+kernel-internal[bot]@users.noreply.github.com> Date: Mon, 21 Sep 2026 18:58:00 +0000 Subject: [PATCH 3/7] feat: Distinguish optimistic managed auth reauth Stainless-Generated-From: 31a3e7fafe482f5af315d990f10750d7a0110016 --- src/kernel/types/auth/managed_auth.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/kernel/types/auth/managed_auth.py b/src/kernel/types/auth/managed_auth.py index 62fa7852..be202e61 100644 --- a/src/kernel/types/auth/managed_auth.py +++ b/src/kernel/types/auth/managed_auth.py @@ -367,10 +367,12 @@ class ManagedAuth(BaseModel): can_reauth: Optional[bool] = None """ - Whether Kernel can automatically re-authenticate this connection when the - session expires. Requires a prior successful login plus either a Kernel - credential or an external credential reference. See `can_reauth_reason` for the - specific outcome. + Whether this connection's stored requirements are eligible for unattended + re-authentication. A true value can represent either fully satisfiable + requirements or a best-effort attempt. It does not account for whether automatic + re-authentication is enabled or parent workflow state such as an active flow or + circuit-breaker cooldown, so it does not guarantee an attempt on the next health + check. See `can_reauth_reason` for the specific outcome. """ can_reauth_reason: Optional[ @@ -381,6 +383,7 @@ class ManagedAuth(BaseModel): "viable_plans_found", "no_requirements_recorded", "totp_reauth_allowed", + "optimistic_totp_attempt", "requirements_satisfiable", "no_prior_successful_login", "no_credential", @@ -395,7 +398,7 @@ class ManagedAuth(BaseModel): ] = None """ Machine-readable reason for the current value of `can_reauth`. Affirmative - values (re-auth is possible): + values (requirements are eligible for unattended re-authentication): - `external_credential` — an external credential provider is attached - `cua_has_credential` — CUA flow with a stored credential @@ -404,8 +407,12 @@ class ManagedAuth(BaseModel): - `viable_plans_found` — at least one stored login plan can be replayed - `no_requirements_recorded` — no recorded credential requirements to fail against - - `totp_reauth_allowed` — TOTP is the only recorded requirement and is safe to - attempt automatically + - `totp_reauth_allowed` — TOTP is the only recorded requirement and a stored + secret can generate the code + - `optimistic_totp_attempt` — TOTP was previously required but no reusable + secret is stored; the connection remains eligible for a + circuit-breaker-bounded attempt because the site may not challenge returning + sessions - `requirements_satisfiable` — recorded requirements contain no recognized blocker From 17a7960d9304fdceb54d59b09277651b6166fdb1 Mon Sep 17 00:00:00 2001 From: "kernel-internal[bot]" <260533166+kernel-internal[bot]@users.noreply.github.com> Date: Mon, 21 Sep 2026 19:22:18 +0000 Subject: [PATCH 4/7] feat: Persist stable managed auth completion timestamps Stainless-Generated-From: 6427817227cf91c697de16f53ac309df45b1b532 --- src/kernel/types/auth/managed_auth_timeline_event.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/kernel/types/auth/managed_auth_timeline_event.py b/src/kernel/types/auth/managed_auth_timeline_event.py index b2e0213b..79eee70c 100644 --- a/src/kernel/types/auth/managed_auth_timeline_event.py +++ b/src/kernel/types/auth/managed_auth_timeline_event.py @@ -38,6 +38,14 @@ class ManagedAuthTimelineEvent(BaseModel): browser_session_id: Optional[str] = None """Browser session that produced the event, if one was created.""" + completed_at: Optional[datetime] = None + """When the login/reauth attempt first reached a terminal status. + + Stable across retries and subsequent cleanup writes. Absent for in-progress + attempts, health checks, and historical attempts without a recorded completion + time. + """ + error_code: Optional[str] = None """Machine-readable error code. Present when a login/reauth event failed.""" From e230ce3a684ce7723256170443ba0b84b08310a4 Mon Sep 17 00:00:00 2001 From: "kernel-internal[bot]" <260533166+kernel-internal[bot]@users.noreply.github.com> Date: Mon, 21 Sep 2026 19:52:02 +0000 Subject: [PATCH 5/7] feat: Allow managed auth logins to disable learned skills Stainless-Generated-From: 9c2ffa1553e5fe09f6a36fa423af3e7308eb7d14 --- src/kernel/resources/auth/connections.py | 12 ++++++++++++ src/kernel/types/auth/connection_login_params.py | 9 ++++++++- tests/api_resources/auth/test_connections.py | 2 ++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/kernel/resources/auth/connections.py b/src/kernel/resources/auth/connections.py index 62858fdd..fae767b7 100644 --- a/src/kernel/resources/auth/connections.py +++ b/src/kernel/resources/auth/connections.py @@ -477,6 +477,7 @@ def login( browser_telemetry: Optional[connection_login_params.BrowserTelemetry] | Omit = omit, proxy: connection_login_params.Proxy | Omit = omit, record_session: bool | Omit = omit, + skill_mode: Literal["enabled", "disabled"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -502,6 +503,10 @@ def login( record_session: Override the connection's default for recording this login's browser session. When omitted, the connection's record_session default is used. + skill_mode: Controls whether this login reads and writes learned domain skills. Automatic + reauths inherit the selected mode until a later accepted login sets enabled or + omits this field. Defaults to enabled when omitted. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -520,6 +525,7 @@ def login( "browser_telemetry": browser_telemetry, "proxy": proxy, "record_session": record_session, + "skill_mode": skill_mode, }, connection_login_params.ConnectionLoginParams, ), @@ -1100,6 +1106,7 @@ async def login( browser_telemetry: Optional[connection_login_params.BrowserTelemetry] | Omit = omit, proxy: connection_login_params.Proxy | Omit = omit, record_session: bool | Omit = omit, + skill_mode: Literal["enabled", "disabled"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -1125,6 +1132,10 @@ async def login( record_session: Override the connection's default for recording this login's browser session. When omitted, the connection's record_session default is used. + skill_mode: Controls whether this login reads and writes learned domain skills. Automatic + reauths inherit the selected mode until a later accepted login sets enabled or + omits this field. Defaults to enabled when omitted. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1143,6 +1154,7 @@ async def login( "browser_telemetry": browser_telemetry, "proxy": proxy, "record_session": record_session, + "skill_mode": skill_mode, }, connection_login_params.ConnectionLoginParams, ), diff --git a/src/kernel/types/auth/connection_login_params.py b/src/kernel/types/auth/connection_login_params.py index cbe2bf3b..0d62506d 100644 --- a/src/kernel/types/auth/connection_login_params.py +++ b/src/kernel/types/auth/connection_login_params.py @@ -3,7 +3,7 @@ from __future__ import annotations from typing import Optional -from typing_extensions import TypedDict +from typing_extensions import Literal, TypedDict from .managed_auth_browser_config_param import ManagedAuthBrowserConfigParam from ..browsers.browser_telemetry_categories_config_param import BrowserTelemetryCategoriesConfigParam @@ -40,6 +40,13 @@ class ConnectionLoginParams(TypedDict, total=False): When omitted, the connection's record_session default is used. """ + skill_mode: Literal["enabled", "disabled"] + """Controls whether this login reads and writes learned domain skills. + + Automatic reauths inherit the selected mode until a later accepted login sets + enabled or omits this field. Defaults to enabled when omitted. + """ + class BrowserTelemetryExportOtlpDestination(TypedDict, total=False): """OTLP destination to export this session's captured telemetry to. diff --git a/tests/api_resources/auth/test_connections.py b/tests/api_resources/auth/test_connections.py index 53a55fa7..311b9971 100644 --- a/tests/api_resources/auth/test_connections.py +++ b/tests/api_resources/auth/test_connections.py @@ -525,6 +525,7 @@ def test_method_login_with_all_params(self, client: Kernel) -> None: "name": "name", }, record_session=True, + skill_mode="enabled", ) assert_matches_type(LoginResponse, connection, path=["response"]) @@ -1187,6 +1188,7 @@ async def test_method_login_with_all_params(self, async_client: AsyncKernel) -> "name": "name", }, record_session=True, + skill_mode="enabled", ) assert_matches_type(LoginResponse, connection, path=["response"]) From 76b3d8871e29d47cfda20f68ab23152daf1790c6 Mon Sep 17 00:00:00 2001 From: "kernel-internal[bot]" <260533166+kernel-internal[bot]@users.noreply.github.com> Date: Tue, 22 Sep 2026 15:02:56 +0000 Subject: [PATCH 6/7] feat: Implement Search API v1 providers Stainless-Generated-From: 88a2e9eb1b30837e304011693f8598389cfb45bb --- .stats.yml | 2 +- api.md | 37 + src/kernel/_client.py | 44 ++ src/kernel/resources/__init__.py | 14 + src/kernel/resources/search/__init__.py | 47 ++ src/kernel/resources/search/contents.py | 220 ++++++ src/kernel/resources/search/providers.py | 187 +++++ src/kernel/resources/search/search.py | 536 +++++++++++++++ src/kernel/types/__init__.py | 8 + src/kernel/types/attempt.py | 20 + src/kernel/types/provider_target_param.py | 636 ++++++++++++++++++ src/kernel/types/result.py | 115 ++++ src/kernel/types/search/__init__.py | 9 + .../types/search/content_fetch_params.py | 97 +++ src/kernel/types/search/provider.py | 136 ++++ .../types/search/provider_list_params.py | 12 + .../types/search/provider_list_response.py | 10 + src/kernel/types/search/search.py | 56 ++ src/kernel/types/search_create_params.py | 186 +++++ src/kernel/types/strategy_param.py | 60 ++ src/kernel/types/usage.py | 24 + src/kernel/types/warning.py | 24 + tests/api_resources/search/__init__.py | 1 + tests/api_resources/search/test_contents.py | 150 +++++ tests/api_resources/search/test_providers.py | 96 +++ tests/api_resources/test_search.py | 265 ++++++++ 26 files changed, 2991 insertions(+), 1 deletion(-) create mode 100644 src/kernel/resources/search/__init__.py create mode 100644 src/kernel/resources/search/contents.py create mode 100644 src/kernel/resources/search/providers.py create mode 100644 src/kernel/resources/search/search.py create mode 100644 src/kernel/types/attempt.py create mode 100644 src/kernel/types/provider_target_param.py create mode 100644 src/kernel/types/result.py create mode 100644 src/kernel/types/search/__init__.py create mode 100644 src/kernel/types/search/content_fetch_params.py create mode 100644 src/kernel/types/search/provider.py create mode 100644 src/kernel/types/search/provider_list_params.py create mode 100644 src/kernel/types/search/provider_list_response.py create mode 100644 src/kernel/types/search/search.py create mode 100644 src/kernel/types/search_create_params.py create mode 100644 src/kernel/types/strategy_param.py create mode 100644 src/kernel/types/usage.py create mode 100644 src/kernel/types/warning.py create mode 100644 tests/api_resources/search/__init__.py create mode 100644 tests/api_resources/search/test_contents.py create mode 100644 tests/api_resources/search/test_providers.py create mode 100644 tests/api_resources/test_search.py diff --git a/.stats.yml b/.stats.yml index 40c9d3b0..e8ac4eb6 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1 +1 @@ -configured_endpoints: 165 +configured_endpoints: 169 diff --git a/api.md b/api.md index 90bb1465..7e82ddfb 100644 --- a/api.md +++ b/api.md @@ -735,3 +735,40 @@ Methods: - client.credential_providers.delete(id) -> None - client.credential_providers.list_items(id) -> CredentialProviderListItemsResponse - client.credential_providers.test(id) -> CredentialProviderTestResult + +# Search + +Types: + +```python +from kernel.types import Attempt, ProviderTarget, Request, Result, Search, Strategy, Usage, Warning +``` + +Methods: + +- client.search.create(\*\*params) -> Search +- client.search.retrieve(id) -> Search + +## Contents + +Types: + +```python +from kernel.types.search import FetchRequest, Response +``` + +Methods: + +- client.search.contents.fetch(id, \*\*params) -> None + +## Providers + +Types: + +```python +from kernel.types.search import Provider, ProviderListResponse +``` + +Methods: + +- client.search.providers.list(\*\*params) -> ProviderListResponse diff --git a/src/kernel/_client.py b/src/kernel/_client.py index 13a6e3dc..4ffa9faf 100644 --- a/src/kernel/_client.py +++ b/src/kernel/_client.py @@ -57,6 +57,7 @@ from .resources import ( apps, auth, + search, vaults, proxies, api_keys, @@ -85,6 +86,7 @@ from .resources.deployments import DeploymentsResource, AsyncDeploymentsResource from .resources.invocations import InvocationsResource, AsyncInvocationsResource from .resources.browser_pools import BrowserPoolsResource, AsyncBrowserPoolsResource + from .resources.search.search import SearchResource, AsyncSearchResource from .resources.vaults.vaults import VaultsResource, AsyncVaultsResource from .resources.browsers.browsers import BrowsersResource, AsyncBrowsersResource from .resources.projects.projects import ProjectsResource, AsyncProjectsResource @@ -348,6 +350,13 @@ def credential_providers(self) -> CredentialProvidersResource: return CredentialProvidersResource(self) + @cached_property + def search(self) -> SearchResource: + """Search the web and retrieve content for selected results.""" + from .resources.search import SearchResource + + return SearchResource(self) + @cached_property def with_raw_response(self) -> KernelWithRawResponse: return KernelWithRawResponse(self) @@ -752,6 +761,13 @@ def credential_providers(self) -> AsyncCredentialProvidersResource: return AsyncCredentialProvidersResource(self) + @cached_property + def search(self) -> AsyncSearchResource: + """Search the web and retrieve content for selected results.""" + from .resources.search import AsyncSearchResource + + return AsyncSearchResource(self) + @cached_property def with_raw_response(self) -> AsyncKernelWithRawResponse: return AsyncKernelWithRawResponse(self) @@ -1058,6 +1074,13 @@ def credential_providers(self) -> credential_providers.CredentialProvidersResour return CredentialProvidersResourceWithRawResponse(self._client.credential_providers) + @cached_property + def search(self) -> search.SearchResourceWithRawResponse: + """Search the web and retrieve content for selected results.""" + from .resources.search import SearchResourceWithRawResponse + + return SearchResourceWithRawResponse(self._client.search) + class AsyncKernelWithRawResponse: _client: AsyncKernel @@ -1196,6 +1219,13 @@ def credential_providers(self) -> credential_providers.AsyncCredentialProvidersR return AsyncCredentialProvidersResourceWithRawResponse(self._client.credential_providers) + @cached_property + def search(self) -> search.AsyncSearchResourceWithRawResponse: + """Search the web and retrieve content for selected results.""" + from .resources.search import AsyncSearchResourceWithRawResponse + + return AsyncSearchResourceWithRawResponse(self._client.search) + class KernelWithStreamedResponse: _client: Kernel @@ -1334,6 +1364,13 @@ def credential_providers(self) -> credential_providers.CredentialProvidersResour return CredentialProvidersResourceWithStreamingResponse(self._client.credential_providers) + @cached_property + def search(self) -> search.SearchResourceWithStreamingResponse: + """Search the web and retrieve content for selected results.""" + from .resources.search import SearchResourceWithStreamingResponse + + return SearchResourceWithStreamingResponse(self._client.search) + class AsyncKernelWithStreamedResponse: _client: AsyncKernel @@ -1472,6 +1509,13 @@ def credential_providers(self) -> credential_providers.AsyncCredentialProvidersR return AsyncCredentialProvidersResourceWithStreamingResponse(self._client.credential_providers) + @cached_property + def search(self) -> search.AsyncSearchResourceWithStreamingResponse: + """Search the web and retrieve content for selected results.""" + from .resources.search import AsyncSearchResourceWithStreamingResponse + + return AsyncSearchResourceWithStreamingResponse(self._client.search) + Client = Kernel diff --git a/src/kernel/resources/__init__.py b/src/kernel/resources/__init__.py index 21426930..4be8e2ba 100644 --- a/src/kernel/resources/__init__.py +++ b/src/kernel/resources/__init__.py @@ -16,6 +16,14 @@ AuthResourceWithStreamingResponse, AsyncAuthResourceWithStreamingResponse, ) +from .search import ( + SearchResource, + AsyncSearchResource, + SearchResourceWithRawResponse, + AsyncSearchResourceWithRawResponse, + SearchResourceWithStreamingResponse, + AsyncSearchResourceWithStreamingResponse, +) from .vaults import ( VaultsResource, AsyncVaultsResource, @@ -268,4 +276,10 @@ "AsyncCredentialProvidersResourceWithRawResponse", "CredentialProvidersResourceWithStreamingResponse", "AsyncCredentialProvidersResourceWithStreamingResponse", + "SearchResource", + "AsyncSearchResource", + "SearchResourceWithRawResponse", + "AsyncSearchResourceWithRawResponse", + "SearchResourceWithStreamingResponse", + "AsyncSearchResourceWithStreamingResponse", ] diff --git a/src/kernel/resources/search/__init__.py b/src/kernel/resources/search/__init__.py new file mode 100644 index 00000000..0ae39afe --- /dev/null +++ b/src/kernel/resources/search/__init__.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .search import ( + SearchResource, + AsyncSearchResource, + SearchResourceWithRawResponse, + AsyncSearchResourceWithRawResponse, + SearchResourceWithStreamingResponse, + AsyncSearchResourceWithStreamingResponse, +) +from .contents import ( + ContentsResource, + AsyncContentsResource, + ContentsResourceWithRawResponse, + AsyncContentsResourceWithRawResponse, + ContentsResourceWithStreamingResponse, + AsyncContentsResourceWithStreamingResponse, +) +from .providers import ( + ProvidersResource, + AsyncProvidersResource, + ProvidersResourceWithRawResponse, + AsyncProvidersResourceWithRawResponse, + ProvidersResourceWithStreamingResponse, + AsyncProvidersResourceWithStreamingResponse, +) + +__all__ = [ + "ContentsResource", + "AsyncContentsResource", + "ContentsResourceWithRawResponse", + "AsyncContentsResourceWithRawResponse", + "ContentsResourceWithStreamingResponse", + "AsyncContentsResourceWithStreamingResponse", + "ProvidersResource", + "AsyncProvidersResource", + "ProvidersResourceWithRawResponse", + "AsyncProvidersResourceWithRawResponse", + "ProvidersResourceWithStreamingResponse", + "AsyncProvidersResourceWithStreamingResponse", + "SearchResource", + "AsyncSearchResource", + "SearchResourceWithRawResponse", + "AsyncSearchResourceWithRawResponse", + "SearchResourceWithStreamingResponse", + "AsyncSearchResourceWithStreamingResponse", +] diff --git a/src/kernel/resources/search/contents.py b/src/kernel/resources/search/contents.py new file mode 100644 index 00000000..f41983c0 --- /dev/null +++ b/src/kernel/resources/search/contents.py @@ -0,0 +1,220 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given +from ..._utils import path_template, maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.search import content_fetch_params + +__all__ = ["ContentsResource", "AsyncContentsResource"] + + +class ContentsResource(SyncAPIResource): + """Search the web and retrieve content for selected results.""" + + @cached_property + def with_raw_response(self) -> ContentsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#accessing-raw-response-data-eg-headers + """ + return ContentsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ContentsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#with_streaming_response + """ + return ContentsResourceWithStreamingResponse(self) + + def fetch( + self, + id: str, + *, + content: content_fetch_params.Content | Omit = omit, + limit: int | Omit = omit, + result_ids: SequenceNotStr[str] | Omit = omit, + timeout_ms: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Deferred result-content retrieval is reserved but not available in this release. + Requests return 404 until the retrieval implementation is shipped. X-Request-Id + identifies this request separately from the search resource. + + Args: + content: Defaults to source:auto when omitted. + + limit: Maximum number of search results to fetch when result_ids is omitted, starting + from rank 1. Mutually exclusive with result_ids. + + result_ids: Kernel-generated IDs from the referenced retained search, in desired response + order. They are not provider-standard IDs. Mutually exclusive with limit. + + timeout_ms: Overall deadline across all selected results. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._post( + path_template("/search/{id}/contents", id=id), + body=maybe_transform( + { + "content": content, + "limit": limit, + "result_ids": result_ids, + "timeout_ms": timeout_ms, + }, + content_fetch_params.ContentFetchParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class AsyncContentsResource(AsyncAPIResource): + """Search the web and retrieve content for selected results.""" + + @cached_property + def with_raw_response(self) -> AsyncContentsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#accessing-raw-response-data-eg-headers + """ + return AsyncContentsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncContentsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#with_streaming_response + """ + return AsyncContentsResourceWithStreamingResponse(self) + + async def fetch( + self, + id: str, + *, + content: content_fetch_params.Content | Omit = omit, + limit: int | Omit = omit, + result_ids: SequenceNotStr[str] | Omit = omit, + timeout_ms: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """ + Deferred result-content retrieval is reserved but not available in this release. + Requests return 404 until the retrieval implementation is shipped. X-Request-Id + identifies this request separately from the search resource. + + Args: + content: Defaults to source:auto when omitted. + + limit: Maximum number of search results to fetch when result_ids is omitted, starting + from rank 1. Mutually exclusive with result_ids. + + result_ids: Kernel-generated IDs from the referenced retained search, in desired response + order. They are not provider-standard IDs. Mutually exclusive with limit. + + timeout_ms: Overall deadline across all selected results. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._post( + path_template("/search/{id}/contents", id=id), + body=await async_maybe_transform( + { + "content": content, + "limit": limit, + "result_ids": result_ids, + "timeout_ms": timeout_ms, + }, + content_fetch_params.ContentFetchParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + +class ContentsResourceWithRawResponse: + def __init__(self, contents: ContentsResource) -> None: + self._contents = contents + + self.fetch = to_raw_response_wrapper( + contents.fetch, + ) + + +class AsyncContentsResourceWithRawResponse: + def __init__(self, contents: AsyncContentsResource) -> None: + self._contents = contents + + self.fetch = async_to_raw_response_wrapper( + contents.fetch, + ) + + +class ContentsResourceWithStreamingResponse: + def __init__(self, contents: ContentsResource) -> None: + self._contents = contents + + self.fetch = to_streamed_response_wrapper( + contents.fetch, + ) + + +class AsyncContentsResourceWithStreamingResponse: + def __init__(self, contents: AsyncContentsResource) -> None: + self._contents = contents + + self.fetch = async_to_streamed_response_wrapper( + contents.fetch, + ) diff --git a/src/kernel/resources/search/providers.py b/src/kernel/resources/search/providers.py new file mode 100644 index 00000000..f913f1cd --- /dev/null +++ b/src/kernel/resources/search/providers.py @@ -0,0 +1,187 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.search import provider_list_params +from ...types.search.provider_list_response import ProviderListResponse + +__all__ = ["ProvidersResource", "AsyncProvidersResource"] + + +class ProvidersResource(SyncAPIResource): + """Search the web and retrieve content for selected results.""" + + @cached_property + def with_raw_response(self) -> ProvidersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#accessing-raw-response-data-eg-headers + """ + return ProvidersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ProvidersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#with_streaming_response + """ + return ProvidersResourceWithStreamingResponse(self) + + def list( + self, + *, + slug: Literal["brave", "exa", "perplexity", "context", "parallel", "valyu", "octen", "you", "tavily", "serpapi"] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProviderListResponse: + """Lists providers, capabilities, and machine-readable native-option schemas. + + Auto + and fallback are strategies, not provider entries. The list is not paginated and + contains no latency benchmarks. X-Request-Id identifies the request. + + Args: + slug: Optional concrete provider slug filter. Omit to list every provider. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/search/providers", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"slug": slug}, provider_list_params.ProviderListParams), + ), + cast_to=ProviderListResponse, + ) + + +class AsyncProvidersResource(AsyncAPIResource): + """Search the web and retrieve content for selected results.""" + + @cached_property + def with_raw_response(self) -> AsyncProvidersResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#accessing-raw-response-data-eg-headers + """ + return AsyncProvidersResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncProvidersResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#with_streaming_response + """ + return AsyncProvidersResourceWithStreamingResponse(self) + + async def list( + self, + *, + slug: Literal["brave", "exa", "perplexity", "context", "parallel", "valyu", "octen", "you", "tavily", "serpapi"] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProviderListResponse: + """Lists providers, capabilities, and machine-readable native-option schemas. + + Auto + and fallback are strategies, not provider entries. The list is not paginated and + contains no latency benchmarks. X-Request-Id identifies the request. + + Args: + slug: Optional concrete provider slug filter. Omit to list every provider. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/search/providers", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform({"slug": slug}, provider_list_params.ProviderListParams), + ), + cast_to=ProviderListResponse, + ) + + +class ProvidersResourceWithRawResponse: + def __init__(self, providers: ProvidersResource) -> None: + self._providers = providers + + self.list = to_raw_response_wrapper( + providers.list, + ) + + +class AsyncProvidersResourceWithRawResponse: + def __init__(self, providers: AsyncProvidersResource) -> None: + self._providers = providers + + self.list = async_to_raw_response_wrapper( + providers.list, + ) + + +class ProvidersResourceWithStreamingResponse: + def __init__(self, providers: ProvidersResource) -> None: + self._providers = providers + + self.list = to_streamed_response_wrapper( + providers.list, + ) + + +class AsyncProvidersResourceWithStreamingResponse: + def __init__(self, providers: AsyncProvidersResource) -> None: + self._providers = providers + + self.list = async_to_streamed_response_wrapper( + providers.list, + ) diff --git a/src/kernel/resources/search/search.py b/src/kernel/resources/search/search.py new file mode 100644 index 00000000..850363c6 --- /dev/null +++ b/src/kernel/resources/search/search.py @@ -0,0 +1,536 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import date +from typing_extensions import Literal + +import httpx + +from ...types import search_create_params +from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ..._utils import path_template, maybe_transform, async_maybe_transform +from .contents import ( + ContentsResource, + AsyncContentsResource, + ContentsResourceWithRawResponse, + AsyncContentsResourceWithRawResponse, + ContentsResourceWithStreamingResponse, + AsyncContentsResourceWithStreamingResponse, +) +from ..._compat import cached_property +from .providers import ( + ProvidersResource, + AsyncProvidersResource, + ProvidersResourceWithRawResponse, + AsyncProvidersResourceWithRawResponse, + ProvidersResourceWithStreamingResponse, + AsyncProvidersResourceWithStreamingResponse, +) +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.search.search import Search +from ...types.strategy_param import StrategyParam + +__all__ = ["SearchResource", "AsyncSearchResource"] + + +class SearchResource(SyncAPIResource): + """Search the web and retrieve content for selected results.""" + + @cached_property + def contents(self) -> ContentsResource: + """Search the web and retrieve content for selected results.""" + return ContentsResource(self._client) + + @cached_property + def providers(self) -> ProvidersResource: + """Search the web and retrieve content for selected results.""" + return ProvidersResource(self._client) + + @cached_property + def with_raw_response(self) -> SearchResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#accessing-raw-response-data-eg-headers + """ + return SearchResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> SearchResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#with_streaming_response + """ + return SearchResourceWithStreamingResponse(self) + + def create( + self, + *, + query: str, + content: search_create_params.Content | Omit = omit, + country: str | Omit = omit, + end_date: Union[str, date] | Omit = omit, + exclude_domains: SequenceNotStr[str] | Omit = omit, + include_domains: SequenceNotStr[str] | Omit = omit, + include_raw: bool | Omit = omit, + language: str | Omit = omit, + max_results: int | Omit = omit, + recency: Literal["hour", "day", "week", "month", "year"] | Omit = omit, + safe_search: Literal["off", "moderate", "strict"] | Omit = omit, + start_date: Union[str, date] | Omit = omit, + strategy: StrategyParam | Omit = omit, + strict_params: bool | Omit = omit, + timeout_ms: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Search: + """Returns ranked results from one serving provider. + + The default strategy selects a + provider that supports the requested options. The fallback strategy tries + providers in the supplied order. Results are not blended across providers. + Portable filters may be approximated or omitted according to provider + capabilities; warnings describe those outcomes unless strict_params is true. + Native options apply only to their selected provider. + + Args: + query: Primary search query. A provider-native multi-query option applies only to that + provider; other providers in a fallback chain receive this query. + + content: Optional portable content retrieval. Pass true for defaults or an options + object. Omission never starts Kernel browser work; provider-supplied content is + still returned when available, including when requested through native options. + Both inline and deferred retrieval use the same options schema. + + country: ISO 3166-1 alpha-2 search locale preference. + + end_date: Inclusive publication-date upper bound; must not precede start_date. If recency + is also supplied, recency takes precedence with a warning. Unsupported or + approximated filtering is reported, or rejected under strict_params. + + exclude_domains: Hostname exclusions, with the same best-effort/strict behavior as + include_domains. Provider-specific combinations that cannot be represented are + reported via warnings or rejected in strict mode. + + include_domains: Hostname inclusion preference, matching a hostname and its subdomains. Empty + means unrestricted. Translated, emulated, or dropped with a warning according to + provider capability unless strict_params is true. Native boost modes remain + advisory and are identified in warnings. + + include_raw: Include untouched per-result payloads and the full serving-provider response in + raw fields. Off by default; native top-level outputs such as answer remain + available without it. + + language: BCP 47 search language preference. + + max_results: Requested result count from 1 through 100. The effective count is clamped to the + serving provider's cap with a warning. Effective native counts are the lower of + this limit and supplied provider-native count aliases. Strict mode rejects + unsupported counts. + + recency: Relative search window. Takes precedence over start_date/end_date with a warning + if both are set. Provider-native recency behavior is retained, including + documented hour-to-day widening. Unsupported filters are rejected only in strict + mode. + + safe_search: Optional safety preference. Omit to use provider defaults. Unsupported values + are dropped with a warning unless strict_params is true. A search filter is not + an authorization boundary. + + start_date: Inclusive publication-date lower bound. If recency is also supplied, recency + takes precedence with a warning. Provider date semantics, precision, and + unsupported filters are reported; unknown source dates are not fabricated or + universally post-filtered. + + strategy: Omitted strategy defaults to auto. + + strict_params: When false, unsupported portable parameters are omitted and approximations are + described in warnings. When true, every supplied portable parameter must be + honored exactly. Requests that cannot be served with those parameters are + rejected. This does not guarantee identical rankings or document timestamps + across indexes. Authentication and project isolation are always enforced. + + timeout_ms: Overall deadline across search attempts and inline retrieval. No new attempt + starts after the deadline. Completed search results survive inline retrieval + timeouts. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/search", + body=maybe_transform( + { + "query": query, + "content": content, + "country": country, + "end_date": end_date, + "exclude_domains": exclude_domains, + "include_domains": include_domains, + "include_raw": include_raw, + "language": language, + "max_results": max_results, + "recency": recency, + "safe_search": safe_search, + "start_date": start_date, + "strategy": strategy, + "strict_params": strict_params, + "timeout_ms": timeout_ms, + }, + search_create_params.SearchCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Search, + ) + + def retrieve( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Search: + """ + Returns the retained search resource exactly as it was returned by POST /search: + results, attempts, warnings, usage, and expires_at. No provider is called and + nothing is billed. Use it to look up a search by ID for debugging, cost review, + or to recover result IDs before calling the contents endpoint. Inline content + fetched at search time is included; content fetched later through the contents + endpoint is not merged in. Missing, expired, or inaccessible searches + return 404. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._get( + path_template("/search/{id}", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Search, + ) + + +class AsyncSearchResource(AsyncAPIResource): + """Search the web and retrieve content for selected results.""" + + @cached_property + def contents(self) -> AsyncContentsResource: + """Search the web and retrieve content for selected results.""" + return AsyncContentsResource(self._client) + + @cached_property + def providers(self) -> AsyncProvidersResource: + """Search the web and retrieve content for selected results.""" + return AsyncProvidersResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncSearchResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#accessing-raw-response-data-eg-headers + """ + return AsyncSearchResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncSearchResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#with_streaming_response + """ + return AsyncSearchResourceWithStreamingResponse(self) + + async def create( + self, + *, + query: str, + content: search_create_params.Content | Omit = omit, + country: str | Omit = omit, + end_date: Union[str, date] | Omit = omit, + exclude_domains: SequenceNotStr[str] | Omit = omit, + include_domains: SequenceNotStr[str] | Omit = omit, + include_raw: bool | Omit = omit, + language: str | Omit = omit, + max_results: int | Omit = omit, + recency: Literal["hour", "day", "week", "month", "year"] | Omit = omit, + safe_search: Literal["off", "moderate", "strict"] | Omit = omit, + start_date: Union[str, date] | Omit = omit, + strategy: StrategyParam | Omit = omit, + strict_params: bool | Omit = omit, + timeout_ms: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Search: + """Returns ranked results from one serving provider. + + The default strategy selects a + provider that supports the requested options. The fallback strategy tries + providers in the supplied order. Results are not blended across providers. + Portable filters may be approximated or omitted according to provider + capabilities; warnings describe those outcomes unless strict_params is true. + Native options apply only to their selected provider. + + Args: + query: Primary search query. A provider-native multi-query option applies only to that + provider; other providers in a fallback chain receive this query. + + content: Optional portable content retrieval. Pass true for defaults or an options + object. Omission never starts Kernel browser work; provider-supplied content is + still returned when available, including when requested through native options. + Both inline and deferred retrieval use the same options schema. + + country: ISO 3166-1 alpha-2 search locale preference. + + end_date: Inclusive publication-date upper bound; must not precede start_date. If recency + is also supplied, recency takes precedence with a warning. Unsupported or + approximated filtering is reported, or rejected under strict_params. + + exclude_domains: Hostname exclusions, with the same best-effort/strict behavior as + include_domains. Provider-specific combinations that cannot be represented are + reported via warnings or rejected in strict mode. + + include_domains: Hostname inclusion preference, matching a hostname and its subdomains. Empty + means unrestricted. Translated, emulated, or dropped with a warning according to + provider capability unless strict_params is true. Native boost modes remain + advisory and are identified in warnings. + + include_raw: Include untouched per-result payloads and the full serving-provider response in + raw fields. Off by default; native top-level outputs such as answer remain + available without it. + + language: BCP 47 search language preference. + + max_results: Requested result count from 1 through 100. The effective count is clamped to the + serving provider's cap with a warning. Effective native counts are the lower of + this limit and supplied provider-native count aliases. Strict mode rejects + unsupported counts. + + recency: Relative search window. Takes precedence over start_date/end_date with a warning + if both are set. Provider-native recency behavior is retained, including + documented hour-to-day widening. Unsupported filters are rejected only in strict + mode. + + safe_search: Optional safety preference. Omit to use provider defaults. Unsupported values + are dropped with a warning unless strict_params is true. A search filter is not + an authorization boundary. + + start_date: Inclusive publication-date lower bound. If recency is also supplied, recency + takes precedence with a warning. Provider date semantics, precision, and + unsupported filters are reported; unknown source dates are not fabricated or + universally post-filtered. + + strategy: Omitted strategy defaults to auto. + + strict_params: When false, unsupported portable parameters are omitted and approximations are + described in warnings. When true, every supplied portable parameter must be + honored exactly. Requests that cannot be served with those parameters are + rejected. This does not guarantee identical rankings or document timestamps + across indexes. Authentication and project isolation are always enforced. + + timeout_ms: Overall deadline across search attempts and inline retrieval. No new attempt + starts after the deadline. Completed search results survive inline retrieval + timeouts. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/search", + body=await async_maybe_transform( + { + "query": query, + "content": content, + "country": country, + "end_date": end_date, + "exclude_domains": exclude_domains, + "include_domains": include_domains, + "include_raw": include_raw, + "language": language, + "max_results": max_results, + "recency": recency, + "safe_search": safe_search, + "start_date": start_date, + "strategy": strategy, + "strict_params": strict_params, + "timeout_ms": timeout_ms, + }, + search_create_params.SearchCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Search, + ) + + async def retrieve( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> Search: + """ + Returns the retained search resource exactly as it was returned by POST /search: + results, attempts, warnings, usage, and expires_at. No provider is called and + nothing is billed. Use it to look up a search by ID for debugging, cost review, + or to recover result IDs before calling the contents endpoint. Inline content + fetched at search time is included; content fetched later through the contents + endpoint is not merged in. Missing, expired, or inaccessible searches + return 404. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._get( + path_template("/search/{id}", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Search, + ) + + +class SearchResourceWithRawResponse: + def __init__(self, search: SearchResource) -> None: + self._search = search + + self.create = to_raw_response_wrapper( + search.create, + ) + self.retrieve = to_raw_response_wrapper( + search.retrieve, + ) + + @cached_property + def contents(self) -> ContentsResourceWithRawResponse: + """Search the web and retrieve content for selected results.""" + return ContentsResourceWithRawResponse(self._search.contents) + + @cached_property + def providers(self) -> ProvidersResourceWithRawResponse: + """Search the web and retrieve content for selected results.""" + return ProvidersResourceWithRawResponse(self._search.providers) + + +class AsyncSearchResourceWithRawResponse: + def __init__(self, search: AsyncSearchResource) -> None: + self._search = search + + self.create = async_to_raw_response_wrapper( + search.create, + ) + self.retrieve = async_to_raw_response_wrapper( + search.retrieve, + ) + + @cached_property + def contents(self) -> AsyncContentsResourceWithRawResponse: + """Search the web and retrieve content for selected results.""" + return AsyncContentsResourceWithRawResponse(self._search.contents) + + @cached_property + def providers(self) -> AsyncProvidersResourceWithRawResponse: + """Search the web and retrieve content for selected results.""" + return AsyncProvidersResourceWithRawResponse(self._search.providers) + + +class SearchResourceWithStreamingResponse: + def __init__(self, search: SearchResource) -> None: + self._search = search + + self.create = to_streamed_response_wrapper( + search.create, + ) + self.retrieve = to_streamed_response_wrapper( + search.retrieve, + ) + + @cached_property + def contents(self) -> ContentsResourceWithStreamingResponse: + """Search the web and retrieve content for selected results.""" + return ContentsResourceWithStreamingResponse(self._search.contents) + + @cached_property + def providers(self) -> ProvidersResourceWithStreamingResponse: + """Search the web and retrieve content for selected results.""" + return ProvidersResourceWithStreamingResponse(self._search.providers) + + +class AsyncSearchResourceWithStreamingResponse: + def __init__(self, search: AsyncSearchResource) -> None: + self._search = search + + self.create = async_to_streamed_response_wrapper( + search.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + search.retrieve, + ) + + @cached_property + def contents(self) -> AsyncContentsResourceWithStreamingResponse: + """Search the web and retrieve content for selected results.""" + return AsyncContentsResourceWithStreamingResponse(self._search.contents) + + @cached_property + def providers(self) -> AsyncProvidersResourceWithStreamingResponse: + """Search the web and retrieve content for selected results.""" + return AsyncProvidersResourceWithStreamingResponse(self._search.providers) diff --git a/src/kernel/types/__init__.py b/src/kernel/types/__init__.py index 0d25350f..968e4021 100644 --- a/src/kernel/types/__init__.py +++ b/src/kernel/types/__init__.py @@ -6,7 +6,10 @@ from .. import _compat from .tags import Tags as Tags from .proxy import Proxy as Proxy +from .usage import Usage as Usage from .vault import Vault as Vault +from .result import Result as Result +from .search import Search as Search from .shared import ( LogEvent as LogEvent, AppAction as AppAction, @@ -20,9 +23,11 @@ ) from .target import Target as Target from .api_key import APIKey as APIKey +from .attempt import Attempt as Attempt from .browser import Browser as Browser from .profile import Profile as Profile from .project import Project as Project +from .warning import Warning as Warning from .analysis import Analysis as Analysis from .evidence import Evidence as Evidence from .credential import Credential as Credential @@ -32,6 +37,7 @@ from .browser_usage import BrowserUsage as BrowserUsage from .browser_memory import BrowserMemory as BrowserMemory from .recommendation import Recommendation as Recommendation +from .strategy_param import StrategyParam as StrategyParam from .app_list_params import AppListParams as AppListParams from .audit_log_entry import AuditLogEntry as AuditLogEntry from .created_api_key import CreatedAPIKey as CreatedAPIKey @@ -60,6 +66,7 @@ from .browser_proxy_config import BrowserProxyConfig as BrowserProxyConfig from .browser_repl_content import BrowserReplContent as BrowserReplContent from .proxy_check_response import ProxyCheckResponse as ProxyCheckResponse +from .search_create_params import SearchCreateParams as SearchCreateParams from .api_key_create_params import APIKeyCreateParams as APIKeyCreateParams from .api_key_rotate_params import APIKeyRotateParams as APIKeyRotateParams from .api_key_update_params import APIKeyUpdateParams as APIKeyUpdateParams @@ -73,6 +80,7 @@ from .profile_update_params import ProfileUpdateParams as ProfileUpdateParams from .project_create_params import ProjectCreateParams as ProjectCreateParams from .project_update_params import ProjectUpdateParams as ProjectUpdateParams +from .provider_target_param import ProviderTargetParam as ProviderTargetParam from .proxy_create_response import ProxyCreateResponse as ProxyCreateResponse from .proxy_update_response import ProxyUpdateResponse as ProxyUpdateResponse from .recommendation_result import RecommendationResult as RecommendationResult diff --git a/src/kernel/types/attempt.py b/src/kernel/types/attempt.py new file mode 100644 index 00000000..70863016 --- /dev/null +++ b/src/kernel/types/attempt.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["Attempt"] + + +class Attempt(BaseModel): + duration_ms: int + + outcome: Literal["success", "empty", "error", "timeout"] + + provider: str + + error_code: Optional[str] = None + + retryable: Optional[bool] = None diff --git a/src/kernel/types/provider_target_param.py b/src/kernel/types/provider_target_param.py new file mode 100644 index 00000000..7c3c314f --- /dev/null +++ b/src/kernel/types/provider_target_param.py @@ -0,0 +1,636 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Optional +from datetime import date, datetime +from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict + +from .._types import SequenceNotStr +from .._utils import PropertyInfo + +__all__ = [ + "ProviderTargetParam", + "SearchBraveTarget", + "SearchBraveTargetOptions", + "SearchExaTarget", + "SearchExaTargetOptions", + "SearchExaTargetOptionsContents", + "SearchPerplexityTarget", + "SearchPerplexityTargetOptions", + "SearchContextTarget", + "SearchContextTargetOptions", + "SearchContextTargetOptionsMarkdownOptions", + "SearchContextTargetOptionsMarkdownOptionsPdf", + "SearchParallelTarget", + "SearchParallelTargetOptions", + "SearchParallelTargetOptionsAdvancedSettings", + "SearchParallelTargetOptionsAdvancedSettingsExcerptSettings", + "SearchParallelTargetOptionsAdvancedSettingsFetchPolicy", + "SearchParallelTargetOptionsAdvancedSettingsSourcePolicy", + "SearchValyuTarget", + "SearchValyuTargetOptions", + "SearchOctenTarget", + "SearchOctenTargetOptions", + "SearchOctenTargetOptionsFullContent", + "SearchOctenTargetOptionsHighlight", + "SearchYouTarget", + "SearchYouTargetOptions", + "SearchYouTargetOptionsExtraction", + "SearchYouTargetOptionsExtractionFullPage", + "SearchTavilyTarget", + "SearchTavilyTargetOptions", + "SearchSerpAPITarget", + "SearchSerpAPITargetOptions", +] + + +class SearchBraveTargetOptions(TypedDict, total=False): + count: int + """Provider-native count. + + Lower-only alias for max_results; cannot raise the effective result cap. + """ + + extra_snippets: bool + """Request additional snippets from Brave.""" + + goggles: str + """Goggles re-ranking definition URL.""" + + goggles_id: str + """Deprecated Brave Goggle identifier. Prefer goggles.""" + + include_fetch_metadata: bool + """Include Brave's fetch metadata.""" + + offset: int + """Page offset supported by Brave.""" + + operators: str + """Brave search operators.""" + + result_filter: str + """Comma-separated result types to include, e.g. "web,news".""" + + search_lang: str + """Language of the search, e.g. "en".""" + + spellcheck: bool + """Apply Brave's query spellcheck.""" + + ui_lang: str + """Language for UI strings in the response.""" + + units: Literal["metric", "imperial"] + """Measurement units.""" + + +class SearchBraveTarget(TypedDict, total=False): + provider: Required[Literal["brave"]] + + options: SearchBraveTargetOptions + + +class SearchExaTargetOptionsContents(TypedDict, total=False): + """Provider-native content retrieval. + + Available without requesting Kernel browser retrieval; may incur provider retrieval charges. + """ + + highlights: bool + """Return query-relevant provider excerpts.""" + + text: bool + """Return provider page text.""" + + +class SearchExaTargetOptions(TypedDict, total=False): + category: str + """Provider data-category hint.""" + + compliance: str + """Provider-native compliance controls. + + Requires support and authorization on the provider account. + """ + + contents: SearchExaTargetOptionsContents + """Provider-native content retrieval. + + Available without requesting Kernel browser retrieval; may incur provider + retrieval charges. + """ + + max_age_hours: Annotated[float, PropertyInfo(alias="maxAgeHours")] + """Provider-native cache-age control. + + Unlike content.max_age_hours, this retains Exa semantics, including any native + sentinel values. It does not imply a cross-provider freshness guarantee. + """ + + num_results: Annotated[int, PropertyInfo(alias="numResults")] + """Provider-native count. Lower-only alias for max_results.""" + + type: Literal["auto", "fast", "instant"] + """Search mode supported by Exa.""" + + +class SearchExaTarget(TypedDict, total=False): + provider: Required[Literal["exa"]] + + options: SearchExaTargetOptions + + +class SearchPerplexityTargetOptions(TypedDict, total=False): + last_updated_after_filter: str + """MM/DD/YYYY. Filters by last-updated date, not published date.""" + + last_updated_before_filter: str + """MM/DD/YYYY upper bound on last-updated date.""" + + max_results: int + """Provider-native count. Lower-only alias for max_results.""" + + max_tokens: int + """Values outside the documented range are rejected.""" + + max_tokens_per_page: int + """Per-page token cap.""" + + query: SequenceNotStr[str] + """Provider-native multi-query form, applied only to Perplexity. + + Other fallback providers receive the top-level query. Each query may incur a + separate provider charge. + """ + + search_context_size: Literal["low", "medium", "high"] + """Provider context size supported by the selected model.""" + + search_language_filter: SequenceNotStr[str] + """ISO 639-1 language codes, max 20.""" + + +class SearchPerplexityTarget(TypedDict, total=False): + provider: Required[Literal["perplexity"]] + + options: SearchPerplexityTargetOptions + + +class SearchContextTargetOptionsMarkdownOptionsPdf(TypedDict, total=False): + should_parse: Annotated[bool, PropertyInfo(alias="shouldParse")] + + +class SearchContextTargetOptionsMarkdownOptions(TypedDict, total=False): + enabled: bool + + include_frames: Annotated[bool, PropertyInfo(alias="includeFrames")] + + include_images: Annotated[bool, PropertyInfo(alias="includeImages")] + + include_links: Annotated[bool, PropertyInfo(alias="includeLinks")] + + max_age_ms: Annotated[int, PropertyInfo(alias="maxAgeMs")] + + pdf: SearchContextTargetOptionsMarkdownOptionsPdf + + shorten_base64_images: Annotated[bool, PropertyInfo(alias="shortenBase64Images")] + + timeout_ms: Annotated[int, PropertyInfo(alias="timeoutMS")] + + use_main_content_only: Annotated[bool, PropertyInfo(alias="useMainContentOnly")] + + wait_for_ms: Annotated[int, PropertyInfo(alias="waitForMs")] + + +class SearchContextTargetOptions(TypedDict, total=False): + country: str + """ISO 3166-1 alpha-2 country code.""" + + exclude_domains: Annotated[SequenceNotStr[str], PropertyInfo(alias="excludeDomains")] + """Blocklist of result domains.""" + + freshness: Literal["last_24_hours", "last_week", "last_month", "last_year"] + """Restrict results to content published within this window.""" + + include_domains: Annotated[SequenceNotStr[str], PropertyInfo(alias="includeDomains")] + """Allowlist of result domains.""" + + markdown_options: Annotated[SearchContextTargetOptionsMarkdownOptions, PropertyInfo(alias="markdownOptions")] + + num_results: Annotated[int, PropertyInfo(alias="numResults")] + """Number of results to request from Context.dev.""" + + query_fanout: Annotated[bool, PropertyInfo(alias="queryFanout")] + """Expand the query into multiple parallel variants.""" + + tags: SequenceNotStr[str] + """Usage tracking tags.""" + + timeout_ms: Annotated[int, PropertyInfo(alias="timeoutMS")] + """Context.dev request timeout in milliseconds.""" + + +class SearchContextTarget(TypedDict, total=False): + provider: Required[Literal["context"]] + + options: SearchContextTargetOptions + + +class SearchParallelTargetOptionsAdvancedSettingsExcerptSettings(TypedDict, total=False): + max_chars_per_result: Optional[int] + + +class SearchParallelTargetOptionsAdvancedSettingsFetchPolicy(TypedDict, total=False): + disable_cache_fallback: bool + """When false, the provider may return cached content after live fetching fails.""" + + max_age_seconds: Optional[int] + """Native live-fetch trigger; minimum 600 seconds. + + Not the unified hard-freshness control. + """ + + timeout_seconds: Optional[float] + """Native live-fetch timeout, bounded by the remaining overall deadline.""" + + +class SearchParallelTargetOptionsAdvancedSettingsSourcePolicy(TypedDict, total=False): + after_date: Annotated[Union[str, date, None], PropertyInfo(format="iso8601")] + """Native publication-date lower bound.""" + + exclude_domains: SequenceNotStr[str] + """ + Native exclusions; the provider ignores these when native include_domains is + non-empty. + """ + + include_domains: SequenceNotStr[str] + """Native domain/path restrictions. + + Explicit unified domain parameters take precedence. Combined include/exclude + native lists cannot exceed 200 entries. + """ + + +class SearchParallelTargetOptionsAdvancedSettings(TypedDict, total=False): + """Explicit search settings. + + Unified search parameters are re-applied to overlapping settings; native result counts are lower-only. + """ + + excerpt_settings: SearchParallelTargetOptionsAdvancedSettingsExcerptSettings + + fetch_policy: SearchParallelTargetOptionsAdvancedSettingsFetchPolicy + + location: Optional[str] + """Native ISO 3166-1 alpha-2 location preference.""" + + max_results: Optional[int] + """Native count; lower-only alias for unified max_results.""" + + source_policy: SearchParallelTargetOptionsAdvancedSettingsSourcePolicy + + +class SearchParallelTargetOptions(TypedDict, total=False): + advanced_settings: SearchParallelTargetOptionsAdvancedSettings + """Explicit search settings. + + Unified search parameters are re-applied to overlapping settings; native result + counts are lower-only. + """ + + client_model: str + """Client model hint.""" + + max_chars_total: int + """Cap total characters returned.""" + + mode: Literal["turbo", "fast", "basic", "advanced"] + """Search mode. + + Basic is used when omitted; each mode can have different latency and charges. + """ + + objective: str + """The goal behind the search, stated separately from the query.""" + + search_queries: SequenceNotStr[str] + """Provider-native multi-query search. Defaults to [query] for this provider.""" + + session_id: str + """Group related searches.""" + + +class SearchParallelTarget(TypedDict, total=False): + provider: Required[Literal["parallel"]] + + options: SearchParallelTargetOptions + + +class SearchValyuTargetOptions(TypedDict, total=False): + fast_mode: bool + """Trade depth for latency.""" + + historical_cache: bool + """Allow historical cached results.""" + + include_abstracts: bool + """Include abstracts for academic sources.""" + + instructions: str + """Natural-language retrieval guidance.""" + + is_tool_call: bool + """Mark the search as an agent tool call.""" + + max_num_results: int + """Provider-native count. Lower-only alias for max_results.""" + + max_price: float + """Provider-native USD-per-thousand-results price ceiling. Forwarded to Valyu.""" + + relevance_threshold: float + """Provider-native minimum relevance threshold. + + Not a normalized cross-provider score. + """ + + response_length: Literal["short", "medium", "large", "max"] + """Provider result-content length preset.""" + + search_type: str + """Corpus selector, including all, web, proprietary, and news. + + Provider corpus choice may change billing; Kernel does not force web-only + searches. + """ + + source_biases: SequenceNotStr[str] + """Bias retrieval toward these sources.""" + + url_only: bool + """Return URLs without content.""" + + +class SearchValyuTarget(TypedDict, total=False): + provider: Required[Literal["valyu"]] + + options: SearchValyuTargetOptions + + +class SearchOctenTargetOptionsFullContent(TypedDict, total=False): + enable: bool + + max_tokens: int + + +class SearchOctenTargetOptionsHighlight(TypedDict, total=False): + enable: bool + + max_tokens: int + + +class SearchOctenTargetOptions(TypedDict, total=False): + count: int + + end_time: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + + exclude_domains: SequenceNotStr[str] + + exclude_text: SequenceNotStr[str] + + format: Literal["markdown", "text"] + + full_content: SearchOctenTargetOptionsFullContent + + highlight: SearchOctenTargetOptionsHighlight + + include_domains: SequenceNotStr[str] + + include_images: bool + + include_text: SequenceNotStr[str] + + language: SequenceNotStr[str] + + safesearch: Literal["off", "strict"] + + start_time: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + + time_basis: Literal["auto", "published", "crawled"] + + time_range: Literal["day", "week", "month", "year", "d", "w", "m", "y"] + + topic: Literal["general", "news"] + + +class SearchOctenTarget(TypedDict, total=False): + provider: Required[Literal["octen"]] + + options: SearchOctenTargetOptions + + +class SearchYouTargetOptionsExtractionFullPage(TypedDict, total=False): + extraction_formats: List[Literal["html", "markdown"]] + + +class SearchYouTargetOptionsExtraction(TypedDict, total=False): + """Provider-native page extraction. + + Both modes may incur per-row charges; full_page may retrieve web and news rows. + """ + + extraction_mode: Required[Literal["highlights", "full_page"]] + + full_page: SearchYouTargetOptionsExtractionFullPage + + +class SearchYouTargetOptions(TypedDict, total=False): + boost_domains: SequenceNotStr[str] + """Prefer these domains without excluding others. + + Cannot be combined with include_domains if the provider does not accept the + combination. + """ + + count: int + """Provider-native per-section count. + + Lower-only alias for max_results. Web and news sections may produce more rows + than Kernel returns. + """ + + crawl_timeout: int + """ + Native extraction timeout in seconds, bounded by the remaining Kernel request + deadline. + """ + + extraction: SearchYouTargetOptionsExtraction + """Provider-native page extraction. + + Both modes may incur per-row charges; full_page may retrieve web and news rows. + """ + + knowledge: Literal["core"] + """Request licensed-data output. + + URL-less knowledge entries are not converted into web results; include_raw + exposes the full provider response separately. + """ + + language: str + """BCP 47 result language from You.com's 51-value enum, e.g. + + "EN", "JA". Default EN. + """ + + offset: int + """Page offset supported by You.com.""" + + +class SearchYouTarget(TypedDict, total=False): + provider: Required[Literal["you"]] + + options: SearchYouTargetOptions + + +class SearchTavilyTargetOptions(TypedDict, total=False): + auto_parameters: bool + """Allow the provider to choose search parameters. + + May select a different billing tier; explicit caller values retain + provider-native precedence. + """ + + chunks_per_source: int + """Provider excerpts per source, up to 500 characters each.""" + + exact_match: bool + """Require the quoted phrases in the query verbatim, bypassing semantic matches.""" + + filter_by_language: bool + """Strictly filter non-matching languages. Requires `language`.""" + + include_answer: Union[bool, Literal["basic", "advanced"]] + """Request the provider's generated answer. + + Returned as answer on the search response, independently of include_raw. + """ + + include_domains_mode: Literal["filter", "boost"] + """Native filter versus ranking boost semantics. + + Boost influences ranking rather than restricting results to the listed domains. + Requires include_domains. + """ + + include_favicon: bool + """Favicon URL per result.""" + + include_image_descriptions: bool + """Describe each image. Needs include_images.""" + + include_images: bool + """Query-related images plus per-result images.""" + + include_raw_content: Union[bool, Literal["markdown", "text"]] + """Request native full-page content. + + Defaults to markdown when omitted for this provider, False disables that native + retrieval; it does not disable explicitly requested Kernel browser retrieval. + """ + + language: str + """ISO 639-1 code or English language name. + + Ranking boost unless filter_by_language. + """ + + max_results: int + """Provider-native count. Lower-only alias for max_results.""" + + search_depth: Literal["advanced", "basic", "fast", "ultra-fast"] + """Provider relevance and latency tier. + + Some tiers cannot be combined with native safe search; conflicts are described + in warnings. + """ + + topic: Literal["general", "news", "finance"] + """Provider corpus selector. Publication metadata depends on the selected topic.""" + + +class SearchTavilyTarget(TypedDict, total=False): + provider: Required[Literal["tavily"]] + + options: SearchTavilyTargetOptions + + +class SearchSerpAPITargetOptions(TypedDict, total=False): + engine: Required[str] + """SerpApi engine identifier. + + The Kernel integration currently supports google only. + """ + + device: Literal["desktop", "mobile", "tablet"] + """Device profile used for the search.""" + + filter: Literal[0, 1] + """Google duplicate-content filter.""" + + gl: str + """Two-letter Google country code.""" + + google_domain: str + """Google domain to search when using the google engine.""" + + hl: str + """Interface language code.""" + + location: str + """Free-form geographic location used for localized results.""" + + nfpr: Literal[0, 1] + """Google auto-correction filter.""" + + no_cache: bool + """When true, bypass SerpApi cached results when supported.""" + + num: int + """Number of results requested from the search engine.""" + + safe: Literal["active", "off"] + """Safe-search setting for engines that support it.""" + + start: int + """Zero-based result offset for pagination.""" + + tbm: str + """Google vertical search selector, such as images, video, news, or shopping.""" + + tbs: str + """Google time and search modifiers, including freshness filters.""" + + +class SearchSerpAPITarget(TypedDict, total=False): + provider: Required[Literal["serpapi"]] + + options: SearchSerpAPITargetOptions + + +ProviderTargetParam: TypeAlias = Union[ + SearchBraveTarget, + SearchExaTarget, + SearchPerplexityTarget, + SearchContextTarget, + SearchParallelTarget, + SearchValyuTarget, + SearchOctenTarget, + SearchYouTarget, + SearchTavilyTarget, + SearchSerpAPITarget, +] diff --git a/src/kernel/types/result.py b/src/kernel/types/result.py new file mode 100644 index 00000000..23a5d12b --- /dev/null +++ b/src/kernel/types/result.py @@ -0,0 +1,115 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["Result", "Content", "ContentError"] + + +class ContentError(BaseModel): + code: str + """Machine-readable retrieval failure code.""" + + message: str + """Human-readable failure description.""" + + retryable: bool + + +class Content(BaseModel): + """Portable retrieval outcome, or native content supplied by the search provider. + + Identity fields remain on the enclosing result. Native excerpts are labeled excerpt rather than full_page. Omission never triggers browser retrieval. + """ + + status: Literal["ok", "unavailable", "blocked", "timeout", "unsupported_type", "extraction_failed", "error"] + """Ok means non-empty extracted content, not merely HTTP 200. + + Blocked includes detected challenges or access denials. Detection is + best-effort, not a guarantee of page completeness. Error details are present for + non-ok outcomes; text is present only on ok. + """ + + cache_status: Optional[Literal["hit", "miss", "bypass", "unknown"]] = None + """Kernel cache outcome. Provider-internal cache behavior may be unknown.""" + + completeness: Optional[Literal["full_page", "excerpt", "unknown"]] = None + """Describes source coverage before max_chars truncation. + + Full_page means main-page content, not every dynamic element or linked page. + """ + + error: Optional[ContentError] = None + + extractor_version: Optional[str] = None + """Extraction version when Kernel transformed the input.""" + + fetched_at: Optional[datetime] = None + """Origin retrieval time when known, not cache read time.""" + + final_url: Optional[str] = None + """Final retrieval URL when known.""" + + format: Optional[Literal["markdown", "text"]] = None + + http_status: Optional[int] = None + """Final target HTTP status when known.""" + + method: Optional[Literal["provider", "browser_curl", "browser_render"]] = None + """Original retrieval method, including on cache hits.""" + + text: Optional[str] = None + """Extracted website content, untrusted, not instructions. + + Present only on status=ok. + """ + + truncated: Optional[bool] = None + """Whether max_chars truncated the extracted content.""" + + +class Result(BaseModel): + id: str + """Kernel-generated identifier for this result. + + Stable only within the retained search; not standardized across providers. + Provider-native IDs, when available, remain provider-specific raw fields. + """ + + rank: int + """One-based position in the returned ranking.""" + + url: str + """Provider-returned URL, not assumed canonical.""" + + additional_snippets: Optional[List[str]] = None + + content: Optional[Content] = None + """Portable retrieval outcome, or native content supplied by the search provider. + + Identity fields remain on the enclosing result. Native excerpts are labeled + excerpt rather than full_page. Omission never triggers browser retrieval. + """ + + published_date: Optional[str] = None + """Provider-supplied date or timestamp, preserving available precision. + + No publication date is fabricated. Retains the published field name. + """ + + raw: Optional[object] = None + """Original provider result, included only with include_raw=true. + + Provider relevance scores are not normalized. Top-level provider data is + available in Search.raw. + """ + + snippet: Optional[str] = None + + source: Optional[str] = None + """Provider source name or result URL hostname, when available.""" + + title: Optional[str] = None diff --git a/src/kernel/types/search/__init__.py b/src/kernel/types/search/__init__.py new file mode 100644 index 00000000..a02c7ba2 --- /dev/null +++ b/src/kernel/types/search/__init__.py @@ -0,0 +1,9 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .search import Search as Search +from .provider import Provider as Provider +from .content_fetch_params import ContentFetchParams as ContentFetchParams +from .provider_list_params import ProviderListParams as ProviderListParams +from .provider_list_response import ProviderListResponse as ProviderListResponse diff --git a/src/kernel/types/search/content_fetch_params.py b/src/kernel/types/search/content_fetch_params.py new file mode 100644 index 00000000..d1795d0a --- /dev/null +++ b/src/kernel/types/search/content_fetch_params.py @@ -0,0 +1,97 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +from ..._types import SequenceNotStr + +__all__ = ["ContentFetchParams", "Content", "ContentBrowser"] + + +class ContentFetchParams(TypedDict, total=False): + content: Content + """Defaults to source:auto when omitted.""" + + limit: int + """ + Maximum number of search results to fetch when result_ids is omitted, starting + from rank 1. Mutually exclusive with result_ids. + """ + + result_ids: SequenceNotStr[str] + """ + Kernel-generated IDs from the referenced retained search, in desired response + order. They are not provider-standard IDs. Mutually exclusive with limit. + """ + + timeout_ms: int + """Overall deadline across all selected results.""" + + +class ContentBrowser(TypedDict, total=False): + """Invalid with source=provider. + + Supplying browser_id requires + source=browser so the chosen identity is not bypassed. + """ + + browser_id: str + """Existing browser session ID authorized for the caller and selected project. + + Reuses its cookies, proxy, and browser configuration. Kernel does not delete a + caller-supplied browser. Render mode uses a temporary tab; website activity may + still change shared cookies and storage. When omitted, Kernel obtains isolated + browser capacity in the caller's account and releases it after retrieval. That + capacity is not retained for later interaction. Existing browser quotas apply. + """ + + mode: Literal["curl", "render"] + """Curl uses the browser HTTP stack without navigation or JavaScript execution. + + Render navigates a temporary page and extracts from its DOM. The selected mode + is used for the retrieval. + """ + + +class Content(TypedDict, total=False): + """Defaults to source:auto when omitted.""" + + browser: ContentBrowser + """Invalid with source=provider. + + Supplying browser_id requires source=browser so the chosen identity is not + bypassed. + """ + + format: Literal["markdown", "text"] + + max_age_hours: int + """Maximum acceptable age of cached page content, measured from origin retrieval. + + 0 forces a live fetch. Governs the Kernel content cache, which is scoped to the + caller organization and project and separated by retrieval context; fetches + through a caller-supplied browser_id bypass that cache. Mapped to the provider + freshness control when source is provider and the provider supports one; + otherwise provider content age is reported as unknown via fetched_at. + """ + + max_chars: int + """Per-result Unicode character limit after extraction.""" + + source: Literal["auto", "provider", "browser"] + """ + provider uses the search provider's native content retrieval; browser fetches + each URL through a Kernel browser; auto prefers Kernel browser retrieval and + falls back to provider-native content when browser retrieval is unavailable or + unsuitable. Defaults to auto for both inline and deferred retrieval. Deferred + provider retrieval requires post_hoc capability; an explicit provider source + without it is a 400. Missing documents produce per-result unavailable outcomes, + not request failures. + """ + + timeout_ms: int + """Per-result deadline including capacity acquisition, retrieval, and extraction. + + Also bounded by the overall request deadline. + """ diff --git a/src/kernel/types/search/provider.py b/src/kernel/types/search/provider.py new file mode 100644 index 00000000..fcefff3a --- /dev/null +++ b/src/kernel/types/search/provider.py @@ -0,0 +1,136 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Optional +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = [ + "Provider", + "Content", + "Params", + "ParamsCountry", + "ParamsEndDate", + "ParamsExcludeDomains", + "ParamsIncludeDomains", + "ParamsLanguage", + "ParamsRecency", + "ParamsSafeSearch", + "ParamsStartDate", + "ProviderOptions", +] + + +class Content(BaseModel): + freshness_control: bool + """Can enforce the requested maximum content age.""" + + inline: bool + """Supports content retrieval with the search request.""" + + post_hoc: bool + """Supports content retrieval after the search completes.""" + + +class ParamsCountry(BaseModel): + support: Literal["native", "emulated", "unsupported"] + + notes: Optional[str] = None + """Translation behavior, limitations, and precision.""" + + +class ParamsEndDate(BaseModel): + support: Literal["native", "emulated", "unsupported"] + + notes: Optional[str] = None + """Translation behavior, limitations, and precision.""" + + +class ParamsExcludeDomains(BaseModel): + support: Literal["native", "emulated", "unsupported"] + + notes: Optional[str] = None + """Translation behavior, limitations, and precision.""" + + +class ParamsIncludeDomains(BaseModel): + support: Literal["native", "emulated", "unsupported"] + + notes: Optional[str] = None + """Translation behavior, limitations, and precision.""" + + +class ParamsLanguage(BaseModel): + support: Literal["native", "emulated", "unsupported"] + + notes: Optional[str] = None + """Translation behavior, limitations, and precision.""" + + +class ParamsRecency(BaseModel): + support: Literal["native", "emulated", "unsupported"] + + notes: Optional[str] = None + """Translation behavior, limitations, and precision.""" + + +class ParamsSafeSearch(BaseModel): + support: Literal["native", "emulated", "unsupported"] + + notes: Optional[str] = None + """Translation behavior, limitations, and precision.""" + + +class ParamsStartDate(BaseModel): + support: Literal["native", "emulated", "unsupported"] + + notes: Optional[str] = None + """Translation behavior, limitations, and precision.""" + + +class Params(BaseModel): + country: ParamsCountry + + end_date: ParamsEndDate + + exclude_domains: ParamsExcludeDomains + + include_domains: ParamsIncludeDomains + + language: ParamsLanguage + + recency: ParamsRecency + + safe_search: ParamsSafeSearch + + start_date: ParamsStartDate + + +class ProviderOptions(BaseModel): + schema_: Dict[str, object] = FieldInfo(alias="schema") + """JSON Schema for the provider-native options accepted by POST /search.""" + + schema_ref: str + """OpenAPI component name for the matching typed provider-options schema.""" + + examples: Optional[List[Dict[str, object]]] = None + + +class Provider(BaseModel): + content: Content + + max_results_cap: int + + params: Params + + provider_options: ProviderOptions + + slug: str + + notes: Optional[List[str]] = None + """ + Provider-specific limitations, conditional filter support, and warnings about + search modes. + """ diff --git a/src/kernel/types/search/provider_list_params.py b/src/kernel/types/search/provider_list_params.py new file mode 100644 index 00000000..07ef4659 --- /dev/null +++ b/src/kernel/types/search/provider_list_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["ProviderListParams"] + + +class ProviderListParams(TypedDict, total=False): + slug: Literal["brave", "exa", "perplexity", "context", "parallel", "valyu", "octen", "you", "tavily", "serpapi"] + """Optional concrete provider slug filter. Omit to list every provider.""" diff --git a/src/kernel/types/search/provider_list_response.py b/src/kernel/types/search/provider_list_response.py new file mode 100644 index 00000000..8bafd3c6 --- /dev/null +++ b/src/kernel/types/search/provider_list_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .provider import Provider + +__all__ = ["ProviderListResponse"] + +ProviderListResponse: TypeAlias = List[Provider] diff --git a/src/kernel/types/search/search.py b/src/kernel/types/search/search.py new file mode 100644 index 00000000..e02b1dde --- /dev/null +++ b/src/kernel/types/search/search.py @@ -0,0 +1,56 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime + +from ..usage import Usage +from ..result import Result +from ..attempt import Attempt +from ..warning import Warning +from ..._models import BaseModel + +__all__ = ["Search"] + + +class Search(BaseModel): + """Retained search results and provider attempt history.""" + + id: str + """Search resource ID. Request tracing uses X-Request-Id.""" + + attempts: List[Attempt] + + expires_at: datetime + """Expiration of result IDs for deferred retrieval. + + Results expire 24 hours after search completion. + """ + + provider: str + """Concrete serving provider, never auto or fallback.""" + + query: str + """Echo of the query. + + Native multi-query inputs are visible in the selected strategy target and the + optional raw response. + """ + + results: List[Result] + + usage: Usage + + warnings: List[Warning] + + answer: Optional[str] = None + """Provider-generated answer when requested (e.g. + + via Tavily include_answer or Perplexity). Preserved independently of + include_raw. + """ + + raw: Optional[object] = None + """ + Full serving-provider response, including top-level metadata that does not + belong to a result. Present only with include_raw=true; untrusted provider data. + """ diff --git a/src/kernel/types/search_create_params.py b/src/kernel/types/search_create_params.py new file mode 100644 index 00000000..da84a3d7 --- /dev/null +++ b/src/kernel/types/search_create_params.py @@ -0,0 +1,186 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import date +from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict + +from .._types import SequenceNotStr +from .._utils import PropertyInfo +from .strategy_param import StrategyParam + +__all__ = ["SearchCreateParams", "Content", "ContentSearchContentOptions", "ContentSearchContentOptionsBrowser"] + + +class SearchCreateParams(TypedDict, total=False): + query: Required[str] + """Primary search query. + + A provider-native multi-query option applies only to that provider; other + providers in a fallback chain receive this query. + """ + + content: Content + """Optional portable content retrieval. + + Pass true for defaults or an options object. Omission never starts Kernel + browser work; provider-supplied content is still returned when available, + including when requested through native options. Both inline and deferred + retrieval use the same options schema. + """ + + country: str + """ISO 3166-1 alpha-2 search locale preference.""" + + end_date: Annotated[Union[str, date], PropertyInfo(format="iso8601")] + """Inclusive publication-date upper bound; must not precede start_date. + + If recency is also supplied, recency takes precedence with a warning. + Unsupported or approximated filtering is reported, or rejected under + strict_params. + """ + + exclude_domains: SequenceNotStr[str] + """ + Hostname exclusions, with the same best-effort/strict behavior as + include_domains. Provider-specific combinations that cannot be represented are + reported via warnings or rejected in strict mode. + """ + + include_domains: SequenceNotStr[str] + """Hostname inclusion preference, matching a hostname and its subdomains. + + Empty means unrestricted. Translated, emulated, or dropped with a warning + according to provider capability unless strict_params is true. Native boost + modes remain advisory and are identified in warnings. + """ + + include_raw: bool + """ + Include untouched per-result payloads and the full serving-provider response in + raw fields. Off by default; native top-level outputs such as answer remain + available without it. + """ + + language: str + """BCP 47 search language preference.""" + + max_results: int + """Requested result count from 1 through 100. + + The effective count is clamped to the serving provider's cap with a warning. + Effective native counts are the lower of this limit and supplied provider-native + count aliases. Strict mode rejects unsupported counts. + """ + + recency: Literal["hour", "day", "week", "month", "year"] + """Relative search window. + + Takes precedence over start_date/end_date with a warning if both are set. + Provider-native recency behavior is retained, including documented hour-to-day + widening. Unsupported filters are rejected only in strict mode. + """ + + safe_search: Literal["off", "moderate", "strict"] + """Optional safety preference. + + Omit to use provider defaults. Unsupported values are dropped with a warning + unless strict_params is true. A search filter is not an authorization boundary. + """ + + start_date: Annotated[Union[str, date], PropertyInfo(format="iso8601")] + """Inclusive publication-date lower bound. + + If recency is also supplied, recency takes precedence with a warning. Provider + date semantics, precision, and unsupported filters are reported; unknown source + dates are not fabricated or universally post-filtered. + """ + + strategy: StrategyParam + """Omitted strategy defaults to auto.""" + + strict_params: bool + """ + When false, unsupported portable parameters are omitted and approximations are + described in warnings. When true, every supplied portable parameter must be + honored exactly. Requests that cannot be served with those parameters are + rejected. This does not guarantee identical rankings or document timestamps + across indexes. Authentication and project isolation are always enforced. + """ + + timeout_ms: int + """ + Overall deadline across search attempts and inline retrieval. No new attempt + starts after the deadline. Completed search results survive inline retrieval + timeouts. + """ + + +class ContentSearchContentOptionsBrowser(TypedDict, total=False): + """Invalid with source=provider. + + Supplying browser_id requires + source=browser so the chosen identity is not bypassed. + """ + + browser_id: str + """Existing browser session ID authorized for the caller and selected project. + + Reuses its cookies, proxy, and browser configuration. Kernel does not delete a + caller-supplied browser. Render mode uses a temporary tab; website activity may + still change shared cookies and storage. When omitted, Kernel obtains isolated + browser capacity in the caller's account and releases it after retrieval. That + capacity is not retained for later interaction. Existing browser quotas apply. + """ + + mode: Literal["curl", "render"] + """Curl uses the browser HTTP stack without navigation or JavaScript execution. + + Render navigates a temporary page and extracts from its DOM. The selected mode + is used for the retrieval. + """ + + +class ContentSearchContentOptions(TypedDict, total=False): + browser: ContentSearchContentOptionsBrowser + """Invalid with source=provider. + + Supplying browser_id requires source=browser so the chosen identity is not + bypassed. + """ + + format: Literal["markdown", "text"] + + max_age_hours: int + """Maximum acceptable age of cached page content, measured from origin retrieval. + + 0 forces a live fetch. Governs the Kernel content cache, which is scoped to the + caller organization and project and separated by retrieval context; fetches + through a caller-supplied browser_id bypass that cache. Mapped to the provider + freshness control when source is provider and the provider supports one; + otherwise provider content age is reported as unknown via fetched_at. + """ + + max_chars: int + """Per-result Unicode character limit after extraction.""" + + source: Literal["auto", "provider", "browser"] + """ + provider uses the search provider's native content retrieval; browser fetches + each URL through a Kernel browser; auto prefers Kernel browser retrieval and + falls back to provider-native content when browser retrieval is unavailable or + unsuitable. Defaults to auto for both inline and deferred retrieval. Deferred + provider retrieval requires post_hoc capability; an explicit provider source + without it is a 400. Missing documents produce per-result unavailable outcomes, + not request failures. + """ + + timeout_ms: int + """Per-result deadline including capacity acquisition, retrieval, and extraction. + + Also bounded by the overall request deadline. + """ + + +Content: TypeAlias = Union[Literal[True], ContentSearchContentOptions] diff --git a/src/kernel/types/strategy_param.py b/src/kernel/types/strategy_param.py new file mode 100644 index 00000000..d755a092 --- /dev/null +++ b/src/kernel/types/strategy_param.py @@ -0,0 +1,60 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .provider_target_param import ProviderTargetParam + +__all__ = ["StrategyParam", "SearchAutoStrategy", "SearchPinnedStrategy", "SearchFallbackStrategy"] + + +class SearchAutoStrategy(TypedDict, total=False): + type: Required[Literal["auto"]] + """Let Kernel choose an eligible provider by capability fit.""" + + fallback_on: List[Literal["error", "timeout", "empty"]] + """ + Conditions that advance to the next provider under auto routing or an explicit + providers chain. Ignored when provider pins a single provider. error means a + retryable provider failure, including rate limiting, not invalid caller input or + caller quotas. empty means zero results after required filtering. An empty list + disables fallback. If every attempt is empty or fails, the response is the first + valid empty response with the full attempt trail, or a 502 if none succeeded. + """ + + provider_options: Iterable[ProviderTargetParam] + """ + Provider targets available to auto routing, each paired with typed native + options. Provider names must be unique. + """ + + +class SearchPinnedStrategy(TypedDict, total=False): + provider: Required[ProviderTargetParam] + """Provider name paired with its typed native options.""" + + type: Required[Literal["pinned"]] + """Use exactly the selected provider with no cross-provider fallback.""" + + +class SearchFallbackStrategy(TypedDict, total=False): + providers: Required[Iterable[ProviderTargetParam]] + """Ordered provider targets. Provider names must be unique.""" + + type: Required[Literal["fallback"]] + """Try providers in order and advance when fallback_on matches the outcome.""" + + fallback_on: List[Literal["error", "timeout", "empty"]] + """ + Conditions that advance to the next provider under auto routing or an explicit + providers chain. Ignored when provider pins a single provider. error means a + retryable provider failure, including rate limiting, not invalid caller input or + caller quotas. empty means zero results after required filtering. An empty list + disables fallback. If every attempt is empty or fails, the response is the first + valid empty response with the full attempt trail, or a 502 if none succeeded. + """ + + +StrategyParam: TypeAlias = Union[SearchAutoStrategy, SearchPinnedStrategy, SearchFallbackStrategy] diff --git a/src/kernel/types/usage.py b/src/kernel/types/usage.py new file mode 100644 index 00000000..76be908c --- /dev/null +++ b/src/kernel/types/usage.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .._models import BaseModel + +__all__ = ["Usage"] + + +class Usage(BaseModel): + content_fetches: int + """ + Number of result URLs for which a Kernel browser retrieval was attempted, + excluding cache-only hits. + """ + + results_count: int + """ + Number of result entries returned, including failed entries on the contents + endpoint. + """ + + cost: Optional[float] = None + """Total customer charge in USD when billing data is available.""" diff --git a/src/kernel/types/warning.py b/src/kernel/types/warning.py new file mode 100644 index 00000000..fc138975 --- /dev/null +++ b/src/kernel/types/warning.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .._models import BaseModel + +__all__ = ["Warning"] + + +class Warning(BaseModel): + code: str + """ + Examples: param_unsupported, preference_unsupported, max_results_clamped, + domains_truncated, recency_emulated, filter_emulated, date_filter_overridden, + provider_ineligible, fallback_failed, content_partial. + """ + + message: str + + param: Optional[str] = None + + provider: Optional[str] = None + + result_id: Optional[str] = None diff --git a/tests/api_resources/search/__init__.py b/tests/api_resources/search/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/search/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/search/test_contents.py b/tests/api_resources/search/test_contents.py new file mode 100644 index 00000000..941e6018 --- /dev/null +++ b/tests/api_resources/search/test_contents.py @@ -0,0 +1,150 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from kernel import Kernel, AsyncKernel + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestContents: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_fetch(self, client: Kernel) -> None: + content = client.search.contents.fetch( + id="srch_abc123", + ) + assert content is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_fetch_with_all_params(self, client: Kernel) -> None: + content = client.search.contents.fetch( + id="srch_abc123", + content={ + "browser": { + "browser_id": "browser_id", + "mode": "curl", + }, + "format": "markdown", + "max_age_hours": 0, + "max_chars": 100, + "source": "auto", + "timeout_ms": 1000, + }, + limit=1, + result_ids=["string"], + timeout_ms=1000, + ) + assert content is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_fetch(self, client: Kernel) -> None: + response = client.search.contents.with_raw_response.fetch( + id="srch_abc123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + content = response.parse() + assert content is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_fetch(self, client: Kernel) -> None: + with client.search.contents.with_streaming_response.fetch( + id="srch_abc123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + content = response.parse() + assert content is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_fetch(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.search.contents.with_raw_response.fetch( + id="", + ) + + +class TestAsyncContents: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_fetch(self, async_client: AsyncKernel) -> None: + content = await async_client.search.contents.fetch( + id="srch_abc123", + ) + assert content is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_fetch_with_all_params(self, async_client: AsyncKernel) -> None: + content = await async_client.search.contents.fetch( + id="srch_abc123", + content={ + "browser": { + "browser_id": "browser_id", + "mode": "curl", + }, + "format": "markdown", + "max_age_hours": 0, + "max_chars": 100, + "source": "auto", + "timeout_ms": 1000, + }, + limit=1, + result_ids=["string"], + timeout_ms=1000, + ) + assert content is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_fetch(self, async_client: AsyncKernel) -> None: + response = await async_client.search.contents.with_raw_response.fetch( + id="srch_abc123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + content = await response.parse() + assert content is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_fetch(self, async_client: AsyncKernel) -> None: + async with async_client.search.contents.with_streaming_response.fetch( + id="srch_abc123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + content = await response.parse() + assert content is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_fetch(self, async_client: AsyncKernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.search.contents.with_raw_response.fetch( + id="", + ) diff --git a/tests/api_resources/search/test_providers.py b/tests/api_resources/search/test_providers.py new file mode 100644 index 00000000..0f511099 --- /dev/null +++ b/tests/api_resources/search/test_providers.py @@ -0,0 +1,96 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from kernel import Kernel, AsyncKernel +from tests.utils import assert_matches_type +from kernel.types.search import ProviderListResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestProviders: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list(self, client: Kernel) -> None: + provider = client.search.providers.list() + assert_matches_type(ProviderListResponse, provider, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list_with_all_params(self, client: Kernel) -> None: + provider = client.search.providers.list( + slug="brave", + ) + assert_matches_type(ProviderListResponse, provider, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list(self, client: Kernel) -> None: + response = client.search.providers.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + provider = response.parse() + assert_matches_type(ProviderListResponse, provider, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Kernel) -> None: + with client.search.providers.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + provider = response.parse() + assert_matches_type(ProviderListResponse, provider, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncProviders: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncKernel) -> None: + provider = await async_client.search.providers.list() + assert_matches_type(ProviderListResponse, provider, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncKernel) -> None: + provider = await async_client.search.providers.list( + slug="brave", + ) + assert_matches_type(ProviderListResponse, provider, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncKernel) -> None: + response = await async_client.search.providers.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + provider = await response.parse() + assert_matches_type(ProviderListResponse, provider, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncKernel) -> None: + async with async_client.search.providers.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + provider = await response.parse() + assert_matches_type(ProviderListResponse, provider, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_search.py b/tests/api_resources/test_search.py new file mode 100644 index 00000000..ef559856 --- /dev/null +++ b/tests/api_resources/test_search.py @@ -0,0 +1,265 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from kernel import Kernel, AsyncKernel +from tests.utils import assert_matches_type +from kernel._utils import parse_date +from kernel.types.search import Search + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestSearch: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create(self, client: Kernel) -> None: + search = client.search.create( + query="x", + ) + assert_matches_type(Search, search, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create_with_all_params(self, client: Kernel) -> None: + search = client.search.create( + query="x", + content=True, + country="se", + end_date=parse_date("2019-12-27"), + exclude_domains=["string"], + include_domains=["string"], + include_raw=True, + language="language", + max_results=1, + recency="hour", + safe_search="off", + start_date=parse_date("2019-12-27"), + strategy={ + "type": "auto", + "fallback_on": ["error"], + "provider_options": [ + { + "provider": "brave", + "options": { + "count": 1, + "extra_snippets": True, + "goggles": "goggles", + "goggles_id": "goggles_id", + "include_fetch_metadata": True, + "offset": 0, + "operators": "operators", + "result_filter": "result_filter", + "search_lang": "search_lang", + "spellcheck": True, + "ui_lang": "ui_lang", + "units": "metric", + }, + } + ], + }, + strict_params=True, + timeout_ms=1000, + ) + assert_matches_type(Search, search, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_create(self, client: Kernel) -> None: + response = client.search.with_raw_response.create( + query="x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + search = response.parse() + assert_matches_type(Search, search, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_create(self, client: Kernel) -> None: + with client.search.with_streaming_response.create( + query="x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + search = response.parse() + assert_matches_type(Search, search, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_retrieve(self, client: Kernel) -> None: + search = client.search.retrieve( + "srch_abc123", + ) + assert_matches_type(Search, search, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_retrieve(self, client: Kernel) -> None: + response = client.search.with_raw_response.retrieve( + "srch_abc123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + search = response.parse() + assert_matches_type(Search, search, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_retrieve(self, client: Kernel) -> None: + with client.search.with_streaming_response.retrieve( + "srch_abc123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + search = response.parse() + assert_matches_type(Search, search, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_retrieve(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.search.with_raw_response.retrieve( + "", + ) + + +class TestAsyncSearch: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create(self, async_client: AsyncKernel) -> None: + search = await async_client.search.create( + query="x", + ) + assert_matches_type(Search, search, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncKernel) -> None: + search = await async_client.search.create( + query="x", + content=True, + country="se", + end_date=parse_date("2019-12-27"), + exclude_domains=["string"], + include_domains=["string"], + include_raw=True, + language="language", + max_results=1, + recency="hour", + safe_search="off", + start_date=parse_date("2019-12-27"), + strategy={ + "type": "auto", + "fallback_on": ["error"], + "provider_options": [ + { + "provider": "brave", + "options": { + "count": 1, + "extra_snippets": True, + "goggles": "goggles", + "goggles_id": "goggles_id", + "include_fetch_metadata": True, + "offset": 0, + "operators": "operators", + "result_filter": "result_filter", + "search_lang": "search_lang", + "spellcheck": True, + "ui_lang": "ui_lang", + "units": "metric", + }, + } + ], + }, + strict_params=True, + timeout_ms=1000, + ) + assert_matches_type(Search, search, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_create(self, async_client: AsyncKernel) -> None: + response = await async_client.search.with_raw_response.create( + query="x", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + search = await response.parse() + assert_matches_type(Search, search, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_create(self, async_client: AsyncKernel) -> None: + async with async_client.search.with_streaming_response.create( + query="x", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + search = await response.parse() + assert_matches_type(Search, search, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve(self, async_client: AsyncKernel) -> None: + search = await async_client.search.retrieve( + "srch_abc123", + ) + assert_matches_type(Search, search, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncKernel) -> None: + response = await async_client.search.with_raw_response.retrieve( + "srch_abc123", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + search = await response.parse() + assert_matches_type(Search, search, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncKernel) -> None: + async with async_client.search.with_streaming_response.retrieve( + "srch_abc123", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + search = await response.parse() + assert_matches_type(Search, search, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncKernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.search.with_raw_response.retrieve( + "", + ) From 762b97ac2f0e73568cdf0f668a7bca2fde8b7017 Mon Sep 17 00:00:00 2001 From: "kernel-internal[bot]" <260533166+kernel-internal[bot]@users.noreply.github.com> Date: Tue, 22 Sep 2026 15:07:57 +0000 Subject: [PATCH 7/7] release: 0.111.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 12 ++++++++++++ pyproject.toml | 2 +- src/kernel/_version.py | 2 +- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index c37434e9..2969a756 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.110.0" + ".": "0.111.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 67530bf8..587846b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## [0.111.0](https://github.com/kernel/kernel-python-sdk/compare/v0.110.0...v0.111.0) (2026-09-22) + + +### Features + +* Allow managed auth logins to disable learned skills ([e230ce3](https://github.com/kernel/kernel-python-sdk/commit/e230ce3a684ce7723256170443ba0b84b08310a4)) +* Distinguish optimistic managed auth reauth ([41059ae](https://github.com/kernel/kernel-python-sdk/commit/41059ae6d345b924d7e508e43a8b1d0842c58556)) +* Implement Search API v1 providers ([76b3d88](https://github.com/kernel/kernel-python-sdk/commit/76b3d8871e29d47cfda20f68ab23152daf1790c6)) +* Persist stable managed auth completion timestamps ([17a7960](https://github.com/kernel/kernel-python-sdk/commit/17a7960d9304fdceb54d59b09277651b6166fdb1)) +* Publish restricted_route_unavailable and unknown proxy_error codes ([64805ae](https://github.com/kernel/kernel-python-sdk/commit/64805ae68f0978264fb77801e8e94a470a039e94)) +* Support native prepared Adyen Sessions checkout ([5f2df0a](https://github.com/kernel/kernel-python-sdk/commit/5f2df0a4170aa146eabb23f576195d1a06621925)) + ## [0.110.0](https://github.com/kernel/kernel-python-sdk/compare/v0.109.0...v0.110.0) (2026-09-18) diff --git a/pyproject.toml b/pyproject.toml index ef25af35..c8bc1630 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "kernel" -version = "0.110.0" +version = "0.111.0" description = "The official Python library for the kernel API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/kernel/_version.py b/src/kernel/_version.py index 78e78477..bd2462d5 100644 --- a/src/kernel/_version.py +++ b/src/kernel/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "kernel" -__version__ = "0.110.0" # x-release-please-version +__version__ = "0.111.0" # x-release-please-version