relai 0.3.3__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.
- {relai-0.3.3/relai.egg-info → relai-0.3.4}/PKG-INFO +22 -14
- {relai-0.3.3 → relai-0.3.4}/README.md +20 -13
- {relai-0.3.3 → relai-0.3.4}/pyproject.toml +2 -1
- {relai-0.3.3 → relai-0.3.4}/relai/maestro/optimizer.py +40 -30
- {relai-0.3.3 → relai-0.3.4}/relai/mocker/tool.py +13 -12
- {relai-0.3.3 → relai-0.3.4}/relai/simulator.py +4 -4
- {relai-0.3.3 → relai-0.3.4/relai.egg-info}/PKG-INFO +22 -14
- {relai-0.3.3 → relai-0.3.4}/LICENSE.md +0 -0
- {relai-0.3.3 → relai-0.3.4}/relai/__init__.py +0 -0
- {relai-0.3.3 → relai-0.3.4}/relai/_client.py +0 -0
- {relai-0.3.3 → relai-0.3.4}/relai/_exceptions.py +0 -0
- {relai-0.3.3 → relai-0.3.4}/relai/benchmark.py +0 -0
- {relai-0.3.3 → relai-0.3.4}/relai/critico/__init__.py +0 -0
- {relai-0.3.3 → relai-0.3.4}/relai/critico/critico.py +0 -0
- {relai-0.3.3 → relai-0.3.4}/relai/critico/evaluate.py +0 -0
- {relai-0.3.3 → relai-0.3.4}/relai/data.py +0 -0
- {relai-0.3.3 → relai-0.3.4}/relai/exporter.py +0 -0
- {relai-0.3.3 → relai-0.3.4}/relai/flags.py +0 -0
- {relai-0.3.3 → relai-0.3.4}/relai/logger.py +0 -0
- {relai-0.3.3 → relai-0.3.4}/relai/maestro/__init__.py +0 -0
- {relai-0.3.3 → relai-0.3.4}/relai/maestro/graph.py +0 -0
- {relai-0.3.3 → relai-0.3.4}/relai/maestro/params.py +0 -0
- {relai-0.3.3 → relai-0.3.4}/relai/maestro/utils.py +0 -0
- {relai-0.3.3 → relai-0.3.4}/relai/mocker/__init__.py +0 -0
- {relai-0.3.3 → relai-0.3.4}/relai/mocker/base_mocker.py +0 -0
- {relai-0.3.3 → relai-0.3.4}/relai/mocker/persona.py +0 -0
- {relai-0.3.3 → relai-0.3.4}/relai/schema/visual.py +0 -0
- {relai-0.3.3 → relai-0.3.4}/relai/utils.py +0 -0
- {relai-0.3.3 → relai-0.3.4}/relai.egg-info/SOURCES.txt +0 -0
- {relai-0.3.3 → relai-0.3.4}/relai.egg-info/dependency_links.txt +0 -0
- {relai-0.3.3 → relai-0.3.4}/relai.egg-info/requires.txt +0 -0
- {relai-0.3.3 → relai-0.3.4}/relai.egg-info/top_level.txt +0 -0
- {relai-0.3.3 → 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.
|
|
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,6 +205,7 @@ 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: Development Status :: 4 - Beta
|
|
208
209
|
Classifier: Programming Language :: Python :: 3.10
|
|
209
210
|
Classifier: Programming Language :: Python :: 3.11
|
|
210
211
|
Classifier: Programming Language :: Python :: 3.12
|
|
@@ -314,16 +315,22 @@ register_param(
|
|
|
314
315
|
|
|
315
316
|
|
|
316
317
|
async def agent_fn(tape: SimulationTape) -> AgentOutputs:
|
|
317
|
-
|
|
318
|
-
agent
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
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
|
+
|
|
327
334
|
|
|
328
335
|
|
|
329
336
|
async def main() -> None:
|
|
@@ -363,10 +370,10 @@ async def main() -> None:
|
|
|
363
370
|
# params.load("saved_config.json") # load previous params if available
|
|
364
371
|
await maestro.optimize_config(
|
|
365
372
|
total_rollouts=20, # Total number of rollouts to use for optimization.
|
|
366
|
-
batch_size=
|
|
373
|
+
batch_size=2, # Base batch size to use for individual optimization steps. Defaults to 4.
|
|
367
374
|
explore_radius=1, # A positive integer controlling the aggressiveness of exploration during optimization.
|
|
368
375
|
explore_factor=0.5, # A float between 0 to 1 controlling the exploration-exploitation trade-off.
|
|
369
|
-
verbose=
|
|
376
|
+
verbose=False, # If True, additional information will be printed during the optimization step.
|
|
370
377
|
)
|
|
371
378
|
params.save("saved_config.json") # save optimized params for future usage
|
|
372
379
|
|
|
@@ -377,7 +384,7 @@ async def main() -> None:
|
|
|
377
384
|
await maestro.optimize_structure(
|
|
378
385
|
total_rollouts=10, # Total number of rollouts to use for optimization.
|
|
379
386
|
code_paths=["stock-assistant.py"], # A list of paths corresponding to code implementations of the agent.
|
|
380
|
-
verbose=
|
|
387
|
+
verbose=False, # If True, additional information will be printed during the optimization step.
|
|
381
388
|
)
|
|
382
389
|
|
|
383
390
|
|
|
@@ -404,6 +411,7 @@ Maestro is a holistic agent optimizer. It consumes evaluator/user feedback to im
|
|
|
404
411
|
|
|
405
412
|
- 📘 **Documentation:** [docs.relai.ai](http://docs.relai.ai)
|
|
406
413
|
- 🧪 **Examples:** [relai-sdk/examples](examples)
|
|
414
|
+
- 📖 **Tutorials:** [docs.relai.ai/tutorials/index.html](https://docs.relai.ai/tutorials/index.html)
|
|
407
415
|
- 🌐 **Website:** [relai.ai](https://relai.ai)
|
|
408
416
|
- 📰 **Maestro Technical Report:** [ArXiV](https://arxiv.org/abs/2509.04642)
|
|
409
417
|
- 🌐 **Join the Community:** [Discord](https://discord.gg/sjaHJ34YYE)
|
|
@@ -91,16 +91,22 @@ register_param(
|
|
|
91
91
|
|
|
92
92
|
|
|
93
93
|
async def agent_fn(tape: SimulationTape) -> AgentOutputs:
|
|
94
|
-
|
|
95
|
-
agent
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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
|
+
|
|
104
110
|
|
|
105
111
|
|
|
106
112
|
async def main() -> None:
|
|
@@ -140,10 +146,10 @@ async def main() -> None:
|
|
|
140
146
|
# params.load("saved_config.json") # load previous params if available
|
|
141
147
|
await maestro.optimize_config(
|
|
142
148
|
total_rollouts=20, # Total number of rollouts to use for optimization.
|
|
143
|
-
batch_size=
|
|
149
|
+
batch_size=2, # Base batch size to use for individual optimization steps. Defaults to 4.
|
|
144
150
|
explore_radius=1, # A positive integer controlling the aggressiveness of exploration during optimization.
|
|
145
151
|
explore_factor=0.5, # A float between 0 to 1 controlling the exploration-exploitation trade-off.
|
|
146
|
-
verbose=
|
|
152
|
+
verbose=False, # If True, additional information will be printed during the optimization step.
|
|
147
153
|
)
|
|
148
154
|
params.save("saved_config.json") # save optimized params for future usage
|
|
149
155
|
|
|
@@ -154,7 +160,7 @@ async def main() -> None:
|
|
|
154
160
|
await maestro.optimize_structure(
|
|
155
161
|
total_rollouts=10, # Total number of rollouts to use for optimization.
|
|
156
162
|
code_paths=["stock-assistant.py"], # A list of paths corresponding to code implementations of the agent.
|
|
157
|
-
verbose=
|
|
163
|
+
verbose=False, # If True, additional information will be printed during the optimization step.
|
|
158
164
|
)
|
|
159
165
|
|
|
160
166
|
|
|
@@ -181,6 +187,7 @@ Maestro is a holistic agent optimizer. It consumes evaluator/user feedback to im
|
|
|
181
187
|
|
|
182
188
|
- 📘 **Documentation:** [docs.relai.ai](http://docs.relai.ai)
|
|
183
189
|
- 🧪 **Examples:** [relai-sdk/examples](examples)
|
|
190
|
+
- 📖 **Tutorials:** [docs.relai.ai/tutorials/index.html](https://docs.relai.ai/tutorials/index.html)
|
|
184
191
|
- 🌐 **Website:** [relai.ai](https://relai.ai)
|
|
185
192
|
- 📰 **Maestro Technical Report:** [ArXiV](https://arxiv.org/abs/2509.04642)
|
|
186
193
|
- 🌐 **Join the Community:** [Discord](https://discord.gg/sjaHJ34YYE)
|
|
@@ -14,6 +14,7 @@ readme = "README.md"
|
|
|
14
14
|
license = {file = "LICENSE.md" }
|
|
15
15
|
classifiers = [
|
|
16
16
|
"License :: OSI Approved :: Apache Software License",
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
17
18
|
"Programming Language :: Python :: 3.10",
|
|
18
19
|
"Programming Language :: Python :: 3.11",
|
|
19
20
|
"Programming Language :: Python :: 3.12",
|
|
@@ -29,7 +30,7 @@ dependencies = [
|
|
|
29
30
|
"opentelemetry-instrumentation>=0.58b0",
|
|
30
31
|
"openinference-instrumentation>=0.1.38",
|
|
31
32
|
]
|
|
32
|
-
version = "0.3.
|
|
33
|
+
version = "0.3.4"
|
|
33
34
|
|
|
34
35
|
[tool.setuptools.packages.find]
|
|
35
36
|
where = ["."]
|
|
@@ -134,8 +134,7 @@ class Maestro:
|
|
|
134
134
|
"""
|
|
135
135
|
self.total_visits += 1
|
|
136
136
|
self.versions[self.current_version]["average_score"] = (
|
|
137
|
-
self.versions[self.current_version]["average_score"] * self.versions[self.current_version]["visits"]
|
|
138
|
-
+ score
|
|
137
|
+
self.versions[self.current_version]["average_score"] * self.versions[self.current_version]["visits"] + score
|
|
139
138
|
) / (self.versions[self.current_version]["visits"] + 1.0)
|
|
140
139
|
self.versions[self.current_version]["visits"] += 1
|
|
141
140
|
|
|
@@ -374,7 +373,7 @@ class Maestro:
|
|
|
374
373
|
async def optimize_config(
|
|
375
374
|
self,
|
|
376
375
|
total_rollouts: int,
|
|
377
|
-
batch_size: int =
|
|
376
|
+
batch_size: int = 8,
|
|
378
377
|
explore_radius: int = 5,
|
|
379
378
|
explore_factor: float = 0.5,
|
|
380
379
|
verbose: bool = False,
|
|
@@ -384,7 +383,7 @@ class Maestro:
|
|
|
384
383
|
|
|
385
384
|
Args:
|
|
386
385
|
total_rollouts (int): Total number of rollouts to use for optimization.
|
|
387
|
-
batch_size (int): Base batch size to use for individual optimization steps. Defaults to
|
|
386
|
+
batch_size (int): Base batch size to use for individual optimization steps. Defaults to 8.
|
|
388
387
|
explore_radius (int): A positive integer controlling the aggressiveness of exploration during optimization.
|
|
389
388
|
A larger `explore_radius` encourages the optimizer to make more substantial changes between successive configurations.
|
|
390
389
|
Defaults to 5.
|
|
@@ -407,16 +406,17 @@ class Maestro:
|
|
|
407
406
|
if explore_factor <= 0 or explore_factor >= 1:
|
|
408
407
|
raise ValueError(f"`explore_factor` must be a float between 0 and 1, got {explore_factor}.")
|
|
409
408
|
|
|
410
|
-
|
|
411
|
-
#
|
|
409
|
+
group_size = (batch_size + 1) // 2
|
|
410
|
+
# total_rollouts = (iterate_steps * group_size * 4 + select_steps * group_size) * num_rounds
|
|
411
|
+
# explore_factor = (iterate_steps * group_size * 4) / (iterate_steps * group_size * 4 + select_steps * group_size)
|
|
412
412
|
iterate_steps: int = explore_radius
|
|
413
413
|
select_steps: int = int(explore_radius * 4 * (1 - explore_factor) / explore_factor)
|
|
414
|
-
num_rounds: int = int(total_rollouts / (iterate_steps *
|
|
415
|
-
total_rollouts = num_rounds * (iterate_steps *
|
|
414
|
+
num_rounds: int = int(total_rollouts / (iterate_steps * group_size * 4 + select_steps * group_size))
|
|
415
|
+
total_rollouts = num_rounds * (iterate_steps * group_size * 4 + select_steps * group_size)
|
|
416
416
|
|
|
417
417
|
print("optimize_config settings:")
|
|
418
418
|
print(" total_rollouts: ", total_rollouts)
|
|
419
|
-
print(" batch_size: ",
|
|
419
|
+
print(" (adjusted) batch_size: ", group_size * 2)
|
|
420
420
|
print(" explore_radius: ", explore_radius)
|
|
421
421
|
print(" explore_factor: ", explore_factor)
|
|
422
422
|
print("-" * 60)
|
|
@@ -428,29 +428,33 @@ class Maestro:
|
|
|
428
428
|
if num_rounds == 0:
|
|
429
429
|
raise ValueError(
|
|
430
430
|
f"`total_rollouts` is too small for the given `batch_size` {batch_size}, `explore_radius` {explore_radius}, and `explore_factor` {explore_factor}. "
|
|
431
|
-
f"Please increase `total_rollouts` to at least {iterate_steps *
|
|
431
|
+
f"Please increase `total_rollouts` to at least {iterate_steps * group_size * 4 + select_steps * group_size}."
|
|
432
432
|
)
|
|
433
433
|
|
|
434
434
|
sampler = ProportionalSampler(
|
|
435
435
|
elements=self.setups,
|
|
436
436
|
weights=[setup["weight"] for setup in self.setups],
|
|
437
437
|
)
|
|
438
|
-
group_id = uuid4().hex
|
|
438
|
+
group_id = "Maestro-Config-" + uuid4().hex
|
|
439
439
|
pbar = tqdm(total=total_rollouts, desc="Total rollouts consumed for config optimization")
|
|
440
440
|
|
|
441
441
|
for round in range(num_rounds):
|
|
442
|
-
print("=" * 30 + f" Round {round + 1}/{num_rounds} begins" + "=" * 30)
|
|
443
|
-
print("Total versions: ", len(self.versions))
|
|
442
|
+
print("\n\n" + "=" * 30 + f" Round {round + 1}/{num_rounds} begins" + "=" * 30)
|
|
443
|
+
print("Total versions accepted: ", len(self.versions))
|
|
444
444
|
print("Rebase to version: ", self.current_version)
|
|
445
|
-
print(
|
|
446
|
-
|
|
447
|
-
|
|
445
|
+
print(
|
|
446
|
+
"Score for the current base version: %s based on %s rollouts"
|
|
447
|
+
% (
|
|
448
|
+
self.versions[self.current_version]["average_score"],
|
|
449
|
+
self.versions[self.current_version]["visits"] * group_size,
|
|
450
|
+
)
|
|
451
|
+
)
|
|
448
452
|
print("\n\n")
|
|
449
453
|
|
|
450
454
|
new_version = False
|
|
451
455
|
for _ in range(iterate_steps):
|
|
452
456
|
changes_accepted = await self._iterate(
|
|
453
|
-
batch_size=
|
|
457
|
+
batch_size=group_size, verbose=verbose, sampler=sampler, group_id=group_id, pbar=pbar
|
|
454
458
|
)
|
|
455
459
|
if changes_accepted:
|
|
456
460
|
new_version = True
|
|
@@ -474,7 +478,7 @@ class Maestro:
|
|
|
474
478
|
for _ in range(select_steps):
|
|
475
479
|
await self._select(explore=True)
|
|
476
480
|
|
|
477
|
-
setups = sampler.sample(
|
|
481
|
+
setups = sampler.sample(group_size)
|
|
478
482
|
awaitables = []
|
|
479
483
|
criticos = []
|
|
480
484
|
for setup in setups:
|
|
@@ -518,17 +522,21 @@ class Maestro:
|
|
|
518
522
|
# Switch to the current version with highest score
|
|
519
523
|
await self._select(explore=False)
|
|
520
524
|
|
|
521
|
-
print("=" * 30 + f" Round {round + 1}/{num_rounds} finishes" + "=" * 30)
|
|
522
|
-
print("Total versions: ", len(self.versions))
|
|
523
|
-
print("Best version: ", self.current_version)
|
|
524
|
-
print(
|
|
525
|
-
|
|
526
|
-
|
|
525
|
+
print("\n\n" + "=" * 30 + f" Round {round + 1}/{num_rounds} finishes" + "=" * 30)
|
|
526
|
+
print("Total versions accepted: ", len(self.versions))
|
|
527
|
+
print("Best version index: ", self.current_version)
|
|
528
|
+
print(
|
|
529
|
+
"Score for the best version: %s based on %s rollouts"
|
|
530
|
+
% (
|
|
531
|
+
self.versions[self.current_version]["average_score"],
|
|
532
|
+
self.versions[self.current_version]["visits"] * group_size,
|
|
533
|
+
)
|
|
534
|
+
)
|
|
527
535
|
|
|
528
536
|
print(
|
|
529
|
-
"
|
|
537
|
+
"All versions: ",
|
|
530
538
|
{
|
|
531
|
-
i: {"score": self.versions[i]["average_score"], "
|
|
539
|
+
i: {"score": self.versions[i]["average_score"], "rollouts evaluated": self.versions[i]["visits"] * group_size}
|
|
532
540
|
for i in range(len(self.versions))
|
|
533
541
|
},
|
|
534
542
|
)
|
|
@@ -599,7 +607,7 @@ class Maestro:
|
|
|
599
607
|
|
|
600
608
|
print("optimize_structure settings:")
|
|
601
609
|
print(" total_rollouts: ", total_rollouts)
|
|
602
|
-
print("
|
|
610
|
+
print("=" * 80 + "\n\n")
|
|
603
611
|
|
|
604
612
|
if code_paths is not None:
|
|
605
613
|
code = extract_code(code_paths=code_paths)
|
|
@@ -610,9 +618,10 @@ class Maestro:
|
|
|
610
618
|
elements=self.setups,
|
|
611
619
|
weights=[setup["weight"] for setup in self.setups],
|
|
612
620
|
)
|
|
613
|
-
group_id = uuid4().hex
|
|
621
|
+
group_id = "Maestro-Struct-" + uuid4().hex
|
|
614
622
|
|
|
615
|
-
print("
|
|
623
|
+
print("=" * 80)
|
|
624
|
+
print("Running the agent to collect traces...\n\n")
|
|
616
625
|
|
|
617
626
|
setups = sampler.sample(total_rollouts)
|
|
618
627
|
awaitables = []
|
|
@@ -625,7 +634,8 @@ class Maestro:
|
|
|
625
634
|
|
|
626
635
|
test_cases, _ = await self._evaluate(awaitables=awaitables, criticos=criticos, verbose=verbose)
|
|
627
636
|
|
|
628
|
-
print("
|
|
637
|
+
print("=" * 80)
|
|
638
|
+
print("Optimizing structure...\n\n")
|
|
629
639
|
suggestion = await self._client.optimize_structure(
|
|
630
640
|
{
|
|
631
641
|
"agent_name": get_full_func_name(self.agent_fn),
|
|
@@ -4,6 +4,7 @@ from uuid import uuid4
|
|
|
4
4
|
|
|
5
5
|
from agents import Agent, Runner, SQLiteSession
|
|
6
6
|
|
|
7
|
+
from ..utils import no_trace
|
|
7
8
|
from .base_mocker import BaseMocker
|
|
8
9
|
|
|
9
10
|
|
|
@@ -48,12 +49,12 @@ class MockTool(BaseMocker):
|
|
|
48
49
|
"kwargs": kwargs,
|
|
49
50
|
}
|
|
50
51
|
)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
with no_trace():
|
|
53
|
+
result = Runner.run_sync(
|
|
54
|
+
self.agent,
|
|
55
|
+
agent_input,
|
|
56
|
+
session=self._session,
|
|
57
|
+
)
|
|
57
58
|
output = result.final_output
|
|
58
59
|
return output
|
|
59
60
|
|
|
@@ -64,11 +65,11 @@ class MockTool(BaseMocker):
|
|
|
64
65
|
"kwargs": kwargs,
|
|
65
66
|
}
|
|
66
67
|
)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
with no_trace():
|
|
69
|
+
result = await Runner.run(
|
|
70
|
+
self.agent,
|
|
71
|
+
agent_input,
|
|
72
|
+
session=self._session,
|
|
73
|
+
)
|
|
73
74
|
output = result.final_output
|
|
74
75
|
return output
|
|
@@ -213,7 +213,7 @@ class SyncSimulator(BaseSimulator):
|
|
|
213
213
|
a new UUID will be generated.
|
|
214
214
|
"""
|
|
215
215
|
agent_logs: list[AgentLog] = []
|
|
216
|
-
group_id = uuid4().hex if group_id is None else group_id
|
|
216
|
+
group_id = ("Simulate-" + uuid4().hex) if group_id is None else group_id
|
|
217
217
|
tracking_on()
|
|
218
218
|
for tape, config in self.tape_and_config_generator(num_runs):
|
|
219
219
|
with _simulate(config), create_logging_span(tape.id):
|
|
@@ -248,7 +248,7 @@ class SyncSimulator(BaseSimulator):
|
|
|
248
248
|
a new UUID will be generated.
|
|
249
249
|
"""
|
|
250
250
|
agent_logs: list[AgentLog] = []
|
|
251
|
-
group_id = uuid4().hex if group_id is None else group_id
|
|
251
|
+
group_id = ("Simulate-" + uuid4().hex) if group_id is None else group_id
|
|
252
252
|
tracking_on()
|
|
253
253
|
for tape in simulation_tapes:
|
|
254
254
|
new_tape = tape.copy()
|
|
@@ -312,7 +312,7 @@ class AsyncSimulator(BaseSimulator):
|
|
|
312
312
|
a new UUID will be generated.
|
|
313
313
|
"""
|
|
314
314
|
agent_logs: list[AgentLog] = []
|
|
315
|
-
group_id = uuid4().hex if group_id is None else group_id
|
|
315
|
+
group_id = ("Simulate-" + uuid4().hex) if group_id is None else group_id
|
|
316
316
|
tracking_on()
|
|
317
317
|
for tape, config in self.tape_and_config_generator(num_runs):
|
|
318
318
|
with _simulate(config), create_logging_span(tape.id):
|
|
@@ -347,7 +347,7 @@ class AsyncSimulator(BaseSimulator):
|
|
|
347
347
|
a new UUID will be generated.
|
|
348
348
|
"""
|
|
349
349
|
agent_logs: list[AgentLog] = []
|
|
350
|
-
group_id = uuid4().hex if group_id is None else group_id
|
|
350
|
+
group_id = ("Simulate-" + uuid4().hex) if group_id is None else group_id
|
|
351
351
|
tracking_on()
|
|
352
352
|
for tape in simulation_tapes:
|
|
353
353
|
new_tape = tape.copy()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: relai
|
|
3
|
-
Version: 0.3.
|
|
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,6 +205,7 @@ 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: Development Status :: 4 - Beta
|
|
208
209
|
Classifier: Programming Language :: Python :: 3.10
|
|
209
210
|
Classifier: Programming Language :: Python :: 3.11
|
|
210
211
|
Classifier: Programming Language :: Python :: 3.12
|
|
@@ -314,16 +315,22 @@ register_param(
|
|
|
314
315
|
|
|
315
316
|
|
|
316
317
|
async def agent_fn(tape: SimulationTape) -> AgentOutputs:
|
|
317
|
-
|
|
318
|
-
agent
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
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
|
+
|
|
327
334
|
|
|
328
335
|
|
|
329
336
|
async def main() -> None:
|
|
@@ -363,10 +370,10 @@ async def main() -> None:
|
|
|
363
370
|
# params.load("saved_config.json") # load previous params if available
|
|
364
371
|
await maestro.optimize_config(
|
|
365
372
|
total_rollouts=20, # Total number of rollouts to use for optimization.
|
|
366
|
-
batch_size=
|
|
373
|
+
batch_size=2, # Base batch size to use for individual optimization steps. Defaults to 4.
|
|
367
374
|
explore_radius=1, # A positive integer controlling the aggressiveness of exploration during optimization.
|
|
368
375
|
explore_factor=0.5, # A float between 0 to 1 controlling the exploration-exploitation trade-off.
|
|
369
|
-
verbose=
|
|
376
|
+
verbose=False, # If True, additional information will be printed during the optimization step.
|
|
370
377
|
)
|
|
371
378
|
params.save("saved_config.json") # save optimized params for future usage
|
|
372
379
|
|
|
@@ -377,7 +384,7 @@ async def main() -> None:
|
|
|
377
384
|
await maestro.optimize_structure(
|
|
378
385
|
total_rollouts=10, # Total number of rollouts to use for optimization.
|
|
379
386
|
code_paths=["stock-assistant.py"], # A list of paths corresponding to code implementations of the agent.
|
|
380
|
-
verbose=
|
|
387
|
+
verbose=False, # If True, additional information will be printed during the optimization step.
|
|
381
388
|
)
|
|
382
389
|
|
|
383
390
|
|
|
@@ -404,6 +411,7 @@ Maestro is a holistic agent optimizer. It consumes evaluator/user feedback to im
|
|
|
404
411
|
|
|
405
412
|
- 📘 **Documentation:** [docs.relai.ai](http://docs.relai.ai)
|
|
406
413
|
- 🧪 **Examples:** [relai-sdk/examples](examples)
|
|
414
|
+
- 📖 **Tutorials:** [docs.relai.ai/tutorials/index.html](https://docs.relai.ai/tutorials/index.html)
|
|
407
415
|
- 🌐 **Website:** [relai.ai](https://relai.ai)
|
|
408
416
|
- 📰 **Maestro Technical Report:** [ArXiV](https://arxiv.org/abs/2509.04642)
|
|
409
417
|
- 🌐 **Join the Community:** [Discord](https://discord.gg/sjaHJ34YYE)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|