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.
- {react_agent_harness-0.3.1/react_agent_harness.egg-info → react_agent_harness-0.3.2}/PKG-INFO +1 -1
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/README.md +17 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/agents/base.py +7 -5
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/steering.py +29 -16
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/pyproject.toml +1 -1
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2/react_agent_harness.egg-info}/PKG-INFO +1 -1
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_steering.py +6 -21
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_streaming.py +64 -23
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/LICENSE +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/agents/__init__.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/__init__.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/annotation.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/checkpoint.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/cli.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/events.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/executor_bridge.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/hitl.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/llm/__init__.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/llm/_streaming.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/llm/auth.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/llm/claude_code.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/llm/openai.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/llm/openai_codex.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/otel.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/runtime.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/harness/utils.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/memory/__init__.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/memory/episodic_lance.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/memory/manager.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/memory/redis_store.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/memory/stores.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/memory/working.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/orchestrator/__init__.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/orchestrator/planner.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/react_agent_harness.egg-info/SOURCES.txt +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/react_agent_harness.egg-info/dependency_links.txt +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/react_agent_harness.egg-info/entry_points.txt +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/react_agent_harness.egg-info/requires.txt +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/react_agent_harness.egg-info/top_level.txt +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/setup.cfg +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_agents_base.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_annotation.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_checkpoint_resume.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_claude_code_llm.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_cli.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_executor_bridge.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_http_fetch.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_llm_auth.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_mcp_adapter.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_memory.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_openai_codex_llm.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_openai_llm.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_orchestrator.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_otel.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_parse_action_json.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_redis_store.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_utils.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_vision.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tests/test_working_memory.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tools/__init__.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tools/builtin/__init__.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tools/builtin/fetch_image.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tools/builtin/http_fetch.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tools/mcp/__init__.py +0 -0
- {react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/tools/mcp/adapter.py +0 -0
|
@@ -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
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
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
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
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(
|
|
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.
|
|
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 = [
|
|
@@ -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(
|
|
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",
|
|
24
|
-
|
|
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,
|
|
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",
|
|
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",
|
|
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",
|
|
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
|
-
{
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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": {},
|
|
136
|
-
"
|
|
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(
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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,
|
|
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,
|
|
168
|
-
|
|
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
|
|
|
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
|
{react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/react_agent_harness.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/react_agent_harness.egg-info/requires.txt
RENAMED
|
File without changes
|
{react_agent_harness-0.3.1 → react_agent_harness-0.3.2}/react_agent_harness.egg-info/top_level.txt
RENAMED
|
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
|
|
File without changes
|