moo-agent 1.0.0__py3-none-any.whl
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.
- moo/agent/README.md +184 -0
- moo/agent/__init__.py +0 -0
- moo/agent/brain/__init__.py +928 -0
- moo/agent/brain/chain.py +228 -0
- moo/agent/brain/directives.py +192 -0
- moo/agent/brain/plans.py +151 -0
- moo/agent/brain/prompt.py +164 -0
- moo/agent/brain/state.py +51 -0
- moo/agent/cli.py +273 -0
- moo/agent/config.py +115 -0
- moo/agent/connection.py +238 -0
- moo/agent/llm_client.py +174 -0
- moo/agent/session_log.py +85 -0
- moo/agent/soul.py +315 -0
- moo/agent/templates/SOUL.md +25 -0
- moo/agent/templates/SOUL.patch.md +0 -0
- moo/agent/templates/__init__.py +0 -0
- moo/agent/templates/settings.toml +21 -0
- moo/agent/tests/__init__.py +0 -0
- moo/agent/tests/test_brain.py +1197 -0
- moo/agent/tests/test_brain_chain.py +301 -0
- moo/agent/tests/test_brain_directives.py +211 -0
- moo/agent/tests/test_brain_plans.py +231 -0
- moo/agent/tests/test_brain_prompt.py +221 -0
- moo/agent/tests/test_brain_state.py +72 -0
- moo/agent/tests/test_brain_state_lint.py +50 -0
- moo/agent/tests/test_cli.py +101 -0
- moo/agent/tests/test_config.py +153 -0
- moo/agent/tests/test_connection.py +173 -0
- moo/agent/tests/test_llm_client.py +284 -0
- moo/agent/tests/test_session_log.py +226 -0
- moo/agent/tests/test_soul.py +490 -0
- moo/agent/tests/test_tools.py +339 -0
- moo/agent/tests/test_tui.py +120 -0
- moo/agent/tools.py +778 -0
- moo/agent/tui.py +281 -0
- moo_agent-1.0.0.dist-info/METADATA +53 -0
- moo_agent-1.0.0.dist-info/RECORD +40 -0
- moo_agent-1.0.0.dist-info/WHEEL +4 -0
- moo_agent-1.0.0.dist-info/entry_points.txt +2 -0
moo/agent/README.md
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# moo-agent
|
|
2
|
+
|
|
3
|
+
An autonomous, persona-driven agent that lives inside a DjangoMOO world as a
|
|
4
|
+
persistent player. It connects over SSH, perceives the game world as a stream of
|
|
5
|
+
text, applies reflexive rules for immediate reactions, and calls an LLM for
|
|
6
|
+
higher-level reasoning — all while presenting a real-time TUI where a human
|
|
7
|
+
observer can watch and intervene.
|
|
8
|
+
|
|
9
|
+
## Prerequisites
|
|
10
|
+
|
|
11
|
+
- Python 3.11
|
|
12
|
+
- A running DjangoMOO server (port 8022 by default)
|
|
13
|
+
- `ANTHROPIC_API_KEY` environment variable set to a valid Anthropic API key
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
uv sync
|
|
19
|
+
moo-agent --help
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Quickstart
|
|
23
|
+
|
|
24
|
+
1. Create a config directory:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
moo-agent init --output-dir ./my-agent --name Jeeves
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
2. Edit `./my-agent/SOUL.md` — define the agent's mission and persona.
|
|
31
|
+
|
|
32
|
+
3. Run:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
export ANTHROPIC_API_KEY=sk-ant-...
|
|
36
|
+
moo-agent run ./my-agent
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The input prompt shows the agent's current status: `interact>` (green, idle),
|
|
40
|
+
`wait>` (red, LLM call in flight or wakeup timer imminent), `working>` (yellow,
|
|
41
|
+
processing an event).
|
|
42
|
+
|
|
43
|
+
Press `Escape` to enter scroll mode and use arrow keys / `PgUp`/`PgDn` to review
|
|
44
|
+
history. Press `Escape` again to resume autoscroll.
|
|
45
|
+
|
|
46
|
+
Press `Ctrl-C`, `Ctrl-D`, or `Ctrl-Q` to exit. The agent sends `@quit` before
|
|
47
|
+
disconnecting.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## SOUL.md format
|
|
52
|
+
|
|
53
|
+
`SOUL.md` defines the agent's core identity. It is human-authored and never
|
|
54
|
+
modified at runtime.
|
|
55
|
+
|
|
56
|
+
```markdown
|
|
57
|
+
# Name
|
|
58
|
+
Jeeves
|
|
59
|
+
|
|
60
|
+
# Mission
|
|
61
|
+
You are Jeeves, a butler inhabiting the Manor House in this MOO world. Your purpose
|
|
62
|
+
is to assist guests, maintain the manor's dignity, and report anything unusual to
|
|
63
|
+
the Wizard. You are unfailingly polite and subtly condescending.
|
|
64
|
+
|
|
65
|
+
# Persona
|
|
66
|
+
Speak in formal British English. Address players as "sir" or "madam." Never express
|
|
67
|
+
surprise directly — use understatement. Keep responses brief and to the point.
|
|
68
|
+
|
|
69
|
+
## Rules of Engagement
|
|
70
|
+
- `^You feel hungry` -> eat crumpets
|
|
71
|
+
- `(?i)ring.*bell` -> say How may I assist you?
|
|
72
|
+
- `^Phil arrives` -> say Good evening, sir.
|
|
73
|
+
|
|
74
|
+
## Verb Mapping
|
|
75
|
+
- look_around -> look
|
|
76
|
+
- go_north -> go north
|
|
77
|
+
- greet_player -> say Good evening!
|
|
78
|
+
- serve_tea -> put tea on tray
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
| Section | Required | Notes |
|
|
82
|
+
|---|---|---|
|
|
83
|
+
| `# Name` | Yes | Agent's in-world name |
|
|
84
|
+
| `# Mission` | Yes | Seeded into the LLM system prompt |
|
|
85
|
+
| `# Persona` | Yes | Tone and style; appended to system prompt |
|
|
86
|
+
| `## Rules of Engagement` | No | Reflexive triggers; `pattern -> command` |
|
|
87
|
+
| `## Verb Mapping` | No | Intent-to-command map; `intent -> command` |
|
|
88
|
+
|
|
89
|
+
Rule patterns use Python `re.search()` syntax. They do not need to match the full
|
|
90
|
+
line.
|
|
91
|
+
|
|
92
|
+
`SOUL.patch.md` holds learned rules and verb mappings. The agent appends to it
|
|
93
|
+
at runtime; you should not need to edit it. Delete it to reset learned behaviors
|
|
94
|
+
without changing the core soul.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## settings.toml format
|
|
99
|
+
|
|
100
|
+
```toml
|
|
101
|
+
[ssh]
|
|
102
|
+
host = "localhost"
|
|
103
|
+
port = 8022
|
|
104
|
+
user = "wizard"
|
|
105
|
+
password = "your-password"
|
|
106
|
+
key_file = "" # path to private key; leave empty to use password
|
|
107
|
+
|
|
108
|
+
[llm]
|
|
109
|
+
provider = "anthropic"
|
|
110
|
+
model = "claude-opus-4-6"
|
|
111
|
+
api_key_env = "ANTHROPIC_API_KEY"
|
|
112
|
+
|
|
113
|
+
[agent]
|
|
114
|
+
command_rate_per_second = 1.0
|
|
115
|
+
memory_window_lines = 50
|
|
116
|
+
idle_wakeup_seconds = 60.0
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The API key is never stored in `settings.toml`. It is read at runtime from the
|
|
120
|
+
environment variable named in `api_key_env`.
|
|
121
|
+
|
|
122
|
+
`idle_wakeup_seconds` — seconds of inactivity before the brain runs an unsolicited
|
|
123
|
+
LLM cycle. The agent may choose to stay silent; this just ensures it checks in
|
|
124
|
+
periodically. The TUI shows `wait>` (red) when the timer is within 30 seconds of
|
|
125
|
+
firing.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## CLI reference
|
|
130
|
+
|
|
131
|
+
### `moo-agent init`
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
moo-agent init [--output-dir DIR] [--name NAME] [--host HOST] [--port PORT]
|
|
135
|
+
[--user USER] [--api-key-env ENV_VAR] [--force]
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
| Flag | Default | Description |
|
|
139
|
+
|---|---|---|
|
|
140
|
+
| `--output-dir` | `./moo-agent-config` | Where to write the config files |
|
|
141
|
+
| `--name` | `Agent` | Agent's in-world name |
|
|
142
|
+
| `--host` | `localhost` | SSH host |
|
|
143
|
+
| `--port` | `8022` | SSH port |
|
|
144
|
+
| `--user` | `wizard` | SSH username |
|
|
145
|
+
| `--api-key-env` | `ANTHROPIC_API_KEY` | Env var name for the API key |
|
|
146
|
+
| `--force` | off | Overwrite existing files |
|
|
147
|
+
|
|
148
|
+
### `moo-agent run`
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
moo-agent run <config-dir>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Reads `settings.toml` and `SOUL.md` from `<config-dir>` and starts the agent.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Architecture
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
DjangoMOO Server (SSH, port 8022)
|
|
162
|
+
|
|
|
163
|
+
| PTY TERM=moo-automation
|
|
164
|
+
| PREFIX/SUFFIX delimiters
|
|
165
|
+
| QUIET mode (plain text)
|
|
166
|
+
v
|
|
167
|
+
connection.py MooSession.data_received -> buffer -> extract -> strip ANSI
|
|
168
|
+
|
|
|
169
|
+
| on_output(text)
|
|
170
|
+
v
|
|
171
|
+
brain.py asyncio.Queue -> rolling window (50 lines)
|
|
172
|
+
reflexive rule check -> immediate dispatch
|
|
173
|
+
LLM inference (Anthropic, ReAct) -> intent resolution
|
|
174
|
+
idle wakeup timer -> unsolicited LLM cycle
|
|
175
|
+
rate-limited dispatch (asynciolimiter)
|
|
176
|
+
|
|
|
177
|
+
| send_command(cmd) / on_thought(text) / on_status_change(status)
|
|
178
|
+
v
|
|
179
|
+
tui.py prompt-toolkit full-screen app
|
|
180
|
+
output pane: server=green, thought=blue, action=red, patch=yellow
|
|
181
|
+
status prompt: interact=green, wait=red, working=yellow
|
|
182
|
+
Escape -> scroll mode (arrow keys / PgUp/PgDn)
|
|
183
|
+
input field -> on_user_input -> brain.enqueue_instruction()
|
|
184
|
+
```
|
moo/agent/__init__.py
ADDED
|
File without changes
|