feat: agent with loop strategy
This commit is contained in:
parent
905e3c91ab
commit
a2b7feec16
2 changed files with 45 additions and 2 deletions
10
README.md
10
README.md
|
|
@ -8,7 +8,7 @@ Python-based Telnet helper for connecting to MUD servers, handling login flows,
|
||||||
- Loads credentials and connection settings from a local `.env` file.
|
- Loads credentials and connection settings from a local `.env` file.
|
||||||
- Interactive console session that mirrors server output and lets you type commands directly.
|
- Interactive console session that mirrors server output and lets you type commands directly.
|
||||||
- Optional always-on tool mode plus an on-demand `#execute <tool>` escape hatch for ad-hoc automations.
|
- Optional always-on tool mode plus an on-demand `#execute <tool>` escape hatch for ad-hoc automations.
|
||||||
- Higher-level agents (`FixedStrategyAgent` so far) that can string multiple tools together via `#agent <spec>`.
|
- Higher-level agents (`fixed`, `loop`) that can string multiple tools together via `#agent <spec>`.
|
||||||
- Built-in tools (`SimpleTool`, `ExploreTool`, `CommunicationTool`, `MovementTool`, `IntelligentCommunicationTool`) with a pluggable interface for custom behaviours.
|
- Built-in tools (`SimpleTool`, `ExploreTool`, `CommunicationTool`, `MovementTool`, `IntelligentCommunicationTool`) with a pluggable interface for custom behaviours.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
@ -50,6 +50,14 @@ Python-based Telnet helper for connecting to MUD servers, handling login flows,
|
||||||
|
|
||||||
This example uses the fixed strategy agent to run `move` and then `explore` once. The first token after `#agent` selects the agent type (`fixed` today, more to come), and any remaining text is passed as that agent's configuration.
|
This example uses the fixed strategy agent to run `move` and then `explore` once. The first token after `#agent` selects the agent type (`fixed` today, more to come), and any remaining text is passed as that agent's configuration.
|
||||||
|
|
||||||
|
7. To run a looping agent that repeats tools, use:
|
||||||
|
|
||||||
|
```text
|
||||||
|
#agent loop move,explore
|
||||||
|
```
|
||||||
|
|
||||||
|
Append `:delay` to pause between iterations, e.g. `#agent loop move,explore:2.5`.
|
||||||
|
|
||||||
## Environment Variables
|
## Environment Variables
|
||||||
|
|
||||||
All variables can be placed in the `.env` file (one `KEY=value` per line) or provided through the shell environment.
|
All variables can be placed in the `.env` file (one `KEY=value` per line) or provided through the shell environment.
|
||||||
|
|
|
||||||
37
agents.py
37
agents.py
|
|
@ -2,9 +2,10 @@ from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
|
import itertools
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from threading import Event
|
from threading import Event
|
||||||
from typing import Callable, Iterable
|
from typing import Callable
|
||||||
|
|
||||||
|
|
||||||
ToolInvoker = Callable[[str], bool]
|
ToolInvoker = Callable[[str], bool]
|
||||||
|
|
@ -39,6 +40,30 @@ class FixedStrategyAgent(Agent):
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class LoopAgent(Agent):
|
||||||
|
"""Continuously execute a fixed strategy until stopped."""
|
||||||
|
|
||||||
|
plan: str
|
||||||
|
delay: float = 0.0
|
||||||
|
|
||||||
|
def run(self, *, invoke_tool: ToolInvoker, stop_event: Event) -> None:
|
||||||
|
steps = [part.strip() for part in self.plan.split(",") if part.strip()]
|
||||||
|
if not steps:
|
||||||
|
print("[Agent] No tools configured for loop strategy", file=sys.stderr)
|
||||||
|
return
|
||||||
|
|
||||||
|
for step in itertools.cycle(steps):
|
||||||
|
if stop_event.is_set():
|
||||||
|
break
|
||||||
|
success = invoke_tool(step)
|
||||||
|
if not success:
|
||||||
|
break
|
||||||
|
if self.delay > 0:
|
||||||
|
if stop_event.wait(self.delay):
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
def build_agent(spec: str) -> Agent:
|
def build_agent(spec: str) -> Agent:
|
||||||
normalized = spec.strip()
|
normalized = spec.strip()
|
||||||
if not normalized:
|
if not normalized:
|
||||||
|
|
@ -50,5 +75,15 @@ def build_agent(spec: str) -> Agent:
|
||||||
|
|
||||||
if kind in {"fixed", "strategy", "fixedstrategy"}:
|
if kind in {"fixed", "strategy", "fixedstrategy"}:
|
||||||
return FixedStrategyAgent(config)
|
return FixedStrategyAgent(config)
|
||||||
|
if kind in {"loop", "cycle"}:
|
||||||
|
delay = 0.0
|
||||||
|
if ":" in config:
|
||||||
|
plan, delay_str = config.split(":", 1)
|
||||||
|
config = plan.strip()
|
||||||
|
try:
|
||||||
|
delay = float(delay_str.strip())
|
||||||
|
except ValueError:
|
||||||
|
print(f"[Agent] Invalid delay '{delay_str}', defaulting to 0")
|
||||||
|
return LoopAgent(config, delay=delay)
|
||||||
|
|
||||||
raise RuntimeError(f"Unknown agent type '{kind}'")
|
raise RuntimeError(f"Unknown agent type '{kind}'")
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue