Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
195 commits
Select commit Hold shift + click to select a range
173085d
feat: initial implementation of ADK middleware for AG-UI Protocol
mefogle Jul 4, 2025
b9c2977
feat: major refactoring and enhancements to ADK middleware
mefogle Jul 5, 2025
40ef583
chore: update all python3 references to python for consistency
mefogle Jul 5, 2025
04d4cda
feat: add default app_name behavior using agent name from registry
mefogle Jul 5, 2025
6b7108a
Merge branch 'ag-ui-protocol:main' into adk-middleware
contextablemark Jul 5, 2025
865f7c7
refactor: move all tests to tests/ directory for better organization
mefogle Jul 5, 2025
86094a4
fix: update changelog for test reorganization
mefogle Jul 5, 2025
5f73078
Updating requirements.txt.
mefogle Jul 5, 2025
d81d82b
Added version for asyncio.
mefogle Jul 5, 2025
11aca27
docs: update README to reflect current implementation status
mefogle Jul 5, 2025
aa04096
feat: implement full pytest compatibility for test suite
mefogle Jul 5, 2025
2683a30
fix: remove accidentally committed ADK_Middleware directory and CLAUD…
mefogle Jul 5, 2025
a1ebaa3
docs: update README feature status to reflect current implementation
mefogle Jul 5, 2025
555a3e3
refactor: separate dev dependencies and fix README examples
mefogle Jul 6, 2025
589303c
feat: add automatic session memory and refactor session management
mefogle Jul 6, 2025
eebd544
refactor: simplify logging system to use standard Python logging
mefogle Jul 6, 2025
51b663f
fix adk_middleware python module and added adk-middleware demo in doj…
syedfakher27 Jul 6, 2025
afbaf00
import change
syedfakher27 Jul 7, 2025
246bee6
venv in git ignore
syedfakher27 Jul 7, 2025
e41471d
fixing test adk_middleware imports
syedfakher27 Jul 7, 2025
ad407cb
all test cases fixed
syedfakher27 Jul 7, 2025
41dd2c1
Merge pull request #1 from syedfakher27/adk-middleware
contextablemark Jul 7, 2025
be845b3
Update documentation and fix session attribute name
mefogle Jul 7, 2025
5c89c7f
Fix test failures: Update attribute name references
mefogle Jul 7, 2025
443ea4d
Fix test failures: Update attribute name references
mefogle Jul 7, 2025
e14f0b6
Fix session manager last_update_time timestamp bug
mefogle Jul 7, 2025
d9d712d
Merge adk-middleware branch to get session manager timestamp fix
mefogle Jul 7, 2025
0e40baa
Add complete bidirectional tool support for ADK middleware
mefogle Jul 7, 2025
64b93f0
Merge pull request #2 from Contextable/feature/tool-support
contextablemark Jul 7, 2025
c053ed6
added tool based generative ui demo
syedfakher27 Jul 8, 2025
f0dea33
print remove
syedfakher27 Jul 8, 2025
e2d06f0
fix tool wrapper test case
syedfakher27 Jul 8, 2025
4b8d173
fix test_endpoint
syedfakher27 Jul 8, 2025
9429aac
test cases fixed
syedfakher27 Jul 8, 2025
05c847e
Update typescript-sdk/integrations/adk-middleware/src/adk_middleware/…
contextablemark Jul 8, 2025
e1fa842
Merge pull request #3 from syedfakher27/adk-middleware
contextablemark Jul 8, 2025
2eb3f28
Release 0.3.2: Hybrid tool execution model with per-tool configuration
mefogle Jul 8, 2025
90deb89
Merge pull request #4 from Contextable/feature/hybrid-tool-execution
contextablemark Jul 8, 2025
5c59fc3
Comprehensive unit test coverage improvements for low-coverage modules
mefogle Jul 8, 2025
eb9d998
Update changelog for improved test coverage
mefogle Jul 8, 2025
64f6a82
Merge pull request #5 from Contextable/improve-unit-test-coverage
contextablemark Jul 8, 2025
eeb47f1
tool submission changes for ADK middleware
syedfakher27 Jul 9, 2025
aae9227
refactor: align tool behavior with ADK standards and fix test coverage
mefogle Jul 9, 2025
0765e9c
Complete ADK middleware test suite fixes - achieve 100% test pass rate
mefogle Jul 10, 2025
4ab8703
Merge pull request #7 from Contextable/refactor-adk-tool-implementation
contextablemark Jul 10, 2025
befc12c
feat: simplify to all-long-running tool architecture with critical bu…
mefogle Jul 11, 2025
517593d
prompt change
syedfakher27 Jul 11, 2025
801bcd7
feat: merge adk-middleware improvements into all-long-running archite…
mefogle Jul 11, 2025
88b1a32
Merge pull request #8 from Contextable/feature/all-long-running-tools…
contextablemark Jul 11, 2025
4a49c62
Merge branch 'ag-ui-protocol:main' into adk-middleware
contextablemark Jul 11, 2025
0f7e780
Merge branch 'ag-ui-protocol:main' into adk-middleware
contextablemark Jul 12, 2025
520e442
feat: add GitHub Actions CI workflow for ADK middleware
mefogle Jul 13, 2025
e74ffc2
Merge pull request #15 from Contextable/feature/ci-integration
contextablemark Jul 13, 2025
e2bb46b
feat: fix memory persistence and tool ID mapping (v0.4.1)
mefogle Jul 13, 2025
9e39785
Merge pull request #16 from Contextable/feature/memory-bank
contextablemark Jul 13, 2025
077989d
Adding files that were left out of PR #16 and removing unusable workf…
mefogle Jul 13, 2025
dacd7cb
Merge pull request #17 from Contextable/feature/memory-bank
contextablemark Jul 13, 2025
b5b29d5
fix: update test to check debug logging instead of info
mefogle Jul 13, 2025
64ac064
Merge pull request #18 from Contextable/fix/endpoint-logging-test
contextablemark Jul 13, 2025
7cb6b36
shared state demo for dojo app
syedfakher27 Jul 13, 2025
d332319
shared_state_agent added
syedfakher27 Jul 13, 2025
3f464a7
Merge remote-tracking branch 'upstream/adk-middleware' into adk-middl…
syedfakher27 Jul 13, 2025
a956e78
fix: resolve EventType.STATE_DELTA patch error (issue #20)
mefogle Jul 13, 2025
0a2212d
Merge pull request #21 from Contextable/fix/issue-20-state-delta-patc…
contextablemark Jul 13, 2025
58b45bd
feat: add SystemMessage support and fix tool result race condition
mefogle Jul 14, 2025
5975788
Merge pull request #23 from Contextable/feature/system-message-suppor…
contextablemark Jul 14, 2025
5f61634
dojo app backend command added
syedfakher27 Jul 14, 2025
0f00725
session update comments added
syedfakher27 Jul 14, 2025
a37a7fd
Merge remote-tracking branch 'upstream/adk-middleware' into adk-middl…
syedfakher27 Jul 14, 2025
a45eff2
_create_state_delta_event added back
syedfakher27 Jul 14, 2025
365efe0
added memory back again
syedfakher27 Jul 14, 2025
0f35666
simple instructions
syedfakher27 Jul 14, 2025
2f2449c
twice generative AI and HITL fixed
syedfakher27 Jul 14, 2025
e39cd4e
unit test updated for _translate_function_calls
syedfakher27 Jul 14, 2025
0d65159
Update typescript-sdk/integrations/adk-middleware/examples/shared_sta…
syedfakher27 Jul 15, 2025
3e211d0
Update typescript-sdk/integrations/adk-middleware/tests/test_event_tr…
syedfakher27 Jul 15, 2025
74b7f40
Update typescript-sdk/integrations/adk-middleware/examples/fastapi_se…
syedfakher27 Jul 15, 2025
bf4dc54
Update typescript-sdk/integrations/adk-middleware/examples/shared_sta…
syedfakher27 Jul 15, 2025
c7d5e54
Update typescript-sdk/integrations/adk-middleware/examples/shared_sta…
syedfakher27 Jul 15, 2025
ef563f9
Update typescript-sdk/integrations/adk-middleware/src/adk_middleware/…
syedfakher27 Jul 15, 2025
378c642
Update typescript-sdk/integrations/adk-middleware/examples/shared_sta…
syedfakher27 Jul 15, 2025
9339691
Update typescript-sdk/integrations/adk-middleware/examples/fastapi_se…
syedfakher27 Jul 15, 2025
e47627c
test cases for session management added
syedfakher27 Jul 15, 2025
25d3f69
Update typescript-sdk/integrations/adk-middleware/examples/shared_sta…
contextablemark Jul 15, 2025
edc9d25
Update typescript-sdk/integrations/adk-middleware/examples/shared_sta…
contextablemark Jul 15, 2025
1108526
Update typescript-sdk/integrations/adk-middleware/examples/shared_sta…
contextablemark Jul 15, 2025
27b8730
Merge pull request #19 from syedfakher27/adk-middleware
syedfakher27 Jul 15, 2025
aec1385
adk_shared_state_agent fixed
syedfakher27 Jul 15, 2025
4df0a2c
fix: resolve flaky test_bulk_update_user_state_mixed_results
mefogle Jul 17, 2025
81b6c92
Merge pull request #27 from Contextable/fix/flaky-session-test
contextablemark Jul 17, 2025
17b7da5
Merge pull request #26 from syedfakher27/adk-middleware
contextablemark Jul 17, 2025
8d36475
Merge branch 'ag-ui-protocol:main' into adk-middleware
contextablemark Jul 19, 2025
bae3bd7
snapshot error fixed
syedfakher27 Jul 20, 2025
1790c4b
function response
syedfakher27 Jul 20, 2025
35047b5
Merge pull request #29 from syedfakher27/adk-middleware
syedfakher27 Jul 20, 2025
24f41a1
Update agent.py
syedfakher27 Jul 21, 2025
a1410c6
Merge remote-tracking branch 'upstream/adk-middleware' into adk-middl…
syedfakher27 Jul 21, 2025
1ff5971
Merge pull request #31 from syedfakher27/adk-middleware
contextablemark Jul 22, 2025
47c8dc3
refactor: use SessionManager methods for pending tool call state mana…
mefogle Jul 24, 2025
ac914b9
removing the print statements
syedfakher27 Jul 26, 2025
3f4342b
long running tool backend handling
syedfakher27 Jul 26, 2025
62da096
update the instruction for the chat demo
syedfakher27 Jul 26, 2025
878cf54
predictive state demo added
syedfakher27 Jul 26, 2025
5e2ec4b
Update typescript-sdk/integrations/adk-middleware/examples/fastapi_se…
syedfakher27 Jul 26, 2025
edd8897
fix: use SessionManager methods for pending tool call state management
mefogle Jul 26, 2025
6d7d558
Merge pull request #34 from Contextable/issue-25-fix
contextablemark Jul 26, 2025
94cf5da
Merge remote-tracking branch 'upstream/adk-middleware' into adk-middl…
syedfakher27 Jul 26, 2025
ac2830a
backend tool pending issue fixed
syedfakher27 Jul 26, 2025
34be480
Update Changelog.md
syedfakher27 Jul 26, 2025
cf9d1c0
TestEventTranslatorComprehensive tests fixed
syedfakher27 Jul 26, 2025
b9b85e1
recipe prompt change
syedfakher27 Jul 29, 2025
626d9ba
model updated for human in loop
syedfakher27 Jul 30, 2025
5243567
Initial documentation changes
contextablemark Aug 2, 2025
20bce0b
Merge branch 'main' into adk-middleware
contextablemark Aug 2, 2025
1f9da91
feat: eliminate AgentRegistry and implement direct agent embedding
mefogle Aug 2, 2025
f45b00e
docs: update documentation to remove AgentRegistry references
mefogle Aug 2, 2025
14bab93
stopping condition added
syedfakher27 Aug 5, 2025
527c112
feat: make session_service configurable in ADKAgent constructor
mefogle Aug 5, 2025
8e13a52
print statement removed
syedfakher27 Aug 5, 2025
d5ddc14
Merge pull request #33 from syedfakher27/adk-middleware
contextablemark Aug 5, 2025
c1e5b53
Merge branch 'ag-ui-protocol:main' into adk-middleware
contextablemark Aug 5, 2025
f897d0b
Merge branch 'adk-middleware' into issue-24-cleanup-agent-registration
contextablemark Aug 5, 2025
0330453
Removing registry entries and redundant constructor.
mefogle Aug 5, 2025
82b4395
Added support for agentFilesMapper.
mefogle Aug 5, 2025
ceec7e6
Merge branch 'ag-ui-protocol:main' into adk-middleware
contextablemark Aug 5, 2025
849ca93
Merge branch 'adk-middleware' into issue-24-cleanup-agent-registration
mefogle Aug 5, 2025
848b465
Fix ADKAgent test suite for new architecture
mefogle Aug 5, 2025
5d16bb1
Merge pull request #36 from Contextable/issue-24-cleanup-agent-regist…
contextablemark Aug 5, 2025
e821ba4
Added in updated file content.
mefogle Aug 5, 2025
20d8971
Merge pull request #40 from Contextable/issue-24-cleanup-agent-regist…
contextablemark Aug 5, 2025
c4c175e
Add e2e tests for ADK middleware agentic chat
mefogle Aug 6, 2025
629cfe0
Merge pull request #41 from Contextable/feature/adk-e2e-tests
contextablemark Aug 6, 2025
bea6ef9
Merge branch 'ag-ui-protocol:main' into adk-middleware
contextablemark Aug 6, 2025
2aec7e0
feat: Make ADK middleware base URL configurable via environment variable
mefogle Aug 7, 2025
cedc747
Merge pull request #43 from Contextable/railway
contextablemark Aug 7, 2025
9924908
feat: Upgrade Google ADK dependency to 1.9.0
mefogle Aug 7, 2025
e04c063
Merge pull request #44 from Contextable/adk-upgrade
contextablemark Aug 7, 2025
5e54f15
Merge branch 'adk-middleware' into issue-35
contextablemark Aug 7, 2025
9a1b9ce
docs: Extensive documentation restructuring for improved organization
mefogle Aug 7, 2025
3313c27
Merge pull request #45 from Contextable/issue-35
contextablemark Aug 7, 2025
97996a2
Merge branch 'ag-ui-protocol:main' into adk-middleware
contextablemark Aug 7, 2025
41660e5
fix: support instructions provider for agents
evgeny-l Aug 8, 2025
0c1fd6d
fix: support of before_agent_callback in case of a direct content res…
evgeny-l Aug 8, 2025
70aa99e
Merge branch 'ag-ui-protocol:main' into adk-middleware
contextablemark Aug 11, 2025
b7063c6
Added aiohttp dependency.
mefogle Aug 12, 2025
4b3207c
Merge pull request #50 from Contextable/aiohttp_issue
contextablemark Aug 12, 2025
b7aca0f
Merge branch 'ag-ui-protocol:main' into adk-middleware
contextablemark Aug 14, 2025
4ce24b9
- General cleanup
mefogle Aug 14, 2025
7abe5b9
Merge pull request #52 from Contextable/general-cleanup
contextablemark Aug 14, 2025
27a9925
Update typescript-sdk/integrations/adk-middleware/src/adk_middleware/…
evgeny-l Aug 14, 2025
9d418d3
Update typescript-sdk/integrations/adk-middleware/tests/test_text_eve…
evgeny-l Aug 14, 2025
60bd9a1
fix: support of before_agent_callback in case of a direct content res…
evgeny-l Aug 14, 2025
4255743
fix: support instructions provider for agents - handle sync cases and…
evgeny-l Aug 14, 2025
446f2e9
Merge pull request #49 from evgeny-l/adk-middleware-before-agent-call…
contextablemark Aug 14, 2025
f20257f
Merge pull request #48 from evgeny-l/adk-middleware-instructions-prov…
contextablemark Aug 14, 2025
c1596c9
Merge branch 'ag-ui-protocol:main' into adk-middleware
contextablemark Aug 16, 2025
aaae5da
fix: update tests to match new logging levels from PR #49
contextablemark Aug 16, 2025
0835b5b
Merge pull request #53 from Contextable/fix/test-logging-levels
contextablemark Aug 16, 2025
3b84edd
fix: change misleading 'Session not found' warnings to debug messages
contextablemark Aug 19, 2025
856fac3
Merge pull request #54 from Contextable/fix/session-not-found-warning
contextablemark Aug 19, 2025
e4ffff6
Merge branch 'ag-ui-protocol:main' into adk-middleware
contextablemark Aug 24, 2025
00f3b5f
Merge branch 'ag-ui-protocol:main' into adk-middleware
contextablemark Aug 27, 2025
6703c09
Merge branch 'ag-ui-protocol:main' into adk-middleware
contextablemark Aug 29, 2025
bff1b59
Merge branch 'ag-ui-protocol:main' into adk-middleware
contextablemark Sep 3, 2025
3d54ae7
Merge branch 'ag-ui-protocol:main' into adk-middleware
contextablemark Sep 9, 2025
d6e083d
Merge branch 'ag-ui-protocol:main' into adk-middleware
contextablemark Sep 15, 2025
9334451
fix: make error handling test more robust
contextablemark Sep 15, 2025
bb3e812
Merge pull request #68 from Contextable/fix/test-error-handling
contextablemark Sep 15, 2025
d3d2054
feat: upgrade Google ADK requirement to >=1.14.0
contextablemark Sep 15, 2025
f73d20b
Merge pull request #69 from Contextable/update/adk-latest-version
contextablemark Sep 15, 2025
b8b9071
feat: optimize session state management with dictionary-based lookups
contextablemark Sep 15, 2025
c5dd37c
Merge pull request #71 from Contextable/fix/session-state-management-…
contextablemark Sep 15, 2025
aaac172
refactor: remove redundant execution checks in _start_new_execution
contextablemark Sep 15, 2025
a89a8cd
Merge pull request #73 from Contextable/refactor/remove-redundant-exe…
contextablemark Sep 15, 2025
aa9368d
move examples folder out before refactor
maxkorp Sep 16, 2025
c203e3e
New examples folder
maxkorp Sep 16, 2025
667ab7f
Add creds check
maxkorp Sep 16, 2025
24914ee
delete moved code
maxkorp Sep 16, 2025
f0f7bd4
move remaining examples2 to examples/other
maxkorp Sep 16, 2025
7c90e4e
make haiku generator more flexible
maxkorp Sep 16, 2025
6f6067f
fixup docs route
maxkorp Sep 16, 2025
96fbff9
codegen
maxkorp Sep 16, 2025
6db3741
Restructure adk examples to use uv
maxkorp Sep 16, 2025
ad28e3d
Merge remote-tracking branch 'origin/adk-middleware' into adk-middleware
maxkorp Sep 16, 2025
ca7f08d
Fix HITL examples via prompt
maxkorp Sep 16, 2025
cced002
Merge remote-tracking branch 'origin/main' into adk-middleware
maxkorp Sep 16, 2025
5bac82f
Migrate e2e tests from old e2e2 package
maxkorp Sep 16, 2025
2680589
fix agentic chat tests with prompting
maxkorp Sep 16, 2025
6b8a1aa
fix irrelevant testcase
maxkorp Sep 16, 2025
d7ba909
wrap all e2e in descriptors
maxkorp Sep 16, 2025
10720e5
update genned docs
maxkorp Sep 16, 2025
5c2329f
fix absolute path
maxkorp Sep 16, 2025
f5b8514
disable predictive state for now
maxkorp Sep 16, 2025
f1c4531
Merge pull request #74 from ag-ui-protocol/adk-middleware
contextablemark Sep 16, 2025
ea51575
Update README.md
contextablemark Sep 17, 2025
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
14 changes: 14 additions & 0 deletions typescript-sdk/integrations/adk-middleware/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added
- **NEW**: SystemMessage support for ADK agents (issue #22) - SystemMessages as first message are now appended to agent instructions
- **NEW**: Comprehensive tests for SystemMessage functionality including edge cases

### Fixed
- **FIXED**: Race condition in tool result processing causing "No pending tool calls found" warnings
- **FIXED**: Tool call removal now happens after pending check to prevent race conditions
- **IMPROVED**: Better handling of empty tool result content with graceful JSON parsing fallback

### Enhanced
- **LOGGING**: Added debug logging for tool result processing to aid in troubleshooting
- **ARCHITECTURE**: Consolidated agent copying logic to avoid creating multiple unnecessary copies
- **CLEANUP**: Removed unused toolset parameter from `_run_adk_in_background` method

## [0.4.1] - 2025-07-13

### Fixed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@
"""

import uvicorn
import logging
from fastapi import FastAPI
from .tool_based_generative_ui.agent import haiku_generator_agent
from .human_in_the_loop.agent import human_in_loop_agent
from .shared_state.agent import shared_state_agent

# Basic logging configuration
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# These imports will work once google.adk is available
try:
# from src.adk_agent import ADKAgent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
RunStartedEvent, RunFinishedEvent, RunErrorEvent,
TextMessageStartEvent, TextMessageContentEvent, TextMessageEndEvent,
StateSnapshotEvent, StateDeltaEvent,
Context, ToolMessage, ToolCallEndEvent
Context, ToolMessage, ToolCallEndEvent, SystemMessage
)

from google.adk import Runner
Expand Down Expand Up @@ -427,6 +427,8 @@ async def _handle_tool_result_submission(
# Could add more specific check here for the exact tool_call_id
# but for now just log that we're processing a tool result while tools are pending
logger.debug(f"Processing tool result {tool_call_id} for thread {thread_id} with pending tools")
# Remove from pending tool calls now that we're processing it
await self._remove_pending_tool_call(thread_id, tool_call_id)
else:
# No pending tools - this could be a stale result or from a different session
logger.warning(f"No pending tool calls found for tool result {tool_call_id} in thread {thread_id}")
Expand Down Expand Up @@ -477,9 +479,6 @@ async def _extract_tool_results(self, input: RunAgentInput) -> List[Dict]:
# Debug: Log the extracted tool message
logger.info(f"Extracted most recent ToolMessage: role={most_recent_tool_message.role}, tool_call_id={most_recent_tool_message.tool_call_id}, content='{most_recent_tool_message.content}'")

# Remove from pending tool calls when response is received
await self._remove_pending_tool_call(input.thread_id, most_recent_tool_message.tool_call_id)

return [{
'tool_name': tool_name,
'message': most_recent_tool_message
Expand Down Expand Up @@ -692,13 +691,47 @@ async def _start_background_execution(
registry = AgentRegistry.get_instance()
adk_agent = registry.get_agent(agent_id)

# Create dynamic toolset if tools provided
# Prepare agent modifications (SystemMessage and tools)
agent_updates = {}

# Handle SystemMessage if it's the first message - append to agent instructions
if input.messages and isinstance(input.messages[0], SystemMessage):
system_content = input.messages[0].content
if system_content:
# Get existing instruction (may be None or empty)
current_instruction = getattr(adk_agent, 'instruction', '') or ''

# Append SystemMessage content to existing instructions
if current_instruction:
new_instruction = f"{current_instruction}\n\n{system_content}"
else:
new_instruction = system_content

agent_updates['instruction'] = new_instruction
logger.debug(f"Will append SystemMessage to agent instructions: '{system_content[:100]}...'")

# Create dynamic toolset if tools provided and prepare tool updates
toolset = None
if input.tools:
toolset = ClientProxyToolset(
ag_ui_tools=input.tools,
event_queue=event_queue
)

# Get existing tools from the agent
existing_tools = []
if hasattr(adk_agent, 'tools') and adk_agent.tools:
existing_tools = list(adk_agent.tools) if isinstance(adk_agent.tools, (list, tuple)) else [adk_agent.tools]

# Combine existing tools with our proxy toolset
combined_tools = existing_tools + [toolset]
agent_updates['tools'] = combined_tools
logger.debug(f"Will combine {len(existing_tools)} existing tools with proxy toolset")

# Create a single copy of the agent with all updates if any modifications needed
if agent_updates:
adk_agent = adk_agent.model_copy(update=agent_updates)
logger.debug(f"Created modified agent copy with updates: {list(agent_updates.keys())}")

# Create background task
logger.debug(f"Creating background task for thread {input.thread_id}")
Expand All @@ -708,7 +741,6 @@ async def _start_background_execution(
adk_agent=adk_agent,
user_id=user_id,
app_name=app_name,
toolset=toolset,
event_queue=event_queue
)
)
Expand All @@ -726,34 +758,20 @@ async def _run_adk_in_background(
adk_agent: ADKBaseAgent,
user_id: str,
app_name: str,
toolset: Optional[ClientProxyToolset],
event_queue: asyncio.Queue
):
"""Run ADK agent in background, emitting events to queue.

Args:
input: The run input
adk_agent: The ADK agent to run
adk_agent: The ADK agent to run (already prepared with tools and SystemMessage)
user_id: User ID
app_name: App name
toolset: Optional client proxy toolset
event_queue: Queue for emitting events
"""
try:
# Handle tool combination if toolset provided - use agent cloning to avoid mutating original
if toolset:
# Get existing tools from the agent
existing_tools = []
if hasattr(adk_agent, 'tools') and adk_agent.tools:
existing_tools = list(adk_agent.tools) if isinstance(adk_agent.tools, (list, tuple)) else [adk_agent.tools]

# Combine existing tools with our proxy toolset
combined_tools = existing_tools + [toolset]

# Create a copy of the agent with the combined tools (avoid mutating original)
adk_agent = adk_agent.model_copy(update={'tools': combined_tools})

logger.debug(f"Combined {len(existing_tools)} existing tools with proxy toolset via agent cloning")
# Agent is already prepared with tools and SystemMessage instructions (if any)
# from _start_background_execution, so no additional agent copying needed here

# Create runner
runner = self._create_runner(
Expand Down Expand Up @@ -867,9 +885,10 @@ async def _run_adk_in_background(
)
await event_queue.put(None)
finally:
# Clean up toolset
if toolset:
await toolset.close()
# Background task cleanup completed
# Note: toolset cleanup is handled by garbage collection
# since toolset is now embedded in the agent's tools
pass

async def _cleanup_stale_executions(self):
"""Clean up stale executions."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,11 +301,11 @@ def _create_state_delta_event(
A StateDeltaEvent
"""
# Convert to JSON Patch format (RFC 6902)
# For now, we'll use a simple "replace" operation for each key
# Use "add" operation which works for both new and existing paths
patches = []
for key, value in state_delta.items():
patches.append({
"op": "replace",
"op": "add",
"path": f"/{key}",
"value": value
})
Expand Down
124 changes: 123 additions & 1 deletion typescript-sdk/integrations/adk-middleware/tests/test_adk_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from adk_middleware import ADKAgent, AgentRegistry,SessionManager
from ag_ui.core import (
RunAgentInput, EventType, UserMessage, Context,
RunStartedEvent, RunFinishedEvent, TextMessageChunkEvent
RunStartedEvent, RunFinishedEvent, TextMessageChunkEvent, SystemMessage
)
from google.adk.agents import Agent

Expand Down Expand Up @@ -192,6 +192,128 @@ async def test_cleanup(self, adk_agent):
mock_execution.cancel.assert_called_once()
assert len(adk_agent._active_executions) == 0

@pytest.mark.asyncio
async def test_system_message_appended_to_instructions(self, registry):
"""Test that SystemMessage as first message gets appended to agent instructions."""
# Create an agent with initial instructions
mock_agent = Agent(
name="test_agent",
instruction="You are a helpful assistant."
)
registry.set_default_agent(mock_agent)

adk_agent = ADKAgent(app_name="test_app", user_id="test_user")

# Create input with SystemMessage as first message
system_input = RunAgentInput(
thread_id="test_thread",
run_id="test_run",
messages=[
SystemMessage(id="sys_1", role="system", content="Be very concise in responses."),
UserMessage(id="msg_1", role="user", content="Hello")
],
context=[],
state={},
tools=[],
forwarded_props={}
)

# Mock the background execution to capture the modified agent
captured_agent = None
original_run_background = adk_agent._run_adk_in_background

async def mock_run_background(input, adk_agent, user_id, app_name, event_queue):
nonlocal captured_agent
captured_agent = adk_agent
# Just put a completion event in the queue and return
await event_queue.put(None)

with patch.object(adk_agent, '_run_adk_in_background', side_effect=mock_run_background):
# Start execution to trigger agent modification
execution = await adk_agent._start_background_execution(system_input, "default")

# Wait briefly for the background task to start
await asyncio.sleep(0.01)

# Verify the agent's instruction was modified
assert captured_agent is not None
expected_instruction = "You are a helpful assistant.\n\nBe very concise in responses."
assert captured_agent.instruction == expected_instruction

@pytest.mark.asyncio
async def test_system_message_not_first_ignored(self, registry):
"""Test that SystemMessage not as first message is ignored."""
mock_agent = Agent(
name="test_agent",
instruction="You are a helpful assistant."
)
registry.set_default_agent(mock_agent)

adk_agent = ADKAgent(app_name="test_app", user_id="test_user")

# Create input with SystemMessage as second message
system_input = RunAgentInput(
thread_id="test_thread",
run_id="test_run",
messages=[
UserMessage(id="msg_1", role="user", content="Hello"),
SystemMessage(id="sys_1", role="system", content="Be very concise in responses.")
],
context=[],
state={},
tools=[],
forwarded_props={}
)

# Mock the background execution to capture the agent
captured_agent = None

async def mock_run_background(input, adk_agent, user_id, app_name, event_queue):
nonlocal captured_agent
captured_agent = adk_agent
await event_queue.put(None)

with patch.object(adk_agent, '_run_adk_in_background', side_effect=mock_run_background):
execution = await adk_agent._start_background_execution(system_input, "default")
await asyncio.sleep(0.01)

# Verify the agent's instruction was NOT modified
assert captured_agent.instruction == "You are a helpful assistant."

@pytest.mark.asyncio
async def test_system_message_with_no_existing_instruction(self, registry):
"""Test SystemMessage handling when agent has no existing instruction."""
mock_agent = Agent(name="test_agent") # No instruction
registry.set_default_agent(mock_agent)

adk_agent = ADKAgent(app_name="test_app", user_id="test_user")

system_input = RunAgentInput(
thread_id="test_thread",
run_id="test_run",
messages=[
SystemMessage(id="sys_1", role="system", content="You are a math tutor.")
],
context=[],
state={},
tools=[],
forwarded_props={}
)

captured_agent = None

async def mock_run_background(input, adk_agent, user_id, app_name, event_queue):
nonlocal captured_agent
captured_agent = adk_agent
await event_queue.put(None)

with patch.object(adk_agent, '_run_adk_in_background', side_effect=mock_run_background):
execution = await adk_agent._start_background_execution(system_input, "default")
await asyncio.sleep(0.01)

# Verify the SystemMessage became the instruction
assert captured_agent.instruction == "You are a math tutor."


@pytest.fixture(autouse=True)
def reset_registry():
Expand Down
Loading