feat: agent with loop strategy

This commit is contained in:
Daniel Eder 2025-09-28 11:14:44 +02:00
parent 905e3c91ab
commit a2b7feec16
2 changed files with 45 additions and 2 deletions

View file

@ -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.

View file

@ -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}'")