react-agent-harness 0.3.1__tar.gz → 0.3.2__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.
Files changed (65) hide show
  1. {react_agent_harness-0.3.1/react_agent_harness.egg-info → react_agent_harness-0.3.2}/PKG-INFO +1 -1
  2. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/README.md +17 -0
  3. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/agents/base.py +7 -5
  4. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/steering.py +29 -16
  5. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/pyproject.toml +1 -1
  6. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2/react_agent_harness.egg-info}/PKG-INFO +1 -1
  7. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_steering.py +6 -21
  8. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_streaming.py +64 -23
  9. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/LICENSE +0 -0
  10. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/agents/__init__.py +0 -0
  11. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/__init__.py +0 -0
  12. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/annotation.py +0 -0
  13. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/checkpoint.py +0 -0
  14. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/cli.py +0 -0
  15. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/events.py +0 -0
  16. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/executor_bridge.py +0 -0
  17. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/hitl.py +0 -0
  18. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/llm/__init__.py +0 -0
  19. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/llm/_streaming.py +0 -0
  20. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/llm/auth.py +0 -0
  21. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/llm/claude_code.py +0 -0
  22. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/llm/openai.py +0 -0
  23. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/llm/openai_codex.py +0 -0
  24. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/otel.py +0 -0
  25. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/runtime.py +0 -0
  26. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/utils.py +0 -0
  27. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/memory/__init__.py +0 -0
  28. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/memory/episodic_lance.py +0 -0
  29. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/memory/manager.py +0 -0
  30. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/memory/redis_store.py +0 -0
  31. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/memory/stores.py +0 -0
  32. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/memory/working.py +0 -0
  33. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/orchestrator/__init__.py +0 -0
  34. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/orchestrator/planner.py +0 -0
  35. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/react_agent_harness.egg-info/SOURCES.txt +0 -0
  36. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/react_agent_harness.egg-info/dependency_links.txt +0 -0
  37. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/react_agent_harness.egg-info/entry_points.txt +0 -0
  38. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/react_agent_harness.egg-info/requires.txt +0 -0
  39. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/react_agent_harness.egg-info/top_level.txt +0 -0
  40. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/setup.cfg +0 -0
  41. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_agents_base.py +0 -0
  42. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_annotation.py +0 -0
  43. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_checkpoint_resume.py +0 -0
  44. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_claude_code_llm.py +0 -0
  45. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_cli.py +0 -0
  46. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_executor_bridge.py +0 -0
  47. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_http_fetch.py +0 -0
  48. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_llm_auth.py +0 -0
  49. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_mcp_adapter.py +0 -0
  50. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_memory.py +0 -0
  51. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_openai_codex_llm.py +0 -0
  52. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_openai_llm.py +0 -0
  53. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_orchestrator.py +0 -0
  54. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_otel.py +0 -0
  55. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_parse_action_json.py +0 -0
  56. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_redis_store.py +0 -0
  57. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_utils.py +0 -0
  58. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_vision.py +0 -0
  59. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_working_memory.py +0 -0
  60. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tools/__init__.py +0 -0
  61. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tools/builtin/__init__.py +0 -0
  62. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tools/builtin/fetch_image.py +0 -0
  63. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tools/builtin/http_fetch.py +0 -0
  64. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tools/mcp/__init__.py +0 -0
  65. {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tools/mcp/adapter.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: react-agent-harness
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: Multi-agent LLM orchestration: hybrid DAG planning, two-tier memory, streaming
5
5
  Requires-Python: >=3.10
6
6
  License-File: LICENSE
@@ -909,3 +909,20 @@ key-bindings (like Enter-submits and Alt-Enter/Ctrl-J-newline) across both paths
909
909
 
910
910
  See `examples/complex_sysaudit_demo.py` for stdin steering across three
911
911
  agents alongside HITL on the shell tool.
912
+
913
+ ## AgentConfig reference
914
+
915
+ | Field | Default | Description |
916
+ |---|---|---|
917
+ | `agent_id` | required | Unique identifier for the agent |
918
+ | `role` | required | Plain-English description used by the planner for agent selection |
919
+ | `system_prompt` | required | Base system prompt for the agent |
920
+ | `allowed_tools` | required | Tool names the agent may call |
921
+ | `max_steps` | `10` | Maximum ReAct iterations before the run is terminated |
922
+ | `max_wall_time_seconds` | (guardrail) | See `GuardrailConfig` |
923
+ | `memory_context_enabled` | `True` | Prepend relevant long-term memory to the system prompt |
924
+ | `confidence_from_llm` | `True` | Use the `confidence` field from the LLM response; set `False` to always return `1.0` |
925
+ | `working_memory_max_tokens` | `8000` | Token budget for in-context working memory before rolling summarisation kicks in |
926
+ | `hitl_tools` | `[]` | Tool names that require human approval before execution |
927
+ | `checkpoint_every` | `0` | Write a crash-resumable checkpoint every N steps; `0` disables periodic checkpoints |
928
+ | `stream_tokens` | `False` | Emit `TOKEN` events as the LLM streams. Disabled by default — enable if you want to render partial output in real time: `AgentConfig(..., stream_tokens=True)` |
@@ -61,6 +61,7 @@ class AgentConfig:
61
61
  max_steps: int = 10
62
62
  memory_context_enabled: bool = True
63
63
  confidence_from_llm: bool = True # if False, confidence=1.0 on success
64
+ stream_tokens: bool = False # if True, TOKEN events are emitted as the LLM streams
64
65
  working_memory_max_tokens: int = 8000 # WorkingMemory eviction threshold; tune per agent
65
66
  hitl_tools: list[str] = None # tools requiring human approval; None = no HITL
66
67
  checkpoint_every: int = 0 # write a resumable checkpoint every N steps; 0 = disabled
@@ -649,11 +650,12 @@ class BaseAgent:
649
650
  messages=messages,
650
651
  ):
651
652
  accumulated += token
652
- yield BusEvent(
653
- type=EventType.TOKEN,
654
- agent_id=self.config.agent_id,
655
- token=token,
656
- )
653
+ if self.config.stream_tokens:
654
+ yield BusEvent(
655
+ type=EventType.TOKEN,
656
+ agent_id=self.config.agent_id,
657
+ token=token,
658
+ )
657
659
  response = _parse_action_json(accumulated)
658
660
  if response is None:
659
661
  logger.warning(
@@ -150,7 +150,6 @@ class StdinRouter:
150
150
  input_: Any | None = None,
151
151
  output: Any | None = None,
152
152
  history: Any | None = None,
153
- patch_stdout_: bool = True,
154
153
  ) -> None:
155
154
  self._task: asyncio.Task | None = None
156
155
  self._stop = asyncio.Event()
@@ -159,8 +158,6 @@ class StdinRouter:
159
158
  # subscription_id → (prefix, callback). prefix=None is catch-all.
160
159
  self._subs: dict[int, tuple[str | None, Callable[[str], None]]] = {}
161
160
  self._next_sub_id: int = 0
162
- # Tests turn off patch_stdout to avoid interfering with pytest capture.
163
- self._patch_stdout = patch_stdout_
164
161
  self._session: PromptSession = PromptSession(
165
162
  history=history or InMemoryHistory(),
166
163
  input=input_,
@@ -282,18 +279,13 @@ class StdinRouter:
282
279
  # ── Internals ─────────────────────────────────────────────────────────────
283
280
 
284
281
  async def _run(self) -> None:
285
- # patch_stdout makes prints from other tasks scroll above the prompt
286
- # instead of corrupting the input line. Tests skip it because it
287
- # interferes with pytest's stdout capture.
288
- cm = patch_stdout(raw=True) if self._patch_stdout else contextlib.nullcontext()
289
- with cm:
290
- while not self._stop.is_set():
291
- claim = self._hitl_claim
292
- if claim is not None:
293
- await self._serve_hitl(*claim)
294
- self._hitl_claim = None
295
- else:
296
- await self._serve_steering()
282
+ while not self._stop.is_set():
283
+ claim = self._hitl_claim
284
+ if claim is not None:
285
+ await self._serve_hitl(*claim)
286
+ self._hitl_claim = None
287
+ else:
288
+ await self._serve_steering()
297
289
 
298
290
  async def _serve_steering(self) -> None:
299
291
  try:
@@ -575,10 +567,13 @@ class _StdinSteeringFactory:
575
567
  self,
576
568
  router: StdinRouter | None = None,
577
569
  prefix_template: str = "{agent_id}",
570
+ patch_stdout_: bool = True,
578
571
  ) -> None:
579
572
  self._router = router or StdinRouter()
580
573
  self._owned = router is None
581
574
  self._prefix_template = prefix_template
575
+ self._patch_stdout = patch_stdout_ and router is None # only patch when we own the router
576
+ self._patch_stdout_cm: Any | None = None
582
577
  # Ref-counted lifecycle: nested AgentRuntime wraps (dispatch_stream
583
578
  # → run_stream) re-enter the factory; only the outermost
584
579
  # enter/exit actually starts/stops the router.
@@ -590,6 +585,9 @@ class _StdinSteeringFactory:
590
585
 
591
586
  async def __aenter__(self) -> _StdinSteeringFactory:
592
587
  if self._owned and self._enter_count == 0:
588
+ if self._patch_stdout:
589
+ self._patch_stdout_cm = patch_stdout(raw=True)
590
+ self._patch_stdout_cm.__enter__()
593
591
  await self._router.__aenter__()
594
592
  self._enter_count += 1
595
593
  return self
@@ -598,11 +596,15 @@ class _StdinSteeringFactory:
598
596
  self._enter_count = max(0, self._enter_count - 1)
599
597
  if self._owned and self._enter_count == 0:
600
598
  await self._router.__aexit__(exc_type, exc, tb)
599
+ if self._patch_stdout_cm is not None:
600
+ self._patch_stdout_cm.__exit__(exc_type, exc, tb)
601
+ self._patch_stdout_cm = None
601
602
 
602
603
 
603
604
  def stdin_steering_factory(
604
605
  router: StdinRouter | None = None,
605
606
  prefix_template: str = "{agent_id}",
607
+ patch_stdout_: bool = True,
606
608
  ) -> _StdinSteeringFactory:
607
609
  """Return a steering factory that lifecycles its own StdinRouter.
608
610
 
@@ -616,7 +618,9 @@ def stdin_steering_factory(
616
618
  `prefix_template` may reference `{agent_id}`; default subscribes
617
619
  each agent to its own `agent_id`.
618
620
  """
619
- return _StdinSteeringFactory(router=router, prefix_template=prefix_template)
621
+ return _StdinSteeringFactory(
622
+ router=router, prefix_template=prefix_template, patch_stdout_=patch_stdout_
623
+ )
620
624
 
621
625
 
622
626
  # ── Direct-use shims (no AgentRuntime / no factory) ───────────────────────────
@@ -639,6 +643,7 @@ class StdinSteer:
639
643
  agents: BaseAgent | list[BaseAgent],
640
644
  *,
641
645
  router: StdinRouter | None = None,
646
+ patch_stdout_: bool = True,
642
647
  ) -> None:
643
648
  if not isinstance(agents, list):
644
649
  agents = [agents]
@@ -647,9 +652,14 @@ class StdinSteer:
647
652
  self._agents = agents
648
653
  self._router = router or StdinRouter()
649
654
  self._owned_router = router is None
655
+ self._patch_stdout = patch_stdout_
656
+ self._patch_stdout_cm: Any | None = None
650
657
  self._sub_ids: list[int] = []
651
658
 
652
659
  async def __aenter__(self) -> StdinSteer:
660
+ if self._patch_stdout:
661
+ self._patch_stdout_cm = patch_stdout(raw=True)
662
+ self._patch_stdout_cm.__enter__()
653
663
  if self._owned_router:
654
664
  await self._router.start()
655
665
  # Always register one subscription per agent under its agent_id.
@@ -672,3 +682,6 @@ class StdinSteer:
672
682
  self._sub_ids.clear()
673
683
  if self._owned_router:
674
684
  await self._router.stop()
685
+ if self._patch_stdout_cm is not None:
686
+ self._patch_stdout_cm.__exit__(exc_type, exc, tb)
687
+ self._patch_stdout_cm = None
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "react-agent-harness"
7
- version = "0.3.1"
7
+ version = "0.3.2"
8
8
  description = "Multi-agent LLM orchestration: hybrid DAG planning, two-tier memory, streaming"
9
9
  requires-python = ">=3.10"
10
10
  dependencies = [
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: react-agent-harness
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: Multi-agent LLM orchestration: hybrid DAG planning, two-tier memory, streaming
5
5
  Requires-Python: >=3.10
6
6
  License-File: LICENSE
@@ -64,7 +64,6 @@ def _piped_router():
64
64
  router = StdinRouter(
65
65
  input_=pipe_in,
66
66
  output=DummyOutput(),
67
- patch_stdout_=False,
68
67
  )
69
68
  yield router, pipe_in
70
69
 
@@ -329,20 +328,6 @@ async def test_router_routes_to_catchall_subscriber():
329
328
  assert received == ["plain line"]
330
329
 
331
330
 
332
- @pytest.mark.asyncio
333
- async def test_router_default_patch_stdout_context_starts():
334
- """Default patch_stdout path uses a sync context manager but still runs in async loop."""
335
- received: list[str] = []
336
- with create_pipe_input() as pipe_in:
337
- router = StdinRouter(input_=pipe_in, output=DummyOutput())
338
- router.subscribe(None, received.append)
339
- await router.start()
340
- pipe_in.send_text("plain line\r")
341
- await _drain()
342
- await router.stop()
343
- assert received == ["plain line"]
344
-
345
-
346
331
  @pytest.mark.asyncio
347
332
  async def test_router_routes_by_prefix():
348
333
  a_received: list[str] = []
@@ -448,7 +433,7 @@ async def test_router_claim_next_line_resolves_with_typed_answer():
448
433
 
449
434
 
450
435
  def test_router_rejects_star_as_subscription_prefix():
451
- router = StdinRouter(patch_stdout_=False)
436
+ router = StdinRouter()
452
437
  with pytest.raises(ValueError):
453
438
  router.subscribe("*", lambda _t: None)
454
439
 
@@ -462,7 +447,7 @@ async def test_stdin_single_agent_no_prefix_needed():
462
447
  with _piped_router() as (router, pipe_in):
463
448
  await router.start()
464
449
  try:
465
- async with StdinSteer(a, router=router):
450
+ async with StdinSteer(a, router=router, patch_stdout_=False):
466
451
  pipe_in.send_text("just do it\r")
467
452
  await _drain()
468
453
  finally:
@@ -476,7 +461,7 @@ async def test_stdin_single_agent_prefix_also_works():
476
461
  with _piped_router() as (router, pipe_in):
477
462
  await router.start()
478
463
  try:
479
- async with StdinSteer(a, router=router):
464
+ async with StdinSteer(a, router=router, patch_stdout_=False):
480
465
  pipe_in.send_text("a: explicit\r")
481
466
  await _drain()
482
467
  finally:
@@ -491,7 +476,7 @@ async def test_stdin_multi_agent_prefix_routes():
491
476
  with _piped_router() as (router, pipe_in):
492
477
  await router.start()
493
478
  try:
494
- async with StdinSteer([a, b], router=router):
479
+ async with StdinSteer([a, b], router=router, patch_stdout_=False):
495
480
  pipe_in.send_text("a: do A\r")
496
481
  await _drain()
497
482
  pipe_in.send_text("b: do B\r")
@@ -509,7 +494,7 @@ async def test_stdin_multi_agent_broadcast():
509
494
  with _piped_router() as (router, pipe_in):
510
495
  await router.start()
511
496
  try:
512
- async with StdinSteer([a, b], router=router):
497
+ async with StdinSteer([a, b], router=router, patch_stdout_=False):
513
498
  pipe_in.send_text("*: stop now\r")
514
499
  await _drain()
515
500
  finally:
@@ -525,7 +510,7 @@ async def test_stdin_steer_registers_as_active_router():
525
510
  await router.start()
526
511
  try:
527
512
  assert get_active_router() is None
528
- async with StdinSteer(a, router=router):
513
+ async with StdinSteer(a, router=router, patch_stdout_=False):
529
514
  assert get_active_router() is router
530
515
  assert get_active_router() is None
531
516
  finally:
@@ -5,6 +5,7 @@ Verifies that BaseAgent.run_stream() and Orchestrator.run_stream() yield the
5
5
  expected BusEvent sequence, and that the blocking run() drains to the same
6
6
  result the stream's DONE event carries.
7
7
  """
8
+
8
9
  from __future__ import annotations
9
10
 
10
11
  from agents.base import AgentConfig
@@ -20,8 +21,11 @@ from tests.conftest import EchoTool, ScriptedLLM
20
21
  async def test_agent_run_stream_finish_yields_task_done(agent_factory):
21
22
  """Finish on first step → just one TASK_DONE event (no THOUGHT/ACTION pairs)."""
22
23
  cfg = AgentConfig(
23
- agent_id="a", role="r", system_prompt="finish.",
24
- allowed_tools=[], working_memory_max_tokens=2000,
24
+ agent_id="a",
25
+ role="r",
26
+ system_prompt="finish.",
27
+ allowed_tools=[],
28
+ working_memory_max_tokens=2000,
25
29
  )
26
30
  agent = agent_factory(cfg)
27
31
  events = [e async for e in agent.run_stream("hi")]
@@ -34,7 +38,8 @@ async def test_agent_run_stream_finish_yields_task_done(agent_factory):
34
38
 
35
39
 
36
40
  async def test_agent_run_stream_tool_call_yields_action_and_observation(
37
- agent_factory, llm: ScriptedLLM,
41
+ agent_factory,
42
+ llm: ScriptedLLM,
38
43
  ):
39
44
  """A tool-using step should yield THOUGHT → ACTION → OBSERVATION → ... → TASK_DONE."""
40
45
  step = {"n": 0}
@@ -47,7 +52,9 @@ async def test_agent_run_stream_tool_call_yields_action_and_observation(
47
52
 
48
53
  llm.routes = {"react": react}
49
54
  cfg = AgentConfig(
50
- agent_id="a", role="r", system_prompt="ReAct format.",
55
+ agent_id="a",
56
+ role="r",
57
+ system_prompt="ReAct format.",
51
58
  allowed_tools=["echo"],
52
59
  )
53
60
  agent = agent_factory(cfg, tools={"echo": EchoTool()})
@@ -68,7 +75,10 @@ async def test_agent_run_stream_tool_call_yields_action_and_observation(
68
75
  async def test_agent_run_is_drain_of_run_stream(agent_factory):
69
76
  """run() and the TASK_DONE payload from run_stream() must agree."""
70
77
  cfg = AgentConfig(
71
- agent_id="a", role="r", system_prompt="finish.", allowed_tools=[],
78
+ agent_id="a",
79
+ role="r",
80
+ system_prompt="finish.",
81
+ allowed_tools=[],
72
82
  )
73
83
  agent = agent_factory(cfg)
74
84
 
@@ -98,7 +108,11 @@ async def test_agent_forwards_token_events_when_llm_streams(agent_factory):
98
108
  yield tok
99
109
 
100
110
  cfg = AgentConfig(
101
- agent_id="a", role="r", system_prompt="ReAct.", allowed_tools=[],
111
+ agent_id="a",
112
+ role="r",
113
+ system_prompt="ReAct.",
114
+ allowed_tools=[],
115
+ stream_tokens=True,
102
116
  )
103
117
  agent = agent_factory(cfg)
104
118
  agent._llm = StreamingLLM()
@@ -119,10 +133,20 @@ def _orchestrator_routes():
119
133
  def planner(system, messages, kwargs):
120
134
  return {
121
135
  "tasks": [
122
- {"id": "t1", "agent_id": "analyst", "instruction": "do x",
123
- "depends_on": [], "on_failure": "skip"},
124
- {"id": "t2", "agent_id": "reporter", "instruction": "do y",
125
- "depends_on": ["t1"], "on_failure": "skip"},
136
+ {
137
+ "id": "t1",
138
+ "agent_id": "analyst",
139
+ "instruction": "do x",
140
+ "depends_on": [],
141
+ "on_failure": "skip",
142
+ },
143
+ {
144
+ "id": "t2",
145
+ "agent_id": "reporter",
146
+ "instruction": "do y",
147
+ "depends_on": ["t1"],
148
+ "on_failure": "skip",
149
+ },
126
150
  ],
127
151
  "rationale": "two tasks",
128
152
  }
@@ -132,8 +156,10 @@ def _orchestrator_routes():
132
156
 
133
157
  def extract(system, messages, kwargs):
134
158
  return {
135
- "semantic_facts": {}, "episodic_summary": "ok",
136
- "metadata": {}, "ttl_seconds": None,
159
+ "semantic_facts": {},
160
+ "episodic_summary": "ok",
161
+ "metadata": {},
162
+ "ttl_seconds": None,
137
163
  }
138
164
 
139
165
  return {
@@ -147,14 +173,24 @@ def _build_runtime(llm):
147
173
  tools = ToolRegistry().register(EchoTool())
148
174
  agents = (
149
175
  AgentRegistry()
150
- .register(AgentConfig(
151
- agent_id="analyst", role="r", system_prompt="ReAct.",
152
- allowed_tools=["echo"], max_steps=2,
153
- ))
154
- .register(AgentConfig(
155
- agent_id="reporter", role="r", system_prompt="ReAct.",
156
- allowed_tools=["echo"], max_steps=2,
157
- ))
176
+ .register(
177
+ AgentConfig(
178
+ agent_id="analyst",
179
+ role="r",
180
+ system_prompt="ReAct.",
181
+ allowed_tools=["echo"],
182
+ max_steps=2,
183
+ )
184
+ )
185
+ .register(
186
+ AgentConfig(
187
+ agent_id="reporter",
188
+ role="r",
189
+ system_prompt="ReAct.",
190
+ allowed_tools=["echo"],
191
+ max_steps=2,
192
+ )
193
+ )
158
194
  )
159
195
  memory = MemoryManager(
160
196
  semantic_store=InMemorySemanticStore(),
@@ -162,10 +198,15 @@ def _build_runtime(llm):
162
198
  llm=llm,
163
199
  )
164
200
  return AgentRuntime(
165
- agent_registry=agents, tool_registry=tools, memory=memory, llm=llm,
201
+ agent_registry=agents,
202
+ tool_registry=tools,
203
+ memory=memory,
204
+ llm=llm,
166
205
  guardrail_config=GuardrailConfig(
167
- max_total_cost_usd=5.0, max_wall_time_seconds=30,
168
- max_replan_count=1, confidence_threshold=0.5,
206
+ max_total_cost_usd=5.0,
207
+ max_wall_time_seconds=30,
208
+ max_replan_count=1,
209
+ confidence_threshold=0.5,
169
210
  ),
170
211
  )
171
212