relai 0.3.2__tar.gz → 0.3.4__tar.gz

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.

Potentially problematic release.


This version of relai might be problematic. Click here for more details.

Files changed (34) hide show
  1. {relai-0.3.2/relai.egg-info → relai-0.3.4}/PKG-INFO +194 -8
  2. relai-0.3.4/README.md +224 -0
  3. {relai-0.3.2 → relai-0.3.4}/pyproject.toml +5 -3
  4. {relai-0.3.2 → relai-0.3.4}/relai/logger.py +5 -2
  5. {relai-0.3.2 → relai-0.3.4}/relai/maestro/optimizer.py +127 -87
  6. {relai-0.3.2 → relai-0.3.4}/relai/mocker/persona.py +6 -2
  7. {relai-0.3.2 → relai-0.3.4}/relai/mocker/tool.py +13 -12
  8. {relai-0.3.2 → relai-0.3.4}/relai/simulator.py +16 -8
  9. {relai-0.3.2 → relai-0.3.4}/relai/utils.py +37 -0
  10. {relai-0.3.2 → relai-0.3.4/relai.egg-info}/PKG-INFO +194 -8
  11. relai-0.3.2/README.md +0 -38
  12. {relai-0.3.2 → relai-0.3.4}/LICENSE.md +0 -0
  13. {relai-0.3.2 → relai-0.3.4}/relai/__init__.py +0 -0
  14. {relai-0.3.2 → relai-0.3.4}/relai/_client.py +0 -0
  15. {relai-0.3.2 → relai-0.3.4}/relai/_exceptions.py +0 -0
  16. {relai-0.3.2 → relai-0.3.4}/relai/benchmark.py +0 -0
  17. {relai-0.3.2 → relai-0.3.4}/relai/critico/__init__.py +0 -0
  18. {relai-0.3.2 → relai-0.3.4}/relai/critico/critico.py +0 -0
  19. {relai-0.3.2 → relai-0.3.4}/relai/critico/evaluate.py +0 -0
  20. {relai-0.3.2 → relai-0.3.4}/relai/data.py +0 -0
  21. {relai-0.3.2 → relai-0.3.4}/relai/exporter.py +0 -0
  22. {relai-0.3.2 → relai-0.3.4}/relai/flags.py +0 -0
  23. {relai-0.3.2 → relai-0.3.4}/relai/maestro/__init__.py +0 -0
  24. {relai-0.3.2 → relai-0.3.4}/relai/maestro/graph.py +0 -0
  25. {relai-0.3.2 → relai-0.3.4}/relai/maestro/params.py +0 -0
  26. {relai-0.3.2 → relai-0.3.4}/relai/maestro/utils.py +0 -0
  27. {relai-0.3.2 → relai-0.3.4}/relai/mocker/__init__.py +0 -0
  28. {relai-0.3.2 → relai-0.3.4}/relai/mocker/base_mocker.py +0 -0
  29. {relai-0.3.2 → relai-0.3.4}/relai/schema/visual.py +0 -0
  30. {relai-0.3.2 → relai-0.3.4}/relai.egg-info/SOURCES.txt +0 -0
  31. {relai-0.3.2 → relai-0.3.4}/relai.egg-info/dependency_links.txt +0 -0
  32. {relai-0.3.2 → relai-0.3.4}/relai.egg-info/requires.txt +0 -0
  33. {relai-0.3.2 → relai-0.3.4}/relai.egg-info/top_level.txt +0 -0
  34. {relai-0.3.2 → relai-0.3.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: relai
3
- Version: 0.3.2
3
+ Version: 0.3.4
4
4
  Summary: An SDK for building reliable AI agents
5
5
  Author-email: RELAI <priyatham@relai.ai>, RELAI <wwx@relai.ai>
6
6
  License: Apache License
@@ -205,12 +205,12 @@ License: Apache License
205
205
  See the License for the specific language governing permissions and
206
206
  limitations under the License.
207
207
  Classifier: License :: OSI Approved :: Apache Software License
208
- Classifier: Programming Language :: Python :: 3.9
208
+ Classifier: Development Status :: 4 - Beta
209
209
  Classifier: Programming Language :: Python :: 3.10
210
210
  Classifier: Programming Language :: Python :: 3.11
211
211
  Classifier: Programming Language :: Python :: 3.12
212
212
  Classifier: Programming Language :: Python :: 3.13
213
- Requires-Python: >=3.9
213
+ Requires-Python: >=3.10
214
214
  Description-Content-Type: text/markdown
215
215
  License-File: LICENSE.md
216
216
  Requires-Dist: pydantic>=2.11.5
@@ -226,14 +226,22 @@ Dynamic: license-file
226
226
  <img align="center" src="docs/assets/relai-logo.png" width="460px" />
227
227
  </p>
228
228
  <p align="left">
229
- <h1 align="center">RELAI: Simulate → Evaluate → Optimize AI Agents</h1>
229
+ <h1 align="center">Simulate → Evaluate → Optimize AI Agents</h1>
230
+ <p align="center">
231
+ <a href="https://pypi.org/project/relai/"><img alt="PyPI" src="https://img.shields.io/pypi/v/relai.svg"></a>
232
+ <img alt="Python" src="https://img.shields.io/pypi/pyversions/relai.svg">
233
+ <a href="LICENSE.md"><img alt="License" src="https://img.shields.io/badge/license-Apache--2.0-blue.svg"></a>
234
+ <a href="http://docs.relai.ai"><img alt="Docs" src="https://img.shields.io/badge/docs-online-brightgreen.svg"></a>
235
+ <a href="https://github.com/relai-ai/relai-sdk/actions/workflows/upload-to-package-index.yml"><img alt="CI" src="https://img.shields.io/github/actions/workflow/status/relai-ai/relai-sdk/upload-to-package-index.yml?branch=main"></a>
236
+ </p>
237
+
230
238
 
231
239
  **RELAI** is an SDK for building **reliable AI agents**. It streamlines the hardest parts of agent development—**simulation**, **evaluation**, and **optimization**—so you can iterate quickly with confidence.
232
240
 
233
241
  **What you get**
234
- - **Agent Simulation** — Create full/partial environments, define **LLM personas**, mock **MCP** servers & tools, and generate **synthetic data**. Optionally **condition simulation on real samples** to better match production.
235
- - **Agent Evaluation** — Mix **code-based** and **LLM-based** custom evaluators or use **RELAI platform evaluators**. Turn human reviews into **benchmarks** you can re-run.
236
- - **Agent Optimization (Maestro)** — Holistic optimizer that uses evaluator signals & feedback to improve prompts/configs **and** suggest **graph-level** changes. Also selects **best model/tool/graph** based on observed performance.
242
+ - **Agent Simulation** — Create full/partial environments, define LLM personas, mock MCP servers & tools, and generate synthetic data. Optionally condition simulation on real samples to better match production.
243
+ - **Agent Evaluation** — Mix code-based and LLM-based custom evaluators or use RELAI platform evaluators. Turn human reviews into benchmarks you can re-run.
244
+ - **Agent Optimization (Maestro)** — Holistic optimizer that uses evaluator signals & feedback to improve **prompts/configs** and suggest **graph-level** changes. Maestro selects best model/tool/graph based on observed performance.
237
245
 
238
246
  ## Quickstart
239
247
 
@@ -249,10 +257,161 @@ uv add relai
249
257
  export RELAI_API_KEY="<RELAI_API_KEY>"
250
258
  ```
251
259
 
260
+ ### Example: A simple Stock Assistant Agent (Simulate → Evaluate → Optimize)
261
+ Prerequisites: Needs an OpenAI API key and `openai-agents` installed to run the base agent.
262
+ To use Maestro graph optimizer, save the following in a file called `stock-assistant.py` (or change the `code_paths` argument to `maestro.optimize_structure`).
263
+ ```python
264
+ # ============================================================================
265
+ # STEP 0 — Prerequisites
266
+ # ============================================================================
267
+ # export OPENAI_API_KEY="sk-..."
268
+ # `uv add openai-agents`
269
+ # export RELAI_API_KEY="relai-..."
270
+ # Save as `stock-assistant.py`
271
+
272
+ import asyncio
273
+
274
+ from agents import Agent, Runner
275
+
276
+ from relai import (
277
+ AgentOutputs,
278
+ AsyncRELAI,
279
+ AsyncSimulator,
280
+ SimulationTape,
281
+ random_env_generator,
282
+ )
283
+ from relai.critico import Critico
284
+ from relai.critico.evaluate import RELAIFormatEvaluator
285
+ from relai.maestro import Maestro, params, register_param
286
+ from relai.mocker import Persona
287
+ from relai.simulator import simulated
288
+
289
+ # ============================================================================
290
+ # STEP 1.1 — Decorate inputs/tools that will be simulated
291
+ # ============================================================================
292
+
293
+
294
+ @simulated
295
+ async def get_user_query() -> str:
296
+ """Get user's query about stock prices."""
297
+ # In a real agent, this function might get input from a chat interface.
298
+ return input("Enter you stock query: ")
299
+
300
+
301
+ # ============================================================================
302
+ # STEP 1.2 — Register parameters for optimization
303
+ # ============================================================================
304
+
305
+ register_param(
306
+ "prompt",
307
+ type="prompt",
308
+ init_value="You are a helpful assistant for stock price questions.",
309
+ desc="system prompt for the agent",
310
+ )
311
+
312
+ # ============================================================================
313
+ # STEP 2 — Your agent core
314
+ # ============================================================================
315
+
316
+
317
+ async def agent_fn(tape: SimulationTape) -> AgentOutputs:
318
+ # It is good practice to catch exceptions in agent function
319
+ # especially if the agent might raise errors with different configs
320
+ try:
321
+ question = await get_user_query()
322
+ agent = Agent(
323
+ name="Stock assistant",
324
+ instructions=params.prompt, # access registered parameter
325
+ model="gpt-5-mini",
326
+ )
327
+ result = await Runner.run(agent, question)
328
+ tape.extras["format_rubrics"] = {"Prices must include cents (eg: $XXX.XX)": 1.0}
329
+ tape.agent_inputs["question"] = question # trace inputs for later auditing
330
+ return {"summary": result.final_output}
331
+ except Exception as e:
332
+ return {"summary": str(e)}
333
+
334
+
335
+
336
+ async def main() -> None:
337
+ # Set up your simulation environment
338
+ # Bind Personas/MockTools to fully-qualified function names
339
+ env_generator = random_env_generator(
340
+ config_set={
341
+ "__main__.get_user_query": [Persona(user_persona="A polite and curious user.")],
342
+ }
343
+ )
344
+
345
+ async with AsyncRELAI() as client:
346
+ # ============================================================================
347
+ # STEP 3 — Simulate
348
+ # ============================================================================
349
+ simulator = AsyncSimulator(agent_fn=agent_fn, env_generator=env_generator, client=client)
350
+ agent_logs = await simulator.run(num_runs=1)
351
+
352
+ # ============================================================================
353
+ # STEP 4 — Evaluate with Critico
354
+ # ============================================================================
355
+ critico = Critico(client=client)
356
+ format_evaluator = RELAIFormatEvaluator(client=client)
357
+ critico.add_evaluators({format_evaluator: 1.0})
358
+ critico_logs = await critico.evaluate(agent_logs)
359
+
360
+ # Publish evaluation report to the RELAI platform
361
+ await critico.report(critico_logs)
362
+
363
+ maestro = Maestro(client=client, agent_fn=agent_fn, log_to_platform=True, name="Stock assistant")
364
+ maestro.add_setup(simulator=simulator, critico=critico)
365
+
366
+ # ============================================================================
367
+ # STEP 5.1 — Optimize configs with Maestro (the parameters registered earlier in STEP 2)
368
+ # ============================================================================
369
+
370
+ # params.load("saved_config.json") # load previous params if available
371
+ await maestro.optimize_config(
372
+ total_rollouts=20, # Total number of rollouts to use for optimization.
373
+ batch_size=2, # Base batch size to use for individual optimization steps. Defaults to 4.
374
+ explore_radius=1, # A positive integer controlling the aggressiveness of exploration during optimization.
375
+ explore_factor=0.5, # A float between 0 to 1 controlling the exploration-exploitation trade-off.
376
+ verbose=False, # If True, additional information will be printed during the optimization step.
377
+ )
378
+ params.save("saved_config.json") # save optimized params for future usage
379
+
380
+ # ============================================================================
381
+ # STEP 5.2 — Optimize agent structure with Maestro (changes that cannot be achieved by setting parameters alone)
382
+ # ============================================================================
383
+
384
+ await maestro.optimize_structure(
385
+ total_rollouts=10, # Total number of rollouts to use for optimization.
386
+ code_paths=["stock-assistant.py"], # A list of paths corresponding to code implementations of the agent.
387
+ verbose=False, # If True, additional information will be printed during the optimization step.
388
+ )
389
+
390
+
391
+ if __name__ == "__main__":
392
+ asyncio.run(main())
393
+
394
+ ```
395
+ ## Simulation
396
+ Create controlled environments where agents interact and generate traces. Compose LLM personas, mock MCP tools/servers, and synthetic data; optionally condition on real events to align simulation ⇄ production.
397
+
398
+ ➡️ Learn more: [Simulator](https://docs.relai.ai/simulator.html)
399
+
400
+ ## Evaluation (Critico)
401
+ Use code-based or LLM-based evaluators—or RELAI platform evaluators—and convert human reviews into benchmarks you can re-run in Simuation/CI pipeline.
402
+
403
+ ➡️ Learn more: [Evaluator](https://docs.relai.ai/evaluator.html)
404
+
405
+ ## Optimization (Maestro)
406
+ Maestro is a holistic agent optimizer. It consumes evaluator/user feedback to improve prompts, configs, and even graph structure when prompt tuning isn’t enough. It can also select the best model, best tool, and best graph based on observed performance.
407
+
408
+ ➡️ Learn more: [Maestro](https://docs.relai.ai/maestro.html)
409
+
252
410
  ## Links
253
411
 
254
- - 📘 **Documentation:** [docs.relai.ai](#)
412
+ - 📘 **Documentation:** [docs.relai.ai](http://docs.relai.ai)
255
413
  - 🧪 **Examples:** [relai-sdk/examples](examples)
414
+ - 📖 **Tutorials:** [docs.relai.ai/tutorials/index.html](https://docs.relai.ai/tutorials/index.html)
256
415
  - 🌐 **Website:** [relai.ai](https://relai.ai)
257
416
  - 📰 **Maestro Technical Report:** [ArXiV](https://arxiv.org/abs/2509.04642)
258
417
  - 🌐 **Join the Community:** [Discord](https://discord.gg/sjaHJ34YYE)
@@ -260,3 +419,30 @@ export RELAI_API_KEY="<RELAI_API_KEY>"
260
419
  ## License
261
420
 
262
421
  Apache 2.0
422
+
423
+ ## Citation
424
+ If you use the SDK in your research, please consider citing our work:
425
+
426
+ ```
427
+ @misc{relai_sdk,
428
+ author = {RELAI, Inc.,},
429
+ title = {relai-sdk},
430
+ year = {2025},
431
+ howpublished = {\url{https://github.com/relai-ai/relai-sdk}},
432
+ note = {GitHub repository},
433
+ urldate = {2025-10-20}
434
+ }
435
+
436
+ @misc{wang2025maestrojointgraph,
437
+ title={Maestro: Joint Graph & Config Optimization for Reliable AI Agents},
438
+ author={Wenxiao Wang and Priyatham Kattakinda and Soheil Feizi},
439
+ year={2025},
440
+ eprint={2509.04642},
441
+ archivePrefix={arXiv},
442
+ primaryClass={cs.AI},
443
+ url={https://arxiv.org/abs/2509.04642},
444
+ }
445
+ ```
446
+
447
+ <p align="center"> <sub>Made with ❤️ by the RELAI team — <a href="https://relai.ai">relai.ai</a> • <a href="https://discord.gg/sjaHJ34YYE">Community</a></sub> </p>
448
+
relai-0.3.4/README.md ADDED
@@ -0,0 +1,224 @@
1
+ <p align="center">
2
+ <img align="center" src="docs/assets/relai-logo.png" width="460px" />
3
+ </p>
4
+ <p align="left">
5
+ <h1 align="center">Simulate → Evaluate → Optimize AI Agents</h1>
6
+ <p align="center">
7
+ <a href="https://pypi.org/project/relai/"><img alt="PyPI" src="https://img.shields.io/pypi/v/relai.svg"></a>
8
+ <img alt="Python" src="https://img.shields.io/pypi/pyversions/relai.svg">
9
+ <a href="LICENSE.md"><img alt="License" src="https://img.shields.io/badge/license-Apache--2.0-blue.svg"></a>
10
+ <a href="http://docs.relai.ai"><img alt="Docs" src="https://img.shields.io/badge/docs-online-brightgreen.svg"></a>
11
+ <a href="https://github.com/relai-ai/relai-sdk/actions/workflows/upload-to-package-index.yml"><img alt="CI" src="https://img.shields.io/github/actions/workflow/status/relai-ai/relai-sdk/upload-to-package-index.yml?branch=main"></a>
12
+ </p>
13
+
14
+
15
+ **RELAI** is an SDK for building **reliable AI agents**. It streamlines the hardest parts of agent development—**simulation**, **evaluation**, and **optimization**—so you can iterate quickly with confidence.
16
+
17
+ **What you get**
18
+ - **Agent Simulation** — Create full/partial environments, define LLM personas, mock MCP servers & tools, and generate synthetic data. Optionally condition simulation on real samples to better match production.
19
+ - **Agent Evaluation** — Mix code-based and LLM-based custom evaluators or use RELAI platform evaluators. Turn human reviews into benchmarks you can re-run.
20
+ - **Agent Optimization (Maestro)** — Holistic optimizer that uses evaluator signals & feedback to improve **prompts/configs** and suggest **graph-level** changes. Maestro selects best model/tool/graph based on observed performance.
21
+
22
+ ## Quickstart
23
+
24
+ Create a free account and get a RELAI API key: [platform.relai.ai/settings/access/api-keys](https://platform.relai.ai/settings/access/api-keys)
25
+
26
+ ### Installation and Setup
27
+
28
+ ```bash
29
+ pip install relai
30
+ # or
31
+ uv add relai
32
+
33
+ export RELAI_API_KEY="<RELAI_API_KEY>"
34
+ ```
35
+
36
+ ### Example: A simple Stock Assistant Agent (Simulate → Evaluate → Optimize)
37
+ Prerequisites: Needs an OpenAI API key and `openai-agents` installed to run the base agent.
38
+ To use Maestro graph optimizer, save the following in a file called `stock-assistant.py` (or change the `code_paths` argument to `maestro.optimize_structure`).
39
+ ```python
40
+ # ============================================================================
41
+ # STEP 0 — Prerequisites
42
+ # ============================================================================
43
+ # export OPENAI_API_KEY="sk-..."
44
+ # `uv add openai-agents`
45
+ # export RELAI_API_KEY="relai-..."
46
+ # Save as `stock-assistant.py`
47
+
48
+ import asyncio
49
+
50
+ from agents import Agent, Runner
51
+
52
+ from relai import (
53
+ AgentOutputs,
54
+ AsyncRELAI,
55
+ AsyncSimulator,
56
+ SimulationTape,
57
+ random_env_generator,
58
+ )
59
+ from relai.critico import Critico
60
+ from relai.critico.evaluate import RELAIFormatEvaluator
61
+ from relai.maestro import Maestro, params, register_param
62
+ from relai.mocker import Persona
63
+ from relai.simulator import simulated
64
+
65
+ # ============================================================================
66
+ # STEP 1.1 — Decorate inputs/tools that will be simulated
67
+ # ============================================================================
68
+
69
+
70
+ @simulated
71
+ async def get_user_query() -> str:
72
+ """Get user's query about stock prices."""
73
+ # In a real agent, this function might get input from a chat interface.
74
+ return input("Enter you stock query: ")
75
+
76
+
77
+ # ============================================================================
78
+ # STEP 1.2 — Register parameters for optimization
79
+ # ============================================================================
80
+
81
+ register_param(
82
+ "prompt",
83
+ type="prompt",
84
+ init_value="You are a helpful assistant for stock price questions.",
85
+ desc="system prompt for the agent",
86
+ )
87
+
88
+ # ============================================================================
89
+ # STEP 2 — Your agent core
90
+ # ============================================================================
91
+
92
+
93
+ async def agent_fn(tape: SimulationTape) -> AgentOutputs:
94
+ # It is good practice to catch exceptions in agent function
95
+ # especially if the agent might raise errors with different configs
96
+ try:
97
+ question = await get_user_query()
98
+ agent = Agent(
99
+ name="Stock assistant",
100
+ instructions=params.prompt, # access registered parameter
101
+ model="gpt-5-mini",
102
+ )
103
+ result = await Runner.run(agent, question)
104
+ tape.extras["format_rubrics"] = {"Prices must include cents (eg: $XXX.XX)": 1.0}
105
+ tape.agent_inputs["question"] = question # trace inputs for later auditing
106
+ return {"summary": result.final_output}
107
+ except Exception as e:
108
+ return {"summary": str(e)}
109
+
110
+
111
+
112
+ async def main() -> None:
113
+ # Set up your simulation environment
114
+ # Bind Personas/MockTools to fully-qualified function names
115
+ env_generator = random_env_generator(
116
+ config_set={
117
+ "__main__.get_user_query": [Persona(user_persona="A polite and curious user.")],
118
+ }
119
+ )
120
+
121
+ async with AsyncRELAI() as client:
122
+ # ============================================================================
123
+ # STEP 3 — Simulate
124
+ # ============================================================================
125
+ simulator = AsyncSimulator(agent_fn=agent_fn, env_generator=env_generator, client=client)
126
+ agent_logs = await simulator.run(num_runs=1)
127
+
128
+ # ============================================================================
129
+ # STEP 4 — Evaluate with Critico
130
+ # ============================================================================
131
+ critico = Critico(client=client)
132
+ format_evaluator = RELAIFormatEvaluator(client=client)
133
+ critico.add_evaluators({format_evaluator: 1.0})
134
+ critico_logs = await critico.evaluate(agent_logs)
135
+
136
+ # Publish evaluation report to the RELAI platform
137
+ await critico.report(critico_logs)
138
+
139
+ maestro = Maestro(client=client, agent_fn=agent_fn, log_to_platform=True, name="Stock assistant")
140
+ maestro.add_setup(simulator=simulator, critico=critico)
141
+
142
+ # ============================================================================
143
+ # STEP 5.1 — Optimize configs with Maestro (the parameters registered earlier in STEP 2)
144
+ # ============================================================================
145
+
146
+ # params.load("saved_config.json") # load previous params if available
147
+ await maestro.optimize_config(
148
+ total_rollouts=20, # Total number of rollouts to use for optimization.
149
+ batch_size=2, # Base batch size to use for individual optimization steps. Defaults to 4.
150
+ explore_radius=1, # A positive integer controlling the aggressiveness of exploration during optimization.
151
+ explore_factor=0.5, # A float between 0 to 1 controlling the exploration-exploitation trade-off.
152
+ verbose=False, # If True, additional information will be printed during the optimization step.
153
+ )
154
+ params.save("saved_config.json") # save optimized params for future usage
155
+
156
+ # ============================================================================
157
+ # STEP 5.2 — Optimize agent structure with Maestro (changes that cannot be achieved by setting parameters alone)
158
+ # ============================================================================
159
+
160
+ await maestro.optimize_structure(
161
+ total_rollouts=10, # Total number of rollouts to use for optimization.
162
+ code_paths=["stock-assistant.py"], # A list of paths corresponding to code implementations of the agent.
163
+ verbose=False, # If True, additional information will be printed during the optimization step.
164
+ )
165
+
166
+
167
+ if __name__ == "__main__":
168
+ asyncio.run(main())
169
+
170
+ ```
171
+ ## Simulation
172
+ Create controlled environments where agents interact and generate traces. Compose LLM personas, mock MCP tools/servers, and synthetic data; optionally condition on real events to align simulation ⇄ production.
173
+
174
+ ➡️ Learn more: [Simulator](https://docs.relai.ai/simulator.html)
175
+
176
+ ## Evaluation (Critico)
177
+ Use code-based or LLM-based evaluators—or RELAI platform evaluators—and convert human reviews into benchmarks you can re-run in Simuation/CI pipeline.
178
+
179
+ ➡️ Learn more: [Evaluator](https://docs.relai.ai/evaluator.html)
180
+
181
+ ## Optimization (Maestro)
182
+ Maestro is a holistic agent optimizer. It consumes evaluator/user feedback to improve prompts, configs, and even graph structure when prompt tuning isn’t enough. It can also select the best model, best tool, and best graph based on observed performance.
183
+
184
+ ➡️ Learn more: [Maestro](https://docs.relai.ai/maestro.html)
185
+
186
+ ## Links
187
+
188
+ - 📘 **Documentation:** [docs.relai.ai](http://docs.relai.ai)
189
+ - 🧪 **Examples:** [relai-sdk/examples](examples)
190
+ - 📖 **Tutorials:** [docs.relai.ai/tutorials/index.html](https://docs.relai.ai/tutorials/index.html)
191
+ - 🌐 **Website:** [relai.ai](https://relai.ai)
192
+ - 📰 **Maestro Technical Report:** [ArXiV](https://arxiv.org/abs/2509.04642)
193
+ - 🌐 **Join the Community:** [Discord](https://discord.gg/sjaHJ34YYE)
194
+
195
+ ## License
196
+
197
+ Apache 2.0
198
+
199
+ ## Citation
200
+ If you use the SDK in your research, please consider citing our work:
201
+
202
+ ```
203
+ @misc{relai_sdk,
204
+ author = {RELAI, Inc.,},
205
+ title = {relai-sdk},
206
+ year = {2025},
207
+ howpublished = {\url{https://github.com/relai-ai/relai-sdk}},
208
+ note = {GitHub repository},
209
+ urldate = {2025-10-20}
210
+ }
211
+
212
+ @misc{wang2025maestrojointgraph,
213
+ title={Maestro: Joint Graph & Config Optimization for Reliable AI Agents},
214
+ author={Wenxiao Wang and Priyatham Kattakinda and Soheil Feizi},
215
+ year={2025},
216
+ eprint={2509.04642},
217
+ archivePrefix={arXiv},
218
+ primaryClass={cs.AI},
219
+ url={https://arxiv.org/abs/2509.04642},
220
+ }
221
+ ```
222
+
223
+ <p align="center"> <sub>Made with ❤️ by the RELAI team — <a href="https://relai.ai">relai.ai</a> • <a href="https://discord.gg/sjaHJ34YYE">Community</a></sub> </p>
224
+
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "relai"
7
- requires-python = ">=3.9"
7
+ requires-python = ">=3.10"
8
8
  authors = [
9
9
  {name = "RELAI", email = "priyatham@relai.ai"},
10
10
  {name = "RELAI", email = "wwx@relai.ai"},
@@ -14,7 +14,7 @@ readme = "README.md"
14
14
  license = {file = "LICENSE.md" }
15
15
  classifiers = [
16
16
  "License :: OSI Approved :: Apache Software License",
17
- "Programming Language :: Python :: 3.9",
17
+ "Development Status :: 4 - Beta",
18
18
  "Programming Language :: Python :: 3.10",
19
19
  "Programming Language :: Python :: 3.11",
20
20
  "Programming Language :: Python :: 3.12",
@@ -30,7 +30,7 @@ dependencies = [
30
30
  "opentelemetry-instrumentation>=0.58b0",
31
31
  "openinference-instrumentation>=0.1.38",
32
32
  ]
33
- version = "0.3.2"
33
+ version = "0.3.4"
34
34
 
35
35
  [tool.setuptools.packages.find]
36
36
  where = ["."]
@@ -40,6 +40,8 @@ include = ["relai*"]
40
40
  dev = [
41
41
  "build>=1.3.0",
42
42
  "google-genai>=1.45.0",
43
+ "langchain>=1.0.1",
44
+ "langgraph>=1.0.1",
43
45
  "mkdocs>=1.6.1",
44
46
  "mkdocs-material>=9.6.14",
45
47
  "mkdocstrings[python]>=0.29.1",
@@ -31,8 +31,11 @@ def flatten(mapping: Mapping[str, Any]) -> Iterator[tuple[str, AttributeValue]]:
31
31
  yield f"{key}.{sub_key}", sub_value
32
32
  elif isinstance(value, list) and any(isinstance(item, Mapping) for item in value):
33
33
  for index, sub_mapping in enumerate(value):
34
- for sub_key, sub_value in flatten(sub_mapping):
35
- yield f"{key}.{index}.{sub_key}", sub_value
34
+ if isinstance(sub_mapping, Mapping):
35
+ for sub_key, sub_value in flatten(sub_mapping):
36
+ yield f"{key}.{index}.{sub_key}", sub_value
37
+ else:
38
+ yield f"{key}.{index}", sub_mapping
36
39
  else:
37
40
  if isinstance(value, Enum):
38
41
  value = value.value