agent-starter-pack 0.2.3__py3-none-any.whl → 0.3.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.
Potentially problematic release.
This version of agent-starter-pack might be problematic. Click here for more details.
- {agent_starter_pack-0.2.3.dist-info → agent_starter_pack-0.3.0.dist-info}/METADATA +8 -4
- {agent_starter_pack-0.2.3.dist-info → agent_starter_pack-0.3.0.dist-info}/RECORD +61 -46
- agents/adk_base/README.md +14 -0
- agents/adk_base/app/agent.py +66 -0
- agents/adk_base/notebooks/adk_app_testing.ipynb +305 -0
- agents/adk_base/template/.templateconfig.yaml +21 -0
- agents/adk_base/tests/integration/test_agent.py +58 -0
- agents/agentic_rag/README.md +1 -0
- agents/agentic_rag/app/agent.py +44 -89
- agents/agentic_rag/app/templates.py +0 -25
- agents/agentic_rag/notebooks/adk_app_testing.ipynb +305 -0
- agents/agentic_rag/template/.templateconfig.yaml +3 -1
- agents/agentic_rag/tests/integration/test_agent.py +34 -27
- agents/langgraph_base_react/README.md +1 -1
- agents/langgraph_base_react/template/.templateconfig.yaml +1 -1
- src/base_template/Makefile +9 -0
- src/base_template/README.md +1 -1
- src/base_template/app/__init__.py +3 -0
- src/base_template/app/utils/tracing.py +11 -1
- src/base_template/app/utils/typing.py +54 -4
- src/base_template/deployment/terraform/dev/variables.tf +4 -0
- src/base_template/deployment/terraform/dev/vars/env.tfvars +0 -3
- src/base_template/deployment/terraform/variables.tf +4 -0
- src/base_template/deployment/terraform/vars/env.tfvars +0 -4
- src/base_template/pyproject.toml +5 -3
- src/{deployment_targets/agent_engine → base_template}/tests/unit/test_dummy.py +2 -1
- src/cli/commands/create.py +10 -2
- src/cli/commands/setup_cicd.py +3 -0
- src/cli/utils/gcp.py +1 -1
- src/cli/utils/template.py +27 -25
- src/data_ingestion/data_ingestion_pipeline/components/ingest_data.py +2 -1
- src/deployment_targets/agent_engine/app/agent_engine_app.py +62 -11
- src/deployment_targets/agent_engine/app/utils/gcs.py +1 -1
- src/deployment_targets/agent_engine/tests/integration/test_agent_engine_app.py +63 -0
- src/deployment_targets/agent_engine/tests/load_test/load_test.py +9 -2
- src/deployment_targets/cloud_run/app/server.py +41 -15
- src/deployment_targets/cloud_run/tests/integration/test_server_e2e.py +60 -3
- src/deployment_targets/cloud_run/tests/load_test/README.md +1 -1
- src/deployment_targets/cloud_run/tests/load_test/load_test.py +57 -24
- src/frontends/live_api_react/frontend/package-lock.json +3 -3
- src/frontends/streamlit_adk/frontend/side_bar.py +214 -0
- src/frontends/streamlit_adk/frontend/streamlit_app.py +314 -0
- src/frontends/streamlit_adk/frontend/style/app_markdown.py +37 -0
- src/frontends/streamlit_adk/frontend/utils/chat_utils.py +84 -0
- src/frontends/streamlit_adk/frontend/utils/local_chat_history.py +110 -0
- src/frontends/streamlit_adk/frontend/utils/message_editing.py +61 -0
- src/frontends/streamlit_adk/frontend/utils/multimodal_utils.py +223 -0
- src/frontends/streamlit_adk/frontend/utils/stream_handler.py +311 -0
- src/frontends/streamlit_adk/frontend/utils/title_summary.py +129 -0
- src/resources/locks/uv-adk_base-agent_engine.lock +5335 -0
- src/resources/locks/uv-adk_base-cloud_run.lock +5927 -0
- src/resources/locks/uv-agentic_rag-agent_engine.lock +882 -676
- src/resources/locks/uv-agentic_rag-cloud_run.lock +1014 -835
- src/resources/locks/uv-crewai_coding_crew-agent_engine.lock +712 -606
- src/resources/locks/uv-crewai_coding_crew-cloud_run.lock +770 -672
- src/resources/locks/uv-langgraph_base_react-agent_engine.lock +602 -529
- src/resources/locks/uv-langgraph_base_react-cloud_run.lock +763 -665
- src/resources/locks/uv-live_api-cloud_run.lock +760 -662
- agents/agentic_rag/notebooks/evaluating_langgraph_agent.ipynb +0 -1561
- src/base_template/tests/unit/test_utils/test_tracing_exporter.py +0 -140
- src/deployment_targets/cloud_run/tests/unit/test_server.py +0 -124
- {agent_starter_pack-0.2.3.dist-info → agent_starter_pack-0.3.0.dist-info}/WHEEL +0 -0
- {agent_starter_pack-0.2.3.dist-info → agent_starter_pack-0.3.0.dist-info}/entry_points.txt +0 -0
- {agent_starter_pack-0.2.3.dist-info → agent_starter_pack-0.3.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
# Copyright 2025 Google LLC
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
from collections.abc import Generator
|
|
16
|
-
from typing import Any
|
|
17
|
-
from unittest.mock import Mock, patch
|
|
18
|
-
|
|
19
|
-
import pytest
|
|
20
|
-
from google.cloud import logging as google_cloud_logging
|
|
21
|
-
from google.cloud import storage
|
|
22
|
-
from opentelemetry.sdk.trace import ReadableSpan
|
|
23
|
-
|
|
24
|
-
from app.utils.tracing import CloudTraceLoggingSpanExporter
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
@pytest.fixture
|
|
28
|
-
def mock_logging_client() -> Mock:
|
|
29
|
-
"""Create a mock logging client."""
|
|
30
|
-
return Mock(spec=google_cloud_logging.Client)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
@pytest.fixture
|
|
34
|
-
def mock_storage_client() -> Mock:
|
|
35
|
-
"""Create a mock storage client."""
|
|
36
|
-
return Mock(spec=storage.Client)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
@pytest.fixture
|
|
40
|
-
def mock_credentials() -> Any:
|
|
41
|
-
"""Create mock credentials."""
|
|
42
|
-
return Mock()
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
@pytest.fixture
|
|
46
|
-
def patch_auth(mock_credentials: Any) -> Generator[Mock, None, None]:
|
|
47
|
-
"""Patch the google.auth.default function."""
|
|
48
|
-
with patch(
|
|
49
|
-
"google.auth.default", return_value=(mock_credentials, "project")
|
|
50
|
-
) as mock_auth:
|
|
51
|
-
yield mock_auth
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
@pytest.fixture
|
|
55
|
-
def patch_clients(
|
|
56
|
-
mock_logging_client: Mock, mock_storage_client: Mock
|
|
57
|
-
) -> Generator[None, None, None]:
|
|
58
|
-
"""Patch the logging and storage clients."""
|
|
59
|
-
with patch("google.cloud.logging.Client", return_value=mock_logging_client):
|
|
60
|
-
with patch("google.cloud.storage.Client", return_value=mock_storage_client):
|
|
61
|
-
yield
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
@pytest.fixture
|
|
65
|
-
def exporter(
|
|
66
|
-
mock_logging_client: Mock,
|
|
67
|
-
mock_storage_client: Mock,
|
|
68
|
-
patch_auth: Any,
|
|
69
|
-
mock_credentials: Any,
|
|
70
|
-
patch_clients: Any,
|
|
71
|
-
) -> CloudTraceLoggingSpanExporter:
|
|
72
|
-
"""Create a CloudTraceLoggingSpanExporter instance for testing."""
|
|
73
|
-
exporter = CloudTraceLoggingSpanExporter(
|
|
74
|
-
project_id="test-project",
|
|
75
|
-
logging_client=mock_logging_client,
|
|
76
|
-
storage_client=mock_storage_client,
|
|
77
|
-
bucket_name="test-bucket",
|
|
78
|
-
)
|
|
79
|
-
return exporter
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def test_init(exporter: CloudTraceLoggingSpanExporter) -> None:
|
|
83
|
-
"""Test the initialization of CloudTraceLoggingSpanExporter."""
|
|
84
|
-
assert exporter.project_id == "test-project"
|
|
85
|
-
assert exporter.bucket_name == "test-bucket"
|
|
86
|
-
assert exporter.debug is False
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
def test_store_in_gcs(exporter: CloudTraceLoggingSpanExporter) -> None:
|
|
90
|
-
"""Test the store_in_gcs method of CloudTraceLoggingSpanExporter."""
|
|
91
|
-
span_id = "test-span-id"
|
|
92
|
-
content = "test-content"
|
|
93
|
-
uri = exporter.store_in_gcs(content, span_id)
|
|
94
|
-
assert uri == f"gs://test-bucket/spans/{span_id}.json"
|
|
95
|
-
exporter.bucket.blob.assert_called_once_with(f"spans/{span_id}.json")
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
@patch("json.dumps")
|
|
99
|
-
def test_process_large_attributes_small_payload(
|
|
100
|
-
mock_json_dumps: Mock, exporter: CloudTraceLoggingSpanExporter
|
|
101
|
-
) -> None:
|
|
102
|
-
"""Test processing of small payload attributes."""
|
|
103
|
-
mock_json_dumps.return_value = "a" * 100 # Small payload
|
|
104
|
-
span_dict = {"attributes": {"key": "value"}}
|
|
105
|
-
result = exporter._process_large_attributes(span_dict, "span-id")
|
|
106
|
-
assert result == span_dict
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
@patch("json.dumps")
|
|
110
|
-
def test_process_large_attributes_large_payload(
|
|
111
|
-
mock_json_dumps: Mock, exporter: CloudTraceLoggingSpanExporter
|
|
112
|
-
) -> None:
|
|
113
|
-
"""Test processing of large payload attributes."""
|
|
114
|
-
mock_json_dumps.return_value = "a" * (400 * 1024 + 1) # Large payload
|
|
115
|
-
span_dict = {
|
|
116
|
-
"attributes": {
|
|
117
|
-
"key1": "value1",
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
result = exporter._process_large_attributes(span_dict, "span-id")
|
|
121
|
-
assert "uri_payload" in result["attributes"]
|
|
122
|
-
assert "url_payload" in result["attributes"]
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
@patch.object(CloudTraceLoggingSpanExporter, "_process_large_attributes")
|
|
126
|
-
def test_export(
|
|
127
|
-
mock_process_large_attributes: Mock, exporter: CloudTraceLoggingSpanExporter
|
|
128
|
-
) -> None:
|
|
129
|
-
"""Test the export method of CloudTraceLoggingSpanExporter."""
|
|
130
|
-
mock_span = Mock(spec=ReadableSpan)
|
|
131
|
-
mock_span.get_span_context.return_value.trace_id = 123
|
|
132
|
-
mock_span.get_span_context.return_value.span_id = 456
|
|
133
|
-
mock_span.to_json.return_value = '{"key": "value"}'
|
|
134
|
-
|
|
135
|
-
mock_process_large_attributes.return_value = {"processed": "data"}
|
|
136
|
-
|
|
137
|
-
exporter.export([mock_span])
|
|
138
|
-
|
|
139
|
-
mock_process_large_attributes.assert_called_once()
|
|
140
|
-
exporter.logger.log_struct.assert_called_once()
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
# Copyright 2025 Google LLC
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
import json
|
|
16
|
-
import logging
|
|
17
|
-
import os
|
|
18
|
-
import sys
|
|
19
|
-
from collections.abc import Generator
|
|
20
|
-
from unittest.mock import MagicMock, patch
|
|
21
|
-
|
|
22
|
-
import pytest
|
|
23
|
-
from fastapi.testclient import TestClient
|
|
24
|
-
from google.auth.credentials import Credentials
|
|
25
|
-
from langchain_core.messages import HumanMessage
|
|
26
|
-
|
|
27
|
-
from app.utils.typing import InputChat
|
|
28
|
-
|
|
29
|
-
# Set up logging
|
|
30
|
-
logging.basicConfig(level=logging.INFO)
|
|
31
|
-
logger = logging.getLogger(__name__)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
@pytest.fixture(autouse=True)
|
|
35
|
-
def mock_google_cloud_credentials() -> Generator[None, None, None]:
|
|
36
|
-
"""Mock Google Cloud credentials for testing."""
|
|
37
|
-
with patch.dict(
|
|
38
|
-
os.environ,
|
|
39
|
-
{
|
|
40
|
-
"GOOGLE_APPLICATION_CREDENTIALS": "/path/to/mock/credentials.json",
|
|
41
|
-
"GOOGLE_CLOUD_PROJECT_ID": "mock-project-id",
|
|
42
|
-
},
|
|
43
|
-
):
|
|
44
|
-
yield
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
@pytest.fixture(autouse=True)
|
|
48
|
-
def mock_google_auth_default() -> Generator[None, None, None]:
|
|
49
|
-
"""Mock the google.auth.default function for testing."""
|
|
50
|
-
mock_credentials = MagicMock(spec=Credentials)
|
|
51
|
-
mock_project = "mock-project-id"
|
|
52
|
-
|
|
53
|
-
with patch("google.auth.default", return_value=(mock_credentials, mock_project)):
|
|
54
|
-
yield
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
@pytest.fixture
|
|
58
|
-
def sample_input_chat() -> InputChat:
|
|
59
|
-
"""
|
|
60
|
-
Fixture to create a sample input chat for testing.
|
|
61
|
-
"""
|
|
62
|
-
return InputChat(
|
|
63
|
-
messages=[HumanMessage(content="What is the meaning of life?")],
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def test_redirect_root_to_docs() -> None:
|
|
68
|
-
"""
|
|
69
|
-
Test that the root endpoint (/) redirects to the Swagger UI documentation.
|
|
70
|
-
"""
|
|
71
|
-
# Mock the agent module before importing server
|
|
72
|
-
mock_agent = MagicMock()
|
|
73
|
-
with patch.dict(sys.modules, {"app.agent": mock_agent}):
|
|
74
|
-
# Now import server after the mock is in place
|
|
75
|
-
from app.server import app
|
|
76
|
-
|
|
77
|
-
client = TestClient(app)
|
|
78
|
-
response = client.get("/")
|
|
79
|
-
assert response.status_code == 200
|
|
80
|
-
assert "Swagger UI" in response.text
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
@pytest.mark.asyncio
|
|
84
|
-
async def test_stream_chat_events() -> None:
|
|
85
|
-
"""
|
|
86
|
-
Test the stream endpoint to ensure it correctly handles
|
|
87
|
-
streaming responses and generates the expected events.
|
|
88
|
-
"""
|
|
89
|
-
input_data = {
|
|
90
|
-
"input": {
|
|
91
|
-
"messages": [
|
|
92
|
-
{"type": "human", "content": "Hello, AI!"},
|
|
93
|
-
{"type": "ai", "content": "Hello!"},
|
|
94
|
-
{"type": "human", "content": "What cooking recipes do you suggest?"},
|
|
95
|
-
],
|
|
96
|
-
},
|
|
97
|
-
"config": {"metadata": {"user_id": "test-user", "session_id": "test-session"}},
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
mock_events = [{"content": "Mocked response"}, {"content": "Additional response"}]
|
|
101
|
-
|
|
102
|
-
# Create a mock agent module
|
|
103
|
-
mock_agent_module = MagicMock()
|
|
104
|
-
mock_agent_module.agent = MagicMock()
|
|
105
|
-
mock_agent_module.agent.stream.return_value = mock_events
|
|
106
|
-
|
|
107
|
-
# Patch the module import
|
|
108
|
-
with patch.dict(sys.modules, {"app.agent": mock_agent_module}):
|
|
109
|
-
# Import server after the mock is in place
|
|
110
|
-
from app.server import app
|
|
111
|
-
|
|
112
|
-
client = TestClient(app)
|
|
113
|
-
response = client.post("/stream_messages", json=input_data)
|
|
114
|
-
|
|
115
|
-
assert response.status_code == 200
|
|
116
|
-
|
|
117
|
-
events = []
|
|
118
|
-
for line in response.iter_lines():
|
|
119
|
-
if line:
|
|
120
|
-
events.append(json.loads(line))
|
|
121
|
-
|
|
122
|
-
assert len(events) == 2
|
|
123
|
-
assert events[0]["content"] == "Mocked response"
|
|
124
|
-
assert events[1]["content"] == "Additional response"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|