kagent-adk 0.7.11__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.
kagent/adk/types.py ADDED
@@ -0,0 +1,268 @@
1
+ import logging
2
+ from typing import Any, Callable, Literal, Optional, Union
3
+
4
+ import httpx
5
+ from agentsts.adk import ADKTokenPropagationPlugin
6
+ from google.adk.agents import Agent
7
+ from google.adk.agents.base_agent import BaseAgent
8
+ from google.adk.agents.llm_agent import ToolUnion
9
+ from google.adk.agents.remote_a2a_agent import AGENT_CARD_WELL_KNOWN_PATH, DEFAULT_TIMEOUT, RemoteA2aAgent
10
+ from google.adk.code_executors.base_code_executor import BaseCodeExecutor
11
+ from google.adk.models.anthropic_llm import Claude as ClaudeLLM
12
+ from google.adk.models.google_llm import Gemini as GeminiLLM
13
+ from google.adk.models.lite_llm import LiteLlm
14
+ from google.adk.tools.agent_tool import AgentTool
15
+ from google.adk.tools.mcp_tool import McpToolset, SseConnectionParams, StreamableHTTPConnectionParams
16
+ from pydantic import BaseModel, Field
17
+
18
+ from kagent.adk.sandbox_code_executer import SandboxedLocalCodeExecutor
19
+
20
+ from .models import AzureOpenAI as OpenAIAzure
21
+ from .models import OpenAI as OpenAINative
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+ # Proxy host header used for Gateway API routing when using a proxy
26
+ PROXY_HOST_HEADER = "x-kagent-host"
27
+
28
+
29
+ class HttpMcpServerConfig(BaseModel):
30
+ params: StreamableHTTPConnectionParams
31
+ tools: list[str] = Field(default_factory=list)
32
+
33
+
34
+ class SseMcpServerConfig(BaseModel):
35
+ params: SseConnectionParams
36
+ tools: list[str] = Field(default_factory=list)
37
+
38
+
39
+ class RemoteAgentConfig(BaseModel):
40
+ name: str
41
+ url: str
42
+ headers: dict[str, Any] | None = None
43
+ timeout: float = DEFAULT_TIMEOUT
44
+ description: str = ""
45
+
46
+
47
+ class BaseLLM(BaseModel):
48
+ model: str
49
+ headers: dict[str, str] | None = None
50
+
51
+ # TLS/SSL configuration (applies to all model types)
52
+ tls_disable_verify: bool | None = None
53
+ tls_ca_cert_path: str | None = None
54
+ tls_disable_system_cas: bool | None = None
55
+
56
+
57
+ class OpenAI(BaseLLM):
58
+ base_url: str | None = None
59
+ frequency_penalty: float | None = None
60
+ max_tokens: int | None = None
61
+ n: int | None = None
62
+ presence_penalty: float | None = None
63
+ reasoning_effort: str | None = None
64
+ seed: int | None = None
65
+ temperature: float | None = None
66
+ timeout: int | None = None
67
+ top_p: float | None = None
68
+
69
+ type: Literal["openai"]
70
+
71
+
72
+ class AzureOpenAI(BaseLLM):
73
+ type: Literal["azure_openai"]
74
+
75
+
76
+ class Anthropic(BaseLLM):
77
+ base_url: str | None = None
78
+
79
+ type: Literal["anthropic"]
80
+
81
+
82
+ class GeminiVertexAI(BaseLLM):
83
+ type: Literal["gemini_vertex_ai"]
84
+
85
+
86
+ class GeminiAnthropic(BaseLLM):
87
+ type: Literal["gemini_anthropic"]
88
+
89
+
90
+ class Ollama(BaseLLM):
91
+ type: Literal["ollama"]
92
+
93
+
94
+ class Gemini(BaseLLM):
95
+ type: Literal["gemini"]
96
+
97
+
98
+ class Bedrock(BaseLLM):
99
+ region: str | None = None
100
+ type: Literal["bedrock"]
101
+
102
+
103
+ class AgentConfig(BaseModel):
104
+ model: Union[OpenAI, Anthropic, GeminiVertexAI, GeminiAnthropic, Ollama, AzureOpenAI, Gemini, Bedrock] = Field(
105
+ discriminator="type"
106
+ )
107
+ description: str
108
+ instruction: str
109
+ http_tools: list[HttpMcpServerConfig] | None = None # Streamable HTTP MCP tools
110
+ sse_tools: list[SseMcpServerConfig] | None = None # SSE MCP tools
111
+ remote_agents: list[RemoteAgentConfig] | None = None # remote agents
112
+ execute_code: bool | None = None
113
+ # This stream option refers to LLM response streaming, not A2A streaming
114
+ stream: bool | None = None
115
+
116
+ def to_agent(self, name: str, sts_integration: Optional[ADKTokenPropagationPlugin] = None) -> Agent:
117
+ if name is None or not str(name).strip():
118
+ raise ValueError("Agent name must be a non-empty string.")
119
+ tools: list[ToolUnion] = []
120
+ header_provider = None
121
+ if sts_integration:
122
+ header_provider = sts_integration.header_provider
123
+ if self.http_tools:
124
+ for http_tool in self.http_tools: # add http tools
125
+ # If the proxy is configured, the url and headers are set in the json configuration
126
+ tools.append(
127
+ McpToolset(
128
+ connection_params=http_tool.params, tool_filter=http_tool.tools, header_provider=header_provider
129
+ )
130
+ )
131
+ if self.sse_tools:
132
+ for sse_tool in self.sse_tools: # add sse tools
133
+ # If the proxy is configured, the url and headers are set in the json configuration
134
+ tools.append(
135
+ McpToolset(
136
+ connection_params=sse_tool.params, tool_filter=sse_tool.tools, header_provider=header_provider
137
+ )
138
+ )
139
+ if self.remote_agents:
140
+ for remote_agent in self.remote_agents: # Add remote agents as tools
141
+ # Prepare httpx client parameters
142
+ timeout = httpx.Timeout(timeout=remote_agent.timeout)
143
+ headers: dict[str, str] | None = remote_agent.headers
144
+ base_url: str | None = None
145
+ event_hooks: dict[str, list[Callable[[httpx.Request], None]]] | None = None
146
+
147
+ # If headers includes the proxy host header, it means we're using a proxy
148
+ # RemoteA2aAgent may use URLs from agent card response, so we need to
149
+ # rewrite all request URLs to use the proxy URL while preserving the proxy host header
150
+ if remote_agent.headers and PROXY_HOST_HEADER in remote_agent.headers:
151
+ # Parse the proxy URL to extract base URL
152
+ from urllib.parse import urlparse as parse_url
153
+
154
+ parsed_proxy = parse_url(remote_agent.url)
155
+ proxy_base = f"{parsed_proxy.scheme}://{parsed_proxy.netloc}"
156
+ target_host = remote_agent.headers[PROXY_HOST_HEADER]
157
+
158
+ # Event hook to rewrite request URLs to use proxy while preserving the proxy host header
159
+ # Note: Relative paths are handled by base_url below, so they'll already point to proxy_base
160
+ def make_rewrite_url_to_proxy(proxy_base: str, target_host: str) -> Callable[[httpx.Request], None]:
161
+ async def rewrite_url_to_proxy(request: httpx.Request) -> None:
162
+ parsed = parse_url(str(request.url))
163
+ proxy_netloc = parse_url(proxy_base).netloc
164
+
165
+ # If URL is absolute and points to a different host, rewrite to the proxy base URL
166
+ if parsed.netloc and parsed.netloc != proxy_netloc:
167
+ # This is an absolute URL pointing to the target service, rewrite it
168
+ new_url = f"{proxy_base}{parsed.path}"
169
+ if parsed.query:
170
+ new_url += f"?{parsed.query}"
171
+ request.url = httpx.URL(new_url)
172
+
173
+ # Always set proxy host header for Gateway API routing
174
+ request.headers[PROXY_HOST_HEADER] = target_host
175
+
176
+ return rewrite_url_to_proxy
177
+
178
+ # Set base_url so relative paths work correctly with httpx
179
+ # httpx requires either base_url or absolute URLs - relative paths will fail without base_url
180
+ base_url = proxy_base
181
+ event_hooks = {"request": [make_rewrite_url_to_proxy(proxy_base, target_host)]}
182
+
183
+ # Note: httpx doesn't accept None for base_url/event_hooks, so we only pass the parameters if set
184
+ if base_url and event_hooks:
185
+ client = httpx.AsyncClient(
186
+ timeout=timeout,
187
+ headers=headers,
188
+ base_url=base_url,
189
+ event_hooks=event_hooks,
190
+ )
191
+ elif headers:
192
+ client = httpx.AsyncClient(
193
+ timeout=timeout,
194
+ headers=headers,
195
+ )
196
+ else:
197
+ client = httpx.AsyncClient(
198
+ timeout=timeout,
199
+ )
200
+
201
+ remote_a2a_agent = RemoteA2aAgent(
202
+ name=remote_agent.name,
203
+ agent_card=f"{remote_agent.url}{AGENT_CARD_WELL_KNOWN_PATH}",
204
+ description=remote_agent.description,
205
+ httpx_client=client,
206
+ )
207
+
208
+ tools.append(AgentTool(agent=remote_a2a_agent))
209
+
210
+ extra_headers = self.model.headers or {}
211
+
212
+ code_executor = SandboxedLocalCodeExecutor() if self.execute_code else None
213
+
214
+ if self.model.type == "openai":
215
+ model = OpenAINative(
216
+ type="openai",
217
+ base_url=self.model.base_url,
218
+ default_headers=extra_headers,
219
+ frequency_penalty=self.model.frequency_penalty,
220
+ max_tokens=self.model.max_tokens,
221
+ model=self.model.model,
222
+ n=self.model.n,
223
+ presence_penalty=self.model.presence_penalty,
224
+ reasoning_effort=self.model.reasoning_effort,
225
+ seed=self.model.seed,
226
+ temperature=self.model.temperature,
227
+ timeout=self.model.timeout,
228
+ top_p=self.model.top_p,
229
+ # TLS configuration
230
+ tls_disable_verify=self.model.tls_disable_verify,
231
+ tls_ca_cert_path=self.model.tls_ca_cert_path,
232
+ tls_disable_system_cas=self.model.tls_disable_system_cas,
233
+ )
234
+ elif self.model.type == "anthropic":
235
+ model = LiteLlm(
236
+ model=f"anthropic/{self.model.model}", base_url=self.model.base_url, extra_headers=extra_headers
237
+ )
238
+ elif self.model.type == "gemini_vertex_ai":
239
+ model = GeminiLLM(model=self.model.model)
240
+ elif self.model.type == "gemini_anthropic":
241
+ model = ClaudeLLM(model=self.model.model)
242
+ elif self.model.type == "ollama":
243
+ model = LiteLlm(model=f"ollama_chat/{self.model.model}", extra_headers=extra_headers)
244
+ elif self.model.type == "azure_openai":
245
+ model = OpenAIAzure(
246
+ model=self.model.model,
247
+ type="azure_openai",
248
+ default_headers=extra_headers,
249
+ # TLS configuration
250
+ tls_disable_verify=self.model.tls_disable_verify,
251
+ tls_ca_cert_path=self.model.tls_ca_cert_path,
252
+ tls_disable_system_cas=self.model.tls_disable_system_cas,
253
+ )
254
+ elif self.model.type == "gemini":
255
+ model = self.model.model
256
+ elif self.model.type == "bedrock":
257
+ # LiteLLM handles Bedrock via boto3 internally when model starts with "bedrock/"
258
+ model = LiteLlm(model=f"bedrock/{self.model.model}", extra_headers=extra_headers)
259
+ else:
260
+ raise ValueError(f"Invalid model type: {self.model.type}")
261
+ return Agent(
262
+ name=name,
263
+ model=model,
264
+ description=self.description,
265
+ instruction=self.instruction,
266
+ tools=tools,
267
+ code_executor=code_executor,
268
+ )
@@ -0,0 +1,35 @@
1
+ Metadata-Version: 2.4
2
+ Name: kagent-adk
3
+ Version: 0.7.11
4
+ Summary: kagent-adk is an sdk for integrating adk agents with kagent
5
+ Requires-Python: >=3.11.0
6
+ Requires-Dist: a2a-sdk>=0.3.22
7
+ Requires-Dist: agentsts-adk>=0.0.8
8
+ Requires-Dist: agentsts-core>=0.0.8
9
+ Requires-Dist: aiofiles>=24.1.0
10
+ Requires-Dist: anthropic[vertex]>=0.49.0
11
+ Requires-Dist: anyio>=4.9.0
12
+ Requires-Dist: boto3>=1.28.57
13
+ Requires-Dist: fastapi>=0.115.1
14
+ Requires-Dist: filelock>=3.20.3
15
+ Requires-Dist: google-adk>=1.22.1
16
+ Requires-Dist: google-auth>=2.40.2
17
+ Requires-Dist: google-genai>=1.21.1
18
+ Requires-Dist: httpx>=0.25.0
19
+ Requires-Dist: jsonref>=1.1.0
20
+ Requires-Dist: kagent-core
21
+ Requires-Dist: kagent-skills
22
+ Requires-Dist: litellm>=1.74.3
23
+ Requires-Dist: mcp>=1.25.0
24
+ Requires-Dist: openai>=1.72.0
25
+ Requires-Dist: protobuf>=6
26
+ Requires-Dist: pydantic>=2.5.0
27
+ Requires-Dist: typer>=0.15.0
28
+ Requires-Dist: typing-extensions>=4.8.0
29
+ Requires-Dist: urllib3>=2.6.3
30
+ Requires-Dist: uvicorn>=0.34.0
31
+ Provides-Extra: memory
32
+ Requires-Dist: psutil>=6.1.0; extra == 'memory'
33
+ Provides-Extra: test
34
+ Requires-Dist: pytest-asyncio>=0.25.3; extra == 'test'
35
+ Requires-Dist: pytest>=8.3.5; extra == 'test'
@@ -0,0 +1,34 @@
1
+ kagent/adk/__init__.py,sha256=Cam9hwhl6Z1tZ3WJIB1KATX24MwRMpiyBLYF64DTqQI,182
2
+ kagent/adk/_a2a.py,sha256=kI6XVd_BsUW-M_1Hcysd8O3-EVjPVgawnwOero7J3gE,6157
3
+ kagent/adk/_agent_executor.py,sha256=xxL6IVkWwOeTXZUjGmHGwjoLINZwbP8183xfFnHBlVk,13688
4
+ kagent/adk/_lifespan.py,sha256=3kHVo2CYPu1j4FUpGtnbR6ERyDbq9bMbodMx4v3lOnM,1188
5
+ kagent/adk/_session_service.py,sha256=6kwFS4FF10HlUyyCV2SgwxqKIJ47s0ZZ8KW-iIRDyec,5858
6
+ kagent/adk/_token.py,sha256=OL46m7U5vUTby1WWjVB7Jqzig4TWddzoAmLVLlfSdAg,2515
7
+ kagent/adk/cli.py,sha256=DV8QMNTzPtVMQPB2WlgujwjQc86sJ9DLiOE08BPwhcE,7494
8
+ kagent/adk/sandbox_code_executer.py,sha256=L38xNKi-aD3kDiemWDn4AgIUkgcJydBoHq12FX-p0Vs,2967
9
+ kagent/adk/skill_fetcher.py,sha256=SaoXCjiCeUb_9ct4jqMoBllR7cnwPjdDlpngJ9Vy7Tc,3587
10
+ kagent/adk/types.py,sha256=gf7NozlQ618vvfw-hfXLhQP7FvwZyt2htHD5oSg901o,11121
11
+ kagent/adk/artifacts/__init__.py,sha256=8A-kUfy_itZ-PEH0UQTqACUa7Ihr_3JZPKFKykrUyhc,419
12
+ kagent/adk/artifacts/artifacts_toolset.py,sha256=EJq1I843N0POYaiZw3jF9GIHplQ9PmXKEXrGBxMFTZ8,1941
13
+ kagent/adk/artifacts/return_artifacts_tool.py,sha256=5bz5xP-wzcvxdrbhx-85TUQIWLUUAuwKRbjnilgpzM0,6784
14
+ kagent/adk/artifacts/session_path.py,sha256=hLXHhERhhHSXmYTrx4b5C1blIxhonoYI1JIjjstIw7Y,3912
15
+ kagent/adk/artifacts/stage_artifacts_tool.py,sha256=mGbM1RSvqdg0LZBjnf-ZC5ebOJwgoN0KUKF1jreWh9k,7401
16
+ kagent/adk/converters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ kagent/adk/converters/error_mappings.py,sha256=1KUJPS8VrcaTv6yUKb5Whg-S2XX8YGJmtTIeZqnqvuw,2769
18
+ kagent/adk/converters/event_converter.py,sha256=wVjUYQWFlf5MLrfyxQm_kxDIy_GFCSacBQ1qM1iwsJA,10824
19
+ kagent/adk/converters/part_converter.py,sha256=8Ej9xGRYW8YoPnExGDnEUw1beurCfkNhAvFa-LE_-VM,7512
20
+ kagent/adk/converters/request_converter.py,sha256=X9yIn_01TPbtPHd8xrXBlGHCmYqjS0hnPdwEag6RC3M,1219
21
+ kagent/adk/models/__init__.py,sha256=mqD0JhS9kT1rMpFNLq5-qnjstpp6lzT9xADaOfjrUKY,78
22
+ kagent/adk/models/_openai.py,sha256=iSJ35xBj6l6ehJ5sgC1QR29qBC-fVFokazvNwCcAZog,23858
23
+ kagent/adk/models/_ssl.py,sha256=oxTArH3Ugzc3MW0xVCHitus5bV9bJVCpgopiGCEOnvs,9351
24
+ kagent/adk/tools/README.md,sha256=EE9LItLaQgI7U8pBVI0txo8M4fkY_2GRQBuGHVIHygA,6218
25
+ kagent/adk/tools/__init__.py,sha256=YWNjFwDe7Op547YbHm6OAt5Z-RSp4ybxpdYWp2ReZVY,390
26
+ kagent/adk/tools/bash_tool.py,sha256=PssanZ3LWz3QVsUA_-Y_RrvN2lrMlvERp9JeXT_8cX4,2847
27
+ kagent/adk/tools/file_tools.py,sha256=7nGFx8QW__EyT_K27inVFZfJqggGb7jwvKT-Xg1UotE,6947
28
+ kagent/adk/tools/skill_tool.py,sha256=duP7kXY1ho18ISuCfJAmcCbQCuqGFcnNgeKRtRSUDr4,3831
29
+ kagent/adk/tools/skills_plugin.py,sha256=dPoa4z16R_s3wbzkGO8mBOHYhkvacp8jlakvAlefcww,1715
30
+ kagent/adk/tools/skills_toolset.py,sha256=v2ZNmuGnRIr_h4Db62ydN5clcHtPlMuYQRtgt2l304s,2255
31
+ kagent_adk-0.7.11.dist-info/METADATA,sha256=r4-5wNrh4BhooRXAHg6IGfuKchZBkjmafBPM6UFgiQs,1136
32
+ kagent_adk-0.7.11.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
33
+ kagent_adk-0.7.11.dist-info/entry_points.txt,sha256=yXcEVBh62NJ9prNck4hciUfcTo-uj9sLUAEpmjgSrjI,54
34
+ kagent_adk-0.7.11.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ kagent-adk = kagent.adk.cli:run_cli