|
8 | 8 | ToolCall, |
9 | 9 | ToolCallResult, |
10 | 10 | ) |
11 | | -from pydantic import BaseModel |
12 | 11 | from uipath.runtime.schema import ( |
13 | 12 | UiPathRuntimeEdge, |
14 | 13 | UiPathRuntimeGraph, |
|
25 | 24 | ) |
26 | 25 |
|
27 | 26 |
|
| 27 | +def _conversation_message_item_schema() -> dict[str, Any]: |
| 28 | + """Minimal message schema: only role and contentParts required, contentParts items only need data.inline.""" |
| 29 | + return { |
| 30 | + "type": "object", |
| 31 | + "properties": { |
| 32 | + "role": {"type": "string"}, |
| 33 | + "contentParts": { |
| 34 | + "type": "array", |
| 35 | + "items": { |
| 36 | + "type": "object", |
| 37 | + "properties": { |
| 38 | + "mimeType": {"type": "string"}, |
| 39 | + "data": { |
| 40 | + "type": "object", |
| 41 | + "properties": { |
| 42 | + "inline": {}, |
| 43 | + }, |
| 44 | + "required": ["inline"], |
| 45 | + }, |
| 46 | + "citations": {"type": "array", "items": {"type": "object"}}, |
| 47 | + }, |
| 48 | + "required": ["data"], |
| 49 | + }, |
| 50 | + }, |
| 51 | + "toolCalls": {"type": "array", "items": {"type": "object"}}, |
| 52 | + "interrupts": {"type": "array", "items": {"type": "object"}}, |
| 53 | + }, |
| 54 | + "required": ["role", "contentParts"], |
| 55 | + } |
| 56 | + |
| 57 | + |
| 58 | +def _default_messages_schema() -> dict[str, Any]: |
| 59 | + """Default messages schema using minimal UiPath conversation message format.""" |
| 60 | + return { |
| 61 | + "type": "object", |
| 62 | + "properties": { |
| 63 | + "messages": { |
| 64 | + "type": "array", |
| 65 | + "items": _conversation_message_item_schema(), |
| 66 | + "title": "Messages", |
| 67 | + "description": "UiPath conversation messages", |
| 68 | + } |
| 69 | + }, |
| 70 | + "required": ["messages"], |
| 71 | + } |
| 72 | + |
| 73 | + |
| 74 | +def _default_input_schema() -> dict[str, Any]: |
| 75 | + """Default input schema using UiPath conversation message format.""" |
| 76 | + return _default_messages_schema() |
| 77 | + |
| 78 | + |
| 79 | +def _default_output_schema() -> dict[str, Any]: |
| 80 | + """Default output schema using UiPath conversation message format.""" |
| 81 | + return _default_messages_schema() |
| 82 | + |
| 83 | + |
28 | 84 | def get_entrypoints_schema(workflow: Workflow) -> dict[str, Any]: |
29 | 85 | """ |
30 | 86 | Extract input/output schema from a LlamaIndex workflow. |
31 | 87 |
|
| 88 | + For chat agents (BaseWorkflowAgent), uses the default UiPath messages schema |
| 89 | + for both input and output (matching the google-adk integration convention). |
| 90 | + For regular workflows, extracts schema from StartEvent/StopEvent. |
| 91 | +
|
32 | 92 | Args: |
33 | 93 | workflow: A LlamaIndex Workflow instance |
34 | 94 |
|
35 | 95 | Returns: |
36 | 96 | Dictionary with input and output schemas |
37 | 97 | """ |
38 | 98 | schema = { |
39 | | - "input": {"type": "object", "properties": {}, "required": []}, |
40 | | - "output": {"type": "object", "properties": {}, "required": []}, |
| 99 | + "input": _default_input_schema(), |
| 100 | + "output": _default_output_schema(), |
41 | 101 | } |
42 | 102 |
|
| 103 | + # Chat agents use the messages schema for input/output — do not override from events |
| 104 | + if isinstance(workflow, BaseWorkflowAgent): |
| 105 | + return schema |
| 106 | + |
43 | 107 | # Find the actual StartEvent and StopEvent classes used in this workflow |
44 | 108 | start_event_class = workflow._start_event_class |
45 | 109 | stop_event_class = workflow._stop_event_class |
46 | 110 |
|
47 | 111 | # Generate input schema from StartEvent |
48 | 112 | try: |
49 | | - if isinstance(workflow, BaseWorkflowAgent): |
50 | | - # For workflow agents, define a simple schema with just user_msg |
51 | | - schema["input"] = { |
52 | | - "type": "object", |
53 | | - "properties": { |
54 | | - "user_msg": { |
55 | | - "type": "string", |
56 | | - "title": "User Message", |
57 | | - "description": "The user's question or request", |
58 | | - } |
59 | | - }, |
60 | | - "required": ["user_msg"], |
61 | | - } |
62 | | - else: |
63 | | - input_schema = start_event_class.model_json_schema() |
64 | | - # Resolve references and handle nullable types |
65 | | - unpacked_input, _ = transform_references(input_schema) |
66 | | - schema["input"]["properties"] = transform_nullable_types( |
67 | | - unpacked_input.get("properties", {}) |
68 | | - ) |
69 | | - schema["input"]["required"] = unpacked_input.get("required", []) |
| 113 | + input_schema = start_event_class.model_json_schema() |
| 114 | + # Resolve references and handle nullable types |
| 115 | + unpacked_input, _ = transform_references(input_schema) |
| 116 | + schema["input"]["properties"] = transform_nullable_types( |
| 117 | + unpacked_input.get("properties", {}) |
| 118 | + ) |
| 119 | + schema["input"]["required"] = unpacked_input.get("required", []) |
70 | 120 | except (AttributeError, Exception): |
71 | 121 | pass |
72 | 122 |
|
73 | | - # Handle output schema - check if it's a workflow agent with output_cls first |
74 | | - if isinstance(workflow, BaseWorkflowAgent): |
75 | | - output_cls: type[BaseModel] | None = getattr(workflow, "output_cls", None) |
76 | | - if output_cls is not None: |
77 | | - try: |
78 | | - output_schema = output_cls.model_json_schema() |
79 | | - # Resolve references and handle nullable types |
80 | | - unpacked_output, _ = transform_references(output_schema) |
81 | | - schema["output"]["properties"] = transform_nullable_types( |
82 | | - unpacked_output.get("properties", {}) |
83 | | - ) |
84 | | - schema["output"]["required"] = unpacked_output.get("required", []) |
85 | | - except (AttributeError, Exception): |
86 | | - pass |
87 | 123 | # Check if it's the base StopEvent or a custom subclass |
88 | | - elif stop_event_class is StopEvent: |
| 124 | + if stop_event_class is StopEvent: |
89 | 125 | # base StopEvent |
90 | 126 | schema["output"] = { |
91 | 127 | "type": "object", |
|
0 commit comments