idun-agent-engine 0.3.9__py3-none-any.whl → 0.4.1__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 (45) hide show
  1. idun_agent_engine/_version.py +1 -1
  2. idun_agent_engine/agent/adk/adk.py +5 -2
  3. idun_agent_engine/agent/langgraph/langgraph.py +1 -1
  4. idun_agent_engine/core/app_factory.py +1 -1
  5. idun_agent_engine/core/config_builder.py +11 -5
  6. idun_agent_engine/guardrails/guardrails_hub/__init__.py +2 -2
  7. idun_agent_engine/mcp/__init__.py +18 -2
  8. idun_agent_engine/mcp/helpers.py +135 -43
  9. idun_agent_engine/mcp/registry.py +7 -1
  10. idun_agent_engine/server/lifespan.py +22 -0
  11. idun_agent_engine/telemetry/__init__.py +19 -0
  12. idun_agent_engine/telemetry/config.py +29 -0
  13. idun_agent_engine/telemetry/telemetry.py +248 -0
  14. {idun_agent_engine-0.3.9.dist-info → idun_agent_engine-0.4.1.dist-info}/METADATA +12 -8
  15. {idun_agent_engine-0.3.9.dist-info → idun_agent_engine-0.4.1.dist-info}/RECORD +45 -17
  16. idun_platform_cli/groups/agent/package.py +3 -0
  17. idun_platform_cli/groups/agent/serve.py +2 -0
  18. idun_platform_cli/groups/init.py +25 -0
  19. idun_platform_cli/main.py +3 -0
  20. idun_platform_cli/telemetry.py +54 -0
  21. idun_platform_cli/tui/__init__.py +0 -0
  22. idun_platform_cli/tui/css/__init__.py +0 -0
  23. idun_platform_cli/tui/css/create_agent.py +912 -0
  24. idun_platform_cli/tui/css/main.py +89 -0
  25. idun_platform_cli/tui/main.py +87 -0
  26. idun_platform_cli/tui/schemas/__init__.py +0 -0
  27. idun_platform_cli/tui/schemas/create_agent.py +60 -0
  28. idun_platform_cli/tui/screens/__init__.py +0 -0
  29. idun_platform_cli/tui/screens/create_agent.py +622 -0
  30. idun_platform_cli/tui/utils/__init__.py +0 -0
  31. idun_platform_cli/tui/utils/config.py +182 -0
  32. idun_platform_cli/tui/validators/__init__.py +0 -0
  33. idun_platform_cli/tui/validators/guardrails.py +88 -0
  34. idun_platform_cli/tui/validators/mcps.py +84 -0
  35. idun_platform_cli/tui/validators/observability.py +65 -0
  36. idun_platform_cli/tui/widgets/__init__.py +19 -0
  37. idun_platform_cli/tui/widgets/chat_widget.py +153 -0
  38. idun_platform_cli/tui/widgets/guardrails_widget.py +356 -0
  39. idun_platform_cli/tui/widgets/identity_widget.py +252 -0
  40. idun_platform_cli/tui/widgets/mcps_widget.py +230 -0
  41. idun_platform_cli/tui/widgets/memory_widget.py +195 -0
  42. idun_platform_cli/tui/widgets/observability_widget.py +382 -0
  43. idun_platform_cli/tui/widgets/serve_widget.py +82 -0
  44. {idun_agent_engine-0.3.9.dist-info → idun_agent_engine-0.4.1.dist-info}/WHEEL +0 -0
  45. {idun_agent_engine-0.3.9.dist-info → idun_agent_engine-0.4.1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,248 @@
1
+ """Non-blocking telemetry for Idun Agent Engine.
2
+
3
+ Telemetry is ON by default and can be disabled with `IDUN_TELEMETRY_ENABLED=false`.
4
+
5
+ We persist a stable `distinct_id` in the OS cache directory at:
6
+ `<cache_dir>/idun/telemetry_user_id`
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import os
12
+ import platform
13
+ import re
14
+ import sys
15
+ import threading
16
+ import uuid
17
+ from concurrent.futures import Future, ThreadPoolExecutor
18
+ from dataclasses import dataclass, field
19
+ from pathlib import Path
20
+ from typing import Any
21
+
22
+ from platformdirs import user_cache_dir
23
+
24
+ from .config import telemetry_enabled
25
+
26
+ _POSTHOG_HOST = "https://us.i.posthog.com"
27
+ _POSTHOG_PROJECT_API_KEY = "phc_mpAplkH6w5zK1aSkkG0IL5Ys55m6X34BFvGozB2NqPw"
28
+ _DISTINCT_ID_ENV = "IDUN_TELEMETRY_DISTINCT_ID"
29
+ _CACHE_APP_NAME = "idun"
30
+ _CACHE_DISTINCT_ID_FILE = "telemetry_user_id"
31
+ _MAX_VALUE_LENGTH = 200
32
+ _SENSITIVE_KEY_FRAGMENTS = (
33
+ "api_key",
34
+ "apikey",
35
+ "access_key",
36
+ "accesskey",
37
+ "private_key",
38
+ "privatekey",
39
+ "secret",
40
+ "token",
41
+ "password",
42
+ "passphrase",
43
+ "client_secret",
44
+ "clientsecret",
45
+ "bearer",
46
+ "authorization",
47
+ )
48
+
49
+
50
+ def _is_sensitive_key(key: str) -> bool:
51
+ normalized = re.sub(r"[^a-z0-9]+", "_", key.lower())
52
+ return any(fragment in normalized for fragment in _SENSITIVE_KEY_FRAGMENTS)
53
+
54
+
55
+ def _is_private_key_value(value: str) -> bool:
56
+ upper_value = value.upper()
57
+ return "PRIVATE KEY" in upper_value or "BEGIN OPENSSH PRIVATE KEY" in upper_value
58
+
59
+
60
+ def _truncate_value(value: str) -> str:
61
+ if len(value) <= _MAX_VALUE_LENGTH:
62
+ return value
63
+ return value[:_MAX_VALUE_LENGTH]
64
+
65
+
66
+ def sanitize_telemetry_config(value: Any) -> Any:
67
+ """Return a telemetry-safe copy of config objects."""
68
+ if hasattr(value, "model_dump") and callable(value.model_dump):
69
+ value = value.model_dump() # type: ignore[assignment]
70
+ elif hasattr(value, "dict") and callable(value.dict):
71
+ value = value.dict() # type: ignore[assignment]
72
+
73
+ if isinstance(value, dict):
74
+ sanitized: dict[str, Any] = {}
75
+ for key, item in value.items():
76
+ if isinstance(key, str) and _is_sensitive_key(key):
77
+ sanitized[key] = "[redacted]"
78
+ else:
79
+ sanitized[key] = sanitize_telemetry_config(item)
80
+ return sanitized
81
+
82
+ if isinstance(value, (list, tuple, set)):
83
+ return [sanitize_telemetry_config(item) for item in value]
84
+
85
+ if isinstance(value, str):
86
+ if _is_private_key_value(value):
87
+ return "[redacted]"
88
+ return _truncate_value(value)
89
+
90
+ return value
91
+
92
+
93
+ def _safe_read_text(path: Path) -> str | None:
94
+ try:
95
+ return path.read_text(encoding="utf-8").strip()
96
+ except Exception:
97
+ return None
98
+
99
+
100
+ def _safe_write_text(path: Path, text: str) -> None:
101
+ try:
102
+ path.parent.mkdir(parents=True, exist_ok=True)
103
+ path.write_text(text, encoding="utf-8")
104
+ except Exception:
105
+ # Best-effort only.
106
+ return
107
+
108
+
109
+ def _get_or_create_distinct_id() -> str | None:
110
+ """Return a stable distinct id.
111
+
112
+ Preference order:
113
+ - `IDUN_TELEMETRY_DISTINCT_ID` (if set)
114
+ - A UUID persisted to `<cache_dir>/idun/telemetry_user_id`
115
+ """
116
+
117
+ raw = os.environ.get(_DISTINCT_ID_ENV)
118
+ if raw and raw.strip():
119
+ return raw.strip()
120
+
121
+ cache_dir = Path(user_cache_dir(_CACHE_APP_NAME))
122
+ id_path = cache_dir / _CACHE_DISTINCT_ID_FILE
123
+
124
+ existing = _safe_read_text(id_path)
125
+ if existing:
126
+ return existing
127
+
128
+ new_id = str(uuid.uuid4())
129
+ _safe_write_text(id_path, new_id)
130
+ return new_id
131
+
132
+
133
+ def _common_properties() -> dict[str, Any]:
134
+ from .._version import __version__
135
+
136
+ return {
137
+ "library": "idun-agent-engine",
138
+ "library_version": __version__,
139
+ "python_version": platform.python_version(),
140
+ "python_implementation": platform.python_implementation(),
141
+ "platform": sys.platform,
142
+ "os": platform.system(),
143
+ "os_version": platform.release(),
144
+ }
145
+
146
+
147
+ @dataclass(slots=True)
148
+ class IdunTelemetry:
149
+ """Non-blocking telemetry client."""
150
+
151
+ enabled: bool = field(default_factory=telemetry_enabled)
152
+ _executor: ThreadPoolExecutor | None = field(default=None, init=False, repr=False)
153
+ _client: Any | None = field(default=None, init=False, repr=False)
154
+ _client_lock: threading.Lock = field(
155
+ default_factory=threading.Lock, init=False, repr=False
156
+ )
157
+ _distinct_id: str | None = field(default=None, init=False, repr=False)
158
+
159
+ def _ensure_executor(self) -> ThreadPoolExecutor:
160
+ if self._executor is None:
161
+ self._executor = ThreadPoolExecutor(
162
+ max_workers=1, thread_name_prefix="idun-telemetry"
163
+ )
164
+ return self._executor
165
+
166
+ def _get_client(self) -> Any | None:
167
+ if not self.enabled:
168
+ return None
169
+ if self._client is not None:
170
+ return self._client
171
+
172
+ with self._client_lock:
173
+ if self._client is not None:
174
+ return self._client
175
+ try:
176
+ from posthog import Posthog
177
+ except Exception:
178
+ # Dependency missing or import failure should not break runtime.
179
+ return None
180
+
181
+ client = Posthog(_POSTHOG_PROJECT_API_KEY, host=_POSTHOG_HOST)
182
+ self._client = client
183
+ self._distinct_id = _get_or_create_distinct_id()
184
+ return self._client
185
+
186
+ def capture(self, event: str, properties: dict[str, Any] | None = None) -> Future[None] | None:
187
+ """Capture an event asynchronously (best-effort)."""
188
+
189
+ if not self.enabled:
190
+ return None
191
+
192
+ executor = self._ensure_executor()
193
+
194
+ def _send() -> None:
195
+ client = self._get_client()
196
+ if client is None:
197
+ return
198
+
199
+ merged: dict[str, Any] = _common_properties()
200
+ if properties:
201
+ merged.update(properties)
202
+
203
+ try:
204
+ if self._distinct_id:
205
+ client.capture(
206
+ event=event,
207
+ distinct_id=self._distinct_id,
208
+ properties=merged,
209
+ )
210
+ else:
211
+ client.capture(event=event, properties=merged)
212
+ except Exception:
213
+ # Never fail user code because of telemetry.
214
+ return
215
+
216
+ try:
217
+ return executor.submit(_send)
218
+ except Exception:
219
+ return None
220
+
221
+ def shutdown(self, timeout_seconds: float = 1.0) -> None:
222
+ """Best-effort flush/shutdown without blocking application shutdown."""
223
+
224
+ executor = self._executor
225
+ client = self._client
226
+
227
+ if executor is None:
228
+ return
229
+
230
+ def _shutdown_client() -> None:
231
+ try:
232
+ if client is not None:
233
+ shutdown_fn = getattr(client, "shutdown", None)
234
+ if callable(shutdown_fn):
235
+ shutdown_fn()
236
+ except Exception:
237
+ return
238
+
239
+ try:
240
+ fut = executor.submit(_shutdown_client)
241
+ fut.result(timeout=timeout_seconds)
242
+ except Exception:
243
+ pass
244
+ finally:
245
+ try:
246
+ executor.shutdown(wait=False, cancel_futures=False)
247
+ except Exception:
248
+ pass
@@ -1,17 +1,17 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: idun-agent-engine
3
- Version: 0.3.9
3
+ Version: 0.4.1
4
4
  Summary: Python SDK and runtime to serve AI agents with FastAPI, LangGraph, and observability.
5
5
  Project-URL: Homepage, https://github.com/geoffreyharrazi/idun-agent-platform
6
6
  Project-URL: Repository, https://github.com/geoffreyharrazi/idun-agent-platform
7
7
  Project-URL: Documentation, https://github.com/geoffreyharrazi/idun-agent-platform/tree/main/libs/idun_agent_engine
8
8
  Project-URL: Issues, https://github.com/geoffreyharrazi/idun-agent-platform/issues
9
9
  Author-email: Geoffrey HARRAZI <geoffreyharrazi@gmail.com>
10
- License-Expression: MIT
10
+ License-Expression: GPL-3.0-only
11
11
  Keywords: agents,fastapi,langgraph,llm,observability,sdk
12
12
  Classifier: Framework :: FastAPI
13
13
  Classifier: Intended Audience :: Developers
14
- Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
15
15
  Classifier: Programming Language :: Python :: 3
16
16
  Classifier: Programming Language :: Python :: 3 :: Only
17
17
  Classifier: Programming Language :: Python :: 3.12
@@ -31,12 +31,12 @@ Requires-Dist: deepagents<1.0.0,>=0.2.8
31
31
  Requires-Dist: fastapi<0.116.0,>=0.115.0
32
32
  Requires-Dist: google-adk<2.0.0,>=1.19.0
33
33
  Requires-Dist: google-cloud-logging<4.0.0,>=3.10.0
34
- Requires-Dist: guardrails-ai<0.8.0,>=0.7.0
34
+ Requires-Dist: guardrails-ai<0.8.0,>=0.7.2
35
35
  Requires-Dist: httpx<0.29.0,>=0.28.1
36
36
  Requires-Dist: idun-agent-schema<1.0.0,>=0.3.8
37
37
  Requires-Dist: langchain-core<2.0.0,>=1.0.0
38
38
  Requires-Dist: langchain-google-vertexai<4.0.0,>=2.0.27
39
- Requires-Dist: langchain-mcp-adapters<0.2.0,>=0.1.0
39
+ Requires-Dist: langchain-mcp-adapters<0.3.0,>=0.2.0
40
40
  Requires-Dist: langchain<2.0.0,>=1.0.0
41
41
  Requires-Dist: langfuse-haystack>=2.3.0
42
42
  Requires-Dist: langfuse<4.0.0,>=2.60.8
@@ -51,12 +51,16 @@ Requires-Dist: openinference-instrumentation-mcp<2.0.0,>=1.0.0
51
51
  Requires-Dist: openinference-instrumentation-vertexai<1.0.0,>=0.1.0
52
52
  Requires-Dist: opentelemetry-exporter-gcp-trace<2.0.0,>=1.6.0
53
53
  Requires-Dist: opentelemetry-exporter-otlp-proto-http<2.0.0,>=1.22.0
54
+ Requires-Dist: platformdirs<5.0.0,>=4.0.0
55
+ Requires-Dist: posthog<8.0.0,>=7.0.0
54
56
  Requires-Dist: psycopg-binary<4.0.0,>=3.3.0
55
57
  Requires-Dist: pydantic<3.0.0,>=2.11.7
56
58
  Requires-Dist: python-dotenv>=1.1.1
59
+ Requires-Dist: pyyaml<7.0.0,>=6.0.0
57
60
  Requires-Dist: sqlalchemy<3.0.0,>=2.0.36
58
61
  Requires-Dist: streamlit<2.0.0,>=1.47.1
59
62
  Requires-Dist: tavily-python<0.8.0,>=0.7.9
63
+ Requires-Dist: textual<7.4.0,>=7.3.0
60
64
  Requires-Dist: uvicorn<0.36.0,>=0.35.0
61
65
  Description-Content-Type: text/markdown
62
66
 
@@ -72,7 +76,7 @@ Idun Agent Engine is a lightweight runtime and SDK that wraps your agent with a
72
76
  pip install idun-agent-engine
73
77
  ```
74
78
 
75
- - Requires Python 3.13
79
+ - Requires Python 3.12+
76
80
  - Ships with FastAPI, Uvicorn, LangGraph, SQLite checkpointing, and optional observability hooks
77
81
 
78
82
  ## Quickstart
@@ -319,9 +323,9 @@ from idun_agent_engine import (
319
323
 
320
324
  Issues and PRs are welcome. See the repository:
321
325
 
322
- - Repo: `https://github.com/geoffreyharrazi/idun-agent-platform`
326
+ - Repo: `https://github.com/Idun-Group/idun-agent-platform`
323
327
  - Package path: `libs/idun_agent_engine`
324
- - Open an issue: `https://github.com/geoffreyharrazi/idun-agent-platform/issues`
328
+ - Open an issue: `https://github.com/Idun-Group/idun-agent-platform/issues`
325
329
 
326
330
  Run locally:
327
331
 
@@ -1,29 +1,29 @@
1
1
  idun_agent_engine/__init__.py,sha256=PhOL6foq5V0eXaoXw7xKUeCWXIWrOHrAFB8OuJnBqyM,550
2
- idun_agent_engine/_version.py,sha256=wg5TtrJHehk9ojgri-pSlGNV_tkiMqJWfjSzOxSjvMM,72
2
+ idun_agent_engine/_version.py,sha256=46Sg_0NATQ79huYXlK2uZI6BAN4q9gzxYyxZAuU0Bh0,72
3
3
  idun_agent_engine/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  idun_agent_engine/agent/__init__.py,sha256=foyOoRdI_04q1b6f2A5EXEpWSCKjZxpgWMWrKcsHNl8,220
5
5
  idun_agent_engine/agent/base.py,sha256=c-3gljSHQpm6aY0JNDmXkaPtcW55rXdsI8Cgv9l4bCs,3294
6
6
  idun_agent_engine/agent/adk/__init__.py,sha256=jLV2Z9qQGZtBpF_0pQI1FRCPJ_J1G3Z6cEAzHnQyuu4,83
7
- idun_agent_engine/agent/adk/adk.py,sha256=29YC5rgLjdod-CU3a2JqgAvzYcD5u2EY7pylozGNi9c,11375
7
+ idun_agent_engine/agent/adk/adk.py,sha256=0lfubR5ylfmfuSTOryULxnlJS3gAxpP3xtRaDypGqvE,11415
8
8
  idun_agent_engine/agent/haystack/__init__.py,sha256=y5ADrD8gWBeYIvV7tmu6OpPdJ8POHt-tyraIL7RkkWI,179
9
9
  idun_agent_engine/agent/haystack/haystack.py,sha256=k4NAx_zTBO9uiExM9NtuDAN94H1lrCWtHf1GEWEN16g,10966
10
10
  idun_agent_engine/agent/haystack/haystack_model.py,sha256=EtOYnsWRufcrQufTRMeB3V-rZVQqfnmwKwPsYGfZdCs,362
11
11
  idun_agent_engine/agent/haystack/utils.py,sha256=sKRoPhzZWFw1NPsYwCockafzMBCCq3lGOrndbNE_C3M,609
12
12
  idun_agent_engine/agent/langgraph/__init__.py,sha256=CoBdkp9P4livdy5B0bvj9o7ftoqKmXEr9cZv4TZLncs,107
13
- idun_agent_engine/agent/langgraph/langgraph.py,sha256=vM5ppt0s_2izzZVbVXXGXGCVUGSN-GZhvQ5-6YbOgVM,22904
13
+ idun_agent_engine/agent/langgraph/langgraph.py,sha256=cbVrUs74a0p6omypMHWO3-1uqGLtJdiyAMrCheQHF5w,22966
14
14
  idun_agent_engine/core/__init__.py,sha256=F0DMDlWcSWS_1dvh3xMbrdcVvZRHVnoAFFgREuSJfBI,408
15
- idun_agent_engine/core/app_factory.py,sha256=XiLrctFT_n8LP3flKFwJoJDbiWPiw98N9lbkpR8P1O0,2597
16
- idun_agent_engine/core/config_builder.py,sha256=HpKrWwpohuArICyuOd-0eUQMG0PP2ZfhZzRGjLP9yck,25841
15
+ idun_agent_engine/core/app_factory.py,sha256=2w4o7wV8FQCZdBTk3W7cS0vnmpUM_TdAmphFKHbL31w,2597
16
+ idun_agent_engine/core/config_builder.py,sha256=MosVcPjn7qXUAlmaYvnPquJ0jZ55pDOLfLv0i-D-A28,26049
17
17
  idun_agent_engine/core/engine_config.py,sha256=IR8WhbenDstNSL7ORrUW8AnzgS3exFQxtwip66pFhcM,545
18
18
  idun_agent_engine/core/server_runner.py,sha256=DwN5kHiKVvUJLw5iSkaxs2rKRaMgOwSUZmeUPSuDbf8,4899
19
19
  idun_agent_engine/guardrails/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
20
  idun_agent_engine/guardrails/base.py,sha256=rvi7gcuKK8-3GtGicWzMWYsKKv0g3LjGBI-FycxgKVU,814
21
- idun_agent_engine/guardrails/guardrails_hub/__init__.py,sha256=gz2E0wPBEKi69RRRgo3zDBYwaEyGxH6GDDNcG1l6Y3E,131
21
+ idun_agent_engine/guardrails/guardrails_hub/__init__.py,sha256=MwWdgrM1dNzKwuS9ZEFw5Cin91JXh2PYlMma8yZFO7o,123
22
22
  idun_agent_engine/guardrails/guardrails_hub/guardrails_hub.py,sha256=DgcUIDy9_bcVcpYVvDJowFe_QVlCpEkr8hntPRgRmS0,3456
23
23
  idun_agent_engine/guardrails/guardrails_hub/utils.py,sha256=bC6-MsCVF7xKTr48z7OzJJUeWvqAB7BiHeNTiKsme70,20
24
- idun_agent_engine/mcp/__init__.py,sha256=tsX4sJa7UZD-lr8O1acMwDrdDWJc_hMlB9IrX1NH8Wk,255
25
- idun_agent_engine/mcp/helpers.py,sha256=aFiLlk63pifBjGgctREFWxuSbb-um6QDOVpyikQ5NJ0,3224
26
- idun_agent_engine/mcp/registry.py,sha256=K9-OLF_7FoKmyrwi65i6E3goZROHLRgISlF1yPwkEm8,3996
24
+ idun_agent_engine/mcp/__init__.py,sha256=ygChpEQ4MzMpEifW3szi5kNiLIMhOhJEtqxy0nmewDU,501
25
+ idun_agent_engine/mcp/helpers.py,sha256=b345RHXgeZ15a4gfg8sUJ3Ke7Iwke6FR1RqDRfRUB0c,6589
26
+ idun_agent_engine/mcp/registry.py,sha256=8zt9o8MZmYKx55xb0E7n-qOCR_3m2-XGf7ToQEwHkTU,4229
27
27
  idun_agent_engine/observability/__init__.py,sha256=DCtK6b3xiX4dh0_8GBDOcSXQdcIJz2wTqqPa_ZFAES4,430
28
28
  idun_agent_engine/observability/base.py,sha256=C6mY_ZafDEHkMz8_ZeaEh--pyYuzJYEUqhoJ0sVP2wY,5570
29
29
  idun_agent_engine/observability/gcp_logging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -38,24 +38,52 @@ idun_agent_engine/observability/phoenix_local/__init__.py,sha256=m9dIw1GWGKAW4wP
38
38
  idun_agent_engine/observability/phoenix_local/phoenix_local_handler.py,sha256=wjOZuMpAxdD5D33rzxycNEzFMunETpPnYjiHjbjz5GA,4252
39
39
  idun_agent_engine/server/__init__.py,sha256=WaFektUsy37bNg2niAUy_TykzStukgWPnxC-t49CEwo,177
40
40
  idun_agent_engine/server/dependencies.py,sha256=MVH8STOQ8wu-iYE_28y5dvw5FGT5PX0uQl0ldkpxw6Y,2080
41
- idun_agent_engine/server/lifespan.py,sha256=sp1EaCRKHblRFwYHWWNQzuD3deFiFpb06QlSutvoZRo,3832
41
+ idun_agent_engine/server/lifespan.py,sha256=pTPZ36R4jlx1jq249kpj4DEe-opIGYiRNUHncKlnuGs,4670
42
42
  idun_agent_engine/server/server_config.py,sha256=RYA7Y0c5aRw_WXaX8svFUIEtTPqzn3o-WQRm2p52C6g,213
43
43
  idun_agent_engine/server/routers/__init__.py,sha256=BgNzSVvHtGPGn5zhXhomwpKlDYBkeFi7xCbdcWVOgc8,102
44
44
  idun_agent_engine/server/routers/agent.py,sha256=qLaVRKgMIu-YfOi-tPEzLNRZKZ4DaZEQ8KQ-4HrWbbY,9194
45
45
  idun_agent_engine/server/routers/agui.py,sha256=Z1G4fuo57MazQWfp7ao8QZ1or2H9BXLS_JB1nFPXAkE,1891
46
46
  idun_agent_engine/server/routers/base.py,sha256=wICOXCokCIRjmHuDPDTWqeXqOVPes1CtDtiR_HvtsF0,3756
47
+ idun_agent_engine/telemetry/__init__.py,sha256=oYmmgUYvuwM-eV1qBeTgy6HoG6H3LC_S4fMH04QiMWY,519
48
+ idun_agent_engine/telemetry/config.py,sha256=APSmZWocwSqB1xSxoZkJrSTZnWlBiQdif4whdXi8uBE,845
49
+ idun_agent_engine/telemetry/telemetry.py,sha256=g14ouZnSIV85A58HeAH5IlJ_IDKO_uYo7kFbWRo5PpI,7319
47
50
  idun_agent_engine/templates/__init__.py,sha256=xxbJZXaX6VEm_UrqzAOQcuujpEji5yqYzwQfwiqig8o,31
48
51
  idun_agent_engine/templates/correction.py,sha256=qApH4W99K31maxNrGf0hPVe_Wd4xjYjJrEKlu7PbRpw,1823
49
52
  idun_agent_engine/templates/deep_research.py,sha256=j4WypBkBz7V3EG-U8vawfNXDNhcCf2QiEK0veI4M68s,1077
50
53
  idun_agent_engine/templates/translation.py,sha256=vjp1yEyhDMFO4nEbq5WG7LAA7nLrhVAjznOkV7ob_Ss,2149
51
54
  idun_platform_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
52
- idun_platform_cli/main.py,sha256=jWL7Ob0p4KdRUqgPTP_EB68n7z2LyMKC2DeUsfWlBO4,200
55
+ idun_platform_cli/main.py,sha256=B7b1x0kgfuiAWGmSCFJeu_zkWiodJjOGu0nWuNAWM-k,299
56
+ idun_platform_cli/telemetry.py,sha256=mLTO8717ckmglm_oSl1xFxomk-eqwqrCU9Nl1uq27Dg,1711
53
57
  idun_platform_cli/groups/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
+ idun_platform_cli/groups/init.py,sha256=gBWU7tQ0v9aaPNSQXorKWrOkUc5YgJU06pzDC-qG97U,769
54
59
  idun_platform_cli/groups/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
60
  idun_platform_cli/groups/agent/main.py,sha256=QMGQi3JZ76SeFI3miIjVWpMt0L-hGz5FwxtTPQX4-Uw,301
56
- idun_platform_cli/groups/agent/package.py,sha256=LdIFAcfrlUcCssmSliYQIi0NFMuVkpx6t8WhMHATan8,2525
57
- idun_platform_cli/groups/agent/serve.py,sha256=2AbL0G1WqR33jlyiGaNvAoPZ3G1o52KYUptz_HaAjIg,3863
58
- idun_agent_engine-0.3.9.dist-info/METADATA,sha256=xUkcP9OMVWs9ftXHs0gmTnLdddG_t4eoNGc9Sbs15jI,10692
59
- idun_agent_engine-0.3.9.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
60
- idun_agent_engine-0.3.9.dist-info/entry_points.txt,sha256=XG3oxlSOaCrYKT1oyhKa0Ag1iJPMZ-WF6gaV_mzIJW4,52
61
- idun_agent_engine-0.3.9.dist-info/RECORD,,
61
+ idun_platform_cli/groups/agent/package.py,sha256=JeoQBZ_egkeKhQhB-FuGGrY1T1VG4f4ixuhjt0mDygE,2615
62
+ idun_platform_cli/groups/agent/serve.py,sha256=ujCmJ3JsrjHkXvNwyB7V4poAaTxMQAPcIbRPDVybRQo,3947
63
+ idun_platform_cli/tui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
64
+ idun_platform_cli/tui/main.py,sha256=1gFEdbynBfiBLrZrKvNJN16Uc_3DOJl1spexRz38Q-E,3080
65
+ idun_platform_cli/tui/css/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
66
+ idun_platform_cli/tui/css/create_agent.py,sha256=ZyFNv6-EUTUaJ_817wh0KUvdu8rtuuPj9jTbigLfOR8,14050
67
+ idun_platform_cli/tui/css/main.py,sha256=gJ_kNb2lC2l99lq8NqtYU2imXAjUpxfiOaf1mNJr-Po,1134
68
+ idun_platform_cli/tui/schemas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
69
+ idun_platform_cli/tui/schemas/create_agent.py,sha256=2jsZ5v1sZLKmypgimdVoeVjd-wOylTE3IUYPw63eb8Y,1512
70
+ idun_platform_cli/tui/screens/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
71
+ idun_platform_cli/tui/screens/create_agent.py,sha256=3Yav2gvJhh0el4BTLuYzYELrHWuKDBnNnNHlRIBUEJE,23881
72
+ idun_platform_cli/tui/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
73
+ idun_platform_cli/tui/utils/config.py,sha256=AEgjgnNkCtQwuGxI8lclteunKZXvn_TMx0eBx7uJWto,7286
74
+ idun_platform_cli/tui/validators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
75
+ idun_platform_cli/tui/validators/guardrails.py,sha256=l6TJKxjpr8Nktwndh6C7Juz4oY-bqpg295jtYTKHuQ8,3537
76
+ idun_platform_cli/tui/validators/mcps.py,sha256=oDxbxt7qOzsW8yjd_fwBnlDPOSxPqCXqbF5q8eEYRVQ,2852
77
+ idun_platform_cli/tui/validators/observability.py,sha256=IWNuJg42eZUxjV-7v12kms7DpJsAs3FSSD5zLU5eKUc,2436
78
+ idun_platform_cli/tui/widgets/__init__.py,sha256=w8rQsUxqTtxuhpOPxCgl1pmv2vjCJseKNc1lhfMMkBM,521
79
+ idun_platform_cli/tui/widgets/chat_widget.py,sha256=8RCAY97asVxyy7VV7IJ4kEAX9edK46UGO90BJ0X4BL0,5731
80
+ idun_platform_cli/tui/widgets/guardrails_widget.py,sha256=3EDrfTKXyN7N8qMuWVy-BjK6ia3CZIE0EVm1sh6FhMw,14552
81
+ idun_platform_cli/tui/widgets/identity_widget.py,sha256=LjpX-mgIinxJ5FzKBFz1HYbImwX7khpbetl86LsPnfw,9508
82
+ idun_platform_cli/tui/widgets/mcps_widget.py,sha256=5AToZHU5PAUJEuq0HhL4Mi_VmWlFLyTeY5pohWY3rKw,10974
83
+ idun_platform_cli/tui/widgets/memory_widget.py,sha256=QHCH0et_lJa9pheTpcZdbzTDUzw95Do2koi6hEdmrOc,6996
84
+ idun_platform_cli/tui/widgets/observability_widget.py,sha256=9AO7-nqMEIx_9FCmqbtprxoBejq4w8bR9wOhxl2BbmA,14915
85
+ idun_platform_cli/tui/widgets/serve_widget.py,sha256=0FinYhkyA0LJnX1g4JDrkcD5df-l-qgMxjRjgF0CleQ,2749
86
+ idun_agent_engine-0.4.1.dist-info/METADATA,sha256=xGS6C3n58AGB9WezKja-6Oy2EigEcuO3v8M6JKnZFu0,10870
87
+ idun_agent_engine-0.4.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
88
+ idun_agent_engine-0.4.1.dist-info/entry_points.txt,sha256=XG3oxlSOaCrYKT1oyhKa0Ag1iJPMZ-WF6gaV_mzIJW4,52
89
+ idun_agent_engine-0.4.1.dist-info/RECORD,,
@@ -4,6 +4,8 @@ from pathlib import Path
4
4
 
5
5
  import click
6
6
 
7
+ from idun_platform_cli.telemetry import track_command
8
+
7
9
 
8
10
  class Dependency(StrEnum):
9
11
  """Dependency Enum."""
@@ -57,6 +59,7 @@ CMD ["idun", "agent", "serve", "--source=manager"]
57
59
  @click.command("package")
58
60
  @click.argument("path", default=".")
59
61
  @click.option("--target", required=False, default=".")
62
+ @track_command("agent package")
60
63
  def package_command(path: str, target: str):
61
64
  """Packages the agent and it's dependencies into a Dockerfile. You can specifiy the input path and the destination. Defaults to current directory."""
62
65
  dependency = get_dependencies(path)
@@ -8,6 +8,7 @@ from idun_agent_engine.core.app_factory import create_app
8
8
  from idun_agent_engine.core.config_builder import ConfigBuilder
9
9
  from idun_agent_engine.core.engine_config import EngineConfig
10
10
  from idun_agent_engine.core.server_runner import run_server
11
+ from idun_platform_cli.telemetry import track_command
11
12
 
12
13
 
13
14
  class ServerSource(StrEnum):
@@ -84,6 +85,7 @@ class Serve:
84
85
  @click.command("serve")
85
86
  @click.option("--source", required=True)
86
87
  @click.option("--path")
88
+ @track_command("agent serve")
87
89
  def serve_command(source: str, path: str | None):
88
90
  """Reads a config and exposes it's agent as an API. Config is either fetched from the manager, or from a path.
89
91
 
@@ -0,0 +1,25 @@
1
+ import sys
2
+
3
+ import click
4
+
5
+ from idun_platform_cli.telemetry import track_command
6
+ from idun_platform_cli.tui.main import IdunApp
7
+
8
+
9
+ @click.command("init")
10
+ @track_command("init")
11
+ def init_command() -> None:
12
+ """Starts a terminal user interface that guides you through configuring and managing Idun agents."""
13
+ try:
14
+ app = IdunApp()
15
+ app.run()
16
+ except ImportError as e:
17
+ print(f"[ERROR]: Missing required dependency for TUI: {e}")
18
+ print("[INFO]: Make sure 'textual' is installed in your environment")
19
+ sys.exit(1)
20
+ except KeyboardInterrupt:
21
+ print("\n[INFO]: Initialization cancelled by user")
22
+ sys.exit(0)
23
+ except Exception as e:
24
+ print(f"[ERROR]: Failed to launch the Idun TUI: {e}")
25
+ sys.exit(1)
idun_platform_cli/main.py CHANGED
@@ -1,5 +1,7 @@
1
1
  import click
2
+
2
3
  from idun_platform_cli.groups.agent.main import agent
4
+ from idun_platform_cli.groups.init import init_command
3
5
 
4
6
 
5
7
  @click.group()
@@ -9,6 +11,7 @@ def cli():
9
11
 
10
12
 
11
13
  cli.add_command(agent)
14
+ cli.add_command(init_command, name="init")
12
15
 
13
16
  if __name__ == "__main__":
14
17
  cli()
@@ -0,0 +1,54 @@
1
+ """Telemetry utilities for CLI command tracking."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import functools
6
+ import time
7
+ from typing import Any, Callable, TypeVar
8
+
9
+ from idun_agent_engine.telemetry import get_telemetry, sanitize_telemetry_config
10
+
11
+ F = TypeVar("F", bound=Callable[..., Any])
12
+
13
+
14
+ def track_command(command_name: str) -> Callable[[F], F]:
15
+ """Decorator to track CLI command invocations via telemetry.
16
+
17
+ Args:
18
+ command_name: The name of the command to track (e.g., "init", "agent serve").
19
+
20
+ Returns:
21
+ A decorator that wraps the command function with telemetry tracking.
22
+ """
23
+
24
+ def decorator(func: F) -> F:
25
+ @functools.wraps(func)
26
+ def wrapper(*args: Any, **kwargs: Any) -> Any:
27
+ telemetry = get_telemetry()
28
+ start_time = time.time()
29
+ success = True
30
+ error_message: str | None = None
31
+
32
+ try:
33
+ return func(*args, **kwargs)
34
+ except Exception as e:
35
+ success = False
36
+ error_message = str(e)
37
+ raise
38
+ finally:
39
+ duration_ms = (time.time() - start_time) * 1000
40
+ telemetry.capture(
41
+ "cli command invoked",
42
+ properties={
43
+ "command": command_name,
44
+ "arguments": sanitize_telemetry_config(kwargs),
45
+ "success": success,
46
+ "error": error_message,
47
+ "duration_ms": round(duration_ms, 2),
48
+ },
49
+ )
50
+ telemetry.shutdown(timeout_seconds=0.5)
51
+
52
+ return wrapper # type: ignore[return-value]
53
+
54
+ return decorator
File without changes
File without changes