Compare commits

...

45 Commits

Author SHA1 Message Date
Twisha Bansal
acf56382d7 add comment 2026-02-11 13:31:15 +05:30
Twisha Bansal
fe2dd13968 fix docs 2026-02-11 13:29:33 +05:30
Twisha Bansal
bf3fb86fd2 remove extra file 2026-02-11 13:28:47 +05:30
Twisha Bansal
d3d62a76d4 remove golden.txt file 2026-02-11 13:28:10 +05:30
Twisha Bansal
8fa8840d77 Merge branch 'main' into adk-python-processing 2026-02-11 13:26:28 +05:30
Twisha Bansal
1ecc3cd604 add to docs 2026-02-09 12:27:03 +05:30
Twisha Bansal
acbb9c15ed Update agent.py 2026-02-09 11:23:58 +05:30
Twisha Bansal
7e175c62a0 Update docs/en/samples/pre_post_processing/python/adk/agent.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-09 11:23:23 +05:30
Twisha Bansal
b0947b2adc Update docs/en/samples/pre_post_processing/python/adk/agent.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-09 11:22:51 +05:30
Twisha Bansal
3665b78a4b Update docs/en/samples/pre_post_processing/python/adk/agent.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-09 11:22:37 +05:30
Twisha Bansal
d7d5e75324 Update docs/en/samples/pre_post_processing/python/adk/agent.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-09 11:22:00 +05:30
Twisha Bansal
ad05a12a67 add requirements file 2026-02-09 11:19:34 +05:30
Twisha Bansal
0b23fc950f adk working file 2026-02-09 11:13:09 +05:30
Twisha Bansal
632dd10180 remove license header from docs 2026-02-05 12:14:23 +05:30
Twisha Bansal
9771aa47df Update python.md 2026-02-04 14:58:53 +05:30
Twisha Bansal
a212aedd19 more reliable tests 2026-02-03 18:30:33 +05:30
Twisha Bansal
9210e5555c unnecessary file change removal 2026-02-03 18:15:05 +05:30
Twisha Bansal
b43af71793 fix merge issues 2026-02-03 18:13:49 +05:30
Twisha Bansal
da1f463dd1 more reliable agent queries 2026-02-03 18:08:59 +05:30
Twisha Bansal
3265f7e3a6 better tests 2026-02-03 18:08:59 +05:30
Twisha Bansal
336743f747 add more test case + remove flaky test 2026-02-03 18:08:59 +05:30
Twisha Bansal
911069ae8d Fix tests 2026-02-03 18:08:58 +05:30
Twisha Bansal
cee59d52c3 update requirements file 2026-02-03 18:08:58 +05:30
Twisha Bansal
9517daba09 license fix 2026-02-03 18:08:57 +05:30
Twisha Bansal
3c61ee0597 add sample tests 2026-02-03 18:08:09 +05:30
Twisha Bansal
19271eb9ee docs: clarify that pre/post processing is an orchestration feature
Explicitly document that these capabilities are typically provided by orchestration frameworks (like LangChain, LangGraph) rather than the Toolbox SDK itself, but that Toolbox tools are designed to leverage them.
2026-02-03 18:08:09 +05:30
Twisha Bansal
3a150c77ca Highlight tool level processing 2026-02-03 18:08:09 +05:30
Twisha Bansal
ca6f31a192 fix import 2026-02-03 18:08:09 +05:30
Twisha Bansal
d7faf7700f logic fix 2026-02-03 18:08:09 +05:30
Twisha Bansal
37a60ea2a6 Update docs/en/samples/pre_post_processing/python/langchain/agent.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-03 18:08:09 +05:30
Twisha Bansal
8de16976ae license header 2026-02-03 18:08:08 +05:30
Twisha Bansal
49cb2f39f7 lint 2026-02-03 18:08:08 +05:30
Twisha Bansal
f169874e53 gemini code review 2026-02-03 18:08:08 +05:30
Twisha Bansal
db8c3a3c77 remove not needed files 2026-02-03 18:08:08 +05:30
Twisha Bansal
8b33b0c67f docs: add pre/post processing docs for langchain python 2026-02-03 18:08:08 +05:30
Twisha Bansal
35fa73516b rename file 2026-02-03 15:45:03 +05:30
Twisha Bansal
66df3bfd21 move file around fix 2026-02-03 15:40:49 +05:30
Twisha Bansal
73e0edc3cd move files around 2026-02-03 15:36:56 +05:30
Twisha Bansal
3f32a9aab6 fix paths 2026-02-03 15:29:18 +05:30
Twisha Bansal
28006fc9b2 move files around 2026-02-03 15:27:43 +05:30
Twisha Bansal
56c69131b4 Update run_tests.sh 2026-02-03 15:09:07 +05:30
Twisha Bansal
ad4a509340 Apply suggestion from @gemini-code-assist[bot]
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-03 14:16:47 +05:30
Twisha Bansal
d39acac96c Apply suggestion from @gemini-code-assist[bot]
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-03 14:16:36 +05:30
Twisha Bansal
6df2ad28a9 Apply suggestion from @gemini-code-assist[bot]
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-03 14:15:54 +05:30
Twisha Bansal
8416378613 refactor: consolidate quickstart tests into universal runner 2026-02-03 14:11:54 +05:30
3 changed files with 148 additions and 1 deletions

View File

@@ -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.

View File

@@ -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 before_tool_callback(
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 after_tool_callback(
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=before_tool_callback,
after_tool_callback=after_tool_callback,
)
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())

View File

@@ -0,0 +1,3 @@
google-adk[toolbox]==1.23.0
toolbox-adk==0.5.8
google-genai==1.62.0