atlas-chat 0.1.0__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.
Files changed (250) hide show
  1. atlas/__init__.py +40 -0
  2. atlas/application/__init__.py +7 -0
  3. atlas/application/chat/__init__.py +7 -0
  4. atlas/application/chat/agent/__init__.py +10 -0
  5. atlas/application/chat/agent/act_loop.py +179 -0
  6. atlas/application/chat/agent/factory.py +142 -0
  7. atlas/application/chat/agent/protocols.py +46 -0
  8. atlas/application/chat/agent/react_loop.py +338 -0
  9. atlas/application/chat/agent/think_act_loop.py +171 -0
  10. atlas/application/chat/approval_manager.py +151 -0
  11. atlas/application/chat/elicitation_manager.py +191 -0
  12. atlas/application/chat/events/__init__.py +1 -0
  13. atlas/application/chat/events/agent_event_relay.py +112 -0
  14. atlas/application/chat/modes/__init__.py +1 -0
  15. atlas/application/chat/modes/agent.py +125 -0
  16. atlas/application/chat/modes/plain.py +74 -0
  17. atlas/application/chat/modes/rag.py +81 -0
  18. atlas/application/chat/modes/tools.py +179 -0
  19. atlas/application/chat/orchestrator.py +213 -0
  20. atlas/application/chat/policies/__init__.py +1 -0
  21. atlas/application/chat/policies/tool_authorization.py +99 -0
  22. atlas/application/chat/preprocessors/__init__.py +1 -0
  23. atlas/application/chat/preprocessors/message_builder.py +92 -0
  24. atlas/application/chat/preprocessors/prompt_override_service.py +104 -0
  25. atlas/application/chat/service.py +454 -0
  26. atlas/application/chat/utilities/__init__.py +6 -0
  27. atlas/application/chat/utilities/error_handler.py +367 -0
  28. atlas/application/chat/utilities/event_notifier.py +546 -0
  29. atlas/application/chat/utilities/file_processor.py +613 -0
  30. atlas/application/chat/utilities/tool_executor.py +789 -0
  31. atlas/atlas_chat_cli.py +347 -0
  32. atlas/atlas_client.py +238 -0
  33. atlas/core/__init__.py +0 -0
  34. atlas/core/auth.py +205 -0
  35. atlas/core/authorization_manager.py +27 -0
  36. atlas/core/capabilities.py +123 -0
  37. atlas/core/compliance.py +215 -0
  38. atlas/core/domain_whitelist.py +147 -0
  39. atlas/core/domain_whitelist_middleware.py +82 -0
  40. atlas/core/http_client.py +28 -0
  41. atlas/core/log_sanitizer.py +102 -0
  42. atlas/core/metrics_logger.py +59 -0
  43. atlas/core/middleware.py +131 -0
  44. atlas/core/otel_config.py +242 -0
  45. atlas/core/prompt_risk.py +200 -0
  46. atlas/core/rate_limit.py +0 -0
  47. atlas/core/rate_limit_middleware.py +64 -0
  48. atlas/core/security_headers_middleware.py +51 -0
  49. atlas/domain/__init__.py +37 -0
  50. atlas/domain/chat/__init__.py +1 -0
  51. atlas/domain/chat/dtos.py +85 -0
  52. atlas/domain/errors.py +96 -0
  53. atlas/domain/messages/__init__.py +12 -0
  54. atlas/domain/messages/models.py +160 -0
  55. atlas/domain/rag_mcp_service.py +664 -0
  56. atlas/domain/sessions/__init__.py +7 -0
  57. atlas/domain/sessions/models.py +36 -0
  58. atlas/domain/unified_rag_service.py +371 -0
  59. atlas/infrastructure/__init__.py +10 -0
  60. atlas/infrastructure/app_factory.py +135 -0
  61. atlas/infrastructure/events/__init__.py +1 -0
  62. atlas/infrastructure/events/cli_event_publisher.py +140 -0
  63. atlas/infrastructure/events/websocket_publisher.py +140 -0
  64. atlas/infrastructure/sessions/in_memory_repository.py +56 -0
  65. atlas/infrastructure/transport/__init__.py +7 -0
  66. atlas/infrastructure/transport/websocket_connection_adapter.py +33 -0
  67. atlas/init_cli.py +226 -0
  68. atlas/interfaces/__init__.py +15 -0
  69. atlas/interfaces/events.py +134 -0
  70. atlas/interfaces/llm.py +54 -0
  71. atlas/interfaces/rag.py +40 -0
  72. atlas/interfaces/sessions.py +75 -0
  73. atlas/interfaces/tools.py +57 -0
  74. atlas/interfaces/transport.py +24 -0
  75. atlas/main.py +564 -0
  76. atlas/mcp/api_key_demo/README.md +76 -0
  77. atlas/mcp/api_key_demo/main.py +172 -0
  78. atlas/mcp/api_key_demo/run.sh +56 -0
  79. atlas/mcp/basictable/main.py +147 -0
  80. atlas/mcp/calculator/main.py +149 -0
  81. atlas/mcp/code-executor/execution_engine.py +98 -0
  82. atlas/mcp/code-executor/execution_environment.py +95 -0
  83. atlas/mcp/code-executor/main.py +528 -0
  84. atlas/mcp/code-executor/result_processing.py +276 -0
  85. atlas/mcp/code-executor/script_generation.py +195 -0
  86. atlas/mcp/code-executor/security_checker.py +140 -0
  87. atlas/mcp/corporate_cars/main.py +437 -0
  88. atlas/mcp/csv_reporter/main.py +545 -0
  89. atlas/mcp/duckduckgo/main.py +182 -0
  90. atlas/mcp/elicitation_demo/README.md +171 -0
  91. atlas/mcp/elicitation_demo/main.py +262 -0
  92. atlas/mcp/env-demo/README.md +158 -0
  93. atlas/mcp/env-demo/main.py +199 -0
  94. atlas/mcp/file_size_test/main.py +284 -0
  95. atlas/mcp/filesystem/main.py +348 -0
  96. atlas/mcp/image_demo/main.py +113 -0
  97. atlas/mcp/image_demo/requirements.txt +4 -0
  98. atlas/mcp/logging_demo/README.md +72 -0
  99. atlas/mcp/logging_demo/main.py +103 -0
  100. atlas/mcp/many_tools_demo/main.py +50 -0
  101. atlas/mcp/order_database/__init__.py +0 -0
  102. atlas/mcp/order_database/main.py +369 -0
  103. atlas/mcp/order_database/signal_data.csv +1001 -0
  104. atlas/mcp/pdfbasic/main.py +394 -0
  105. atlas/mcp/pptx_generator/main.py +760 -0
  106. atlas/mcp/pptx_generator/requirements.txt +13 -0
  107. atlas/mcp/pptx_generator/run_test.sh +1 -0
  108. atlas/mcp/pptx_generator/test_pptx_generator_security.py +169 -0
  109. atlas/mcp/progress_demo/main.py +167 -0
  110. atlas/mcp/progress_updates_demo/QUICKSTART.md +273 -0
  111. atlas/mcp/progress_updates_demo/README.md +120 -0
  112. atlas/mcp/progress_updates_demo/main.py +497 -0
  113. atlas/mcp/prompts/main.py +222 -0
  114. atlas/mcp/public_demo/main.py +189 -0
  115. atlas/mcp/sampling_demo/README.md +169 -0
  116. atlas/mcp/sampling_demo/main.py +234 -0
  117. atlas/mcp/thinking/main.py +77 -0
  118. atlas/mcp/tool_planner/main.py +240 -0
  119. atlas/mcp/ui-demo/badmesh.png +0 -0
  120. atlas/mcp/ui-demo/main.py +383 -0
  121. atlas/mcp/ui-demo/templates/button_demo.html +32 -0
  122. atlas/mcp/ui-demo/templates/data_visualization.html +32 -0
  123. atlas/mcp/ui-demo/templates/form_demo.html +28 -0
  124. atlas/mcp/username-override-demo/README.md +320 -0
  125. atlas/mcp/username-override-demo/main.py +308 -0
  126. atlas/modules/__init__.py +0 -0
  127. atlas/modules/config/__init__.py +34 -0
  128. atlas/modules/config/cli.py +231 -0
  129. atlas/modules/config/config_manager.py +1096 -0
  130. atlas/modules/file_storage/__init__.py +22 -0
  131. atlas/modules/file_storage/cli.py +330 -0
  132. atlas/modules/file_storage/content_extractor.py +290 -0
  133. atlas/modules/file_storage/manager.py +295 -0
  134. atlas/modules/file_storage/mock_s3_client.py +402 -0
  135. atlas/modules/file_storage/s3_client.py +417 -0
  136. atlas/modules/llm/__init__.py +19 -0
  137. atlas/modules/llm/caller.py +287 -0
  138. atlas/modules/llm/litellm_caller.py +675 -0
  139. atlas/modules/llm/models.py +19 -0
  140. atlas/modules/mcp_tools/__init__.py +17 -0
  141. atlas/modules/mcp_tools/client.py +2123 -0
  142. atlas/modules/mcp_tools/token_storage.py +556 -0
  143. atlas/modules/prompts/prompt_provider.py +130 -0
  144. atlas/modules/rag/__init__.py +24 -0
  145. atlas/modules/rag/atlas_rag_client.py +336 -0
  146. atlas/modules/rag/client.py +129 -0
  147. atlas/routes/admin_routes.py +865 -0
  148. atlas/routes/config_routes.py +484 -0
  149. atlas/routes/feedback_routes.py +361 -0
  150. atlas/routes/files_routes.py +274 -0
  151. atlas/routes/health_routes.py +40 -0
  152. atlas/routes/mcp_auth_routes.py +223 -0
  153. atlas/server_cli.py +164 -0
  154. atlas/tests/conftest.py +20 -0
  155. atlas/tests/integration/test_mcp_auth_integration.py +152 -0
  156. atlas/tests/manual_test_sampling.py +87 -0
  157. atlas/tests/modules/mcp_tools/test_client_auth.py +226 -0
  158. atlas/tests/modules/mcp_tools/test_client_env.py +191 -0
  159. atlas/tests/test_admin_mcp_server_management_routes.py +141 -0
  160. atlas/tests/test_agent_roa.py +135 -0
  161. atlas/tests/test_app_factory_smoke.py +47 -0
  162. atlas/tests/test_approval_manager.py +439 -0
  163. atlas/tests/test_atlas_client.py +188 -0
  164. atlas/tests/test_atlas_rag_client.py +447 -0
  165. atlas/tests/test_atlas_rag_integration.py +224 -0
  166. atlas/tests/test_attach_file_flow.py +287 -0
  167. atlas/tests/test_auth_utils.py +165 -0
  168. atlas/tests/test_backend_public_url.py +185 -0
  169. atlas/tests/test_banner_logging.py +287 -0
  170. atlas/tests/test_capability_tokens_and_injection.py +203 -0
  171. atlas/tests/test_compliance_level.py +54 -0
  172. atlas/tests/test_compliance_manager.py +253 -0
  173. atlas/tests/test_config_manager.py +617 -0
  174. atlas/tests/test_config_manager_paths.py +12 -0
  175. atlas/tests/test_core_auth.py +18 -0
  176. atlas/tests/test_core_utils.py +190 -0
  177. atlas/tests/test_docker_env_sync.py +202 -0
  178. atlas/tests/test_domain_errors.py +329 -0
  179. atlas/tests/test_domain_whitelist.py +359 -0
  180. atlas/tests/test_elicitation_manager.py +408 -0
  181. atlas/tests/test_elicitation_routing.py +296 -0
  182. atlas/tests/test_env_demo_server.py +88 -0
  183. atlas/tests/test_error_classification.py +113 -0
  184. atlas/tests/test_error_flow_integration.py +116 -0
  185. atlas/tests/test_feedback_routes.py +333 -0
  186. atlas/tests/test_file_content_extraction.py +1134 -0
  187. atlas/tests/test_file_extraction_routes.py +158 -0
  188. atlas/tests/test_file_library.py +107 -0
  189. atlas/tests/test_file_manager_unit.py +18 -0
  190. atlas/tests/test_health_route.py +49 -0
  191. atlas/tests/test_http_client_stub.py +8 -0
  192. atlas/tests/test_imports_smoke.py +30 -0
  193. atlas/tests/test_interfaces_llm_response.py +9 -0
  194. atlas/tests/test_issue_access_denied_fix.py +136 -0
  195. atlas/tests/test_llm_env_expansion.py +836 -0
  196. atlas/tests/test_log_level_sensitive_data.py +285 -0
  197. atlas/tests/test_mcp_auth_routes.py +341 -0
  198. atlas/tests/test_mcp_client_auth.py +331 -0
  199. atlas/tests/test_mcp_data_injection.py +270 -0
  200. atlas/tests/test_mcp_get_authorized_servers.py +95 -0
  201. atlas/tests/test_mcp_hot_reload.py +512 -0
  202. atlas/tests/test_mcp_image_content.py +424 -0
  203. atlas/tests/test_mcp_logging.py +172 -0
  204. atlas/tests/test_mcp_progress_updates.py +313 -0
  205. atlas/tests/test_mcp_prompt_override_system_prompt.py +102 -0
  206. atlas/tests/test_mcp_prompts_server.py +39 -0
  207. atlas/tests/test_mcp_tool_result_parsing.py +296 -0
  208. atlas/tests/test_metrics_logger.py +56 -0
  209. atlas/tests/test_middleware_auth.py +379 -0
  210. atlas/tests/test_prompt_risk_and_acl.py +141 -0
  211. atlas/tests/test_rag_mcp_aggregator.py +204 -0
  212. atlas/tests/test_rag_mcp_service.py +224 -0
  213. atlas/tests/test_rate_limit_middleware.py +45 -0
  214. atlas/tests/test_routes_config_smoke.py +60 -0
  215. atlas/tests/test_routes_files_download_token.py +41 -0
  216. atlas/tests/test_routes_files_health.py +18 -0
  217. atlas/tests/test_runtime_imports.py +53 -0
  218. atlas/tests/test_sampling_integration.py +482 -0
  219. atlas/tests/test_security_admin_routes.py +61 -0
  220. atlas/tests/test_security_capability_tokens.py +65 -0
  221. atlas/tests/test_security_file_stats_scope.py +21 -0
  222. atlas/tests/test_security_header_injection.py +191 -0
  223. atlas/tests/test_security_headers_and_filename.py +63 -0
  224. atlas/tests/test_shared_session_repository.py +101 -0
  225. atlas/tests/test_system_prompt_loading.py +181 -0
  226. atlas/tests/test_token_storage.py +505 -0
  227. atlas/tests/test_tool_approval_config.py +93 -0
  228. atlas/tests/test_tool_approval_utils.py +356 -0
  229. atlas/tests/test_tool_authorization_group_filtering.py +223 -0
  230. atlas/tests/test_tool_details_in_config.py +108 -0
  231. atlas/tests/test_tool_planner.py +300 -0
  232. atlas/tests/test_unified_rag_service.py +398 -0
  233. atlas/tests/test_username_override_in_approval.py +258 -0
  234. atlas/tests/test_websocket_auth_header.py +168 -0
  235. atlas/version.py +6 -0
  236. atlas_chat-0.1.0.data/data/.env.example +253 -0
  237. atlas_chat-0.1.0.data/data/config/defaults/compliance-levels.json +44 -0
  238. atlas_chat-0.1.0.data/data/config/defaults/domain-whitelist.json +123 -0
  239. atlas_chat-0.1.0.data/data/config/defaults/file-extractors.json +74 -0
  240. atlas_chat-0.1.0.data/data/config/defaults/help-config.json +198 -0
  241. atlas_chat-0.1.0.data/data/config/defaults/llmconfig-buggy.yml +11 -0
  242. atlas_chat-0.1.0.data/data/config/defaults/llmconfig.yml +19 -0
  243. atlas_chat-0.1.0.data/data/config/defaults/mcp.json +138 -0
  244. atlas_chat-0.1.0.data/data/config/defaults/rag-sources.json +17 -0
  245. atlas_chat-0.1.0.data/data/config/defaults/splash-config.json +16 -0
  246. atlas_chat-0.1.0.dist-info/METADATA +236 -0
  247. atlas_chat-0.1.0.dist-info/RECORD +250 -0
  248. atlas_chat-0.1.0.dist-info/WHEEL +5 -0
  249. atlas_chat-0.1.0.dist-info/entry_points.txt +4 -0
  250. atlas_chat-0.1.0.dist-info/top_level.txt +1 -0
atlas/domain/errors.py ADDED
@@ -0,0 +1,96 @@
1
+ """Domain-level errors and exceptions."""
2
+
3
+ from typing import Optional
4
+
5
+
6
+ class DomainError(Exception):
7
+ """Base domain error."""
8
+ def __init__(self, message: str, code: Optional[str] = None):
9
+ super().__init__(message)
10
+ self.message = message
11
+ self.code = code
12
+
13
+
14
+ class ValidationError(DomainError):
15
+ """Validation error."""
16
+ pass
17
+
18
+
19
+ class SessionError(DomainError):
20
+ """Session-related error."""
21
+ pass
22
+
23
+
24
+ class MessageError(DomainError):
25
+ """Message-related error."""
26
+ pass
27
+
28
+
29
+ class AuthenticationError(DomainError):
30
+ """Authentication error."""
31
+ pass
32
+
33
+
34
+ class AuthorizationError(DomainError):
35
+ """Authorization error."""
36
+ pass
37
+
38
+
39
+ class ConfigurationError(DomainError):
40
+ """Configuration error."""
41
+ pass
42
+
43
+
44
+ class LLMError(DomainError):
45
+ """LLM-related error."""
46
+ pass
47
+
48
+
49
+ class LLMServiceError(LLMError):
50
+ """Generic LLM service failure that is not a validation issue."""
51
+ pass
52
+
53
+
54
+ class ToolError(DomainError):
55
+ """Tool execution error."""
56
+ pass
57
+
58
+
59
+ class ToolAuthorizationError(AuthorizationError):
60
+ """Raised when user is not authorized to use a specific tool."""
61
+ pass
62
+
63
+
64
+ class DataSourcePermissionError(AuthorizationError):
65
+ """Raised when user lacks permission to access a data source."""
66
+ pass
67
+
68
+
69
+ class LLMConfigurationError(ConfigurationError):
70
+ """Raised when LLM configuration is invalid or incomplete."""
71
+ pass
72
+
73
+
74
+ class SessionNotFoundError(SessionError):
75
+ """Raised when a session cannot be found."""
76
+ pass
77
+
78
+
79
+ class PromptOverrideError(DomainError):
80
+ """Raised when MCP prompt override fails."""
81
+ pass
82
+
83
+
84
+ class RateLimitError(LLMError):
85
+ """Raised when LLM rate limit is exceeded."""
86
+ pass
87
+
88
+
89
+ class LLMTimeoutError(LLMError):
90
+ """Raised when LLM request times out."""
91
+ pass
92
+
93
+
94
+ class LLMAuthenticationError(AuthenticationError):
95
+ """Raised when LLM authentication fails."""
96
+ pass
@@ -0,0 +1,12 @@
1
+ """Domain models for messages."""
2
+
3
+ from .models import ConversationHistory, Message, MessageRole, MessageType, ToolCall, ToolResult
4
+
5
+ __all__ = [
6
+ "Message",
7
+ "MessageRole",
8
+ "MessageType",
9
+ "ToolCall",
10
+ "ToolResult",
11
+ "ConversationHistory",
12
+ ]
@@ -0,0 +1,160 @@
1
+ """Domain models for messages."""
2
+
3
+ from dataclasses import dataclass, field
4
+ from datetime import datetime, timezone
5
+ from enum import Enum
6
+ from typing import Any, Dict, List, Literal, Optional
7
+ from uuid import UUID, uuid4
8
+
9
+
10
+ class MessageRole(Enum):
11
+ """Message role enumeration."""
12
+ USER = "user"
13
+ ASSISTANT = "assistant"
14
+ SYSTEM = "system"
15
+ TOOL = "tool"
16
+
17
+
18
+ class MessageType(Enum):
19
+ """Message type enumeration."""
20
+ CHAT = "chat"
21
+ CHAT_RESPONSE = "chat_response"
22
+ ERROR = "error"
23
+ TOOL_CALL = "tool_call"
24
+ TOOL_RESULT = "tool_result"
25
+ AGENT_UPDATE = "agent_update"
26
+ INTERMEDIATE_UPDATE = "intermediate_update"
27
+ DOWNLOAD_FILE = "download_file"
28
+ FILE_DOWNLOAD = "file_download"
29
+
30
+
31
+ @dataclass
32
+ class Message:
33
+ """Domain model for a chat message."""
34
+ id: UUID = field(default_factory=uuid4)
35
+ role: MessageRole = MessageRole.USER
36
+ content: str = ""
37
+ timestamp: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
38
+ metadata: Dict[str, Any] = field(default_factory=dict)
39
+
40
+ def to_dict(self) -> Dict[str, Any]:
41
+ """Convert to dictionary for serialization."""
42
+ return {
43
+ "id": str(self.id),
44
+ "role": self.role.value,
45
+ "content": self.content,
46
+ "timestamp": self.timestamp.isoformat(),
47
+ "metadata": self.metadata
48
+ }
49
+
50
+ @classmethod
51
+ def from_dict(cls, data: Dict[str, Any]) -> "Message":
52
+ """Create from dictionary."""
53
+ return cls(
54
+ id=UUID(data["id"]) if "id" in data else uuid4(),
55
+ role=MessageRole(data.get("role", "user")),
56
+ content=data.get("content", ""),
57
+ timestamp=datetime.fromisoformat(data["timestamp"]) if "timestamp" in data else datetime.now(timezone.utc),
58
+ metadata=data.get("metadata", {})
59
+ )
60
+
61
+
62
+ @dataclass
63
+ class ToolCall:
64
+ """Domain model for a tool call."""
65
+ id: str
66
+ name: str
67
+ arguments: Dict[str, Any]
68
+
69
+ def to_dict(self) -> Dict[str, Any]:
70
+ """Convert to dictionary."""
71
+ return {
72
+ "id": self.id,
73
+ "name": self.name,
74
+ "arguments": self.arguments
75
+ }
76
+
77
+
78
+ @dataclass
79
+ class ToolResult:
80
+ """Domain model for a tool result with v2 MCP support."""
81
+ tool_call_id: str
82
+ content: str
83
+ success: bool = True
84
+ error: Optional[str] = None
85
+ artifacts: List[Dict[str, Any]] = field(default_factory=list)
86
+ display_config: Optional[Dict[str, Any]] = None
87
+ meta_data: Optional[Dict[str, Any]] = None
88
+
89
+ def to_dict(self) -> Dict[str, Any]:
90
+ """Convert to dictionary."""
91
+ result = {
92
+ "tool_call_id": self.tool_call_id,
93
+ "content": self.content,
94
+ "success": self.success,
95
+ "error": self.error,
96
+ "artifacts": self.artifacts,
97
+ }
98
+ if self.display_config:
99
+ result["display_config"] = self.display_config
100
+ if self.meta_data:
101
+ result["meta_data"] = self.meta_data
102
+ return result
103
+
104
+
105
+ @dataclass
106
+ class ConversationHistory:
107
+ """Domain model for conversation history."""
108
+ messages: List[Message] = field(default_factory=list)
109
+
110
+ def add_message(self, message: Message) -> None:
111
+ """Add a message to the history."""
112
+ self.messages.append(message)
113
+
114
+ def get_messages_for_llm(self) -> List[Dict[str, str]]:
115
+ """Get messages formatted for LLM API."""
116
+ return [
117
+ {"role": msg.role.value, "content": msg.content}
118
+ for msg in self.messages
119
+ ]
120
+
121
+ def to_dict(self) -> List[Dict[str, Any]]:
122
+ """Convert to dictionary list."""
123
+ return [msg.to_dict() for msg in self.messages]
124
+
125
+
126
+ @dataclass
127
+ class ElicitationRequest:
128
+ """Domain model for an elicitation request from MCP server."""
129
+ elicitation_id: str
130
+ tool_call_id: str
131
+ tool_name: str
132
+ message: str
133
+ response_schema: Dict[str, Any]
134
+
135
+ def to_dict(self) -> Dict[str, Any]:
136
+ """Convert to dictionary for WebSocket transmission."""
137
+ return {
138
+ "type": "elicitation_request",
139
+ "elicitation_id": self.elicitation_id,
140
+ "tool_call_id": self.tool_call_id,
141
+ "tool_name": self.tool_name,
142
+ "message": self.message,
143
+ "response_schema": self.response_schema
144
+ }
145
+
146
+
147
+ @dataclass
148
+ class ElicitationResponse:
149
+ """Domain model for an elicitation response from user."""
150
+ elicitation_id: str
151
+ action: Literal["accept", "decline", "cancel"]
152
+ data: Optional[Dict[str, Any]] = None
153
+
154
+ def to_dict(self) -> Dict[str, Any]:
155
+ """Convert to dictionary."""
156
+ return {
157
+ "elicitation_id": self.elicitation_id,
158
+ "action": self.action,
159
+ "data": self.data
160
+ }