Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
02311e8
docs: fix query for langchain pre and post processing docs
twishabansal Feb 20, 2026
55d791f
refactor: consolidate quickstart tests into universal runner
twishabansal Feb 3, 2026
5f7b8fc
Apply suggestion from @gemini-code-assist[bot]
twishabansal Feb 3, 2026
372ef76
Apply suggestion from @gemini-code-assist[bot]
twishabansal Feb 3, 2026
4b90565
Apply suggestion from @gemini-code-assist[bot]
twishabansal Feb 3, 2026
5d2bc98
Update run_tests.sh
twishabansal Feb 3, 2026
9ff6299
move files around
twishabansal Feb 3, 2026
a2ed32e
fix paths
twishabansal Feb 3, 2026
7001ac3
move files around
twishabansal Feb 3, 2026
aca92c6
move file around fix
twishabansal Feb 3, 2026
65e8c6b
rename file
twishabansal Feb 3, 2026
cb07da4
docs: add pre/post processing docs for langchain python
twishabansal Jan 28, 2026
e6028ab
remove not needed files
twishabansal Jan 28, 2026
5b7868b
gemini code review
twishabansal Jan 28, 2026
f755136
lint
twishabansal Jan 28, 2026
1f49cd4
license header
twishabansal Jan 28, 2026
4884904
Update docs/en/samples/pre_post_processing/python/langchain/agent.py
twishabansal Jan 28, 2026
c9914cd
logic fix
twishabansal Jan 28, 2026
3ea0b4d
fix import
twishabansal Jan 28, 2026
e65c0d4
Highlight tool level processing
twishabansal Jan 29, 2026
e24ba33
docs: clarify that pre/post processing is an orchestration feature
twishabansal Jan 30, 2026
d45215b
add sample tests
twishabansal Feb 3, 2026
c228b83
license fix
twishabansal Feb 3, 2026
2aa6804
update requirements file
twishabansal Feb 3, 2026
7429f8b
Fix tests
twishabansal Feb 3, 2026
c428678
add more test case + remove flaky test
twishabansal Feb 3, 2026
db19ec4
better tests
twishabansal Feb 3, 2026
cecdfd9
more reliable agent queries
twishabansal Feb 3, 2026
09557cd
fix merge issues
twishabansal Feb 3, 2026
32950cc
unnecessary file change removal
twishabansal Feb 3, 2026
6ca0e2d
more reliable tests
twishabansal Feb 3, 2026
e6064df
Update python.md
twishabansal Feb 4, 2026
d7b40ca
remove license header from docs
twishabansal Feb 5, 2026
710eb95
adk working file
twishabansal Feb 9, 2026
f1f5e33
add requirements file
twishabansal Feb 9, 2026
02410f6
Update docs/en/samples/pre_post_processing/python/adk/agent.py
twishabansal Feb 9, 2026
1e5d230
Update docs/en/samples/pre_post_processing/python/adk/agent.py
twishabansal Feb 9, 2026
9244e91
Update docs/en/samples/pre_post_processing/python/adk/agent.py
twishabansal Feb 9, 2026
ae9fc99
Update docs/en/samples/pre_post_processing/python/adk/agent.py
twishabansal Feb 9, 2026
4ae080c
Update agent.py
twishabansal Feb 9, 2026
5694bde
add to docs
twishabansal Feb 9, 2026
d764b77
remove golden.txt file
twishabansal Feb 11, 2026
b0d9e8b
remove extra file
twishabansal Feb 11, 2026
162a88d
fix docs
twishabansal Feb 11, 2026
a9f52b7
add comment
twishabansal Feb 11, 2026
06540ea
update method names
twishabansal Feb 18, 2026
8791da8
revert changes
twishabansal Feb 20, 2026
7a8f352
Update python.md
twishabansal Feb 20, 2026
d60af29
Update agent.py
twishabansal Feb 20, 2026
e237d50
Merge branch 'main' into adk-python-processing
twishabansal Feb 20, 2026
7f23059
Merge branch 'main' into adk-python-processing
twishabansal Feb 22, 2026
c22486b
Merge branch 'main' into adk-python-processing
twishabansal Feb 24, 2026
e9b8e82
Merge branch 'main' into adk-python-processing
twishabansal Feb 25, 2026
692740a
Merge branch 'main' into adk-python-processing
twishabansal Feb 26, 2026
dbe1c2d
Merge branch 'main' into adk-python-processing
twishabansal Feb 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion docs/en/samples/pre_post_processing/python.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,14 @@ This guide demonstrates how to implement these patterns in your Toolbox applicat

{{< tabpane persist=header >}}
{{% tab header="ADK" text=true %}}
Coming soon.
The following example demonstrates how to use `ToolboxToolset` with ADK's pre and post processing hooks to implement pre and post processing for tool calls.

```py
{{< include "python/adk/agent.py" >}}
```
You can also add model-level (`before_model_callback`, `after_model_callback`) and agent-level (`before_agent_callback`, `after_agent_callback`) hooks to intercept messages at different stages of the execution loop.

For more information, see the [ADK Callbacks documentation](https://google.github.io/adk-docs/callbacks/types-of-callbacks/).
{{% /tab %}}
{{% tab header="Langchain" text=true %}}
The following example demonstrates how to use `ToolboxClient` with LangChain's middleware to implement pre- and post- processing for tool calls.
Expand Down
137 changes: 137 additions & 0 deletions docs/en/samples/pre_post_processing/python/adk/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import asyncio
from datetime import datetime
from typing import Any, Dict, Optional
from copy import deepcopy

from google.adk import Agent
from google.adk.apps import App
from google.adk.runners import Runner
from google.adk.sessions.in_memory_session_service import InMemorySessionService
from google.adk.tools.tool_context import ToolContext
from google.genai import types
from toolbox_adk import CredentialStrategy, ToolboxToolset, ToolboxTool

SYSTEM_PROMPT = """
You're a helpful hotel assistant. You handle hotel searching, booking and
cancellations. When the user searches for a hotel, mention it's name, id,
location and price tier. Always mention hotel ids while performing any
searches. This is very important for any operations. For any bookings or
cancellations, please provide the appropriate confirmation. Be sure to
update checkin or checkout dates if mentioned by the user.
Don't ask for confirmations from the user.
"""


# Pre processing
async def enfore_business_rules(
tool: ToolboxTool, args: Dict[str, Any], tool_context: ToolContext
) -> Optional[Dict[str, Any]]:
"""
Callback fired before a tool is executed.
Enforces business logic: Max stay duration is 14 days.
"""
tool_name = tool.name
print(f"POLICY CHECK: Intercepting '{tool_name}'")

if tool_name == "update-hotel" and "checkin_date" in args and "checkout_date" in args:
start = datetime.fromisoformat(args["checkin_date"])
end = datetime.fromisoformat(args["checkout_date"])
duration = (end - start).days

if duration > 14:
print("BLOCKED: Stay too long")
return {"result": "Error: Maximum stay duration is 14 days."}
return None


# Post processing
async def enrich_response(
tool: ToolboxTool,
args: Dict[str, Any],
tool_context: ToolContext,
tool_response: Any,
) -> Optional[Any]:
"""
Callback fired after a tool execution.
Enriches response for successful bookings.
"""
if isinstance(tool_response, dict):
result = tool_response.get("result", "")
elif isinstance(tool_response, str):
result = tool_response
else:
return None

tool_name = tool.name
if isinstance(result, str) and "Error" not in result:
if tool_name == "book-hotel":
loyalty_bonus = 500
enriched_result = f"Booking Confirmed!\n You earned {loyalty_bonus} Loyalty Points with this stay.\n\nSystem Details: {result}"

if isinstance(tool_response, dict):
modified_response = deepcopy(tool_response)
modified_response["result"] = enriched_result
return modified_response
else:
return enriched_result
return None


async def run_chat_turn(
runner: Runner, session_id: str, user_id: str, message_text: str
):
"""Executes a single chat turn and prints the interaction."""
print(f"\nUSER: '{message_text}'")
response_text = ""
async for event in runner.run_async(
user_id=user_id,
session_id=session_id,
new_message=types.Content(role="user", parts=[types.Part(text=message_text)]),
):
if event.content and event.content.parts:
for part in event.content.parts:
if part.text:
response_text += part.text

print(f"AI: {response_text}")


async def main():
toolset = ToolboxToolset(
server_url="http://127.0.0.1:5000",
toolset_name="my-toolset",
credentials=CredentialStrategy.toolbox_identity(),
)
tools = await toolset.get_tools()
root_agent = Agent(
name="root_agent",
model="gemini-2.5-flash",
instruction=SYSTEM_PROMPT,
tools=tools,
# add any pre and post processing callbacks
before_tool_callback=enfore_business_rules,
after_tool_callback=enrich_response,
)
app = App(root_agent=root_agent, name="my_agent")
runner = Runner(app=app, session_service=InMemorySessionService())
session_id = "test-session"
user_id = "test-user"
await runner.session_service.create_session(
app_name=app.name, user_id=user_id, session_id=session_id
)

# First turn: Successful booking
await run_chat_turn(runner, session_id, user_id, "Book hotel with id 3.")
print("-" * 50)
# Second turn: Policy violation (stay > 14 days)
await run_chat_turn(
runner,
session_id,
user_id,
"Book a hotel with id 5 with checkin date 2025-01-18 and checkout date 2025-02-10",
)
await toolset.close()


if __name__ == "__main__":
asyncio.run(main())
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
google-adk[toolbox]==1.23.0
toolbox-adk==0.5.8
google-genai==1.62.0
Loading