Skip to content

Commit 4127af9

Browse files
wanlin31copybara-github
authored andcommitted
chore: internal update
PiperOrigin-RevId: 934028508
1 parent 85fbda3 commit 4127af9

80 files changed

Lines changed: 3935 additions & 856 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

google/genai/_gaos/_hooks/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,8 @@
1818

1919
from .sdkhooks import *
2020
from .types import *
21+
from .asynctypes import *
22+
from .asyncsdkhooks import *
23+
from .adapters import *
2124
from .registration import *
25+
from .asyncregistration import *
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
# pyformat: disable
16+
17+
"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
18+
19+
from .asynctypes import (
20+
AsyncAfterErrorHook,
21+
AsyncAfterParseErrorHook,
22+
AsyncAfterSuccessHook,
23+
AsyncBeforeRequestHook,
24+
)
25+
from .types import (
26+
AfterErrorContext,
27+
AfterErrorHook,
28+
AfterParseErrorContext,
29+
AfterParseErrorHook,
30+
AfterSuccessContext,
31+
AfterSuccessHook,
32+
BeforeRequestContext,
33+
BeforeRequestHook,
34+
)
35+
import asyncio
36+
import httpx
37+
from typing import Optional, Tuple, Union
38+
39+
# ============================================================================
40+
# Sync to Async Adapters
41+
# ============================================================================
42+
# PERFORMANCE CONSIDERATIONS:
43+
# - Sync-to-Async adapters use asyncio.to_thread() / run_in_executor() to run
44+
# sync hooks in a thread pool. This adds threading overhead and context
45+
# switching costs.
46+
# - Async-to-Sync adapters use asyncio.run() which creates a new event loop
47+
# for each invocation. This has significant overhead.
48+
# - For optimal performance, register hooks that match the execution context:
49+
# * Use native async hooks (AsyncBeforeRequestHook, etc.) for async methods
50+
# * Use native sync hooks (BeforeRequestHook, etc.) for sync methods
51+
# - Adapters are provided for convenience and backward compatibility, but
52+
# native implementations are strongly recommended for production use.
53+
# ============================================================================
54+
55+
56+
class SyncToAsyncBeforeRequestAdapter(AsyncBeforeRequestHook):
57+
"""Adapts a synchronous BeforeRequestHook to work in async contexts.
58+
59+
PERFORMANCE WARNING: Uses asyncio.to_thread() to run the sync hook in a thread pool.
60+
This introduces:
61+
- Thread pool overhead for spawning/managing worker threads
62+
- Context switching between the async event loop and worker threads
63+
- Memory overhead for thread-local storage
64+
- Potential thread pool exhaustion under high concurrency
65+
66+
For performance-critical applications, prefer registering native AsyncBeforeRequestHook
67+
implementations instead of relying on this adapter.
68+
"""
69+
70+
def __init__(self, sync_hook: BeforeRequestHook):
71+
self._sync_hook = sync_hook
72+
73+
async def before_request(
74+
self, hook_ctx: BeforeRequestContext, request: httpx.Request
75+
) -> Union[httpx.Request, Exception]:
76+
return await asyncio.to_thread(
77+
self._sync_hook.before_request, hook_ctx, request
78+
)
79+
80+
81+
class SyncToAsyncAfterSuccessAdapter(AsyncAfterSuccessHook):
82+
"""Adapts a synchronous AfterSuccessHook to work in async contexts.
83+
84+
PERFORMANCE WARNING: Uses asyncio.to_thread() to run the sync hook in a thread pool.
85+
This introduces threading overhead and context switching costs. Prefer native
86+
AsyncAfterSuccessHook implementations for better performance.
87+
"""
88+
89+
def __init__(self, sync_hook: AfterSuccessHook):
90+
self._sync_hook = sync_hook
91+
92+
async def after_success(
93+
self, hook_ctx: AfterSuccessContext, response: httpx.Response
94+
) -> Union[httpx.Response, Exception]:
95+
return await asyncio.to_thread(
96+
self._sync_hook.after_success, hook_ctx, response
97+
)
98+
99+
100+
class SyncToAsyncAfterErrorAdapter(AsyncAfterErrorHook):
101+
"""Adapts a synchronous AfterErrorHook to work in async contexts.
102+
103+
PERFORMANCE WARNING: Uses asyncio.to_thread() to run the sync hook in a thread pool.
104+
This introduces threading overhead and context switching costs. Prefer native
105+
AsyncAfterErrorHook implementations for better performance.
106+
"""
107+
108+
def __init__(self, sync_hook: AfterErrorHook):
109+
self._sync_hook = sync_hook
110+
111+
async def after_error(
112+
self,
113+
hook_ctx: AfterErrorContext,
114+
response: Optional[httpx.Response],
115+
error: Optional[Exception],
116+
) -> Union[Tuple[Optional[httpx.Response], Optional[Exception]], Exception]:
117+
return await asyncio.to_thread(
118+
self._sync_hook.after_error, hook_ctx, response, error
119+
)
120+
121+
122+
class SyncToAsyncAfterParseErrorAdapter(AsyncAfterParseErrorHook):
123+
"""Adapts a synchronous AfterParseErrorHook to work in async contexts."""
124+
125+
def __init__(self, sync_hook: AfterParseErrorHook):
126+
self._sync_hook = sync_hook
127+
128+
async def after_parse_error(
129+
self,
130+
hook_ctx: AfterParseErrorContext,
131+
response: httpx.Response,
132+
error: Exception,
133+
) -> Exception:
134+
return await asyncio.to_thread(
135+
self._sync_hook.after_parse_error, hook_ctx, response, error
136+
)
137+
138+
139+
# ============================================================================
140+
# Async to Sync Adapters
141+
# ============================================================================
142+
143+
144+
class AsyncToSyncBeforeRequestAdapter(BeforeRequestHook):
145+
"""Adapts an async BeforeRequestHook to work in sync contexts.
146+
147+
PERFORMANCE WARNING: Uses asyncio.run() which creates and tears down a new event
148+
loop for each invocation. This has significant overhead:
149+
- Event loop creation/destruction costs
150+
- Loss of connection pooling and keep-alive benefits
151+
- Cannot leverage existing event loop infrastructure
152+
- Not suitable for high-frequency operations
153+
154+
This adapter is primarily for compatibility in mixed sync/async codebases.
155+
Strongly prefer native sync hooks (BeforeRequestHook) for production use.
156+
"""
157+
158+
def __init__(self, async_hook: AsyncBeforeRequestHook):
159+
self._async_hook = async_hook
160+
161+
def before_request(
162+
self, hook_ctx: BeforeRequestContext, request: httpx.Request
163+
) -> Union[httpx.Request, Exception]:
164+
return asyncio.run(self._async_hook.before_request(hook_ctx, request))
165+
166+
167+
class AsyncToSyncAfterSuccessAdapter(AfterSuccessHook):
168+
"""Adapts an async AfterSuccessHook to work in sync contexts.
169+
170+
PERFORMANCE WARNING: Uses asyncio.run() which creates and tears down a new event
171+
loop for each invocation. This has significant overhead. Strongly prefer native
172+
sync hooks (AfterSuccessHook) for production use.
173+
"""
174+
175+
def __init__(self, async_hook: AsyncAfterSuccessHook):
176+
self._async_hook = async_hook
177+
178+
def after_success(
179+
self, hook_ctx: AfterSuccessContext, response: httpx.Response
180+
) -> Union[httpx.Response, Exception]:
181+
return asyncio.run(self._async_hook.after_success(hook_ctx, response))
182+
183+
184+
class AsyncToSyncAfterErrorAdapter(AfterErrorHook):
185+
"""Adapts an async AfterErrorHook to work in sync contexts.
186+
187+
PERFORMANCE WARNING: Uses asyncio.run() which creates and tears down a new event
188+
loop for each invocation. This has significant overhead. Strongly prefer native
189+
sync hooks (AfterErrorHook) for production use.
190+
"""
191+
192+
def __init__(self, async_hook: AsyncAfterErrorHook):
193+
self._async_hook = async_hook
194+
195+
def after_error(
196+
self,
197+
hook_ctx: AfterErrorContext,
198+
response: Optional[httpx.Response],
199+
error: Optional[Exception],
200+
) -> Union[Tuple[Optional[httpx.Response], Optional[Exception]], Exception]:
201+
return asyncio.run(self._async_hook.after_error(hook_ctx, response, error))
202+
203+
204+
class AsyncToSyncAfterParseErrorAdapter(AfterParseErrorHook):
205+
"""Adapts an async AfterParseErrorHook to work in sync contexts."""
206+
207+
def __init__(self, async_hook: AsyncAfterParseErrorHook):
208+
self._async_hook = async_hook
209+
210+
def after_parse_error(
211+
self,
212+
hook_ctx: AfterParseErrorContext,
213+
response: httpx.Response,
214+
error: Exception,
215+
) -> Exception:
216+
return asyncio.run(
217+
self._async_hook.after_parse_error(hook_ctx, response, error)
218+
)
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
# pyformat: disable
16+
17+
from .asynctypes import AsyncHooks
18+
from .adapters import (
19+
SyncToAsyncAfterErrorAdapter,
20+
SyncToAsyncAfterParseErrorAdapter,
21+
SyncToAsyncBeforeRequestAdapter,
22+
)
23+
from .google_genai_auth import GoogleGenAIAuthHook
24+
from ..lib.compat_errors import CompatErrorHook
25+
from typing import cast
26+
from .types import AfterErrorHook, AfterParseErrorHook
27+
28+
29+
# This file is only ever generated once on the first generation and then is free to be modified.
30+
# Any async hooks you wish to add should be registered in the init_async_hooks function.
31+
# Feel free to define them in this file or in separate files in the hooks folder.
32+
33+
34+
def init_async_hooks(hooks: AsyncHooks):
35+
# pylint: disable=unused-argument
36+
"""Add async hooks by calling hooks.register_{sdk_init/before_request/after_success/after_error}_hook
37+
with an instance of a hook that implements that specific AsyncHook interface.
38+
Async hooks are registered per SDK instance, and are valid for the lifetime of the SDK instance.
39+
40+
Async hooks are invoked in async contexts and allow you to use async/await for non-blocking I/O operations.
41+
42+
Example:
43+
from .asynctypes import AsyncBeforeRequestHook, BeforeRequestContext
44+
import httpx
45+
46+
class MyAsyncHook(AsyncBeforeRequestHook):
47+
async def before_request(self, hook_ctx: BeforeRequestContext, request: httpx.Request):
48+
# Perform async operations
49+
token = await fetch_token_from_external_service()
50+
51+
# Modify request
52+
headers = dict(request.headers)
53+
headers["Authorization"] = f"Bearer {token}"
54+
return httpx.Request(request.method, request.url, headers=headers, content=request.content)
55+
56+
hooks.register_before_request_hook(MyAsyncHook())
57+
"""
58+
hooks.register_before_request_hook(
59+
SyncToAsyncBeforeRequestAdapter(GoogleGenAIAuthHook())
60+
)
61+
hooks.register_after_error_hook(
62+
SyncToAsyncAfterErrorAdapter(cast(AfterErrorHook, CompatErrorHook()))
63+
)
64+
hooks.register_after_parse_error_hook(
65+
SyncToAsyncAfterParseErrorAdapter(cast(AfterParseErrorHook, CompatErrorHook()))
66+
)
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
# pyformat: disable
16+
17+
"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
18+
19+
import httpx
20+
from .asynctypes import (
21+
AsyncBeforeRequestHook,
22+
AsyncAfterSuccessHook,
23+
AsyncAfterErrorHook,
24+
AsyncAfterParseErrorHook,
25+
AsyncHooks,
26+
)
27+
from .types import (
28+
BeforeRequestContext,
29+
AfterSuccessContext,
30+
AfterErrorContext,
31+
AfterParseErrorContext,
32+
)
33+
from typing import List, Optional, Tuple
34+
35+
36+
class AsyncSDKHooks(AsyncHooks):
37+
def __init__(self) -> None:
38+
self.before_request_hooks: List[AsyncBeforeRequestHook] = []
39+
self.after_success_hooks: List[AsyncAfterSuccessHook] = []
40+
self.after_error_hooks: List[AsyncAfterErrorHook] = []
41+
self.after_parse_error_hooks: List[AsyncAfterParseErrorHook] = []
42+
43+
def register_before_request_hook(self, hook: AsyncBeforeRequestHook) -> None:
44+
self.before_request_hooks.append(hook)
45+
46+
def register_after_success_hook(self, hook: AsyncAfterSuccessHook) -> None:
47+
self.after_success_hooks.append(hook)
48+
49+
def register_after_error_hook(self, hook: AsyncAfterErrorHook) -> None:
50+
self.after_error_hooks.append(hook)
51+
52+
def register_after_parse_error_hook(self, hook: AsyncAfterParseErrorHook) -> None:
53+
self.after_parse_error_hooks.append(hook)
54+
55+
async def before_request(
56+
self, hook_ctx: BeforeRequestContext, request: httpx.Request
57+
) -> httpx.Request:
58+
for hook in self.before_request_hooks:
59+
out = await hook.before_request(hook_ctx, request)
60+
if isinstance(out, Exception):
61+
raise out
62+
request = out
63+
64+
return request
65+
66+
async def after_success(
67+
self, hook_ctx: AfterSuccessContext, response: httpx.Response
68+
) -> httpx.Response:
69+
for hook in self.after_success_hooks:
70+
out = await hook.after_success(hook_ctx, response)
71+
if isinstance(out, Exception):
72+
raise out
73+
response = out
74+
return response
75+
76+
async def after_error(
77+
self,
78+
hook_ctx: AfterErrorContext,
79+
response: Optional[httpx.Response],
80+
error: Optional[Exception],
81+
) -> Tuple[Optional[httpx.Response], Optional[Exception]]:
82+
for hook in self.after_error_hooks:
83+
result = await hook.after_error(hook_ctx, response, error)
84+
if isinstance(result, Exception):
85+
raise result
86+
response, error = result
87+
return response, error
88+
89+
async def after_parse_error(
90+
self,
91+
hook_ctx: AfterParseErrorContext,
92+
response: httpx.Response,
93+
error: Exception,
94+
) -> Exception:
95+
for hook in self.after_parse_error_hooks:
96+
error = await hook.after_parse_error(hook_ctx, response, error)
97+
return error

0 commit comments

Comments
 (0)