Skip to content

Commit a5a6c64

Browse files
committed
fix: default messages schema for google adk
1 parent 2206c82 commit a5a6c64

9 files changed

Lines changed: 143 additions & 32 deletions

File tree

packages/uipath-google-adk/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "uipath-google-adk"
3-
version = "0.0.4"
3+
version = "0.0.5"
44
description = "Python SDK that enables developers to build and deploy Google ADK agents to the UiPath Cloud Platform"
55
readme = "README.md"
66
requires-python = ">=3.11"

packages/uipath-google-adk/samples/multi-agent/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
name = "multi-agent"
33
version = "0.0.1"
44
description = "Google ADK multi-agent example with sub-agents and tools"
5+
authors = [{ name = "John Doe" }]
56
readme = "README.md"
67
requires-python = ">=3.11"
78
dependencies = [

packages/uipath-google-adk/samples/quickstart-agent/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ flowchart TB
1919
## Run
2020

2121
```
22-
uipath run agent "What's the weather in San Francisco?"
22+
uipath run agent '{"messages": [{"contentParts": [{"data": {"inline": "What is the weather in San Francisco?"}}], "role": "user"}]}'
2323
```
2424

2525
## Debug

packages/uipath-google-adk/samples/quickstart-agent/pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
name = "quickstart-agent"
33
version = "0.0.1"
44
description = "Quickstart Google ADK agent example"
5+
authors = [{ name = "John Doe" }]
56
readme = "README.md"
67
requires-python = ">=3.11"
78
dependencies = [
@@ -17,3 +18,4 @@ dev = [
1718

1819
[tool.uv]
1920
override-dependencies = ["opentelemetry-sdk>=1.39.0,<1.40.0"]
21+

packages/uipath-google-adk/samples/typed-agent/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
name = "typed-agent"
33
version = "0.0.1"
44
description = "Google ADK agent with strongly-typed input/output schemas"
5+
authors = [{ name = "John Doe" }]
56
readme = "README.md"
67
requires-python = ">=3.11"
78
dependencies = [

packages/uipath-google-adk/src/uipath_google_adk/runtime/runtime.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,14 @@ def _create_success_result(self, output: Any) -> UiPathRuntimeResult:
433433
serialized_output = serialize_defaults(output)
434434

435435
if not isinstance(serialized_output, dict):
436-
serialized_output = {"result": serialized_output}
436+
serialized_output = {
437+
"messages": [
438+
{
439+
"role": "assistant",
440+
"contentParts": [{"data": {"inline": serialized_output}}],
441+
}
442+
]
443+
}
437444

438445
return UiPathRuntimeResult(
439446
output=serialized_output,

packages/uipath-google-adk/src/uipath_google_adk/runtime/schema.py

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
from google.adk.tools.base_tool import BaseTool
1010
from google.adk.tools.base_toolset import BaseToolset
1111
from pydantic import BaseModel, TypeAdapter
12-
from uipath.core.chat import UiPathConversationMessage
1312
from uipath.runtime.schema import (
1413
UiPathRuntimeEdge,
1514
UiPathRuntimeGraph,
@@ -193,50 +192,61 @@ def get_entrypoints_schema(agent: BaseAgent) -> dict[str, Any]:
193192
return schema
194193

195194

196-
def _conversation_messages_schema() -> dict[str, Any]:
197-
"""Generate JSON schema for list[UiPathConversationMessage]."""
198-
adapter = TypeAdapter(list[UiPathConversationMessage])
199-
return adapter.json_schema()
200-
201-
202-
def _default_input_schema() -> dict[str, Any]:
203-
"""Default input schema using UiPath conversation message format."""
204-
messages_schema = _conversation_messages_schema()
205-
schema: dict[str, Any] = {
195+
def _conversation_message_item_schema() -> dict[str, Any]:
196+
"""Minimal message schema: only role and contentParts required, contentParts items only need data.inline."""
197+
return {
206198
"type": "object",
207199
"properties": {
208-
"messages": {
200+
"role": {"type": "string"},
201+
"contentParts": {
209202
"type": "array",
210-
"items": messages_schema["items"],
211-
"title": "Messages",
212-
"description": "UiPath conversation messages",
213-
}
203+
"items": {
204+
"type": "object",
205+
"properties": {
206+
"mimeType": {"type": "string"},
207+
"data": {
208+
"type": "object",
209+
"properties": {
210+
"inline": {},
211+
},
212+
"required": ["inline"],
213+
},
214+
"citations": {"type": "array", "items": {"type": "object"}},
215+
},
216+
"required": ["data"],
217+
},
218+
},
219+
"toolCalls": {"type": "array", "items": {"type": "object"}},
220+
"interrupts": {"type": "array", "items": {"type": "object"}},
214221
},
215-
"required": ["messages"],
222+
"required": ["role", "contentParts"],
216223
}
217-
if "$defs" in messages_schema:
218-
schema["$defs"] = messages_schema["$defs"]
219-
return schema
220224

221225

222-
def _default_output_schema() -> dict[str, Any]:
223-
"""Default output schema using UiPath conversation message format."""
224-
messages_schema = _conversation_messages_schema()
225-
schema: dict[str, Any] = {
226+
def _default_messages_schema() -> dict[str, Any]:
227+
"""Default messages schema using minimal UiPath conversation message format."""
228+
return {
226229
"type": "object",
227230
"properties": {
228231
"messages": {
229232
"type": "array",
230-
"items": messages_schema["items"],
233+
"items": _conversation_message_item_schema(),
231234
"title": "Messages",
232235
"description": "UiPath conversation messages",
233236
}
234237
},
235238
"required": ["messages"],
236239
}
237-
if "$defs" in messages_schema:
238-
schema["$defs"] = messages_schema["$defs"]
239-
return schema
240+
241+
242+
def _default_input_schema() -> dict[str, Any]:
243+
"""Default input schema using UiPath conversation message format."""
244+
return _default_messages_schema()
245+
246+
247+
def _default_output_schema() -> dict[str, Any]:
248+
"""Default output schema using UiPath conversation message format."""
249+
return _default_messages_schema()
240250

241251

242252
def get_agent_graph(agent: BaseAgent) -> UiPathRuntimeGraph:

packages/uipath-google-adk/tests/test_schema.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
from unittest.mock import MagicMock
44

5+
import jsonschema # type: ignore[import-untyped]
56
import pytest
67
from google.adk.agents import BaseAgent, LlmAgent
78
from pydantic import BaseModel
89

910
from uipath_google_adk.runtime.schema import (
11+
_default_input_schema,
1012
get_agent_graph,
1113
get_entrypoints_schema,
1214
resolve_output_schema,
@@ -135,6 +137,94 @@ def test_output_schema_takes_precedence_over_output_key(self):
135137
assert "response" not in schema["output"]["properties"]
136138

137139

140+
class TestDefaultMessagesSchemaValidation:
141+
"""Tests that the default messages schema accepts minimal input."""
142+
143+
def test_minimal_message_with_inline_data(self):
144+
"""Minimal message: only role and contentParts with data.inline."""
145+
schema = _default_input_schema()
146+
data = {
147+
"messages": [
148+
{
149+
"role": "user",
150+
"contentParts": [
151+
{"data": {"inline": "What is the weather in San Francisco?"}}
152+
],
153+
}
154+
]
155+
}
156+
jsonschema.validate(data, schema)
157+
158+
def test_message_with_all_optional_fields(self):
159+
"""Message with all optional fields populated."""
160+
schema = _default_input_schema()
161+
data = {
162+
"messages": [
163+
{
164+
"role": "user",
165+
"contentParts": [
166+
{
167+
"mimeType": "text/plain",
168+
"data": {"inline": "Hello"},
169+
"citations": [],
170+
}
171+
],
172+
"toolCalls": [],
173+
"interrupts": [],
174+
}
175+
]
176+
}
177+
jsonschema.validate(data, schema)
178+
179+
def test_missing_role_fails(self):
180+
"""Message without role should fail validation."""
181+
schema = _default_input_schema()
182+
data = {
183+
"messages": [
184+
{
185+
"contentParts": [{"data": {"inline": "Hello"}}],
186+
}
187+
]
188+
}
189+
with pytest.raises(jsonschema.ValidationError):
190+
jsonschema.validate(data, schema)
191+
192+
def test_missing_content_parts_fails(self):
193+
"""Message without contentParts should fail validation."""
194+
schema = _default_input_schema()
195+
data = {"messages": [{"role": "user"}]}
196+
with pytest.raises(jsonschema.ValidationError):
197+
jsonschema.validate(data, schema)
198+
199+
def test_content_part_missing_data_fails(self):
200+
"""Content part without data should fail validation."""
201+
schema = _default_input_schema()
202+
data = {
203+
"messages": [
204+
{
205+
"role": "user",
206+
"contentParts": [{"mimeType": "text/plain"}],
207+
}
208+
]
209+
}
210+
with pytest.raises(jsonschema.ValidationError):
211+
jsonschema.validate(data, schema)
212+
213+
def test_data_missing_inline_fails(self):
214+
"""Data without inline should fail validation."""
215+
schema = _default_input_schema()
216+
data = {
217+
"messages": [
218+
{
219+
"role": "user",
220+
"contentParts": [{"data": {}}],
221+
}
222+
]
223+
}
224+
with pytest.raises(jsonschema.ValidationError):
225+
jsonschema.validate(data, schema)
226+
227+
138228
class TestResolveOutputSchema:
139229
"""Tests for resolve_output_schema validation."""
140230

packages/uipath-google-adk/uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)