idun-agent-engine 0.4.1__py3-none-any.whl → 0.4.2__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.
- idun_agent_engine/_version.py +1 -1
- idun_agent_engine/agent/adk/adk.py +2 -2
- idun_agent_engine/agent/haystack/__init__.py +0 -2
- idun_agent_engine/agent/haystack/haystack.py +9 -5
- idun_agent_engine/agent/langgraph/langgraph.py +10 -13
- idun_agent_engine/core/config_builder.py +26 -13
- idun_agent_engine/guardrails/guardrails_hub/guardrails_hub.py +52 -9
- idun_agent_engine/mcp/__init__.py +2 -2
- idun_agent_engine/mcp/helpers.py +11 -15
- idun_agent_engine/mcp/registry.py +5 -5
- idun_agent_engine/observability/base.py +11 -2
- idun_agent_engine/observability/gcp_trace/gcp_trace_handler.py +3 -1
- idun_agent_engine/observability/langfuse/langfuse_handler.py +1 -3
- idun_agent_engine/server/dependencies.py +7 -2
- idun_agent_engine/server/lifespan.py +2 -7
- idun_agent_engine/server/routers/agent.py +2 -1
- idun_agent_engine/server/routers/base.py +7 -5
- idun_agent_engine/telemetry/__init__.py +0 -1
- idun_agent_engine/telemetry/config.py +0 -1
- idun_agent_engine/telemetry/telemetry.py +3 -4
- idun_agent_engine/templates/correction.py +4 -7
- idun_agent_engine/templates/deep_research.py +1 -0
- idun_agent_engine/templates/translation.py +4 -4
- {idun_agent_engine-0.4.1.dist-info → idun_agent_engine-0.4.2.dist-info}/METADATA +1 -1
- {idun_agent_engine-0.4.1.dist-info → idun_agent_engine-0.4.2.dist-info}/RECORD +40 -43
- idun_platform_cli/groups/agent/package.py +1 -1
- idun_platform_cli/telemetry.py +2 -1
- idun_platform_cli/tui/schemas/create_agent.py +8 -4
- idun_platform_cli/tui/screens/create_agent.py +38 -12
- idun_platform_cli/tui/utils/config.py +1 -1
- idun_platform_cli/tui/validators/guardrails.py +8 -6
- idun_platform_cli/tui/validators/mcps.py +9 -6
- idun_platform_cli/tui/widgets/chat_widget.py +3 -1
- idun_platform_cli/tui/widgets/guardrails_widget.py +4 -4
- idun_platform_cli/tui/widgets/mcps_widget.py +112 -24
- idun_platform_cli/tui/widgets/memory_widget.py +0 -1
- idun_platform_cli/tui/widgets/observability_widget.py +2 -2
- idun_platform_cli/tui/widgets/serve_widget.py +2 -3
- idun_agent_engine/agent/haystack/haystack_model.py +0 -13
- idun_agent_engine/guardrails/guardrails_hub/utils.py +0 -1
- idun_agent_engine/server/routers/agui.py +0 -47
- {idun_agent_engine-0.4.1.dist-info → idun_agent_engine-0.4.2.dist-info}/WHEEL +0 -0
- {idun_agent_engine-0.4.1.dist-info → idun_agent_engine-0.4.2.dist-info}/entry_points.txt +0 -0
|
@@ -2,11 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
from textual.app import ComposeResult
|
|
4
4
|
from textual.containers import Horizontal, Vertical
|
|
5
|
-
from textual.widgets import Static, Input, Button, RadioSet, RadioButton, TextArea, OptionList
|
|
6
5
|
from textual.widget import Widget
|
|
6
|
+
from textual.widgets import (
|
|
7
|
+
Button,
|
|
8
|
+
Input,
|
|
9
|
+
OptionList,
|
|
10
|
+
RadioButton,
|
|
11
|
+
RadioSet,
|
|
12
|
+
Static,
|
|
13
|
+
TextArea,
|
|
14
|
+
)
|
|
7
15
|
from textual.widgets.option_list import Option
|
|
8
16
|
|
|
9
|
-
|
|
10
17
|
MCP_TEMPLATES = {
|
|
11
18
|
"time": {
|
|
12
19
|
"name": "time-reference",
|
|
@@ -34,14 +41,24 @@ class MCPsWidget(Widget):
|
|
|
34
41
|
templates_row = Horizontal(classes="templates-row")
|
|
35
42
|
templates_row.compose_add_child(Static("Select template:", classes="mcp-label"))
|
|
36
43
|
option_list = OptionList(id="template_selector", classes="template-selector")
|
|
37
|
-
for template_name in MCP_TEMPLATES
|
|
44
|
+
for template_name in MCP_TEMPLATES:
|
|
38
45
|
option_list.add_option(Option(template_name.title(), id=template_name))
|
|
39
46
|
templates_row.compose_add_child(option_list)
|
|
40
|
-
templates_row.compose_add_child(
|
|
47
|
+
templates_row.compose_add_child(
|
|
48
|
+
Button(
|
|
49
|
+
"Add from Template",
|
|
50
|
+
id="add_from_template_button",
|
|
51
|
+
classes="add-template-btn",
|
|
52
|
+
)
|
|
53
|
+
)
|
|
41
54
|
templates_section.compose_add_child(templates_row)
|
|
42
55
|
yield templates_section
|
|
43
56
|
|
|
44
|
-
yield Button(
|
|
57
|
+
yield Button(
|
|
58
|
+
"+ Add Custom MCP Server",
|
|
59
|
+
id="add_custom_mcp_button",
|
|
60
|
+
classes="add-custom-btn",
|
|
61
|
+
)
|
|
45
62
|
|
|
46
63
|
yield Vertical(id="mcps_container", classes="mcps-container")
|
|
47
64
|
|
|
@@ -67,7 +84,9 @@ class MCPsWidget(Widget):
|
|
|
67
84
|
def _add_from_template(self) -> None:
|
|
68
85
|
template_selector = self.query_one("#template_selector", OptionList)
|
|
69
86
|
if template_selector.highlighted is not None:
|
|
70
|
-
option_id = template_selector.get_option_at_index(
|
|
87
|
+
option_id = template_selector.get_option_at_index(
|
|
88
|
+
template_selector.highlighted
|
|
89
|
+
).id
|
|
71
90
|
if option_id and str(option_id) in MCP_TEMPLATES:
|
|
72
91
|
template_data = MCP_TEMPLATES[str(option_id)].copy()
|
|
73
92
|
self._add_mcp_server(template_data)
|
|
@@ -95,52 +114,109 @@ class MCPsWidget(Widget):
|
|
|
95
114
|
|
|
96
115
|
header = Horizontal(classes="mcp-header")
|
|
97
116
|
name_value = template_data.get("name", "") if template_data else ""
|
|
98
|
-
header.compose_add_child(
|
|
99
|
-
|
|
117
|
+
header.compose_add_child(
|
|
118
|
+
Static(
|
|
119
|
+
name_value or f"Server {index + 1}",
|
|
120
|
+
id=f"mcp_name_display_{index}",
|
|
121
|
+
classes="mcp-name-display",
|
|
122
|
+
)
|
|
123
|
+
)
|
|
124
|
+
header.compose_add_child(
|
|
125
|
+
Button("Remove", id=f"remove_mcp_{index}", classes="remove-mcp-btn")
|
|
126
|
+
)
|
|
100
127
|
card.compose_add_child(header)
|
|
101
128
|
|
|
102
129
|
name_row = Horizontal(classes="mcp-field-row")
|
|
103
130
|
name_row.compose_add_child(Static("Name:", classes="mcp-label"))
|
|
104
|
-
name_row.compose_add_child(
|
|
131
|
+
name_row.compose_add_child(
|
|
132
|
+
Input(
|
|
133
|
+
value=name_value,
|
|
134
|
+
placeholder="server-name",
|
|
135
|
+
id=f"mcp_name_{index}",
|
|
136
|
+
classes="mcp-input",
|
|
137
|
+
)
|
|
138
|
+
)
|
|
105
139
|
card.compose_add_child(name_row)
|
|
106
140
|
|
|
107
141
|
transport_row = Horizontal(classes="mcp-field-row")
|
|
108
142
|
transport_row.compose_add_child(Static("Transport:", classes="mcp-label"))
|
|
109
143
|
radio_set = RadioSet(id=f"mcp_transport_{index}")
|
|
110
144
|
|
|
111
|
-
transport_value =
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
145
|
+
transport_value = (
|
|
146
|
+
template_data.get("transport", "streamable_http")
|
|
147
|
+
if template_data
|
|
148
|
+
else "streamable_http"
|
|
149
|
+
)
|
|
150
|
+
radio_set.compose_add_child(
|
|
151
|
+
RadioButton("stdio", id="stdio", value=(transport_value == "stdio"))
|
|
152
|
+
)
|
|
153
|
+
radio_set.compose_add_child(
|
|
154
|
+
RadioButton("sse", id="sse", value=(transport_value == "sse"))
|
|
155
|
+
)
|
|
156
|
+
radio_set.compose_add_child(
|
|
157
|
+
RadioButton(
|
|
158
|
+
"streamable_http",
|
|
159
|
+
id="streamable_http",
|
|
160
|
+
value=(transport_value == "streamable_http"),
|
|
161
|
+
)
|
|
162
|
+
)
|
|
163
|
+
radio_set.compose_add_child(
|
|
164
|
+
RadioButton(
|
|
165
|
+
"websocket", id="websocket", value=(transport_value == "websocket")
|
|
166
|
+
)
|
|
167
|
+
)
|
|
116
168
|
transport_row.compose_add_child(radio_set)
|
|
117
169
|
card.compose_add_child(transport_row)
|
|
118
170
|
|
|
119
|
-
http_fields = Vertical(
|
|
171
|
+
http_fields = Vertical(
|
|
172
|
+
id=f"mcp_http_fields_{index}", classes="http-fields-container"
|
|
173
|
+
)
|
|
120
174
|
http_fields.border_title = "HTTP Configuration"
|
|
121
175
|
|
|
122
176
|
url_row = Horizontal(classes="mcp-field-row")
|
|
123
177
|
url_row.compose_add_child(Static("URL:", classes="mcp-label"))
|
|
124
178
|
url_value = template_data.get("url", "") if template_data else ""
|
|
125
|
-
url_row.compose_add_child(
|
|
179
|
+
url_row.compose_add_child(
|
|
180
|
+
Input(
|
|
181
|
+
value=url_value,
|
|
182
|
+
placeholder="https://api.example.com/mcp",
|
|
183
|
+
id=f"mcp_url_{index}",
|
|
184
|
+
classes="mcp-input",
|
|
185
|
+
)
|
|
186
|
+
)
|
|
126
187
|
http_fields.compose_add_child(url_row)
|
|
127
188
|
|
|
128
189
|
headers_row = Horizontal(classes="mcp-field-row")
|
|
129
190
|
headers_row.compose_add_child(Static("Headers (JSON):", classes="mcp-label"))
|
|
130
191
|
headers_value = template_data.get("headers", "") if template_data else ""
|
|
131
|
-
headers_row.compose_add_child(
|
|
192
|
+
headers_row.compose_add_child(
|
|
193
|
+
TextArea(
|
|
194
|
+
text=str(headers_value) if headers_value else "",
|
|
195
|
+
id=f"mcp_headers_{index}",
|
|
196
|
+
classes="mcp-textarea",
|
|
197
|
+
)
|
|
198
|
+
)
|
|
132
199
|
http_fields.compose_add_child(headers_row)
|
|
133
200
|
|
|
134
201
|
http_fields.display = transport_value in ["sse", "streamable_http", "websocket"]
|
|
135
202
|
card.compose_add_child(http_fields)
|
|
136
203
|
|
|
137
|
-
stdio_fields = Vertical(
|
|
204
|
+
stdio_fields = Vertical(
|
|
205
|
+
id=f"mcp_stdio_fields_{index}", classes="stdio-fields-container"
|
|
206
|
+
)
|
|
138
207
|
stdio_fields.border_title = "Stdio Configuration"
|
|
139
208
|
|
|
140
209
|
command_row = Horizontal(classes="mcp-field-row")
|
|
141
210
|
command_row.compose_add_child(Static("Command:", classes="mcp-label"))
|
|
142
211
|
command_value = template_data.get("command", "") if template_data else ""
|
|
143
|
-
command_row.compose_add_child(
|
|
212
|
+
command_row.compose_add_child(
|
|
213
|
+
Input(
|
|
214
|
+
value=command_value,
|
|
215
|
+
placeholder="npx",
|
|
216
|
+
id=f"mcp_command_{index}",
|
|
217
|
+
classes="mcp-input",
|
|
218
|
+
)
|
|
219
|
+
)
|
|
144
220
|
stdio_fields.compose_add_child(command_row)
|
|
145
221
|
|
|
146
222
|
args_row = Horizontal(classes="mcp-field-row")
|
|
@@ -150,7 +226,9 @@ class MCPsWidget(Widget):
|
|
|
150
226
|
args_list = template_data["args"]
|
|
151
227
|
if isinstance(args_list, list):
|
|
152
228
|
args_value = "\n".join(args_list)
|
|
153
|
-
args_textarea = TextArea(
|
|
229
|
+
args_textarea = TextArea(
|
|
230
|
+
text=args_value, id=f"mcp_args_{index}", classes="mcp-textarea"
|
|
231
|
+
)
|
|
154
232
|
args_textarea.placeholder = "run\n-i\n--rm"
|
|
155
233
|
args_row.compose_add_child(args_textarea)
|
|
156
234
|
stdio_fields.compose_add_child(args_row)
|
|
@@ -160,8 +238,11 @@ class MCPsWidget(Widget):
|
|
|
160
238
|
env_value = ""
|
|
161
239
|
if template_data and "env" in template_data:
|
|
162
240
|
import json
|
|
241
|
+
|
|
163
242
|
env_value = json.dumps(template_data["env"], indent=2)
|
|
164
|
-
env_row.compose_add_child(
|
|
243
|
+
env_row.compose_add_child(
|
|
244
|
+
TextArea(text=env_value, id=f"mcp_env_{index}", classes="mcp-textarea")
|
|
245
|
+
)
|
|
165
246
|
stdio_fields.compose_add_child(env_row)
|
|
166
247
|
|
|
167
248
|
stdio_fields.display = transport_value == "stdio"
|
|
@@ -189,7 +270,9 @@ class MCPsWidget(Widget):
|
|
|
189
270
|
name = name_input.value
|
|
190
271
|
|
|
191
272
|
if not name:
|
|
192
|
-
self.app.notify(
|
|
273
|
+
self.app.notify(
|
|
274
|
+
f"Server {server_id + 1}: Name is required", severity="error"
|
|
275
|
+
)
|
|
193
276
|
return None
|
|
194
277
|
|
|
195
278
|
radio_set = self.query_one(f"#mcp_transport_{server_id}", RadioSet)
|
|
@@ -206,7 +289,9 @@ class MCPsWidget(Widget):
|
|
|
206
289
|
url_input = self.query_one(f"#mcp_url_{server_id}", Input)
|
|
207
290
|
server_config["url"] = url_input.value
|
|
208
291
|
|
|
209
|
-
headers_textarea = self.query_one(
|
|
292
|
+
headers_textarea = self.query_one(
|
|
293
|
+
f"#mcp_headers_{server_id}", TextArea
|
|
294
|
+
)
|
|
210
295
|
if headers_textarea.text.strip():
|
|
211
296
|
server_config["headers"] = headers_textarea.text.strip()
|
|
212
297
|
|
|
@@ -224,7 +309,10 @@ class MCPsWidget(Widget):
|
|
|
224
309
|
servers_data.append(server_config)
|
|
225
310
|
|
|
226
311
|
except Exception:
|
|
227
|
-
self.app.notify(
|
|
312
|
+
self.app.notify(
|
|
313
|
+
f"Error reading MCP server {server_id + 1}: check your configuration.",
|
|
314
|
+
severity="error",
|
|
315
|
+
)
|
|
228
316
|
return None
|
|
229
317
|
|
|
230
318
|
return servers_data
|
|
@@ -4,9 +4,9 @@ from idun_agent_schema.engine.observability_v2 import (
|
|
|
4
4
|
)
|
|
5
5
|
from textual.app import ComposeResult
|
|
6
6
|
from textual.containers import Horizontal, Vertical
|
|
7
|
-
from textual.widgets import Static, Input, RadioSet, RadioButton, Switch
|
|
8
|
-
from textual.widget import Widget
|
|
9
7
|
from textual.reactive import reactive
|
|
8
|
+
from textual.widget import Widget
|
|
9
|
+
from textual.widgets import Input, RadioButton, RadioSet, Static, Switch
|
|
10
10
|
|
|
11
11
|
from idun_platform_cli.tui.validators.observability import validate_observability
|
|
12
12
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"""Serve configuration widget."""
|
|
2
2
|
|
|
3
|
-
from typing import Any
|
|
4
3
|
|
|
5
4
|
from rich.syntax import Syntax
|
|
6
5
|
from textual.app import ComposeResult
|
|
@@ -57,7 +56,7 @@ class ServeWidget(Widget):
|
|
|
57
56
|
self.config_data,
|
|
58
57
|
default_flow_style=False,
|
|
59
58
|
sort_keys=False,
|
|
60
|
-
allow_unicode=True
|
|
59
|
+
allow_unicode=True,
|
|
61
60
|
)
|
|
62
61
|
|
|
63
62
|
syntax = Syntax(
|
|
@@ -67,7 +66,7 @@ class ServeWidget(Widget):
|
|
|
67
66
|
line_numbers=True,
|
|
68
67
|
word_wrap=False,
|
|
69
68
|
indent_guides=True,
|
|
70
|
-
background_color="default"
|
|
69
|
+
background_color="default",
|
|
71
70
|
)
|
|
72
71
|
|
|
73
72
|
self.query_one("#yaml_content", Static).update(syntax)
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
"""Configuration models for Haystack agents."""
|
|
2
|
-
|
|
3
|
-
from typing import Literal
|
|
4
|
-
|
|
5
|
-
from idun_agent_engine.core.engine_config import BaseAgentConfig
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class HaystackAgentConfig(BaseAgentConfig):
|
|
9
|
-
"""Configuration model for Haystack Agents."""
|
|
10
|
-
|
|
11
|
-
type: Literal["haystack"] = "haystack"
|
|
12
|
-
component_type: Literal["pipeline", "agent"]
|
|
13
|
-
component_definition: str
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"""Utils module."""
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
# """AGUI routes for CopilotKit integration with LangGraph agents."""
|
|
2
|
-
|
|
3
|
-
# import logging
|
|
4
|
-
# from typing import Annotated
|
|
5
|
-
|
|
6
|
-
# from ag_ui_langgraph import add_langgraph_fastapi_endpoint
|
|
7
|
-
# from copilotkit import LangGraphAGUIAgent
|
|
8
|
-
# from ag_ui_adk import ADKAgent as ADKAGUIAgent
|
|
9
|
-
# from ag_ui_adk import add_adk_fastapi_endpoint
|
|
10
|
-
# from fastapi import APIRouter, Depends, HTTPException, Request
|
|
11
|
-
|
|
12
|
-
# from idun_agent_engine.agent.langgraph.langgraph import LanggraphAgent
|
|
13
|
-
# from idun_agent_engine.agent.adk.adk import AdkAgent
|
|
14
|
-
# from idun_agent_engine.server.dependencies import get_agent
|
|
15
|
-
|
|
16
|
-
# logging.basicConfig(
|
|
17
|
-
# format="%(asctime)s %(levelname)-8s %(message)s",
|
|
18
|
-
# level=logging.INFO,
|
|
19
|
-
# datefmt="%Y-%m-%d %H:%M:%S",
|
|
20
|
-
# )
|
|
21
|
-
|
|
22
|
-
# logger = logging.getLogger(__name__)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
# def setup_agui_router(app, agent: LanggraphAgent | AdkAgent) -> LangGraphAGUIAgent | ADKAGUIAgent:
|
|
26
|
-
# """Set up AGUI routes for CopilotKit integration.
|
|
27
|
-
|
|
28
|
-
# This function adds the LangGraph agent as a CopilotKit-compatible endpoint.
|
|
29
|
-
|
|
30
|
-
# Args:
|
|
31
|
-
# app: The FastAPI application instance
|
|
32
|
-
# agent: The initialized LangGraph agent instance
|
|
33
|
-
# """
|
|
34
|
-
# try:
|
|
35
|
-
# if isinstance(agent, LanggraphAgent):
|
|
36
|
-
# # Create the AGUI agent wrapper
|
|
37
|
-
# agui_agent = agent.copilotkit_agent_instance
|
|
38
|
-
# elif isinstance(agent, AdkAgent):
|
|
39
|
-
# # Create the AGUI agent wrapper
|
|
40
|
-
# agui_agent = agent.copilotkit_agent_instance # TODO: duplicate in agent.adk.adk.py init
|
|
41
|
-
# else:
|
|
42
|
-
# raise ValueError(f"Unsupported agent type: {type(agent)}")
|
|
43
|
-
# return agui_agent
|
|
44
|
-
# logger.info(f"✅ AGUI endpoint configured at /agui for agent: {agent.name}")
|
|
45
|
-
# except Exception as e:
|
|
46
|
-
# logger.error(f"❌ Failed to setup AGUI router: {e}")
|
|
47
|
-
# raise HTTPException(status_code=500, detail=f"Failed to setup AGUI router: {e}") from e
|
|
File without changes
|
|
File without changes
|