axio-transport-google 0.9.2__tar.gz
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.
- axio_transport_google-0.9.2/.gitignore +14 -0
- axio_transport_google-0.9.2/PKG-INFO +37 -0
- axio_transport_google-0.9.2/README.md +20 -0
- axio_transport_google-0.9.2/pyproject.toml +69 -0
- axio_transport_google-0.9.2/scripts/generate_types.py +254 -0
- axio_transport_google-0.9.2/src/axio_transport_google/__init__.py +947 -0
- axio_transport_google-0.9.2/src/axio_transport_google/_generated_types.py +500 -0
- axio_transport_google-0.9.2/src/axio_transport_google/py.typed +0 -0
- axio_transport_google-0.9.2/src/axio_transport_google/realtime.py +604 -0
- axio_transport_google-0.9.2/src/axio_transport_google/tools.py +76 -0
- axio_transport_google-0.9.2/src/axio_transport_google/tui/__init__.py +15 -0
- axio_transport_google-0.9.2/src/axio_transport_google/tui/google.py +143 -0
- axio_transport_google-0.9.2/tests/test_generated_types.py +267 -0
- axio_transport_google-0.9.2/tests/test_google.py +432 -0
- axio_transport_google-0.9.2/tests/test_realtime.py +421 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: axio-transport-google
|
|
3
|
+
Version: 0.9.2
|
|
4
|
+
Summary: Google GenAI (Gemini) transport for Axio with image and video support
|
|
5
|
+
Project-URL: Documentation, https://docs.axio-agent.com
|
|
6
|
+
Project-URL: Homepage, https://github.com/mosquito/axio-agent
|
|
7
|
+
Project-URL: Repository, https://github.com/mosquito/axio-agent
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: agent,ai,gemini,genai,google,llm,transport
|
|
10
|
+
Requires-Python: >=3.12
|
|
11
|
+
Requires-Dist: axio
|
|
12
|
+
Requires-Dist: axio-transport-anthropic[vertexai]
|
|
13
|
+
Requires-Dist: google-auth[urllib3]>=2.0
|
|
14
|
+
Provides-Extra: tui
|
|
15
|
+
Requires-Dist: textual>=2.1.0; extra == 'tui'
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# axio-transport-google
|
|
19
|
+
|
|
20
|
+
Google GenAI (Gemini) transport for Axio with image and video support.
|
|
21
|
+
|
|
22
|
+
## API reference
|
|
23
|
+
|
|
24
|
+
Request/response types are generated from the Vertex AI discovery documents:
|
|
25
|
+
|
|
26
|
+
- **v1:** https://aiplatform.googleapis.com/$discovery/rest?version=v1
|
|
27
|
+
- **v1beta1:** https://aiplatform.googleapis.com/$discovery/rest?version=v1beta1
|
|
28
|
+
|
|
29
|
+
To regenerate TypedDict definitions after an API update:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
python scripts/generate_types.py [--version v1beta1]
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
This produces `src/axio_transport_google/_generated_types.py`, which the transport
|
|
36
|
+
uses for type annotations. Conformance tests in `tests/test_generated_types.py`
|
|
37
|
+
validate that payload builders match the discovery schema.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# axio-transport-google
|
|
2
|
+
|
|
3
|
+
Google GenAI (Gemini) transport for Axio with image and video support.
|
|
4
|
+
|
|
5
|
+
## API reference
|
|
6
|
+
|
|
7
|
+
Request/response types are generated from the Vertex AI discovery documents:
|
|
8
|
+
|
|
9
|
+
- **v1:** https://aiplatform.googleapis.com/$discovery/rest?version=v1
|
|
10
|
+
- **v1beta1:** https://aiplatform.googleapis.com/$discovery/rest?version=v1beta1
|
|
11
|
+
|
|
12
|
+
To regenerate TypedDict definitions after an API update:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
python scripts/generate_types.py [--version v1beta1]
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
This produces `src/axio_transport_google/_generated_types.py`, which the transport
|
|
19
|
+
uses for type annotations. Conformance tests in `tests/test_generated_types.py`
|
|
20
|
+
validate that payload builders match the discovery schema.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "axio-transport-google"
|
|
3
|
+
version = "0.9.2"
|
|
4
|
+
description = "Google GenAI (Gemini) transport for Axio with image and video support"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
license = {text = "MIT"}
|
|
8
|
+
keywords = ["llm", "agent", "ai", "google", "gemini", "genai", "transport"]
|
|
9
|
+
dependencies = [
|
|
10
|
+
"axio",
|
|
11
|
+
"axio-transport-anthropic[vertexai]",
|
|
12
|
+
"google-auth[urllib3]>=2.0",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
[project.optional-dependencies]
|
|
16
|
+
tui = ["textual>=2.1.0"]
|
|
17
|
+
|
|
18
|
+
[project.entry-points."axio.transport"]
|
|
19
|
+
google = "axio_transport_google:GoogleTransport"
|
|
20
|
+
google-vertex = "axio_transport_google:VertexAITransport"
|
|
21
|
+
|
|
22
|
+
[project.entry-points."axio.transport.realtime"]
|
|
23
|
+
gemini = "axio_transport_google.realtime:GeminiLiveTransport"
|
|
24
|
+
vertex = "axio_transport_google.realtime:VertexLiveTransport"
|
|
25
|
+
|
|
26
|
+
[project.entry-points."axio.transport.settings"]
|
|
27
|
+
google = "axio_transport_google.tui:GoogleSettingsScreen"
|
|
28
|
+
google-vertex = "axio_transport_google.tui:VertexSettingsScreen"
|
|
29
|
+
|
|
30
|
+
[project.entry-points."axio.tools"]
|
|
31
|
+
generate_image = "axio_transport_google.tools:generate_image"
|
|
32
|
+
generate_video = "axio_transport_google.tools:generate_video"
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Documentation = "https://docs.axio-agent.com"
|
|
36
|
+
Homepage = "https://github.com/mosquito/axio-agent"
|
|
37
|
+
Repository = "https://github.com/mosquito/axio-agent"
|
|
38
|
+
|
|
39
|
+
[build-system]
|
|
40
|
+
requires = ["hatchling"]
|
|
41
|
+
build-backend = "hatchling.build"
|
|
42
|
+
|
|
43
|
+
[tool.hatch.build.targets.wheel]
|
|
44
|
+
packages = ["src/axio_transport_google"]
|
|
45
|
+
sources = ["src"]
|
|
46
|
+
|
|
47
|
+
[tool.pytest.ini_options]
|
|
48
|
+
asyncio_mode = "auto"
|
|
49
|
+
|
|
50
|
+
[tool.ruff]
|
|
51
|
+
line-length = 119
|
|
52
|
+
output-format = "concise"
|
|
53
|
+
target-version = "py312"
|
|
54
|
+
|
|
55
|
+
[tool.ruff.lint]
|
|
56
|
+
select = ["E", "F", "I", "UP"]
|
|
57
|
+
|
|
58
|
+
[tool.mypy]
|
|
59
|
+
strict = true
|
|
60
|
+
python_version = "3.12"
|
|
61
|
+
|
|
62
|
+
[dependency-groups]
|
|
63
|
+
dev = [
|
|
64
|
+
"pytest>=8",
|
|
65
|
+
"pytest-asyncio>=0.24",
|
|
66
|
+
"mypy>=1.14",
|
|
67
|
+
"ruff>=0.9",
|
|
68
|
+
"pytest-cov>=7.1.0",
|
|
69
|
+
]
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Generate TypedDict definitions from Google Vertex AI discovery document.
|
|
3
|
+
|
|
4
|
+
API reference (discovery docs):
|
|
5
|
+
https://aiplatform.googleapis.com/$discovery/rest?version=v1
|
|
6
|
+
https://aiplatform.googleapis.com/$discovery/rest?version=v1beta1
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
python scripts/generate_types.py [--version v1beta1] [--output src/axio_transport_google/_generated_types.py]
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import argparse
|
|
15
|
+
import json
|
|
16
|
+
import sys
|
|
17
|
+
import textwrap
|
|
18
|
+
import urllib.request
|
|
19
|
+
from typing import Any, cast
|
|
20
|
+
|
|
21
|
+
DISCOVERY_URL = "https://aiplatform.googleapis.com/$discovery/rest?version={version}"
|
|
22
|
+
|
|
23
|
+
# Schemas relevant to the generateContent API, in dependency order.
|
|
24
|
+
# Keys: short name used in generated code. Values: full discovery schema id.
|
|
25
|
+
SCHEMA_MAP = {
|
|
26
|
+
"Blob": "Blob",
|
|
27
|
+
"FileData": "FileData",
|
|
28
|
+
"FunctionCall": "FunctionCall",
|
|
29
|
+
"FunctionResponse": "FunctionResponse",
|
|
30
|
+
"FunctionResponsePart": "FunctionResponsePart",
|
|
31
|
+
"ExecutableCode": "ExecutableCode",
|
|
32
|
+
"CodeExecutionResult": "CodeExecutionResult",
|
|
33
|
+
"VideoMetadata": "VideoMetadata",
|
|
34
|
+
"Part": "Part",
|
|
35
|
+
"Content": "Content",
|
|
36
|
+
"FunctionDeclaration": "FunctionDeclaration",
|
|
37
|
+
"Tool": "Tool",
|
|
38
|
+
"FunctionCallingConfig": "FunctionCallingConfig",
|
|
39
|
+
"ToolConfig": "ToolConfig",
|
|
40
|
+
"ThinkingConfig": "GenerationConfigThinkingConfig",
|
|
41
|
+
"GenerationConfig": "GenerationConfig",
|
|
42
|
+
"SafetySetting": "SafetySetting",
|
|
43
|
+
"GenerateContentRequest": "GenerateContentRequest",
|
|
44
|
+
"Candidate": "Candidate",
|
|
45
|
+
"UsageMetadata": "GenerateContentResponseUsageMetadata",
|
|
46
|
+
"PromptFeedback": "GenerateContentResponsePromptFeedback",
|
|
47
|
+
"GenerateContentResponse": "GenerateContentResponse",
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# Mapping from discovery type strings to Python type annotations
|
|
51
|
+
TYPE_MAP: dict[str, str] = {
|
|
52
|
+
"string": "str",
|
|
53
|
+
"integer": "int",
|
|
54
|
+
"number": "float",
|
|
55
|
+
"boolean": "bool",
|
|
56
|
+
"any": "Any",
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def fetch_discovery(version: str) -> dict[str, Any]:
|
|
61
|
+
url = DISCOVERY_URL.format(version=version)
|
|
62
|
+
print(f"Fetching {url} ...", file=sys.stderr)
|
|
63
|
+
with urllib.request.urlopen(url) as resp:
|
|
64
|
+
return cast(dict[str, Any], json.loads(resp.read()))
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def resolve_schema_name(full_id: str, version_prefix: str) -> str | None:
|
|
68
|
+
"""Extract the short schema name from the full discovery ID."""
|
|
69
|
+
if full_id.startswith(version_prefix):
|
|
70
|
+
return full_id[len(version_prefix) :]
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def ref_to_short_name(ref: str, version_prefix: str) -> str | None:
|
|
75
|
+
"""Convert a $ref value to our short TypedDict name, if it's in SCHEMA_MAP."""
|
|
76
|
+
short = resolve_schema_name(ref, version_prefix)
|
|
77
|
+
if short is None:
|
|
78
|
+
return None
|
|
79
|
+
for td_name, schema_suffix in SCHEMA_MAP.items():
|
|
80
|
+
if short == schema_suffix:
|
|
81
|
+
return td_name
|
|
82
|
+
return None
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def python_type_for_property(prop: dict[str, Any], version_prefix: str, required: bool = True) -> str:
|
|
86
|
+
"""Convert a discovery property definition to a Python type annotation."""
|
|
87
|
+
if "$ref" in prop:
|
|
88
|
+
td_name = ref_to_short_name(prop["$ref"], version_prefix)
|
|
89
|
+
if td_name:
|
|
90
|
+
return td_name
|
|
91
|
+
return "dict[str, Any]"
|
|
92
|
+
|
|
93
|
+
prop_type = prop.get("type", "any")
|
|
94
|
+
|
|
95
|
+
if prop_type == "array":
|
|
96
|
+
items = prop.get("items", {})
|
|
97
|
+
item_type = python_type_for_property(items, version_prefix)
|
|
98
|
+
return f"list[{item_type}]"
|
|
99
|
+
|
|
100
|
+
if prop_type == "object":
|
|
101
|
+
additional = prop.get("additionalProperties", {})
|
|
102
|
+
if additional:
|
|
103
|
+
val_type = python_type_for_property(additional, version_prefix)
|
|
104
|
+
return f"dict[str, {val_type}]"
|
|
105
|
+
return "dict[str, Any]"
|
|
106
|
+
|
|
107
|
+
if "enum" in prop:
|
|
108
|
+
literals = [f'"{v}"' for v in prop["enum"]]
|
|
109
|
+
single_line = f"Literal[{', '.join(literals)}]"
|
|
110
|
+
if len(single_line) <= 80:
|
|
111
|
+
return single_line
|
|
112
|
+
# Multi-line Literal for long enum lists
|
|
113
|
+
inner = ",\n ".join(literals)
|
|
114
|
+
return f"Literal[\n {inner},\n]"
|
|
115
|
+
|
|
116
|
+
return TYPE_MAP.get(prop_type, "Any")
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def generate_typeddict(
|
|
120
|
+
td_name: str,
|
|
121
|
+
schema: dict[str, Any],
|
|
122
|
+
version_prefix: str,
|
|
123
|
+
) -> str:
|
|
124
|
+
"""Generate a TypedDict class definition from a discovery schema."""
|
|
125
|
+
properties = schema.get("properties", {})
|
|
126
|
+
if not properties:
|
|
127
|
+
return f"class {td_name}(TypedDict, total=False):\n pass\n"
|
|
128
|
+
|
|
129
|
+
lines = [f"class {td_name}(TypedDict, total=False):"]
|
|
130
|
+
|
|
131
|
+
desc = schema.get("description", "")
|
|
132
|
+
if desc:
|
|
133
|
+
wrapped = textwrap.fill(desc, width=100, initial_indent=" ", subsequent_indent=" ")
|
|
134
|
+
lines.append(f' """{wrapped[4:]}"""')
|
|
135
|
+
lines.append("")
|
|
136
|
+
|
|
137
|
+
for prop_name, prop_def in sorted(properties.items()):
|
|
138
|
+
py_type = python_type_for_property(prop_def, version_prefix)
|
|
139
|
+
prop_desc = prop_def.get("description", "")
|
|
140
|
+
if prop_desc:
|
|
141
|
+
short_desc = prop_desc.split(".")[0].strip()
|
|
142
|
+
if len(short_desc) > 90:
|
|
143
|
+
short_desc = short_desc[:87] + "..."
|
|
144
|
+
lines.append(f" # {short_desc}")
|
|
145
|
+
if "\n" in py_type:
|
|
146
|
+
# Multi-line type (e.g. long Literal) — indent to field level
|
|
147
|
+
indented = py_type.replace("\n", "\n ")
|
|
148
|
+
lines.append(f" {prop_name}: {indented}")
|
|
149
|
+
else:
|
|
150
|
+
line = f" {prop_name}: {py_type}"
|
|
151
|
+
if len(line) > 119:
|
|
152
|
+
# Break long single-line annotations
|
|
153
|
+
lines.append(f" {prop_name}: (")
|
|
154
|
+
lines.append(f" {py_type}")
|
|
155
|
+
lines.append(" )")
|
|
156
|
+
else:
|
|
157
|
+
lines.append(line)
|
|
158
|
+
|
|
159
|
+
return "\n".join(lines) + "\n"
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def generate_all(discovery: dict[str, Any], version: str) -> str:
|
|
163
|
+
"""Generate the full _generated_types.py file content."""
|
|
164
|
+
schemas = discovery.get("schemas", {})
|
|
165
|
+
|
|
166
|
+
if version == "v1":
|
|
167
|
+
version_prefix = "GoogleCloudAiplatformV1"
|
|
168
|
+
else:
|
|
169
|
+
version_prefix = "GoogleCloudAiplatformV1beta1"
|
|
170
|
+
|
|
171
|
+
header = f'''\
|
|
172
|
+
"""TypedDict definitions for Google Vertex AI generateContent API.
|
|
173
|
+
|
|
174
|
+
Auto-generated from the Vertex AI discovery document ({version}).
|
|
175
|
+
Do not edit manually — regenerate with:
|
|
176
|
+
python scripts/generate_types.py --version {version}
|
|
177
|
+
|
|
178
|
+
API reference (discovery docs):
|
|
179
|
+
https://aiplatform.googleapis.com/$discovery/rest?version=v1
|
|
180
|
+
https://aiplatform.googleapis.com/$discovery/rest?version=v1beta1
|
|
181
|
+
"""
|
|
182
|
+
|
|
183
|
+
from __future__ import annotations
|
|
184
|
+
|
|
185
|
+
from typing import Any, Literal, TypedDict # noqa: UP035
|
|
186
|
+
|
|
187
|
+
'''
|
|
188
|
+
|
|
189
|
+
parts: list[str] = [header]
|
|
190
|
+
|
|
191
|
+
# Track which schemas we actually found
|
|
192
|
+
generated: list[str] = []
|
|
193
|
+
missing: list[str] = []
|
|
194
|
+
|
|
195
|
+
for td_name, schema_suffix in SCHEMA_MAP.items():
|
|
196
|
+
full_id = f"{version_prefix}{schema_suffix}"
|
|
197
|
+
schema = schemas.get(full_id)
|
|
198
|
+
if schema is None:
|
|
199
|
+
missing.append(f"# WARNING: schema {full_id!r} not found in discovery doc")
|
|
200
|
+
continue
|
|
201
|
+
parts.append(generate_typeddict(td_name, schema, version_prefix))
|
|
202
|
+
parts.append("")
|
|
203
|
+
generated.append(td_name)
|
|
204
|
+
|
|
205
|
+
# __all__ for explicit exports
|
|
206
|
+
all_items = [f' "{n}",' for n in generated]
|
|
207
|
+
all_block = "__all__ = [\n" + "\n".join(all_items) + "\n]\n"
|
|
208
|
+
parts.insert(1, all_block)
|
|
209
|
+
parts.insert(2, "")
|
|
210
|
+
|
|
211
|
+
if missing:
|
|
212
|
+
parts.append("\n".join(missing) + "\n")
|
|
213
|
+
|
|
214
|
+
for m in missing:
|
|
215
|
+
print(m, file=sys.stderr)
|
|
216
|
+
|
|
217
|
+
return "\n".join(parts)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def main() -> None:
|
|
221
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
222
|
+
parser.add_argument(
|
|
223
|
+
"--version",
|
|
224
|
+
default="v1beta1",
|
|
225
|
+
choices=["v1", "v1beta1"],
|
|
226
|
+
help="Discovery document version (default: v1beta1)",
|
|
227
|
+
)
|
|
228
|
+
parser.add_argument(
|
|
229
|
+
"--output",
|
|
230
|
+
default="src/axio_transport_google/_generated_types.py",
|
|
231
|
+
help="Output file path",
|
|
232
|
+
)
|
|
233
|
+
parser.add_argument(
|
|
234
|
+
"--input",
|
|
235
|
+
default=None,
|
|
236
|
+
help="Read discovery doc from file instead of fetching",
|
|
237
|
+
)
|
|
238
|
+
args = parser.parse_args()
|
|
239
|
+
|
|
240
|
+
if args.input:
|
|
241
|
+
with open(args.input) as f:
|
|
242
|
+
discovery = json.load(f)
|
|
243
|
+
else:
|
|
244
|
+
discovery = fetch_discovery(args.version)
|
|
245
|
+
|
|
246
|
+
content = generate_all(discovery, args.version)
|
|
247
|
+
|
|
248
|
+
with open(args.output, "w") as f:
|
|
249
|
+
f.write(content)
|
|
250
|
+
print(f"Generated {args.output} ({len(SCHEMA_MAP)} schemas)", file=sys.stderr)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
if __name__ == "__main__":
|
|
254
|
+
main()
|