feat: autoplay mode
This commit is contained in:
parent
9af879eadc
commit
348398616a
7 changed files with 88 additions and 8 deletions
7
GOAL.md
Normal file
7
GOAL.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
Explore cautiously and map nearby rooms.
|
||||
|
||||
Priorities:
|
||||
- Avoid obvious combat when possible.
|
||||
- Prefer gathering room information before moving.
|
||||
- Respond politely to direct tells.
|
||||
- Keep actions short and reversible.
|
||||
|
|
@ -87,6 +87,7 @@ All variables can be placed in the `.env` file (one `KEY=value` per line) or pro
|
|||
| `MISTLE_TOOL_MODE` | ❌ | Enable full-time tool thread when set to truthy values (`1`, `true`, `yes`, `on`). Defaults to interactive-only mode. |
|
||||
| `MISTLE_TOOL` | ❌ | Select which tool class to instantiate when tool mode is active. Accepted values: `look` (default, alias `simple`), `explore`, `communication`, `movement`, `intelligent`/`intelligentcommunication` (LLM-backed), or custom spec `module:ClassName`. |
|
||||
| `MISTLE_SIDELOAD_TOOL` | ❌ | Comma-separated list of tool specs that should always run in the background (same syntax as `MISTLE_TOOL`). Useful for running `intelligent` alongside another primary tool. |
|
||||
| `MISTLE_AUTOPLAY` | ❌ | When truthy (`1`, `true`, `yes`, `on`), starts an intelligent agent automatically at startup and injects instructions from `GOAL.md`. |
|
||||
| `MISTLE_LLM_MODEL` | ❌ | Override the `litellm` model used by the intelligent tool (defaults to `mistral/mistral-small-2407`). |
|
||||
| `MISTRAL_API_KEY` | ❌ | API key used by `IntelligentCommunicationTool` (via `litellm`) when calling the `mistral/mistral-small-2407` model. |
|
||||
|
||||
|
|
@ -96,6 +97,12 @@ All variables can be placed in the `.env` file (one `KEY=value` per line) or pro
|
|||
- This applies to both the intelligent agent and the intelligent communication tool.
|
||||
- If `SYSTEM.md` is missing or empty, the app falls back to built-in defaults and logs a warning.
|
||||
|
||||
## Goal File
|
||||
|
||||
- `GOAL.md` is used when autoplay is enabled (`MISTLE_AUTOPLAY=true`).
|
||||
- On startup, the app launches the intelligent agent automatically and passes the contents of `GOAL.md` as runtime instructions.
|
||||
- If `GOAL.md` is missing or empty, autoplay still starts but without extra instructions.
|
||||
|
||||
## Tool Development
|
||||
|
||||
- Implement new tools by subclassing `tools.Tool` and overriding `observe()` and `decide()`.
|
||||
|
|
|
|||
|
|
@ -9,10 +9,13 @@ Your goal is to level up as much as possible and explore the world.
|
|||
|
||||
## Tool Usage
|
||||
Use tools only when appropriate. Think how you can solve problems without
|
||||
using a tool. Do not use the "exploration" tool multiple times in a row.
|
||||
using a tool. Only use the "explore" tool as a last resort to gather information
|
||||
as it requires a lot of time to run.
|
||||
|
||||
## Mud Commands
|
||||
The following MUD commands may be helpful to you
|
||||
schau - get a description of the current environment
|
||||
info - examine your own stats
|
||||
hilfe - get additional help in general and about specific commands
|
||||
hilfe - get additional help in general and about specific commands
|
||||
untersuche - examine a single object or detail in the current room or your inventory
|
||||
inv - show your current inventory
|
||||
29
app.py
29
app.py
|
|
@ -6,6 +6,7 @@ from typing import Optional
|
|||
|
||||
from agent_runtime import run_agent
|
||||
from agents import Agent, build_agent
|
||||
from goal_loader import load_goal_instructions
|
||||
from mud_env import load_env_file, read_connection_settings, read_tool_settings
|
||||
from mud_session import (
|
||||
SessionState,
|
||||
|
|
@ -148,7 +149,10 @@ def main() -> int:
|
|||
print(f"[Agent] Failed to configure '{spec}': {exc}", file=sys.stderr)
|
||||
return
|
||||
|
||||
_prime_agent(temp_agent, state.snapshot_output())
|
||||
_start_agent_thread(temp_agent, label=spec)
|
||||
|
||||
def _start_agent_thread(agent: Agent, *, label: str) -> None:
|
||||
_prime_agent(agent, state.snapshot_output())
|
||||
|
||||
def run_tool_instance(tool: Tool) -> bool:
|
||||
run_tool_loop(
|
||||
|
|
@ -160,12 +164,12 @@ def main() -> int:
|
|||
auto_stop=True,
|
||||
auto_stop_idle=AUTO_STOP_IDLE_SECONDS,
|
||||
)
|
||||
_prime_agent(temp_agent, state.snapshot_output())
|
||||
_prime_agent(agent, state.snapshot_output())
|
||||
return True
|
||||
|
||||
thread = Thread(
|
||||
target=run_agent,
|
||||
args=(temp_agent,),
|
||||
args=(agent,),
|
||||
kwargs={
|
||||
"build_tool": build_tool,
|
||||
"run_tool": run_tool_instance,
|
||||
|
|
@ -175,9 +179,26 @@ def main() -> int:
|
|||
daemon=True,
|
||||
)
|
||||
agent_threads.append(thread)
|
||||
print(f"[Agent] Executing {spec!r}")
|
||||
print(f"[Agent] Executing {label!r}")
|
||||
thread.start()
|
||||
|
||||
if tool_settings.autoplay:
|
||||
try:
|
||||
autoplay_agent = build_agent("intelligent", allowed_tools=TOOL_DESCRIPTIONS)
|
||||
except RuntimeError as exc:
|
||||
print(f"[Autoplay] Failed to configure intelligent agent: {exc}", file=sys.stderr)
|
||||
else:
|
||||
goal = load_goal_instructions()
|
||||
if goal:
|
||||
setattr(autoplay_agent, "instruction", goal)
|
||||
print("[Autoplay] Loaded instructions from GOAL.md")
|
||||
else:
|
||||
print(
|
||||
"[Autoplay] GOAL.md missing or empty; starting without extra instructions",
|
||||
file=sys.stderr,
|
||||
)
|
||||
_start_agent_thread(autoplay_agent, label="intelligent (autoplay)")
|
||||
|
||||
interrupted = False
|
||||
try:
|
||||
interactive_session(
|
||||
|
|
|
|||
13
goal_loader.py
Normal file
13
goal_loader.py
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def load_goal_instructions(path: str = "GOAL.md") -> str:
|
||||
goal_path = Path(path)
|
||||
if not goal_path.exists():
|
||||
return ""
|
||||
try:
|
||||
return goal_path.read_text(encoding="utf-8").strip()
|
||||
except OSError: # pragma: no cover - environment specific
|
||||
return ""
|
||||
|
|
@ -20,6 +20,7 @@ class ToolSettings:
|
|||
tool_mode: bool
|
||||
tool_spec: str
|
||||
sideload_specs: list[str]
|
||||
autoplay: bool
|
||||
|
||||
|
||||
def load_env_file(path: str = ".env") -> None:
|
||||
|
|
@ -83,8 +84,10 @@ def read_tool_settings() -> ToolSettings:
|
|||
tool_mode = parse_bool(os.environ.get("MISTLE_TOOL_MODE", ""))
|
||||
tool_spec = os.environ.get("MISTLE_TOOL", "")
|
||||
sideload_specs = parse_csv(os.environ.get("MISTLE_SIDELOAD_TOOL", ""))
|
||||
autoplay = parse_bool(os.environ.get("MISTLE_AUTOPLAY", ""))
|
||||
return ToolSettings(
|
||||
tool_mode=tool_mode,
|
||||
tool_spec=tool_spec,
|
||||
sideload_specs=sideload_specs,
|
||||
autoplay=autoplay,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ from textual.widgets import Footer, Header, Input, Label, Log, Static
|
|||
|
||||
from agent_runtime import run_agent
|
||||
from agents import Agent, build_agent
|
||||
from goal_loader import load_goal_instructions
|
||||
from mud_env import load_env_file, read_connection_settings, read_tool_settings
|
||||
from mud_session import SessionState, graceful_shutdown, login, run_tool_loop
|
||||
from mud_tools import TOOL_DESCRIPTIONS, build_tool
|
||||
|
|
@ -196,6 +197,9 @@ class MudUI(App):
|
|||
sideload_seen.add(lowered)
|
||||
self._launch_persistent_tool(spec)
|
||||
|
||||
if tool_settings.autoplay:
|
||||
self._start_autoplay_agent()
|
||||
|
||||
self._set_status(f"Connected to {connection.host}:{connection.port}")
|
||||
self.input.focus()
|
||||
self.log_mud(f"Connected to {connection.host}:{connection.port}")
|
||||
|
|
@ -326,7 +330,28 @@ class MudUI(App):
|
|||
self.log_brain(f"[Agent] Failed to configure '{spec}': {exc}")
|
||||
return
|
||||
|
||||
self.log_brain(f"[Agent] Executing {spec!r}")
|
||||
self._start_agent_instance(agent, label=spec)
|
||||
|
||||
def _start_autoplay_agent(self) -> None:
|
||||
try:
|
||||
autoplay_agent = build_agent("intelligent", allowed_tools=TOOL_DESCRIPTIONS)
|
||||
except RuntimeError as exc:
|
||||
self.log_brain(f"[Autoplay] Failed to configure intelligent agent: {exc}")
|
||||
return
|
||||
|
||||
goal = load_goal_instructions()
|
||||
if goal:
|
||||
setattr(autoplay_agent, "instruction", goal)
|
||||
self.log_brain("[Autoplay] Loaded instructions from GOAL.md")
|
||||
else:
|
||||
self.log_brain(
|
||||
"[Autoplay] GOAL.md missing or empty; starting without extra instructions"
|
||||
)
|
||||
|
||||
self._start_agent_instance(autoplay_agent, label="intelligent (autoplay)")
|
||||
|
||||
def _start_agent_instance(self, agent: Agent, *, label: str) -> None:
|
||||
self.log_brain(f"[Agent] Executing {label!r}")
|
||||
self._prime_agent(agent)
|
||||
|
||||
def run_tool_instance(tool: Tool) -> bool:
|
||||
|
|
@ -355,7 +380,8 @@ class MudUI(App):
|
|||
stop_event=self._stop_event,
|
||||
)
|
||||
|
||||
self._start_worker(run, name=f"agent-{spec}")
|
||||
worker_name = f"agent-{label.replace(' ', '-').lower()}"
|
||||
self._start_worker(run, name=worker_name)
|
||||
|
||||
def _prime_agent(self, agent: Agent) -> None:
|
||||
last_output = self.state.snapshot_output()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue