Skip to content

Commit 851534c

Browse files
JeyaramjjJeyaram Jeyaraj
andauthored
Python: Add Google AI package scaffolding (#1938)
* feat(python): Add Google AI/Vertex AI package scaffolding (1/6) This is the first PR in a series to port Google service connectors from Semantic Kernel to Agent Framework. Changes: - Created agent_framework_google package structure - Added GoogleAISettings class for Gemini API - Added VertexAISettings class for Vertex AI - Comprehensive test coverage (17 test cases) - Documentation with usage examples and roadmap - Updated .gitignore for internal dev docs Following azure-ai connector pattern as reference (with py.typed). Future PRs will add: - PR #2: GoogleAIChatClient implementation - PR #3: GoogleAI integration tests & samples - PR #4: VertexAIChatClient implementation - PR #5: VertexAI integration tests & samples - PR #6: Advanced features & polish Dependencies verified against Semantic Kernel: - google-generativeai>=0.8,<1 (SK uses ~=0.8) - google-cloud-aiplatform>=1.60,<2 (SK uses ~=1.114.0) * refactor: align with Anthropic pattern - use location, chat_model_id, and version fields for Google settings * Address PR #1938 review comments: migrate to google-genai SDK, add Python 3.14, simplify to Google AI only - Migrate from google-generativeai to google-genai SDK (>=0.2,<1) - Add Python 3.14 classifier support - Simplify to Google AI only (remove VertexAI settings and tests) - Remove google-cloud-aiplatform dependency - Update README to reflect Google AI focus and google-genai SDK - Add comprehensive GAP_ANALYSIS.md with 4-phase implementation plan - Add PR1938_CHECKLIST.md tracking review feedback and next steps - Verify implementation against official Google migration guide - All tests passing (5 tests, 100% coverage) Addresses feedback from @eavanvalkenburg: 1. Added Python 3.14 support 2. Switched to google-genai (GA release, Google-recommended) 3. Removed VertexAI to simplify first iteration * fix: Address pre-commit hooks failures - Export GoogleAISettings in __init__.py for public API - Update README.md example to use SecretStr for type safety - Comment out future code example to avoid pyright validation errors - Auto-format code with ruff Addresses CI feedback from PR reviewer. --------- Co-authored-by: Jeyaram Jeyaraj <jejeyara@microsoft.com>
1 parent 64826b8 commit 851534c

File tree

10 files changed

+666
-199
lines changed

10 files changed

+666
-199
lines changed

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,4 +211,8 @@ WARP.md
211211
**/frontend/dist/
212212

213213
# Database files
214-
*.db
214+
*.db
215+
216+
# Package development docs (internal use only)
217+
**/GAP_ANALYSIS.md
218+
**/PR*_CHECKLIST.md

python/packages/google/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) Microsoft Corporation.
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE

python/packages/google/README.md

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# Get Started with Microsoft Agent Framework Google
2+
3+
> **Note**: This package is currently under active development. The chat client implementation for Google AI is coming soon. This initial release provides the foundational settings and configuration classes.
4+
5+
Please install this package via pip:
6+
7+
```bash
8+
pip install agent-framework-google --pre
9+
```
10+
11+
## Google AI (Gemini API) Integration
12+
13+
This package provides integration with Google's Gemini API for Agent Framework:
14+
15+
- **Google AI (Gemini API)**: Direct access to Google's Gemini models with API key authentication
16+
17+
> **Note**: This package uses the new `google-genai` SDK as recommended by Google. See the [migration guide](https://ai.google.dev/gemini-api/docs/migrate) for more information.
18+
19+
### Current Status
20+
21+
**Available Now:**
22+
- `GoogleAISettings`: Configuration class for Google AI (Gemini API) authentication and settings
23+
24+
**Coming Soon:**
25+
- `GoogleAIChatClient`: Chat client for Google AI with streaming, function calling, and multi-modal support
26+
- Integration tests and usage samples
27+
28+
### Configuration
29+
30+
You can configure the settings class now, which will be used by the chat client in the next release:
31+
32+
#### Google AI Settings
33+
34+
```python
35+
from agent_framework_google import GoogleAISettings
36+
37+
# Configure via environment variables
38+
# GOOGLE_AI_API_KEY=your_api_key
39+
# GOOGLE_AI_CHAT_MODEL_ID=gemini-1.5-pro
40+
41+
settings = GoogleAISettings()
42+
43+
# Or pass parameters directly (pass SecretStr for type safety)
44+
from pydantic import SecretStr
45+
46+
settings = GoogleAISettings(
47+
api_key=SecretStr("your_api_key"),
48+
chat_model_id="gemini-1.5-pro"
49+
)
50+
```
51+
52+
### Future Usage (Coming Soon)
53+
54+
Once the chat client is released, usage will look like this:
55+
56+
```python
57+
# from agent_framework.google import GoogleAIChatClient
58+
#
59+
# # Configure via environment variables
60+
# # GOOGLE_AI_API_KEY=your_api_key
61+
# # GOOGLE_AI_CHAT_MODEL_ID=gemini-1.5-pro
62+
#
63+
# client = GoogleAIChatClient()
64+
# agent = client.create_agent(
65+
# name="Assistant",
66+
# instructions="You are a helpful assistant"
67+
# )
68+
#
69+
# response = await agent.run("Hello!")
70+
# print(response.text)
71+
```
72+
73+
## Configuration
74+
75+
### Environment Variables
76+
77+
**Google AI:**
78+
- `GOOGLE_AI_API_KEY`: Your Google AI API key ([Get one here](https://ai.google.dev/))
79+
- `GOOGLE_AI_CHAT_MODEL_ID`: Model to use (e.g., `gemini-1.5-pro`, `gemini-1.5-flash`)
80+
81+
### Supported Models
82+
83+
- `gemini-1.5-pro`: Most capable model
84+
- `gemini-1.5-flash`: Faster, cost-effective model
85+
- `gemini-2.0-flash-exp`: Experimental latest model
86+
87+
## Features
88+
89+
### Planned Features
90+
- ✅ Chat completion (streaming and non-streaming)
91+
- ✅ Function/tool calling
92+
- ✅ Multi-modal support (text, images, video, audio)
93+
- ✅ System instructions
94+
- ✅ Conversation history management
95+
96+
## Development Roadmap
97+
98+
This package is being developed incrementally:
99+
100+
-**Phase 1 (Current)**: Package structure and settings classes
101+
- 🚧 **Phase 2 (Next)**: Google AI chat client with streaming and function calling
102+
- 🚧 **Phase 3**: Google AI integration tests and samples
103+
- 🚧 **Phase 4**: Advanced features (context caching, safety settings, structured output)
104+
105+
> **Note**: Vertex AI support may be added in a future iteration based on user demand.
106+
107+
## Examples
108+
109+
Examples will be available once the chat client is implemented. Check back soon or watch the [repository](https://github.com/microsoft/agent-framework) for updates.
110+
111+
## Documentation
112+
113+
For more information:
114+
- [Google AI Documentation](https://ai.google.dev/docs)
115+
- [Google Gemini API Migration Guide](https://ai.google.dev/gemini-api/docs/migrate)
116+
- [Agent Framework Documentation](https://aka.ms/agent-framework)
117+
- [Agent Framework Repository](https://github.com/microsoft/agent-framework)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Copyright (c) Microsoft. All rights reserved.
2+
3+
import importlib.metadata
4+
5+
from ._chat_client import GoogleAISettings
6+
7+
# NOTE: Client class will be imported here in a future PR
8+
9+
try:
10+
__version__ = importlib.metadata.version(__name__)
11+
except importlib.metadata.PackageNotFoundError:
12+
__version__ = "0.0.0" # Fallback for development mode
13+
14+
__all__ = [
15+
"GoogleAISettings",
16+
"__version__",
17+
]
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Copyright (c) Microsoft. All rights reserved.
2+
3+
from typing import ClassVar
4+
5+
from agent_framework._pydantic import AFBaseSettings
6+
from pydantic import SecretStr
7+
8+
9+
class GoogleAISettings(AFBaseSettings):
10+
"""Google AI settings for Gemini API access.
11+
12+
The settings are first loaded from environment variables with the prefix 'GOOGLE_AI_'.
13+
If the environment variables are not found, the settings can be loaded from a .env file
14+
with the encoding 'utf-8'. If the settings are not found in the .env file, the settings
15+
are ignored; however, validation will fail alerting that the settings are missing.
16+
17+
Keyword Args:
18+
api_key: The Google AI API key.
19+
chat_model_id: The Google AI chat model ID (e.g., gemini-1.5-pro).
20+
env_file_path: If provided, the .env settings are read from this file path location.
21+
env_file_encoding: The encoding of the .env file, defaults to 'utf-8'.
22+
23+
Examples:
24+
.. code-block:: python
25+
26+
from agent_framework.google import GoogleAISettings
27+
28+
# Using environment variables
29+
# Set GOOGLE_AI_API_KEY=your_api_key
30+
# GOOGLE_AI_CHAT_MODEL_ID=gemini-1.5-pro
31+
32+
settings = GoogleAISettings()
33+
34+
# Or passing parameters directly
35+
settings = GoogleAISettings(api_key="your_api_key", chat_model_id="gemini-1.5-pro")
36+
37+
# Or loading from a .env file
38+
settings = GoogleAISettings(env_file_path="path/to/.env")
39+
"""
40+
41+
env_prefix: ClassVar[str] = "GOOGLE_AI_"
42+
43+
api_key: SecretStr | None = None
44+
chat_model_id: str | None = None
45+
46+
47+
# NOTE: Client implementations will be added in a future PR
48+
# For now, we're only setting up the package structure and settings

python/packages/google/agent_framework_google/py.typed

Whitespace-only changes.
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
[project]
2+
name = "agent-framework-google"
3+
description = "Google AI (Gemini API) integration for Microsoft Agent Framework."
4+
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
5+
readme = "README.md"
6+
requires-python = ">=3.10"
7+
version = "1.0.0b251104"
8+
license-files = ["LICENSE"]
9+
urls.homepage = "https://aka.ms/agent-framework"
10+
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
11+
urls.release_notes = "https://github.com/microsoft/agent-framework/releases?q=tag%3Apython-1&expanded=true"
12+
urls.issues = "https://github.com/microsoft/agent-framework/issues"
13+
classifiers = [
14+
"License :: OSI Approved :: MIT License",
15+
"Development Status :: 4 - Beta",
16+
"Intended Audience :: Developers",
17+
"Programming Language :: Python :: 3",
18+
"Programming Language :: Python :: 3.10",
19+
"Programming Language :: Python :: 3.11",
20+
"Programming Language :: Python :: 3.12",
21+
"Programming Language :: Python :: 3.13",
22+
"Programming Language :: Python :: 3.14",
23+
"Typing :: Typed",
24+
]
25+
dependencies = [
26+
"agent-framework-core",
27+
"google-genai>=0.2,<1",
28+
]
29+
30+
[tool.uv]
31+
prerelease = "if-necessary-or-explicit"
32+
environments = [
33+
"sys_platform == 'darwin'",
34+
"sys_platform == 'linux'",
35+
"sys_platform == 'win32'"
36+
]
37+
38+
[tool.uv-dynamic-versioning]
39+
fallback-version = "0.0.0"
40+
41+
[tool.pytest.ini_options]
42+
testpaths = 'tests'
43+
addopts = "-ra -q -r fEX"
44+
asyncio_mode = "auto"
45+
asyncio_default_fixture_loop_scope = "function"
46+
filterwarnings = [
47+
"ignore:Support for class-based `config` is deprecated:DeprecationWarning:pydantic.*"
48+
]
49+
timeout = 120
50+
51+
[tool.ruff]
52+
extend = "../../pyproject.toml"
53+
54+
[tool.coverage.run]
55+
omit = [
56+
"**/__init__.py"
57+
]
58+
59+
[tool.pyright]
60+
extends = "../../pyproject.toml"
61+
exclude = ['tests']
62+
63+
[tool.mypy]
64+
plugins = ['pydantic.mypy']
65+
strict = true
66+
python_version = "3.10"
67+
ignore_missing_imports = true
68+
disallow_untyped_defs = true
69+
no_implicit_optional = true
70+
check_untyped_defs = true
71+
warn_return_any = true
72+
show_error_codes = true
73+
warn_unused_ignores = false
74+
disallow_incomplete_defs = true
75+
disallow_untyped_decorators = true
76+
77+
[tool.bandit]
78+
targets = ["agent_framework_google"]
79+
exclude_dirs = ["tests"]
80+
81+
[tool.poe]
82+
executor.type = "uv"
83+
include = "../../shared_tasks.toml"
84+
[tool.poe.tasks]
85+
mypy = "mypy --config-file $POE_ROOT/pyproject.toml agent_framework_google"
86+
test = "pytest --cov=agent_framework_google --cov-report=term-missing:skip-covered tests"
87+
88+
[build-system]
89+
requires = ["flit-core >= 3.11,<4.0"]
90+
build-backend = "flit_core.buildapi"
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Copyright (c) Microsoft. All rights reserved.
2+
from typing import Any
3+
4+
from pytest import fixture
5+
6+
7+
@fixture
8+
def exclude_list(request: Any) -> list[str]:
9+
"""Fixture that returns a list of environment variables to exclude."""
10+
return request.param if hasattr(request, "param") else []
11+
12+
13+
@fixture
14+
def override_env_param_dict(request: Any) -> dict[str, str]:
15+
"""Fixture that returns a dict of environment variables to override."""
16+
return request.param if hasattr(request, "param") else {}
17+
18+
19+
@fixture
20+
def google_ai_unit_test_env(monkeypatch, exclude_list, override_env_param_dict): # type: ignore
21+
"""Fixture to set environment variables for GoogleAISettings."""
22+
if exclude_list is None:
23+
exclude_list = []
24+
25+
if override_env_param_dict is None:
26+
override_env_param_dict = {}
27+
28+
env_vars = {
29+
"GOOGLE_AI_API_KEY": "test-api-key-12345",
30+
"GOOGLE_AI_CHAT_MODEL_ID": "gemini-1.5-pro",
31+
}
32+
33+
env_vars.update(override_env_param_dict) # type: ignore
34+
35+
for key, value in env_vars.items():
36+
if key in exclude_list:
37+
monkeypatch.delenv(key, raising=False) # type: ignore
38+
continue
39+
monkeypatch.setenv(key, value) # type: ignore
40+
41+
return env_vars

0 commit comments

Comments
 (0)