idun-agent-engine 0.1.0__py3-none-any.whl → 0.2.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.
Files changed (45) hide show
  1. idun_agent_engine/__init__.py +2 -25
  2. idun_agent_engine/_version.py +1 -1
  3. idun_agent_engine/agent/__init__.py +10 -0
  4. idun_agent_engine/agent/base.py +97 -0
  5. idun_agent_engine/agent/haystack/__init__.py +9 -0
  6. idun_agent_engine/agent/haystack/haystack.py +261 -0
  7. idun_agent_engine/agent/haystack/haystack_model.py +13 -0
  8. idun_agent_engine/agent/haystack/utils.py +13 -0
  9. idun_agent_engine/agent/langgraph/__init__.py +7 -0
  10. idun_agent_engine/agent/langgraph/langgraph.py +431 -0
  11. idun_agent_engine/cli/__init__.py +16 -0
  12. idun_agent_engine/core/__init__.py +11 -0
  13. idun_agent_engine/core/app_factory.py +63 -0
  14. idun_agent_engine/core/config_builder.py +456 -0
  15. idun_agent_engine/core/engine_config.py +22 -0
  16. idun_agent_engine/core/server_runner.py +146 -0
  17. idun_agent_engine/observability/__init__.py +13 -0
  18. idun_agent_engine/observability/base.py +111 -0
  19. idun_agent_engine/observability/langfuse/__init__.py +5 -0
  20. idun_agent_engine/observability/langfuse/langfuse_handler.py +72 -0
  21. idun_agent_engine/observability/phoenix/__init__.py +5 -0
  22. idun_agent_engine/observability/phoenix/phoenix_handler.py +65 -0
  23. idun_agent_engine/observability/phoenix_local/__init__.py +5 -0
  24. idun_agent_engine/observability/phoenix_local/phoenix_local_handler.py +123 -0
  25. idun_agent_engine/py.typed +0 -1
  26. idun_agent_engine/server/__init__.py +5 -0
  27. idun_agent_engine/server/dependencies.py +23 -0
  28. idun_agent_engine/server/lifespan.py +42 -0
  29. idun_agent_engine/server/routers/__init__.py +5 -0
  30. idun_agent_engine/server/routers/agent.py +68 -0
  31. idun_agent_engine/server/routers/base.py +60 -0
  32. idun_agent_engine/server/server_config.py +8 -0
  33. idun_agent_engine-0.2.2.dist-info/METADATA +281 -0
  34. idun_agent_engine-0.2.2.dist-info/RECORD +43 -0
  35. {idun_agent_engine-0.1.0.dist-info → idun_agent_engine-0.2.2.dist-info}/WHEEL +1 -1
  36. idun_agent_engine-0.2.2.dist-info/entry_points.txt +2 -0
  37. idun_platform_cli/__init__.py +0 -0
  38. idun_platform_cli/groups/__init__.py +0 -0
  39. idun_platform_cli/groups/agent/__init__.py +0 -0
  40. idun_platform_cli/groups/agent/main.py +16 -0
  41. idun_platform_cli/groups/agent/package.py +73 -0
  42. idun_platform_cli/groups/agent/serve.py +104 -0
  43. idun_platform_cli/main.py +14 -0
  44. idun_agent_engine-0.1.0.dist-info/METADATA +0 -317
  45. idun_agent_engine-0.1.0.dist-info/RECORD +0 -6
@@ -0,0 +1,281 @@
1
+ Metadata-Version: 2.4
2
+ Name: idun-agent-engine
3
+ Version: 0.2.2
4
+ Summary: Python SDK and runtime to serve AI agents with FastAPI, LangGraph, and observability.
5
+ Project-URL: Homepage, https://github.com/geoffreyharrazi/idun-agent-platform
6
+ Project-URL: Repository, https://github.com/geoffreyharrazi/idun-agent-platform
7
+ Project-URL: Documentation, https://github.com/geoffreyharrazi/idun-agent-platform/tree/main/libs/idun_agent_engine
8
+ Project-URL: Issues, https://github.com/geoffreyharrazi/idun-agent-platform/issues
9
+ Author-email: Geoffrey HARRAZI <geoffreyharrazi@gmail.com>
10
+ License-Expression: MIT
11
+ Keywords: agents,fastapi,langgraph,llm,observability,sdk
12
+ Classifier: Framework :: FastAPI
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Software Development :: Libraries
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: <3.14,>=3.12
22
+ Requires-Dist: ag-ui-protocol<0.2.0,>=0.1.8
23
+ Requires-Dist: aiosqlite<0.22.0,>=0.21.0
24
+ Requires-Dist: arize-phoenix-otel<1.0.0,>=0.2.0
25
+ Requires-Dist: arize-phoenix<12.0.0,>=11.22.0
26
+ Requires-Dist: click>=8.2.1
27
+ Requires-Dist: fastapi<0.117.0,>=0.116.1
28
+ Requires-Dist: google-adk<2.0.0,>=1.9.0
29
+ Requires-Dist: httpx<0.29.0,>=0.28.1
30
+ Requires-Dist: idun-agent-schema<0.3.0,>=0.2.2
31
+ Requires-Dist: langchain-core<0.4.0,>=0.3.72
32
+ Requires-Dist: langchain-google-vertexai<3.0.0,>=2.0.27
33
+ Requires-Dist: langchain<0.4,>=0.3.27
34
+ Requires-Dist: langfuse-haystack>=2.3.0
35
+ Requires-Dist: langfuse==2.60.8
36
+ Requires-Dist: langgraph-checkpoint-sqlite<3.0.0,>=2.0.11
37
+ Requires-Dist: langgraph<0.7.0,>=0.6.3
38
+ Requires-Dist: openinference-instrumentation-langchain<1.0.0,>=0.1.13
39
+ Requires-Dist: pydantic<3.0.0,>=2.11.7
40
+ Requires-Dist: python-dotenv>=1.1.1
41
+ Requires-Dist: sqlalchemy<3.0.0,>=2.0.36
42
+ Requires-Dist: streamlit<2.0.0,>=1.47.1
43
+ Requires-Dist: uvicorn<0.36.0,>=0.35.0
44
+ Description-Content-Type: text/markdown
45
+
46
+ # Idun Agent Engine
47
+
48
+ Turn any LangGraph-based agent into a production-grade API in minutes.
49
+
50
+ Idun Agent Engine is a lightweight runtime and SDK that wraps your agent with a FastAPI server, adds streaming, structured responses, config validation, and optional observability — with zero boilerplate. Use a YAML file or a fluent builder to configure and run.
51
+
52
+ ## Installation
53
+
54
+ ```bash
55
+ pip install idun-agent-engine
56
+ ```
57
+
58
+ - Requires Python 3.13
59
+ - Ships with FastAPI, Uvicorn, LangGraph, SQLite checkpointing, and optional observability hooks
60
+
61
+ ## Quickstart
62
+
63
+ ### 1) Minimal one-liner (from a YAML config)
64
+
65
+ ```python
66
+ from idun_agent_engine.core.server_runner import run_server_from_config
67
+
68
+ run_server_from_config("config.yaml")
69
+ ```
70
+
71
+ Example `config.yaml`:
72
+
73
+ ```yaml
74
+ server:
75
+ api:
76
+ port: 8000
77
+
78
+ agent:
79
+ type: "langgraph"
80
+ config:
81
+ name: "My Example LangGraph Agent"
82
+ graph_definition: "./examples/01_basic_config_file/example_agent.py:app"
83
+ # Optional: conversation persistence
84
+ checkpointer:
85
+ type: "sqlite"
86
+ db_url: "sqlite:///example_checkpoint.db"
87
+ # Optional: provider-agnostic observability
88
+ observability:
89
+ provider: langfuse # or phoenix
90
+ enabled: true
91
+ options:
92
+ host: ${LANGFUSE_HOST}
93
+ public_key: ${LANGFUSE_PUBLIC_KEY}
94
+ secret_key: ${LANGFUSE_SECRET_KEY}
95
+ run_name: "idun-langgraph-run"
96
+ ```
97
+
98
+ Run and open docs at `http://localhost:8000/docs`.
99
+
100
+ ### 2) Programmatic setup with the fluent builder
101
+
102
+ ```python
103
+ from pathlib import Path
104
+ from idun_agent_engine import ConfigBuilder, create_app, run_server
105
+
106
+ config = (
107
+ ConfigBuilder()
108
+ .with_api_port(8000)
109
+ .with_langgraph_agent(
110
+ name="Programmatic Example Agent",
111
+ graph_definition=str(Path("./examples/02_programmatic_config/smart_agent.py:app")),
112
+ sqlite_checkpointer="programmatic_example.db",
113
+ )
114
+ .build()
115
+ )
116
+
117
+ app = create_app(engine_config=config)
118
+ run_server(app, reload=True)
119
+ ```
120
+
121
+ ## Endpoints
122
+
123
+ All servers expose these by default:
124
+
125
+ - POST `/agent/invoke`: single request/response
126
+ - POST `/agent/stream`: server-sent events stream of `ag-ui` protocol events
127
+ - GET `/health`: service health with engine version
128
+ - GET `/`: root landing with links
129
+
130
+ Invoke example:
131
+
132
+ ```bash
133
+ curl -X POST "http://localhost:8000/agent/invoke" \
134
+ -H "Content-Type: application/json" \
135
+ -d '{"query": "Hello!", "session_id": "user-123"}'
136
+ ```
137
+
138
+ Stream example:
139
+
140
+ ```bash
141
+ curl -N -X POST "http://localhost:8000/agent/stream" \
142
+ -H "Content-Type: application/json" \
143
+ -d '{"query": "Tell me a story", "session_id": "user-123"}'
144
+ ```
145
+
146
+ ## LangGraph integration
147
+
148
+ Point the engine to a `StateGraph` variable in your file using `graph_definition`:
149
+
150
+ ```python
151
+ # examples/01_basic_config_file/example_agent.py
152
+ import operator
153
+ from typing import Annotated, TypedDict
154
+ from langgraph.graph import END, StateGraph
155
+
156
+ class AgentState(TypedDict):
157
+ messages: Annotated[list, operator.add]
158
+
159
+ def greeting_node(state):
160
+ user_message = state["messages"][-1] if state["messages"] else ""
161
+ return {"messages": [("ai", f"Hello! You said: '{user_message}'")]}
162
+
163
+ graph = StateGraph(AgentState)
164
+ graph.add_node("greet", greeting_node)
165
+ graph.set_entry_point("greet")
166
+ graph.add_edge("greet", END)
167
+
168
+ # This variable name is referenced by graph_definition
169
+ app = graph
170
+ ```
171
+
172
+ Then reference it in config:
173
+
174
+ ```yaml
175
+ agent:
176
+ type: "langgraph"
177
+ config:
178
+ graph_definition: "./examples/01_basic_config_file/example_agent.py:app"
179
+ ```
180
+
181
+ Behind the scenes, the engine:
182
+
183
+ - Validates config with Pydantic models
184
+ - Loads your `StateGraph` from disk
185
+ - Optionally wires a SQLite checkpointer via `langgraph.checkpoint.sqlite`
186
+ - Exposes `invoke` and `stream` endpoints
187
+ - Bridges LangGraph events to `ag-ui` stream events
188
+
189
+ ## Observability (optional)
190
+
191
+ Enable provider-agnostic observability via the `observability` block in your agent config. Today supports Langfuse and Arize Phoenix (OpenInference) patterns; more coming soon.
192
+
193
+ ```yaml
194
+ agent:
195
+ type: "langgraph"
196
+ config:
197
+ observability:
198
+ provider: langfuse # or phoenix
199
+ enabled: true
200
+ options:
201
+ host: ${LANGFUSE_HOST}
202
+ public_key: ${LANGFUSE_PUBLIC_KEY}
203
+ secret_key: ${LANGFUSE_SECRET_KEY}
204
+ run_name: "idun-langgraph-run"
205
+ ```
206
+
207
+ ## Configuration reference
208
+
209
+ - `server.api.port` (int): HTTP port (default 8000)
210
+ - `agent.type` (enum): currently `langgraph` (CrewAI placeholder exists but not implemented)
211
+ - `agent.config.name` (str): human-readable name
212
+ - `agent.config.graph_definition` (str): absolute or relative `path/to/file.py:variable`
213
+ - `agent.config.checkpointer` (sqlite): `{ type: "sqlite", db_url: "sqlite:///file.db" }`
214
+ - `agent.config.observability` (optional): provider options as shown above
215
+
216
+ Config can be sourced by:
217
+
218
+ - `engine_config` (preferred): pass a validated `EngineConfig` to `create_app`
219
+ - `config_dict`: dict validated at runtime
220
+ - `config_path`: path to YAML; defaults to `config.yaml`
221
+
222
+ ## Examples
223
+
224
+ The `examples/` folder contains complete projects:
225
+
226
+ - `01_basic_config_file`: YAML config + simple agent
227
+ - `02_programmatic_config`: `ConfigBuilder` usage and advanced flows
228
+ - `03_minimal_setup`: one-line server from config
229
+
230
+ Run any example with Python 3.13 installed.
231
+
232
+ ## CLI and runtime helpers
233
+
234
+ Top-level imports for convenience:
235
+
236
+ ```python
237
+ from idun_agent_engine import (
238
+ create_app,
239
+ run_server,
240
+ run_server_from_config,
241
+ run_server_from_builder,
242
+ ConfigBuilder,
243
+ )
244
+ ```
245
+
246
+ - `create_app(...)` builds the FastAPI app and registers routes
247
+ - `run_server(app, ...)` runs with Uvicorn
248
+ - `run_server_from_config(path, ...)` loads config, builds app, and runs
249
+ - `run_server_from_builder(builder, ...)` builds from a builder and runs
250
+
251
+ ## Production notes
252
+
253
+ - Use a process manager (e.g., multiple Uvicorn workers behind a gateway). Note: `reload=True` is for development and incompatible with multi-worker mode.
254
+ - Mount behind a reverse proxy and enable TLS where appropriate.
255
+ - Persist conversations using the SQLite checkpointer in production or replace with a custom checkpointer when available.
256
+
257
+ ## Roadmap
258
+
259
+ - CrewAI adapter (placeholder exists, not yet implemented)
260
+ - Additional stores and checkpointers
261
+ - First-class CLI for `idun` commands
262
+
263
+ ## Contributing
264
+
265
+ Issues and PRs are welcome. See the repository:
266
+
267
+ - Repo: `https://github.com/geoffreyharrazi/idun-agent-platform`
268
+ - Package path: `libs/idun_agent_engine`
269
+ - Open an issue: `https://github.com/geoffreyharrazi/idun-agent-platform/issues`
270
+
271
+ Run locally:
272
+
273
+ ```bash
274
+ cd libs/idun_agent_engine
275
+ poetry install
276
+ poetry run pytest -q
277
+ ```
278
+
279
+ ## License
280
+
281
+ MIT — see `LICENSE` in the repo root.
@@ -0,0 +1,43 @@
1
+ idun_agent_engine/__init__.py,sha256=PhOL6foq5V0eXaoXw7xKUeCWXIWrOHrAFB8OuJnBqyM,550
2
+ idun_agent_engine/_version.py,sha256=sutD0vvlsO_-Z21w6GYb8GcWqm_wIsNhNle8EYA9Mgg,72
3
+ idun_agent_engine/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ idun_agent_engine/agent/__init__.py,sha256=foyOoRdI_04q1b6f2A5EXEpWSCKjZxpgWMWrKcsHNl8,220
5
+ idun_agent_engine/agent/base.py,sha256=xzuHIV_P7EwGyK7V2qbFUZccpm5xHaAjAkIxJL4tAwo,2856
6
+ idun_agent_engine/agent/haystack/__init__.py,sha256=y5ADrD8gWBeYIvV7tmu6OpPdJ8POHt-tyraIL7RkkWI,179
7
+ idun_agent_engine/agent/haystack/haystack.py,sha256=6xq7tOlvQxyc2w9KxikpS5S6vmXjUlK9Giwhmzg2X0w,10556
8
+ idun_agent_engine/agent/haystack/haystack_model.py,sha256=EtOYnsWRufcrQufTRMeB3V-rZVQqfnmwKwPsYGfZdCs,362
9
+ idun_agent_engine/agent/haystack/utils.py,sha256=sKRoPhzZWFw1NPsYwCockafzMBCCq3lGOrndbNE_C3M,609
10
+ idun_agent_engine/agent/langgraph/__init__.py,sha256=CoBdkp9P4livdy5B0bvj9o7ftoqKmXEr9cZv4TZLncs,107
11
+ idun_agent_engine/agent/langgraph/langgraph.py,sha256=Fm6t-TeG_7s0tJHev5sIbKcD7gLLXv22pJH0S14Hp2k,17412
12
+ idun_agent_engine/cli/__init__.py,sha256=5S_Oo7n7YwKk5VPyqborrRqKVz6lvwODQ5olj70wbnQ,490
13
+ idun_agent_engine/core/__init__.py,sha256=F0DMDlWcSWS_1dvh3xMbrdcVvZRHVnoAFFgREuSJfBI,408
14
+ idun_agent_engine/core/app_factory.py,sha256=fqxX6n4huCAsEY5lzPQPtBb7nWWaxzvhYaPsRUbZuEY,2333
15
+ idun_agent_engine/core/config_builder.py,sha256=nqlFEASHN9zlZhUnu5NAhRo2DeFkFVQ0rpx-yfnBuIw,16283
16
+ idun_agent_engine/core/engine_config.py,sha256=pHa-qiYUS7mvzW2eb6sXJoxxJCxC5fwcNUTcqiO90c0,584
17
+ idun_agent_engine/core/server_runner.py,sha256=01_aAJC-s0C5fdkEUQzwk4Vlf1SX4lsZwRTkVaJx0VE,4898
18
+ idun_agent_engine/observability/__init__.py,sha256=Jei-E8SgYulxFu5HkJz9HfcorIfQ6O7WZWGzP41ZK-4,298
19
+ idun_agent_engine/observability/base.py,sha256=uVCptXKmU_8OAvLRZliK5RqG6fOxj3a3bg18GVGMeHU,3575
20
+ idun_agent_engine/observability/langfuse/__init__.py,sha256=J8XcHV4aT1pF97k5EZiqrnYYPs9VjwfV5rUMihc5Pgk,128
21
+ idun_agent_engine/observability/langfuse/langfuse_handler.py,sha256=Hn3FxqiYDrLmGNF3JXNRBpFit_c8s2w61jl2EQO_Lco,2385
22
+ idun_agent_engine/observability/phoenix/__init__.py,sha256=tEwJYijcvSGNhFW4QJmvBcTu1D0YVJkZRTmkNCGTteM,130
23
+ idun_agent_engine/observability/phoenix/phoenix_handler.py,sha256=lGqSq-L1vmoEhAr9rbWO3KlNX5HSgBhCKESHMdZ-AfY,2539
24
+ idun_agent_engine/observability/phoenix_local/__init__.py,sha256=m9dIw1GWGKAW4wP08jxA7j4yrOg0Nxq_08bwVh8YogE,146
25
+ idun_agent_engine/observability/phoenix_local/phoenix_local_handler.py,sha256=wjOZuMpAxdD5D33rzxycNEzFMunETpPnYjiHjbjz5GA,4252
26
+ idun_agent_engine/server/__init__.py,sha256=WaFektUsy37bNg2niAUy_TykzStukgWPnxC-t49CEwo,177
27
+ idun_agent_engine/server/dependencies.py,sha256=7yGYWxqbL4xNafpj8g8-S-TQ_GmGlPnSB_wRbW_lfMA,824
28
+ idun_agent_engine/server/lifespan.py,sha256=BC914qErOmKLNZY0-XkMkYnA0aVhLZFY7nhpKXx2D_g,1301
29
+ idun_agent_engine/server/server_config.py,sha256=RYA7Y0c5aRw_WXaX8svFUIEtTPqzn3o-WQRm2p52C6g,213
30
+ idun_agent_engine/server/routers/__init__.py,sha256=BgNzSVvHtGPGn5zhXhomwpKlDYBkeFi7xCbdcWVOgc8,102
31
+ idun_agent_engine/server/routers/agent.py,sha256=7vVzhnKXYv6yZEKP8o-ETMWhIa0Hd2qyMu63MhoiLL0,2361
32
+ idun_agent_engine/server/routers/base.py,sha256=BWueBPN7ecdNWOyQaxpdpnd6GxOcN78N8bFWN_aNgmU,1899
33
+ idun_platform_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
+ idun_platform_cli/main.py,sha256=jWL7Ob0p4KdRUqgPTP_EB68n7z2LyMKC2DeUsfWlBO4,200
35
+ idun_platform_cli/groups/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
+ idun_platform_cli/groups/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
+ idun_platform_cli/groups/agent/main.py,sha256=QMGQi3JZ76SeFI3miIjVWpMt0L-hGz5FwxtTPQX4-Uw,301
38
+ idun_platform_cli/groups/agent/package.py,sha256=yxDY9zZIof0OrNfJR0Qc6qT3aJAhpL64V93tLgOb8Bg,2602
39
+ idun_platform_cli/groups/agent/serve.py,sha256=IHC3vp_R45RW4enkNQCE-SP_J9GkmapAycktKcxT9Y8,3800
40
+ idun_agent_engine-0.2.2.dist-info/METADATA,sha256=aFxItmgfCjlWJ_NFPnfJIA0wcrrGf7e62dbTzVpPi7I,8660
41
+ idun_agent_engine-0.2.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
42
+ idun_agent_engine-0.2.2.dist-info/entry_points.txt,sha256=XG3oxlSOaCrYKT1oyhKa0Ag1iJPMZ-WF6gaV_mzIJW4,52
43
+ idun_agent_engine-0.2.2.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.1.3
2
+ Generator: hatchling 1.27.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ idun = idun_platform_cli.main:cli
File without changes
File without changes
File without changes
@@ -0,0 +1,16 @@
1
+ """Manage, Deploy and package agents."""
2
+
3
+ import click
4
+
5
+ from .package import package_command
6
+ from .serve import serve_command
7
+
8
+
9
+ @click.group()
10
+ def agent():
11
+ """Agent command entrypoint."""
12
+ pass
13
+
14
+
15
+ agent.add_command(serve_command, name="serve")
16
+ agent.add_command(package_command, name="package")
@@ -0,0 +1,73 @@
1
+ import sys
2
+ from enum import StrEnum
3
+ from pathlib import Path
4
+
5
+ import click
6
+
7
+
8
+ class Dependency(StrEnum):
9
+ """Dependency Enum."""
10
+
11
+ REQUIREMENT = "requirements.txt"
12
+ PYPROJECT = "pyproject.toml"
13
+ NONE = "none"
14
+
15
+
16
+ def get_dependencies(path: str) -> Dependency:
17
+ """Verifies if the path folder contains a `requirements.txt` or `pyproject.toml`, and returns which."""
18
+ """:param path: Path pointing to the agent's folder."""
19
+ agent_path = Path(path).resolve()
20
+ if (agent_path / "requirements.txt").exists():
21
+ return Dependency.REQUIREMENT
22
+ elif (agent_path / "pyproject.toml").exists():
23
+ return Dependency.PYPROJECT
24
+ else:
25
+ return Dependency.NONE
26
+
27
+
28
+ def generate_dockerfile(dependency: Dependency) -> str:
29
+ # TODO: add envs vars based on source
30
+ """Generates Dockerfile based on given params."""
31
+ if dependency == Dependency.NONE:
32
+ print(
33
+ "[ERROR]: No pyproject.toml or requirements.txt found. Please make sure to include them."
34
+ )
35
+ sys.exit(1)
36
+ return "" # Unreachable, but satisfies type checker
37
+ if dependency == Dependency.REQUIREMENT:
38
+ # TODO: use from file
39
+ requirements_dockerfile = f"""FROM python:3.13-slim
40
+ RUN apt-get update && pip install uv
41
+ WORKDIR /app
42
+
43
+ RUN uv pip install idun-agent-schema==0.2.2
44
+ RUN uv pip install idun-agent-engine==0.2.2
45
+
46
+ COPY requirements.txt ./
47
+ COPY config.yaml ./
48
+ COPY agent/ ./agent/
49
+ RUN uv pip install -r requirements.txt --system
50
+
51
+ CMD ["idun", "agent", "serve", "--source=file", "--path", "config.yaml"]
52
+ """
53
+ return requirements_dockerfile
54
+ if dependency == Dependency.PYPROJECT:
55
+ # TODO: implement pyproject.toml support
56
+ raise NotImplementedError("pyproject.toml support is not yet implemented")
57
+ raise ValueError(f"Unknown dependency type: {dependency}")
58
+
59
+
60
+ @click.command("package")
61
+ @click.argument("path", default=".")
62
+ @click.option("--target", required=False, default=".")
63
+ def package_command(path: str, target: str):
64
+ """Packages the agent and it's dependencies into a Dockerfile. You can specifiy the input path and the destination. Defaults to current directory."""
65
+ dependency = get_dependencies(path)
66
+ dockerfile = generate_dockerfile(dependency)
67
+ target_path = Path(target)
68
+ dockerfile_path = target_path / "Dockerfile"
69
+ try:
70
+ dockerfile_path.write_text(dockerfile)
71
+ print(f"Dockerfile generated in {target}")
72
+ except OSError as e:
73
+ print(f"[ERROR]: Cannot write dockerfile to path {target}: {e}")
@@ -0,0 +1,104 @@
1
+ import os
2
+ import sys
3
+ from enum import StrEnum
4
+
5
+ import click
6
+ from idun_agent_engine.core.app_factory import create_app
7
+ from idun_agent_engine.core.config_builder import ConfigBuilder
8
+ from idun_agent_engine.core.engine_config import EngineConfig
9
+ from idun_agent_engine.core.server_runner import run_server
10
+
11
+
12
+ class ServerSource(StrEnum):
13
+ """Enum for source types."""
14
+
15
+ MANAGER = "manager"
16
+ FILE = "file"
17
+
18
+
19
+ class Serve:
20
+ """Helper class to run the server."""
21
+
22
+ def __init__(self, source: ServerSource, path: str | None = None) -> None:
23
+ self._source: ServerSource = source
24
+ self._path: str | None = path or None
25
+
26
+ if self._source == ServerSource.MANAGER and (
27
+ not os.getenv("IDUN_AGENT_API_KEY") or not os.getenv("IDUN_MANAGER_HOST")
28
+ ):
29
+ print(
30
+ "[ERROR]: either IDUN_AGENT_API_KEY or IDUN_MANAGER_HOST are not found. Make sure you add them both to your env variables, as `manager` source requires both."
31
+ )
32
+ sys.exit(1)
33
+
34
+ if self._source == ServerSource.MANAGER:
35
+ self._url: str = os.environ["IDUN_MANAGER_HOST"]
36
+ self._agent_api_key: str = os.environ["IDUN_AGENT_API_KEY"]
37
+
38
+ self._config: EngineConfig | None = self._resolve_source()
39
+
40
+ def _resolve_source(self):
41
+ """Returns the EngineConfig based on the type of the source."""
42
+ if self._source == ServerSource.MANAGER:
43
+ print("Getting the config for the manager...")
44
+ return self._fetch_from_manager()
45
+ elif self._source == ServerSource.FILE:
46
+ print(f"Building config from: {self._path}")
47
+ return self._fetch_from_path()
48
+
49
+ def _fetch_from_path(self) -> EngineConfig | None:
50
+ try:
51
+ config = ConfigBuilder().load_from_file(self._path)
52
+ print(f"Successfully fetched and built config from {self._path}")
53
+ return config
54
+
55
+ except Exception as e:
56
+ print(f"[ERROR]: Cannot fetch config from {self._path}: {e} ")
57
+ sys.exit(1)
58
+
59
+ def _fetch_from_manager(self) -> EngineConfig | None:
60
+ """Fetches the config from the api."""
61
+ try:
62
+ config = (
63
+ ConfigBuilder()
64
+ .with_config_from_api(agent_api_key=self._agent_api_key, url=self._url)
65
+ .build()
66
+ )
67
+ print(f"Successfully fetched and built config from {self._url}")
68
+ return config
69
+ except Exception as e:
70
+ print(f"[ERROR]: Cannot fetch config from {self._url}: {e} ")
71
+ sys.exit(1)
72
+
73
+ def serve(self) -> None:
74
+ """Run the server using the idun engine."""
75
+ try:
76
+ app = create_app(engine_config=self._config)
77
+ run_server(app, port=self._config.server.api.port, reload=False) # pyright: ignore
78
+ except Exception as e:
79
+ raise ValueError(f"[ERROR]: Cannot start the agent server: {e}") from e
80
+
81
+
82
+ @click.command("serve")
83
+ @click.option("--source", required=True)
84
+ @click.option("--path")
85
+ def serve_command(source: str, path: str | None):
86
+ """Reads a config and exposes it's agent as an API. Config is either fetched from the manager, or from a path.
87
+
88
+ Note: Fetching from the manager requires env vars: IDUN_AGENT_API_KEY and IDUN_MANAGER_HOST.
89
+ """
90
+ match source:
91
+ case ServerSource.MANAGER:
92
+ s = Serve(source=source)
93
+ s.serve()
94
+
95
+ case ServerSource.FILE:
96
+ if not path:
97
+ print(
98
+ "[ERROR]: No config path provided. You need to specify the path of your config.yaml"
99
+ )
100
+ sys.exit(1)
101
+ s = Serve(source=source, path=path)
102
+ s.serve()
103
+ case _:
104
+ print(f"[ERROR]: Argument {source} not recognized.")
@@ -0,0 +1,14 @@
1
+ import click
2
+ from idun_platform_cli.groups.agent.main import agent
3
+
4
+
5
+ @click.group()
6
+ def cli():
7
+ """Entrypoint of the CLI."""
8
+ pass
9
+
10
+
11
+ cli.add_command(agent)
12
+
13
+ if __name__ == "__main__":
14
+ cli()