relai 0.3.3__py3-none-any.whl → 0.3.5__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.

Potentially problematic release.


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

@@ -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
 
@@ -161,7 +160,7 @@ class Maestro:
161
160
  return str(agent_outputs)
162
161
 
163
162
  async def _evaluate(
164
- self, awaitables: list[Awaitable], criticos: list[Critico], verbose: bool = False, print_flag: str = ""
163
+ self, awaitables: list[Awaitable], criticos: list[Critico], verbose: bool = True, print_flag: str = ""
165
164
  ) -> tuple[list[dict[str, Any]], list[AgentLog]]:
166
165
  """
167
166
  Run and evaluate the current version of the agent through a set of awaitables.
@@ -170,7 +169,7 @@ class Maestro:
170
169
  awaitables (list[Awaitable]): A list of awaitables, each representing a run of the agent
171
170
  criticos (list[Critico]): A list of Critico objects, each corresponding to an awaitable
172
171
  verbose (bool): If True, additional information will be printed during evaluation.
173
- Defaults to False.
172
+ Defaults to True.
174
173
  print_flag (str): A string to be put next to the printed info when `verbose` is True.
175
174
  Used to distinguish printed info from different types of evaluations.
176
175
 
@@ -228,7 +227,7 @@ class Maestro:
228
227
  self,
229
228
  batch_size: int,
230
229
  sampler: ProportionalSampler,
231
- verbose: bool = False,
230
+ verbose: bool = True,
232
231
  group_id: str | None = None,
233
232
  pbar: tqdm | None = None,
234
233
  ) -> bool:
@@ -245,7 +244,7 @@ class Maestro:
245
244
  `batch_size` of them will be used for preliminary examinations.
246
245
  sampler (ProportionalSampler): Sampler to use for selecting setups.
247
246
  verbose (bool): If True, additional information will be printed during the iterate step.
248
- Defaults to False.
247
+ Defaults to True.
249
248
  group_id (str, optional): An optional group ID to associate all runs together. If not provided,
250
249
  a new UUID will be generated.
251
250
  pbar (tqdm, optional): A progress bar to display the progress of the iteration. Defaults to None.
@@ -374,17 +373,17 @@ class Maestro:
374
373
  async def optimize_config(
375
374
  self,
376
375
  total_rollouts: int,
377
- batch_size: int = 4,
376
+ batch_size: int = 8,
378
377
  explore_radius: int = 5,
379
378
  explore_factor: float = 0.5,
380
- verbose: bool = False,
379
+ verbose: bool = True,
381
380
  ):
382
381
  """
383
382
  Optimize the configs (parameters) of the agent.
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 4.
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.
@@ -393,7 +392,7 @@ class Maestro:
393
392
  while a lower value allocates more rollouts to ensure the discovered configs are thoroughly evaluated.
394
393
  Defaults to 0.5.
395
394
  verbose (bool): If True, related information will be printed during the optimization step.
396
- Defaults to False.
395
+ Defaults to True.
397
396
 
398
397
  Raises:
399
398
  ValueError: If the input parameters are not valid.
@@ -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
- # total_rollouts = (iterate_steps * batch_size * 4 + select_steps * batch_size) * num_rounds
411
- # explore_factor = (iterate_steps * batch_size * 4) / (iterate_steps * batch_size * 4 + select_steps * batch_size)
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 * batch_size * 4 + select_steps * batch_size))
415
- total_rollouts = num_rounds * (iterate_steps * batch_size * 4 + select_steps * batch_size)
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
- print("optimize_config settings:")
417
+ print("\n" + "=" * 30 + "optimize_config settings" + "=" * 30)
418
418
  print(" total_rollouts: ", total_rollouts)
419
- print(" batch_size: ", 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 * batch_size * 4 + select_steps * batch_size}."
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("Score (current base): ", self.versions[self.current_version]["average_score"])
446
- print("Visits (current base): ", self.versions[self.current_version]["visits"])
447
- print("Visits (total): ", self.total_visits)
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=batch_size, verbose=verbose, sampler=sampler, group_id=group_id, pbar=pbar
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(batch_size)
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("Score (best version): ", self.versions[self.current_version]["average_score"])
525
- print("Visits (best version): ", self.versions[self.current_version]["visits"])
526
- print("Visits (total): ", self.total_visits)
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
- "all versions: ",
537
+ "All versions: ",
530
538
  {
531
- i: {"score": self.versions[i]["average_score"], "visits": self.versions[i]["visits"]}
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
  )
@@ -569,7 +577,10 @@ class Maestro:
569
577
  if self.log_to_platform:
570
578
  await sync_to_platform()
571
579
  print(
572
- f"Results of round {round + 1}/{num_rounds} uploaded to RELAI platform, visualization id: {self.config_opt_viz_id}"
580
+ (
581
+ f"Results of round {round + 1}/{num_rounds} uploaded to RELAI platform, "
582
+ f"visualization id: {self.config_opt_viz_id}\n\n\n"
583
+ )
573
584
  )
574
585
 
575
586
  async def optimize_structure(
@@ -577,7 +588,7 @@ class Maestro:
577
588
  total_rollouts: int,
578
589
  description: Optional[str] = None,
579
590
  code_paths: Optional[list[str]] = None,
580
- verbose: bool = False,
591
+ verbose: bool = True,
581
592
  ) -> str:
582
593
  """
583
594
  Propose structural changes (i.e. changes that cannot be achieved by setting parameters alone) to
@@ -591,15 +602,15 @@ class Maestro:
591
602
  code_paths (list[str], optional): A list of paths corresponding to code files containing
592
603
  the implementation of the agent.
593
604
  verbose (bool): If True, additional information will be printed during the optimization.
594
- Defaults to False.
605
+ Defaults to True.
595
606
 
596
607
  Returns:
597
608
  str: Suggestion for structural changes to the agent.
598
609
  """
599
610
 
600
- print("optimize_structure settings:")
611
+ print("\n" + "=" * 30 + "optimize_structure settings" + "=" * 30)
601
612
  print(" total_rollouts: ", total_rollouts)
602
- print("-" * 60 + "\n\n")
613
+ print("=" * 80 + "\n\n")
603
614
 
604
615
  if code_paths is not None:
605
616
  code = extract_code(code_paths=code_paths)
@@ -610,9 +621,10 @@ class Maestro:
610
621
  elements=self.setups,
611
622
  weights=[setup["weight"] for setup in self.setups],
612
623
  )
613
- group_id = uuid4().hex
624
+ group_id = "Maestro-Struct-" + uuid4().hex
614
625
 
615
- print("Running the agent to collect traces...")
626
+ print("=" * 80)
627
+ print("Running the agent to collect traces...\n\n")
616
628
 
617
629
  setups = sampler.sample(total_rollouts)
618
630
  awaitables = []
@@ -625,7 +637,8 @@ class Maestro:
625
637
 
626
638
  test_cases, _ = await self._evaluate(awaitables=awaitables, criticos=criticos, verbose=verbose)
627
639
 
628
- print("Optimizing structure...")
640
+ print("=" * 80)
641
+ print("Optimizing structure...\n\n")
629
642
  suggestion = await self._client.optimize_structure(
630
643
  {
631
644
  "agent_name": get_full_func_name(self.agent_fn),
@@ -664,6 +677,6 @@ class Maestro:
664
677
 
665
678
  if self.log_to_platform:
666
679
  uid = await sync_to_platform()
667
- print(f"Results uploaded to RELAI platform, visualization id: {uid}")
680
+ print(f"Results uploaded to RELAI platform, visualization id: {uid}\n\n\n")
668
681
 
669
682
  return suggestion
relai/mocker/tool.py CHANGED
@@ -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
- result = Runner.run_sync(
53
- self.agent,
54
- agent_input,
55
- session=self._session,
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
- result = await Runner.run(
69
- self.agent,
70
- agent_input,
71
- session=self._session,
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
relai/simulator.py CHANGED
@@ -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
3
+ Version: 0.3.5
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
@@ -235,7 +236,7 @@ Dynamic: license-file
235
236
  </p>
236
237
 
237
238
 
238
- **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.
239
+ **RELAI** is a platform for building **reliable AI agents**. It streamlines the hardest parts of agent development—**simulation**, **evaluation**, and **optimization**—so you can iterate quickly with confidence.
239
240
 
240
241
  **What you get**
241
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.
@@ -314,16 +315,22 @@ register_param(
314
315
 
315
316
 
316
317
  async def agent_fn(tape: SimulationTape) -> AgentOutputs:
317
- question = await get_user_query()
318
- agent = Agent(
319
- name="Stock assistant",
320
- instructions=params.prompt, # access registered parameter
321
- model="gpt-5-mini",
322
- )
323
- result = await Runner.run(agent, question)
324
- tape.extras["format_rubrics"] = {"Prices must include cents (eg: $XXX.XX)": 1.0}
325
- tape.agent_inputs["question"] = question # trace inputs for later auditing
326
- return {"summary": result.final_output}
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=1, # Base batch size to use for individual optimization steps. Defaults to 4.
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=True, # If True, related information will be printed during the optimization step.
376
+ verbose=True, # 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=True, # If True, related information will be printed during the optimization step.
387
+ verbose=True, # 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)
@@ -6,23 +6,23 @@ relai/data.py,sha256=ne0H4EQ0B_yxE9fogoovGExuJuwqutSpuhNsl4UmcsU,7852
6
6
  relai/exporter.py,sha256=jZxrUjlYCOpRr7gdmbg6-LUL_fXmtMgPp89CgvP5Z7A,1932
7
7
  relai/flags.py,sha256=_GrjQg7mZq7BwEIedR6cjWY4grwsryqbKdgyiRr2P7k,1929
8
8
  relai/logger.py,sha256=j6PdzNkltukWAqBGKAB2qH2p61kS60RwsupDz-gELB4,18358
9
- relai/simulator.py,sha256=Ni-RxaCtDfjgYuaYOSRTwVrvxhsX_a76x8Jr1EUEP0M,16401
9
+ relai/simulator.py,sha256=oEC5oLODPo1vLGBaMUdDj0JovZlc595dez931ihDuXk,16465
10
10
  relai/utils.py,sha256=va3xz79NTLJiZKaBrS_3Y8dC4M_JEmf8uOwzwFYYqUU,2359
11
11
  relai/critico/__init__.py,sha256=c_mDXCVEzsQckDS4ZFOmANo8vB5Vjr1bvyQNimAPVR8,52
12
12
  relai/critico/critico.py,sha256=J1ek9v2J5WBnHnZknZEVppIrWGczVHxuRX7ghK6mpXM,7616
13
13
  relai/critico/evaluate.py,sha256=Bd-Hlsh2fz2AQ0SINoyqcdpdbWK2t8yrAPHv6UCueFY,31348
14
14
  relai/maestro/__init__.py,sha256=NVXy0v7yghGwGbtsPti4gQGtVA3vMgXdpIpiJUesqME,186
15
15
  relai/maestro/graph.py,sha256=SyY0rHzes3o5bSqlK66CQDUAeyChUhWJQM3FzJCBvfs,1850
16
- relai/maestro/optimizer.py,sha256=y_1hxyf1z6YLUTBJn84aZGmxtDX162CCG5W6eHUDJF0,29100
16
+ relai/maestro/optimizer.py,sha256=irefqbtD5qfPt2QOQaQwd8bsC3uhx7HdNF9d3KDHgD4,29549
17
17
  relai/maestro/params.py,sha256=-0Dtk23ClHJR6Q-PsaKr-GwUylz0-BIIquJF2eA-p-I,8925
18
18
  relai/maestro/utils.py,sha256=WIE3cR8EMDVfAJozEfngh8DfOQdRPZMxxtN-M1cMmxo,7276
19
19
  relai/mocker/__init__.py,sha256=JP2xlSG6Szc0tSEiZzCN6UXdE66uy7AmRn-p358xFVM,102
20
20
  relai/mocker/base_mocker.py,sha256=BL4WYtdxWHZdKICfo9idW5i5MrkoxJDElcoeGk-jaJM,994
21
21
  relai/mocker/persona.py,sha256=q2A_lwYrp7H6sKkguMIPl7FQ_6pL4kTaxGBJ1kU2aGA,6678
22
- relai/mocker/tool.py,sha256=wgbmOOTlpVClDMWzfuJfsrNwGI99k9CwzjoaRMLkAyo,2112
22
+ relai/mocker/tool.py,sha256=dHXkVcD9D6HMNlBj13V7GTgW_99a_-3tf9rC6iLDFn8,2229
23
23
  relai/schema/visual.py,sha256=Y6BP5CHxLU0e7sTfNjgKmG2GD0R9a8rvITusxd-d-UE,2443
24
- relai-0.3.3.dist-info/licenses/LICENSE.md,sha256=UNo7WT0mbmbUFjRGzRGaBtybmBPB7xd2ls9tfCkv0oc,10979
25
- relai-0.3.3.dist-info/METADATA,sha256=fhqMNABGwuXAYOUL8vYyEjtD937SfTmJOObwktBrM5M,23125
26
- relai-0.3.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
- relai-0.3.3.dist-info/top_level.txt,sha256=pRyA93fRj-HsukRNHyS4sHdvLO4TY8VvBMK44KcxRA4,6
28
- relai-0.3.3.dist-info/RECORD,,
24
+ relai-0.3.5.dist-info/licenses/LICENSE.md,sha256=UNo7WT0mbmbUFjRGzRGaBtybmBPB7xd2ls9tfCkv0oc,10979
25
+ relai-0.3.5.dist-info/METADATA,sha256=ZvzLQHneMR6jcqD-taaKkh9BX93xMHX_LL64AqNnM2U,23533
26
+ relai-0.3.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
+ relai-0.3.5.dist-info/top_level.txt,sha256=pRyA93fRj-HsukRNHyS4sHdvLO4TY8VvBMK44KcxRA4,6
28
+ relai-0.3.5.dist-info/RECORD,,
File without changes