|
18 | 18 | from unittest import mock |
19 | 19 | from unittest.mock import AsyncMock |
20 | 20 |
|
| 21 | +from google.adk.agents.invocation_context import InvocationContext |
21 | 22 | from google.adk.agents.live_request_queue import LiveRequestQueue |
22 | 23 | from google.adk.agents.llm_agent import Agent |
23 | 24 | from google.adk.agents.loop_agent import LoopAgent |
24 | 25 | from google.adk.agents.run_config import RunConfig |
25 | 26 | from google.adk.events.event import Event |
| 27 | +from google.adk.features import FeatureName |
| 28 | +from google.adk.features._feature_registry import temporary_feature_override |
| 29 | +from google.adk.flows.llm_flows.base_llm_flow import _finalize_dynamic_instructions |
26 | 30 | from google.adk.flows.llm_flows.base_llm_flow import _handle_after_model_callback |
27 | 31 | from google.adk.flows.llm_flows.base_llm_flow import _process_agent_tools |
28 | 32 | from google.adk.flows.llm_flows.base_llm_flow import _ReconnectSentinel |
@@ -1922,3 +1926,90 @@ async def test_send_to_model_rejects_function_call(): |
1922 | 1926 | ValueError, match='User message cannot contain function calls' |
1923 | 1927 | ): |
1924 | 1928 | await flow._send_to_model(mock_connection, invocation_context) |
| 1929 | + |
| 1930 | + |
| 1931 | +@pytest.mark.asyncio |
| 1932 | +async def test_finalize_dynamic_instructions_feature_disabled(): |
| 1933 | + """When feature flag is disabled, dynamic instructions append to system instruction.""" |
| 1934 | + |
| 1935 | + agent = Agent(name='test_agent', model='gemini-2.0-flash') |
| 1936 | + |
| 1937 | + invocation_context = mock.Mock(spec=InvocationContext) |
| 1938 | + invocation_context.agent = agent |
| 1939 | + |
| 1940 | + llm_request = LlmRequest() |
| 1941 | + llm_request._append_dynamic_instructions(['dynamic 1', 'dynamic 2']) |
| 1942 | + llm_request.contents.append( |
| 1943 | + types.Content( |
| 1944 | + role='user', parts=[types.Part.from_text(text='user question')] |
| 1945 | + ) |
| 1946 | + ) |
| 1947 | + with temporary_feature_override( |
| 1948 | + FeatureName.DYNAMIC_INSTRUCTION_ROUTING, False |
| 1949 | + ): |
| 1950 | + await _finalize_dynamic_instructions(invocation_context, llm_request) |
| 1951 | + |
| 1952 | + assert llm_request.config.system_instruction is not None |
| 1953 | + assert len(llm_request.contents) == 1 |
| 1954 | + assert llm_request.contents[0].parts[0].text == 'user question' |
| 1955 | + |
| 1956 | + |
| 1957 | +@pytest.mark.asyncio |
| 1958 | +async def test_finalize_dynamic_instructions_feature_enabled(): |
| 1959 | + """When feature flag is enabled, dynamic instructions inject into contents.""" |
| 1960 | + |
| 1961 | + agent = Agent(name='test_agent', model='gemini-2.0-flash') |
| 1962 | + |
| 1963 | + invocation_context = mock.Mock(spec=InvocationContext) |
| 1964 | + invocation_context.agent = agent |
| 1965 | + |
| 1966 | + llm_request = LlmRequest() |
| 1967 | + llm_request._append_dynamic_instructions(['dynamic 1', 'dynamic 2']) |
| 1968 | + llm_request.contents.append( |
| 1969 | + types.Content( |
| 1970 | + role='user', parts=[types.Part.from_text(text='user question')] |
| 1971 | + ) |
| 1972 | + ) |
| 1973 | + |
| 1974 | + with temporary_feature_override( |
| 1975 | + FeatureName.DYNAMIC_INSTRUCTION_ROUTING, True |
| 1976 | + ): |
| 1977 | + await _finalize_dynamic_instructions(invocation_context, llm_request) |
| 1978 | + |
| 1979 | + assert llm_request.config.system_instruction is None |
| 1980 | + assert len(llm_request.contents) == 2 |
| 1981 | + assert llm_request.contents[0].role == 'user' |
| 1982 | + assert llm_request.contents[0].parts[0].text == 'dynamic 1\n\ndynamic 2' |
| 1983 | + assert llm_request.contents[1].role == 'user' |
| 1984 | + assert llm_request.contents[1].parts[0].text == 'user question' |
| 1985 | + |
| 1986 | + |
| 1987 | +@pytest.mark.asyncio |
| 1988 | +async def test_finalize_dynamic_instructions_with_static_instruction(): |
| 1989 | + """When static_instruction is set and feature flag enabled, it injects into contents.""" |
| 1990 | + |
| 1991 | + agent = Agent(name='test_agent', model='gemini-2.0-flash') |
| 1992 | + agent.static_instruction = 'static content' |
| 1993 | + |
| 1994 | + invocation_context = mock.Mock(spec=InvocationContext) |
| 1995 | + invocation_context.agent = agent |
| 1996 | + |
| 1997 | + llm_request = LlmRequest() |
| 1998 | + llm_request._append_dynamic_instructions(['dynamic 1', 'dynamic 2']) |
| 1999 | + llm_request.contents.append( |
| 2000 | + types.Content( |
| 2001 | + role='user', parts=[types.Part.from_text(text='user question')] |
| 2002 | + ) |
| 2003 | + ) |
| 2004 | + |
| 2005 | + with temporary_feature_override( |
| 2006 | + FeatureName.DYNAMIC_INSTRUCTION_ROUTING, True |
| 2007 | + ): |
| 2008 | + await _finalize_dynamic_instructions(invocation_context, llm_request) |
| 2009 | + |
| 2010 | + assert llm_request.config.system_instruction is None |
| 2011 | + assert len(llm_request.contents) == 2 |
| 2012 | + assert llm_request.contents[0].role == 'user' |
| 2013 | + assert llm_request.contents[0].parts[0].text == 'dynamic 1\n\ndynamic 2' |
| 2014 | + assert llm_request.contents[1].role == 'user' |
| 2015 | + assert llm_request.contents[1].parts[0].text == 'user question' |
0 commit comments