google-adk 0.3.0__py3-none-any.whl → 0.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- google/adk/agents/active_streaming_tool.py +1 -0
- google/adk/agents/base_agent.py +27 -29
- google/adk/agents/callback_context.py +4 -4
- google/adk/agents/invocation_context.py +1 -0
- google/adk/agents/langgraph_agent.py +1 -0
- google/adk/agents/live_request_queue.py +1 -0
- google/adk/agents/llm_agent.py +54 -14
- google/adk/agents/run_config.py +4 -0
- google/adk/agents/transcription_entry.py +1 -0
- google/adk/artifacts/base_artifact_service.py +5 -10
- google/adk/artifacts/gcs_artifact_service.py +8 -8
- google/adk/artifacts/in_memory_artifact_service.py +5 -5
- google/adk/auth/auth_credential.py +4 -5
- google/adk/cli/browser/index.html +1 -1
- google/adk/cli/browser/{main-HWIBUY2R.js → main-ULN5R5I5.js} +40 -39
- google/adk/cli/cli.py +54 -47
- google/adk/cli/cli_eval.py +13 -11
- google/adk/cli/cli_tools_click.py +58 -7
- google/adk/cli/fast_api.py +11 -11
- google/adk/cli/fast_api.py.orig +728 -0
- google/adk/evaluation/agent_evaluator.py +3 -3
- google/adk/evaluation/evaluation_constants.py +1 -0
- google/adk/evaluation/evaluation_generator.py +5 -5
- google/adk/evaluation/response_evaluator.py +1 -1
- google/adk/events/event.py +1 -0
- google/adk/events/event_actions.py +10 -4
- google/adk/examples/example.py +1 -0
- google/adk/flows/__init__.py +0 -1
- google/adk/flows/llm_flows/_code_execution.py +10 -10
- google/adk/flows/llm_flows/base_llm_flow.py +40 -15
- google/adk/flows/llm_flows/basic.py +3 -0
- google/adk/flows/llm_flows/contents.py +9 -5
- google/adk/flows/llm_flows/functions.py +38 -16
- google/adk/flows/llm_flows/instructions.py +17 -6
- google/adk/memory/base_memory_service.py +4 -2
- google/adk/memory/in_memory_memory_service.py +2 -2
- google/adk/memory/vertex_ai_rag_memory_service.py +2 -2
- google/adk/models/anthropic_llm.py +20 -2
- google/adk/models/base_llm.py +45 -4
- google/adk/models/gemini_llm_connection.py +14 -1
- google/adk/models/google_llm.py +0 -42
- google/adk/models/lite_llm.py +17 -17
- google/adk/models/llm_request.py +1 -1
- google/adk/models/llm_response.py +1 -1
- google/adk/runners.py +5 -5
- google/adk/sessions/_session_util.py +43 -0
- google/adk/sessions/base_session_service.py +3 -0
- google/adk/sessions/database_session_service.py +63 -46
- google/adk/sessions/in_memory_session_service.py +3 -3
- google/adk/sessions/session.py +1 -0
- google/adk/sessions/vertex_ai_session_service.py +7 -5
- google/adk/tools/agent_tool.py +7 -4
- google/adk/tools/application_integration_tool/__init__.py +2 -0
- google/adk/tools/application_integration_tool/application_integration_toolset.py +48 -26
- google/adk/tools/application_integration_tool/clients/connections_client.py +33 -77
- google/adk/tools/application_integration_tool/integration_connector_tool.py +159 -0
- google/adk/tools/function_tool.py +42 -0
- google/adk/tools/load_artifacts_tool.py +4 -4
- google/adk/tools/load_memory_tool.py +4 -2
- google/adk/tools/mcp_tool/conversion_utils.py +1 -1
- google/adk/tools/mcp_tool/mcp_session_manager.py +14 -0
- google/adk/tools/openapi_tool/common/common.py +2 -5
- google/adk/tools/openapi_tool/openapi_spec_parser/operation_parser.py +13 -3
- google/adk/tools/preload_memory_tool.py +1 -1
- google/adk/tools/tool_context.py +4 -4
- google/adk/version.py +1 -1
- {google_adk-0.3.0.dist-info → google_adk-0.5.0.dist-info}/METADATA +3 -7
- {google_adk-0.3.0.dist-info → google_adk-0.5.0.dist-info}/RECORD +71 -68
- {google_adk-0.3.0.dist-info → google_adk-0.5.0.dist-info}/WHEEL +0 -0
- {google_adk-0.3.0.dist-info → google_adk-0.5.0.dist-info}/entry_points.txt +0 -0
- {google_adk-0.3.0.dist-info → google_adk-0.5.0.dist-info}/licenses/LICENSE +0 -0
google/adk/cli/cli.py
CHANGED
@@ -39,12 +39,12 @@ class InputFile(BaseModel):
|
|
39
39
|
|
40
40
|
async def run_input_file(
|
41
41
|
app_name: str,
|
42
|
+
user_id: str,
|
42
43
|
root_agent: LlmAgent,
|
43
44
|
artifact_service: BaseArtifactService,
|
44
|
-
session: Session,
|
45
45
|
session_service: BaseSessionService,
|
46
46
|
input_path: str,
|
47
|
-
) ->
|
47
|
+
) -> Session:
|
48
48
|
runner = Runner(
|
49
49
|
app_name=app_name,
|
50
50
|
agent=root_agent,
|
@@ -55,9 +55,11 @@ async def run_input_file(
|
|
55
55
|
input_file = InputFile.model_validate_json(f.read())
|
56
56
|
input_file.state['_time'] = datetime.now()
|
57
57
|
|
58
|
-
session
|
58
|
+
session = session_service.create_session(
|
59
|
+
app_name=app_name, user_id=user_id, state=input_file.state
|
60
|
+
)
|
59
61
|
for query in input_file.queries:
|
60
|
-
click.echo(f'user: {query}')
|
62
|
+
click.echo(f'[user]: {query}')
|
61
63
|
content = types.Content(role='user', parts=[types.Part(text=query)])
|
62
64
|
async for event in runner.run_async(
|
63
65
|
user_id=session.user_id, session_id=session.id, new_message=content
|
@@ -65,23 +67,23 @@ async def run_input_file(
|
|
65
67
|
if event.content and event.content.parts:
|
66
68
|
if text := ''.join(part.text or '' for part in event.content.parts):
|
67
69
|
click.echo(f'[{event.author}]: {text}')
|
70
|
+
return session
|
68
71
|
|
69
72
|
|
70
73
|
async def run_interactively(
|
71
|
-
app_name: str,
|
72
74
|
root_agent: LlmAgent,
|
73
75
|
artifact_service: BaseArtifactService,
|
74
76
|
session: Session,
|
75
77
|
session_service: BaseSessionService,
|
76
78
|
) -> None:
|
77
79
|
runner = Runner(
|
78
|
-
app_name=app_name,
|
80
|
+
app_name=session.app_name,
|
79
81
|
agent=root_agent,
|
80
82
|
artifact_service=artifact_service,
|
81
83
|
session_service=session_service,
|
82
84
|
)
|
83
85
|
while True:
|
84
|
-
query = input('user: ')
|
86
|
+
query = input('[user]: ')
|
85
87
|
if not query or not query.strip():
|
86
88
|
continue
|
87
89
|
if query == 'exit':
|
@@ -100,7 +102,8 @@ async def run_cli(
|
|
100
102
|
*,
|
101
103
|
agent_parent_dir: str,
|
102
104
|
agent_folder_name: str,
|
103
|
-
|
105
|
+
input_file: Optional[str] = None,
|
106
|
+
saved_session_file: Optional[str] = None,
|
104
107
|
save_session: bool,
|
105
108
|
) -> None:
|
106
109
|
"""Runs an interactive CLI for a certain agent.
|
@@ -109,8 +112,11 @@ async def run_cli(
|
|
109
112
|
agent_parent_dir: str, the absolute path of the parent folder of the agent
|
110
113
|
folder.
|
111
114
|
agent_folder_name: str, the name of the agent folder.
|
112
|
-
|
113
|
-
|
115
|
+
input_file: Optional[str], the absolute path to the json file that contains
|
116
|
+
the initial session state and user queries, exclusive with
|
117
|
+
saved_session_file.
|
118
|
+
saved_session_file: Optional[str], the absolute path to the json file that
|
119
|
+
contains a previously saved session, exclusive with input_file.
|
114
120
|
save_session: bool, whether to save the session on exit.
|
115
121
|
"""
|
116
122
|
if agent_parent_dir not in sys.path:
|
@@ -118,46 +124,50 @@ async def run_cli(
|
|
118
124
|
|
119
125
|
artifact_service = InMemoryArtifactService()
|
120
126
|
session_service = InMemorySessionService()
|
121
|
-
session = session_service.create_session(
|
122
|
-
app_name=agent_folder_name, user_id='test_user'
|
123
|
-
)
|
124
127
|
|
125
128
|
agent_module_path = os.path.join(agent_parent_dir, agent_folder_name)
|
126
129
|
agent_module = importlib.import_module(agent_folder_name)
|
130
|
+
user_id = 'test_user'
|
131
|
+
session = session_service.create_session(
|
132
|
+
app_name=agent_folder_name, user_id=user_id
|
133
|
+
)
|
127
134
|
root_agent = agent_module.agent.root_agent
|
128
135
|
envs.load_dotenv_for_agent(agent_folder_name, agent_parent_dir)
|
129
|
-
if
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
136
|
+
if input_file:
|
137
|
+
session = await run_input_file(
|
138
|
+
app_name=agent_folder_name,
|
139
|
+
user_id=user_id,
|
140
|
+
root_agent=root_agent,
|
141
|
+
artifact_service=artifact_service,
|
142
|
+
session_service=session_service,
|
143
|
+
input_path=input_file,
|
144
|
+
)
|
145
|
+
elif saved_session_file:
|
146
|
+
|
147
|
+
loaded_session = None
|
148
|
+
with open(saved_session_file, 'r') as f:
|
149
|
+
loaded_session = Session.model_validate_json(f.read())
|
150
|
+
|
151
|
+
if loaded_session:
|
152
|
+
for event in loaded_session.events:
|
153
|
+
session_service.append_event(session, event)
|
154
|
+
content = event.content
|
155
|
+
if not content or not content.parts or not content.parts[0].text:
|
156
|
+
continue
|
157
|
+
if event.author == 'user':
|
158
|
+
click.echo(f'[user]: {content.parts[0].text}')
|
145
159
|
else:
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
else:
|
155
|
-
print(f'Unsupported file type: {json_file_path}')
|
156
|
-
exit(1)
|
160
|
+
click.echo(f'[{event.author}]: {content.parts[0].text}')
|
161
|
+
|
162
|
+
await run_interactively(
|
163
|
+
root_agent,
|
164
|
+
artifact_service,
|
165
|
+
session,
|
166
|
+
session_service,
|
167
|
+
)
|
157
168
|
else:
|
158
|
-
|
169
|
+
click.echo(f'Running agent {root_agent.name}, type exit to exit.')
|
159
170
|
await run_interactively(
|
160
|
-
agent_folder_name,
|
161
171
|
root_agent,
|
162
172
|
artifact_service,
|
163
173
|
session,
|
@@ -165,11 +175,8 @@ async def run_cli(
|
|
165
175
|
)
|
166
176
|
|
167
177
|
if save_session:
|
168
|
-
|
169
|
-
|
170
|
-
else:
|
171
|
-
session_id = input('Session ID to save: ')
|
172
|
-
session_path = f'{agent_module_path}/{session_id}.session.json'
|
178
|
+
session_id = input('Session ID to save: ')
|
179
|
+
session_path = f'{agent_module_path}/{session_id}.session.json'
|
173
180
|
|
174
181
|
# Fetch the session again to get all the details.
|
175
182
|
session = session_service.get_session(
|
google/adk/cli/cli_eval.py
CHANGED
@@ -20,7 +20,7 @@ import os
|
|
20
20
|
import sys
|
21
21
|
import traceback
|
22
22
|
from typing import Any
|
23
|
-
from typing import
|
23
|
+
from typing import AsyncGenerator
|
24
24
|
from typing import Optional
|
25
25
|
import uuid
|
26
26
|
|
@@ -146,7 +146,7 @@ def parse_and_get_evals_to_run(
|
|
146
146
|
return eval_set_to_evals
|
147
147
|
|
148
148
|
|
149
|
-
def run_evals(
|
149
|
+
async def run_evals(
|
150
150
|
eval_set_to_evals: dict[str, list[str]],
|
151
151
|
root_agent: Agent,
|
152
152
|
reset_func: Optional[Any],
|
@@ -154,7 +154,7 @@ def run_evals(
|
|
154
154
|
session_service=None,
|
155
155
|
artifact_service=None,
|
156
156
|
print_detailed_results=False,
|
157
|
-
) ->
|
157
|
+
) -> AsyncGenerator[EvalResult, None]:
|
158
158
|
try:
|
159
159
|
from ..evaluation.agent_evaluator import EvaluationGenerator
|
160
160
|
from ..evaluation.response_evaluator import ResponseEvaluator
|
@@ -181,14 +181,16 @@ def run_evals(
|
|
181
181
|
print(f"Running Eval: {eval_set_file}:{eval_name}")
|
182
182
|
session_id = f"{EVAL_SESSION_ID_PREFIX}{str(uuid.uuid4())}"
|
183
183
|
|
184
|
-
scrape_result =
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
184
|
+
scrape_result = (
|
185
|
+
await EvaluationGenerator._process_query_with_root_agent(
|
186
|
+
data=eval_data,
|
187
|
+
root_agent=root_agent,
|
188
|
+
reset_func=reset_func,
|
189
|
+
initial_session=initial_session,
|
190
|
+
session_id=session_id,
|
191
|
+
session_service=session_service,
|
192
|
+
artifact_service=artifact_service,
|
193
|
+
)
|
192
194
|
)
|
193
195
|
|
194
196
|
eval_metric_results = []
|
@@ -96,6 +96,23 @@ def cli_create_cmd(
|
|
96
96
|
)
|
97
97
|
|
98
98
|
|
99
|
+
def validate_exclusive(ctx, param, value):
|
100
|
+
# Store the validated parameters in the context
|
101
|
+
if not hasattr(ctx, "exclusive_opts"):
|
102
|
+
ctx.exclusive_opts = {}
|
103
|
+
|
104
|
+
# If this option has a value and we've already seen another exclusive option
|
105
|
+
if value is not None and any(ctx.exclusive_opts.values()):
|
106
|
+
exclusive_opt = next(key for key, val in ctx.exclusive_opts.items() if val)
|
107
|
+
raise click.UsageError(
|
108
|
+
f"Options '{param.name}' and '{exclusive_opt}' cannot be set together."
|
109
|
+
)
|
110
|
+
|
111
|
+
# Record this option's value
|
112
|
+
ctx.exclusive_opts[param.name] = value is not None
|
113
|
+
return value
|
114
|
+
|
115
|
+
|
99
116
|
@main.command("run")
|
100
117
|
@click.option(
|
101
118
|
"--save_session",
|
@@ -105,13 +122,43 @@ def cli_create_cmd(
|
|
105
122
|
default=False,
|
106
123
|
help="Optional. Whether to save the session to a json file on exit.",
|
107
124
|
)
|
125
|
+
@click.option(
|
126
|
+
"--replay",
|
127
|
+
type=click.Path(
|
128
|
+
exists=True, dir_okay=False, file_okay=True, resolve_path=True
|
129
|
+
),
|
130
|
+
help=(
|
131
|
+
"The json file that contains the initial state of the session and user"
|
132
|
+
" queries. A new session will be created using this state. And user"
|
133
|
+
" queries are run againt the newly created session. Users cannot"
|
134
|
+
" continue to interact with the agent."
|
135
|
+
),
|
136
|
+
callback=validate_exclusive,
|
137
|
+
)
|
138
|
+
@click.option(
|
139
|
+
"--resume",
|
140
|
+
type=click.Path(
|
141
|
+
exists=True, dir_okay=False, file_okay=True, resolve_path=True
|
142
|
+
),
|
143
|
+
help=(
|
144
|
+
"The json file that contains a previously saved session (by"
|
145
|
+
"--save_session option). The previous session will be re-displayed. And"
|
146
|
+
" user can continue to interact with the agent."
|
147
|
+
),
|
148
|
+
callback=validate_exclusive,
|
149
|
+
)
|
108
150
|
@click.argument(
|
109
151
|
"agent",
|
110
152
|
type=click.Path(
|
111
153
|
exists=True, dir_okay=True, file_okay=False, resolve_path=True
|
112
154
|
),
|
113
155
|
)
|
114
|
-
def cli_run(
|
156
|
+
def cli_run(
|
157
|
+
agent: str,
|
158
|
+
save_session: bool,
|
159
|
+
replay: Optional[str],
|
160
|
+
resume: Optional[str],
|
161
|
+
):
|
115
162
|
"""Runs an interactive CLI for a certain agent.
|
116
163
|
|
117
164
|
AGENT: The path to the agent source code folder.
|
@@ -129,6 +176,8 @@ def cli_run(agent: str, save_session: bool):
|
|
129
176
|
run_cli(
|
130
177
|
agent_parent_dir=agent_parent_folder,
|
131
178
|
agent_folder_name=agent_folder_name,
|
179
|
+
input_file=replay,
|
180
|
+
saved_session_file=resume,
|
132
181
|
save_session=save_session,
|
133
182
|
)
|
134
183
|
)
|
@@ -209,12 +258,14 @@ def cli_eval(
|
|
209
258
|
|
210
259
|
try:
|
211
260
|
eval_results = list(
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
261
|
+
asyncio.run(
|
262
|
+
run_evals(
|
263
|
+
eval_set_to_evals,
|
264
|
+
root_agent,
|
265
|
+
reset_func,
|
266
|
+
eval_metrics,
|
267
|
+
print_detailed_results=print_detailed_results,
|
268
|
+
)
|
218
269
|
)
|
219
270
|
)
|
220
271
|
except ModuleNotFoundError:
|
google/adk/cli/fast_api.py
CHANGED
@@ -467,7 +467,7 @@ def get_fast_api_app(
|
|
467
467
|
)
|
468
468
|
root_agent = await _get_root_agent_async(app_name)
|
469
469
|
eval_results = list(
|
470
|
-
run_evals(
|
470
|
+
await run_evals(
|
471
471
|
eval_set_to_evals,
|
472
472
|
root_agent,
|
473
473
|
getattr(root_agent, "reset_data", None),
|
@@ -503,7 +503,7 @@ def get_fast_api_app(
|
|
503
503
|
"/apps/{app_name}/users/{user_id}/sessions/{session_id}/artifacts/{artifact_name}",
|
504
504
|
response_model_exclude_none=True,
|
505
505
|
)
|
506
|
-
def load_artifact(
|
506
|
+
async def load_artifact(
|
507
507
|
app_name: str,
|
508
508
|
user_id: str,
|
509
509
|
session_id: str,
|
@@ -511,7 +511,7 @@ def get_fast_api_app(
|
|
511
511
|
version: Optional[int] = Query(None),
|
512
512
|
) -> Optional[types.Part]:
|
513
513
|
app_name = agent_engine_id if agent_engine_id else app_name
|
514
|
-
artifact = artifact_service.load_artifact(
|
514
|
+
artifact = await artifact_service.load_artifact(
|
515
515
|
app_name=app_name,
|
516
516
|
user_id=user_id,
|
517
517
|
session_id=session_id,
|
@@ -526,7 +526,7 @@ def get_fast_api_app(
|
|
526
526
|
"/apps/{app_name}/users/{user_id}/sessions/{session_id}/artifacts/{artifact_name}/versions/{version_id}",
|
527
527
|
response_model_exclude_none=True,
|
528
528
|
)
|
529
|
-
def load_artifact_version(
|
529
|
+
async def load_artifact_version(
|
530
530
|
app_name: str,
|
531
531
|
user_id: str,
|
532
532
|
session_id: str,
|
@@ -534,7 +534,7 @@ def get_fast_api_app(
|
|
534
534
|
version_id: int,
|
535
535
|
) -> Optional[types.Part]:
|
536
536
|
app_name = agent_engine_id if agent_engine_id else app_name
|
537
|
-
artifact = artifact_service.load_artifact(
|
537
|
+
artifact = await artifact_service.load_artifact(
|
538
538
|
app_name=app_name,
|
539
539
|
user_id=user_id,
|
540
540
|
session_id=session_id,
|
@@ -549,11 +549,11 @@ def get_fast_api_app(
|
|
549
549
|
"/apps/{app_name}/users/{user_id}/sessions/{session_id}/artifacts",
|
550
550
|
response_model_exclude_none=True,
|
551
551
|
)
|
552
|
-
def list_artifact_names(
|
552
|
+
async def list_artifact_names(
|
553
553
|
app_name: str, user_id: str, session_id: str
|
554
554
|
) -> list[str]:
|
555
555
|
app_name = agent_engine_id if agent_engine_id else app_name
|
556
|
-
return artifact_service.list_artifact_keys(
|
556
|
+
return await artifact_service.list_artifact_keys(
|
557
557
|
app_name=app_name, user_id=user_id, session_id=session_id
|
558
558
|
)
|
559
559
|
|
@@ -561,11 +561,11 @@ def get_fast_api_app(
|
|
561
561
|
"/apps/{app_name}/users/{user_id}/sessions/{session_id}/artifacts/{artifact_name}/versions",
|
562
562
|
response_model_exclude_none=True,
|
563
563
|
)
|
564
|
-
def list_artifact_versions(
|
564
|
+
async def list_artifact_versions(
|
565
565
|
app_name: str, user_id: str, session_id: str, artifact_name: str
|
566
566
|
) -> list[int]:
|
567
567
|
app_name = agent_engine_id if agent_engine_id else app_name
|
568
|
-
return artifact_service.list_versions(
|
568
|
+
return await artifact_service.list_versions(
|
569
569
|
app_name=app_name,
|
570
570
|
user_id=user_id,
|
571
571
|
session_id=session_id,
|
@@ -575,11 +575,11 @@ def get_fast_api_app(
|
|
575
575
|
@app.delete(
|
576
576
|
"/apps/{app_name}/users/{user_id}/sessions/{session_id}/artifacts/{artifact_name}",
|
577
577
|
)
|
578
|
-
def delete_artifact(
|
578
|
+
async def delete_artifact(
|
579
579
|
app_name: str, user_id: str, session_id: str, artifact_name: str
|
580
580
|
):
|
581
581
|
app_name = agent_engine_id if agent_engine_id else app_name
|
582
|
-
artifact_service.delete_artifact(
|
582
|
+
await artifact_service.delete_artifact(
|
583
583
|
app_name=app_name,
|
584
584
|
user_id=user_id,
|
585
585
|
session_id=session_id,
|