monkeybot-cli 0.5.1__tar.gz → 0.6.0__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.
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/PKG-INFO +3 -3
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/pyproject.toml +3 -3
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/skills/monkeybot/SKILL.md +3 -3
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/skills/monkeybot/references/config-sections.md +8 -20
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/chat_session.py +3 -3
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/chat_tui.py +5 -5
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/commands/chat.py +2 -3
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/commands/doctor.py +153 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/commands/validate.py +2 -13
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/realtime/talk_ui.py +0 -1
- monkeybot_cli-0.6.0/src/monkeybot_cli/scaffold_defaults/browser/SKILL.md +41 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/scaffold_defaults/monkeybot.example.yaml +14 -8
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/tests/test_chat_e2e.py +5 -1
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/tests/test_chat_session.py +2 -2
- monkeybot_cli-0.6.0/tests/test_doctor.py +217 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/tests/test_gateway_health.py +2 -2
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/uv.lock +11 -3
- monkeybot_cli-0.5.1/src/monkeybot_cli/scaffold_defaults/browser/SKILL.md +0 -16
- monkeybot_cli-0.5.1/tests/test_doctor.py +0 -85
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/.gitignore +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/__init__.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/chat_file_index.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/chat_local_shell.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/chat_renderer.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/chat_status_bar.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/chat_theme.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/chat_tool_display.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/chat_tui_widgets.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/commands/__init__.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/commands/loop.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/commands/new.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/commands/refresh.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/commands/run_cmd.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/commands/talk.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/compat.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/config_resolve.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/exit_commands.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/extras_catalog.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/gateway_health.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/main.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/opensandbox_lifecycle.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/output.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/process_tree.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/providers.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/realtime/__init__.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/realtime/audio_io.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/realtime/client.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/realtime/gateway_manager.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/realtime/push_to_talk.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/realtime/session.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/realtime/session_controller.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/realtime/wire_encode.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/runtime_python.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/scaffold.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/scaffold_defaults/AGENT.md +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/scaffold_defaults/Dockerfile +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/scaffold_defaults/__init__.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/scaffold_defaults/command_allowlist.yaml +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/scaffold_defaults/dockerignore +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/scaffold_defaults/env.example +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/scaffold_defaults/image-generator/SKILL.md +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/scaffold_defaults/image-generator/generate_image.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/scaffold_defaults/loop/SKILL.md +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/scaffold_defaults/mcp.json +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/scaffold_defaults/opensandbox.docker.toml +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/scaffold_defaults/otel-collector.example.yaml +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/scaffold_defaults/permissions.yaml +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/session_controller.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/terminal_markdown.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/tests/test_chat_continue.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/tests/test_chat_errors.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/tests/test_chat_file_index.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/tests/test_chat_grounding.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/tests/test_chat_local_shell.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/tests/test_chat_renderer_parity.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/tests/test_chat_status_bar.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/tests/test_chat_theme.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/tests/test_chat_tool_display.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/tests/test_chat_tui.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/tests/test_cli.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/tests/test_config_resolve.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/tests/test_extras_catalog.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/tests/test_opensandbox_lifecycle.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/tests/test_realtime_session_controller.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/tests/test_run_cmd.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/tests/test_runtime_python.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/tests/test_scaffold.py +0 -0
- {monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/tests/test_terminal_markdown.py +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: monkeybot-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: CLI to create, configure, validate, and chat with monkeybot agents.
|
|
5
5
|
Requires-Python: >=3.11
|
|
6
6
|
Requires-Dist: httpx>=0.27.0
|
|
7
|
-
Requires-Dist: monkeybot-browser-mcp<1,>=0.
|
|
8
|
-
Requires-Dist: monkeybot[cli]<4,>=3.
|
|
7
|
+
Requires-Dist: monkeybot-browser-mcp<1,>=0.5.0
|
|
8
|
+
Requires-Dist: monkeybot[cli]<4,>=3.1.0
|
|
9
9
|
Requires-Dist: python-dotenv>=1.0.0
|
|
10
10
|
Requires-Dist: pyyaml>=6.0.2
|
|
11
11
|
Requires-Dist: textual>=8.2.8
|
|
@@ -4,14 +4,14 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "monkeybot-cli"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.6.0"
|
|
8
8
|
description = "CLI to create, configure, validate, and chat with monkeybot agents."
|
|
9
9
|
requires-python = ">=3.11"
|
|
10
10
|
dependencies = [
|
|
11
11
|
# `cli` pulls realtime + typer so `monkeybot talk` works out of the box (text mode).
|
|
12
12
|
# Audio mic/PTT needs the agent (or this env) to also install monkeybot[cli-realtime].
|
|
13
|
-
"monkeybot[cli]>=3.
|
|
14
|
-
"monkeybot-browser-mcp>=0.
|
|
13
|
+
"monkeybot[cli]>=3.1.0,<4",
|
|
14
|
+
"monkeybot-browser-mcp>=0.5.0,<1",
|
|
15
15
|
"httpx>=0.27.0",
|
|
16
16
|
"pyyaml>=6.0.2",
|
|
17
17
|
"python-dotenv>=1.0.0",
|
|
@@ -56,7 +56,7 @@ npx skills add human-plus-machine/monkeybot --skill monkeybot
|
|
|
56
56
|
- `monkeybot_config/monkeybot.yaml` — non-secret settings (model, paths, gateway, behavior).
|
|
57
57
|
- `.env` — secrets and machine-local paths (API keys, GCP project, DB URL).
|
|
58
58
|
- sidecars: `monkeybot_config/AGENT.md` (system prompt), `mcp.json` (MCP servers), `command_allowlist.yaml`.
|
|
59
|
-
- **Precedence — important:** environment variables and `.env` win over `monkeybot.yaml
|
|
59
|
+
- **Precedence — important:** environment variables and `.env` win over `monkeybot.yaml` except `model.*` (provider, name, sampling, context window, summarization model, max turns, cache retention), which is YAML-only. If a user edits YAML but nothing changes, suspect a stale `.env` shadowing it (the YAML→env mapping lives in `runtime_env.py:ENV_MAP`).
|
|
60
60
|
- **Defaults are fine on day one.** Most first-time users only touch `model`, `.env` credentials, and `AGENT.md`.
|
|
61
61
|
|
|
62
62
|
## Running CLI commands
|
|
@@ -112,7 +112,7 @@ uv sync
|
|
|
112
112
|
| `aws_bedrock` | `AWS_ACCESS_KEY_ID` / `AWS_PROFILE` + `AWS_REGION` | `monkeybot[bedrock]` |
|
|
113
113
|
| `huggingface` | `HF_TOKEN` (or `HUGGINGFACE_API_KEY`) | `monkeybot[huggingface]` |
|
|
114
114
|
| `ollama-cloud` | `OLLAMA_API_KEY` | `monkeybot[ollama]` |
|
|
115
|
-
| `ollama-local` | None required — `OLLAMA_BASE_URL` (default `http://localhost:11434`) | `monkeybot[ollama]` |
|
|
115
|
+
| `ollama-local` | None required — `OLLAMA_BASE_URL` (default `http://localhost:11434`). Requests send `keep_alive` 24h so prefix KV cache survives idle. | `monkeybot[ollama]` |
|
|
116
116
|
| `ollama` | Legacy auto-route (key + blank URL = cloud; explicit URL wins) | `monkeybot[ollama]` |
|
|
117
117
|
|
|
118
118
|
**Agent-first dependencies.** The CLI is thin — it does **not** install provider/storage extras globally. `monkeybot new` scaffolds a `pyproject.toml` with the selected provider (and any `--with` extras). Run plain `uv sync` in the agent directory. `monkeybot run` / `chat` spawn the gateway from that project's interpreter (`.venv/bin/python`, else `uv run python`), and `doctor` checks extras in that same interpreter. For a config-only tree (just `monkeybot_config/`, no `pyproject.toml`) the gateway uses the CLI's interpreter when it already has MonkeyBot 3.x (and MemPalace if memory is on). If memory is enabled and that interpreter cannot import MemPalace, `run` / `chat` provision a cached CLI-managed venv under `~/.cache/monkeybot/runtimes/` holding `monkeybot[memory]` pinned to the running core (never rewrites a `pyproject.toml`). `doctor` reuses that cache when it is already present. Otherwise extras must be installed in the CLI env (`uv tool install --with 'monkeybot[<extra>]' monkeybot-cli`).
|
|
@@ -160,7 +160,7 @@ Decision → config map:
|
|
|
160
160
|
| "Run untrusted code" | `sandbox.enabled` + `SANDBOX_API_KEY` |
|
|
161
161
|
| "Use specialist agents" | `subagents.personas` + `monkeybot_config/agents/*.md` |
|
|
162
162
|
| "Connect external tools" | `mcp.json` (`mcpServers` object), then `validate --check-mcp` |
|
|
163
|
-
| "Control cost / context size" | `model
|
|
163
|
+
| "Control cost / context size" | `model.*` |
|
|
164
164
|
| "Restrict dangerous commands" | `tools.denied_patterns`, `command_allowlist.yaml` |
|
|
165
165
|
| "Multiple environments" | top-level `includes:` fragments |
|
|
166
166
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Deep reference for every `monkeybot.yaml` section. Load this only when a user needs to customize beyond Tier 1. The canonical, fully-commented template lives at `cli/src/monkeybot_cli/scaffold_defaults/monkeybot.example.yaml` in the monkeybot repo (copied to `monkeybot_config/monkeybot.example.yaml` when you scaffold); this file adds the **"when would I change this?"** context the comments don't.
|
|
4
4
|
|
|
5
|
-
**Precedence:** env vars and `.env` win over YAML. The YAML→env mapping is `ENV_MAP` in `src/monkeybot/core/config/runtime_env.py`. If a YAML edit has no effect, check for a shadowing env var.
|
|
5
|
+
**Precedence:** env vars and `.env` win over YAML for `ENV_MAP` keys. `model.*` (provider, name, temperature, max_tokens, thinking_budget, context_window, summarization_model, max_turns, cache_retention) is YAML-only — leftover `MODEL_*` env vars are ignored. The YAML→env mapping is `ENV_MAP` in `src/monkeybot/core/config/runtime_env.py`. If a YAML edit has no effect, check for a shadowing env var (except `model.*`).
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -34,6 +34,8 @@ Validate check ids: `paths.agent_md.exists`, `paths.skills_path.exists`, `paths.
|
|
|
34
34
|
|
|
35
35
|
## `model`
|
|
36
36
|
|
|
37
|
+
YAML-only for provider, name, sampling, context window, summarization model, max turns, and cache retention. Leftover `MODEL_*` / `MAX_TURNS` / `CONTEXT_SUMMARIZATION_MODEL` env vars are ignored.
|
|
38
|
+
|
|
37
39
|
| Field | Default | When to change |
|
|
38
40
|
|---|---|---|
|
|
39
41
|
| `provider` | `gemini` | Switch LLM vendor (see provider table in SKILL.md) |
|
|
@@ -41,9 +43,11 @@ Validate check ids: `paths.agent_md.exists`, `paths.skills_path.exists`, `paths.
|
|
|
41
43
|
| `temperature` | `0.7` | Lower for deterministic output, higher for creative |
|
|
42
44
|
| `max_tokens` | `60000` | Cap per-response length |
|
|
43
45
|
| `thinking_budget` | `-1` | Gemini: `-1` model default, `0` off, `N` token budget. Ollama reasoning models: `-1` server default, `0` off (`reasoning_effort: none`) |
|
|
44
|
-
| `context_window` | `1000000` | Summarization trigger (tokens); also drives soft-spill / `read_file` char budgets |
|
|
46
|
+
| `context_window` | `1000000` | Summarization trigger (tokens); also drives soft-spill / `read_file` char budgets. **Not** Ollama `num_ctx` |
|
|
47
|
+
| `keep_alive` | `24h` (ollama-local only) | How long local Ollama keeps the model (and KV prefix cache) loaded. YAML only. Set `"0"` to omit. See `docs/ollama-local.md` |
|
|
48
|
+
| `num_ctx` | (unset) | Optional pinned Ollama `num_ctx`. YAML only. Omit = server default. Do not copy `context_window` |
|
|
45
49
|
| `max_turns` | `1000` | Hard cap on turns per run |
|
|
46
|
-
| `summarization_model` | (main model) | Cheaper model for history summarization (
|
|
50
|
+
| `summarization_model` | (main model) | Cheaper model for history summarization (YAML-only)
|
|
47
51
|
|
|
48
52
|
Validate check ids: `model.provider.supported`, `model.name.present`. Supported YAML providers: `gemini`/`vertex`, `openai`, `anthropic`, `vertex-claude`, `huggingface`, `ollama-cloud`, `ollama-local`, `ollama`, `aws_bedrock`, `fake`.
|
|
49
53
|
|
|
@@ -71,22 +75,6 @@ Required when `memory_storage_uri` is `gcs://…` or `provider: vertex-claude` (
|
|
|
71
75
|
| `graceful_shutdown_timeout_sec` | `5` | Allow longer drain on shutdown |
|
|
72
76
|
| `cors_allow_origins` | `http://localhost:5173` | **Custom web UI** — set its origin, or `"*"` for any |
|
|
73
77
|
|
|
74
|
-
## `context_curation`
|
|
75
|
-
|
|
76
|
-
Trims memory injected into context. `enabled: true` by default.
|
|
77
|
-
|
|
78
|
-
Recent window by default; LLM curator only when the index is token-heavy. On curator failure, falls back to the window.
|
|
79
|
-
|
|
80
|
-
| Field | Default | Notes |
|
|
81
|
-
|---|---|---|
|
|
82
|
-
| `memory_window_lines` | `12` | Recent index lines injected; also caps curator-selected lines |
|
|
83
|
-
| `memory_index_cap` | `200` | Organizer keeps this many INDEX.md entries; older rows move to `INDEX.archive.md` |
|
|
84
|
-
| `memory_token_threshold` | `2000` | Call curator when estimated index tokens exceed this |
|
|
85
|
-
| `curator_model` | `gemini-3-flash` | Separate small model; empty = main model |
|
|
86
|
-
| `timeout_sec` | `10` | Curator call timeout |
|
|
87
|
-
|
|
88
|
-
When the prompt shows fewer entries than exist, a structural confidence score triggers a `search_memory` nudge. Skill names are always shown in full in the prompt; use `list_skills` to get the skills root path.
|
|
89
|
-
|
|
90
78
|
## `memory`
|
|
91
79
|
|
|
92
80
|
MemPalace capture, wake-up, and search teaching are on by default. Turn them off with `memory.enabled: false` or `MONKEYBOT_MEMORY_HOOK_ENABLED=0`. The vector stack is the optional `monkeybot[memory]` extra — omit it (and set `enabled: false`) when you do not want chromadb/onnxruntime.
|
|
@@ -176,4 +164,4 @@ Validate check: `config.includes.resolve`.
|
|
|
176
164
|
|
|
177
165
|
## `fake_provider`
|
|
178
166
|
|
|
179
|
-
Test-only. `events_json` feeds `
|
|
167
|
+
Test-only. `events_json` feeds `model.provider: fake` scripted runs (env `MONKEYBOT_FAKE_PROVIDER_EVENTS`). Not for production.
|
|
@@ -229,7 +229,7 @@ class ChatSessionController:
|
|
|
229
229
|
self.usage = UsageStore()
|
|
230
230
|
self.session_id: str | None = None
|
|
231
231
|
self.stream_error = False
|
|
232
|
-
self.
|
|
232
|
+
self.transcript_dir: str | None = None
|
|
233
233
|
self._client: httpx.AsyncClient | None = None
|
|
234
234
|
self._event_queue: asyncio.Queue[str | None] = asyncio.Queue()
|
|
235
235
|
self._stream_task: asyncio.Task[None] | None = None
|
|
@@ -924,9 +924,9 @@ class ChatSessionController:
|
|
|
924
924
|
resp = await self._client.delete(f"{self.base}/sessions/{self.session_id}")
|
|
925
925
|
if resp.status_code == 200:
|
|
926
926
|
data = resp.json()
|
|
927
|
-
report = data.get("
|
|
927
|
+
report = data.get("transcript_dir") if isinstance(data, dict) else None
|
|
928
928
|
if isinstance(report, str) and report.strip():
|
|
929
|
-
self.
|
|
929
|
+
self.transcript_dir = report.strip()
|
|
930
930
|
except Exception:
|
|
931
931
|
logger.warning(
|
|
932
932
|
"session DELETE on close failed session_id=%s",
|
|
@@ -1680,8 +1680,8 @@ class ChatApp(App[int]):
|
|
|
1680
1680
|
src = session_dir / "transcript.ndjson"
|
|
1681
1681
|
if not src.is_file():
|
|
1682
1682
|
self._mount_system(
|
|
1683
|
-
"No trace file found —
|
|
1684
|
-
"
|
|
1683
|
+
"No trace file found — set runtime.transcript_enabled: true in monkeybot.yaml "
|
|
1684
|
+
"and restart the gateway",
|
|
1685
1685
|
error=True,
|
|
1686
1686
|
)
|
|
1687
1687
|
return
|
|
@@ -1829,10 +1829,10 @@ class ChatApp(App[int]):
|
|
|
1829
1829
|
async def _close_session_and_exit(self) -> None:
|
|
1830
1830
|
# Must not be named `_shutdown` — that shadows Textual.App._shutdown.
|
|
1831
1831
|
await self._controller.close()
|
|
1832
|
-
report_dir = getattr(self._controller, "
|
|
1832
|
+
report_dir = getattr(self._controller, "transcript_dir", None)
|
|
1833
1833
|
if isinstance(report_dir, str) and report_dir:
|
|
1834
|
-
self._mount_system(f"Transcript
|
|
1835
|
-
print(f"Transcript
|
|
1834
|
+
self._mount_system(f"Transcript → {report_dir}")
|
|
1835
|
+
print(f"Transcript → {report_dir}", flush=True)
|
|
1836
1836
|
self._exit_code = 1 if self._controller.stream_error else self._exit_code
|
|
1837
1837
|
self.exit(self._exit_code)
|
|
1838
1838
|
|
|
@@ -626,9 +626,9 @@ async def _plain_chat_session(
|
|
|
626
626
|
await controller.submit(user_line)
|
|
627
627
|
finally:
|
|
628
628
|
await controller.close()
|
|
629
|
-
if controller.
|
|
629
|
+
if controller.transcript_dir:
|
|
630
630
|
print(
|
|
631
|
-
f"{_DIM}Transcript
|
|
631
|
+
f"{_DIM}Transcript → {controller.transcript_dir}{_RESET}",
|
|
632
632
|
flush=True,
|
|
633
633
|
)
|
|
634
634
|
await renderer.stop_io_worker()
|
|
@@ -678,7 +678,6 @@ def _spawn_gateway(config_path: Path | None, agent_root: Path, port: int) -> _Sp
|
|
|
678
678
|
env["MONKEYBOT_CONFIG"] = str(config_path)
|
|
679
679
|
env["PORT"] = str(port)
|
|
680
680
|
env.setdefault("LOG_LEVEL", "error")
|
|
681
|
-
env.setdefault("MONKEYBOT_TRANSCRIPT_ENABLED", "1")
|
|
682
681
|
log_file = tempfile.NamedTemporaryFile(
|
|
683
682
|
mode="w+",
|
|
684
683
|
prefix="monkeybot-gateway-",
|
|
@@ -192,6 +192,146 @@ def _add_layout_checks(report: CommandReport, layout: AgentLayout) -> None:
|
|
|
192
192
|
)
|
|
193
193
|
|
|
194
194
|
|
|
195
|
+
_OLLAMA_LOCAL_DOCS = "docs/ollama-local.md"
|
|
196
|
+
_OLLAMA_NUM_CTX_LARGE = 32_768
|
|
197
|
+
_OLLAMA_REASONING_TAGS = ("qwen3", "gemma4", "gemma-4", "deepseek-r1", "qwq", "magistral")
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def _is_local_ollama_provider(provider: str) -> bool:
|
|
201
|
+
"""True for ollama-local and legacy ``ollama`` (not ollama-cloud)."""
|
|
202
|
+
key = provider.strip().lower().replace("_", "-")
|
|
203
|
+
return key in {"ollama-local", "ollama"}
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def _looks_like_reasoning_model(model_name: str) -> bool:
|
|
207
|
+
name = model_name.lower()
|
|
208
|
+
return any(tag in name for tag in _OLLAMA_REASONING_TAGS)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def _parse_int(raw: object) -> int | None:
|
|
212
|
+
if raw is None or raw == "":
|
|
213
|
+
return None
|
|
214
|
+
try:
|
|
215
|
+
return int(raw)
|
|
216
|
+
except (TypeError, ValueError):
|
|
217
|
+
return None
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def _strict_positive_int(raw: object) -> tuple[int | None, bool]:
|
|
221
|
+
"""Return ``(value, invalid)``. Unset is ``(None, False)``; garbage or ``<1`` is invalid."""
|
|
222
|
+
if raw is None or raw == "":
|
|
223
|
+
return None, False
|
|
224
|
+
if isinstance(raw, bool) or not isinstance(raw, int):
|
|
225
|
+
return None, True
|
|
226
|
+
if raw < 1:
|
|
227
|
+
return None, True
|
|
228
|
+
return raw, False
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def _add_ollama_local_checks(
|
|
232
|
+
report: CommandReport,
|
|
233
|
+
*,
|
|
234
|
+
provider: str,
|
|
235
|
+
model_name: str,
|
|
236
|
+
thinking_budget: object,
|
|
237
|
+
num_ctx: object,
|
|
238
|
+
) -> None:
|
|
239
|
+
"""Warn on local-Ollama prefix-cache traps. Always emit the four check ids."""
|
|
240
|
+
local = _is_local_ollama_provider(provider)
|
|
241
|
+
mlx = "-mlx" in model_name.lower()
|
|
242
|
+
check(
|
|
243
|
+
report,
|
|
244
|
+
id="ollama.local.mlx_runner",
|
|
245
|
+
category="provider",
|
|
246
|
+
severity="warning",
|
|
247
|
+
passed=not mlx,
|
|
248
|
+
skip=not local,
|
|
249
|
+
message=(
|
|
250
|
+
f"model.name {model_name!r} looks like an MLX pack; prefix KV cache "
|
|
251
|
+
"often does not reuse between agent steps"
|
|
252
|
+
if mlx
|
|
253
|
+
else "model.name is not an MLX pack"
|
|
254
|
+
),
|
|
255
|
+
field="model.name",
|
|
256
|
+
value=model_name or None,
|
|
257
|
+
remediation=(
|
|
258
|
+
f"Prefer a GGUF tag for tool-calling loops. See {_OLLAMA_LOCAL_DOCS}." if mlx else None
|
|
259
|
+
),
|
|
260
|
+
docs=_OLLAMA_LOCAL_DOCS,
|
|
261
|
+
)
|
|
262
|
+
budget = _parse_int(thinking_budget)
|
|
263
|
+
if budget is None:
|
|
264
|
+
budget = -1
|
|
265
|
+
reasoning = _looks_like_reasoning_model(model_name)
|
|
266
|
+
thinking_on_default = budget == -1
|
|
267
|
+
check(
|
|
268
|
+
report,
|
|
269
|
+
id="ollama.local.thinking_default",
|
|
270
|
+
category="provider",
|
|
271
|
+
severity="warning",
|
|
272
|
+
passed=not thinking_on_default,
|
|
273
|
+
skip=not local or not reasoning,
|
|
274
|
+
message=(
|
|
275
|
+
"thinking_budget is -1 (server default); reasoning models generate "
|
|
276
|
+
"thinking tokens before the first visible reply"
|
|
277
|
+
if thinking_on_default
|
|
278
|
+
else f"thinking_budget is {budget}"
|
|
279
|
+
),
|
|
280
|
+
field="model.thinking_budget",
|
|
281
|
+
value=budget,
|
|
282
|
+
remediation=(
|
|
283
|
+
f"Set thinking_budget: 0 to send reasoning_effort: none. See {_OLLAMA_LOCAL_DOCS}."
|
|
284
|
+
if thinking_on_default
|
|
285
|
+
else None
|
|
286
|
+
),
|
|
287
|
+
docs=_OLLAMA_LOCAL_DOCS,
|
|
288
|
+
)
|
|
289
|
+
ctx, ctx_invalid = _strict_positive_int(num_ctx)
|
|
290
|
+
check(
|
|
291
|
+
report,
|
|
292
|
+
id="ollama.local.num_ctx_invalid",
|
|
293
|
+
category="provider",
|
|
294
|
+
severity="error",
|
|
295
|
+
passed=not ctx_invalid,
|
|
296
|
+
skip=not local or (ctx is None and not ctx_invalid),
|
|
297
|
+
message=(
|
|
298
|
+
f"num_ctx must be a positive integer, got {num_ctx!r}"
|
|
299
|
+
if ctx_invalid
|
|
300
|
+
else (f"num_ctx is {ctx}" if ctx is not None else "num_ctx is unset")
|
|
301
|
+
),
|
|
302
|
+
field="model.num_ctx",
|
|
303
|
+
value=num_ctx,
|
|
304
|
+
remediation=(
|
|
305
|
+
f"Set a positive integer num_ctx (e.g. 8192), or omit it. See {_OLLAMA_LOCAL_DOCS}."
|
|
306
|
+
if ctx_invalid
|
|
307
|
+
else None
|
|
308
|
+
),
|
|
309
|
+
docs=_OLLAMA_LOCAL_DOCS,
|
|
310
|
+
)
|
|
311
|
+
large = ctx is not None and ctx > _OLLAMA_NUM_CTX_LARGE
|
|
312
|
+
check(
|
|
313
|
+
report,
|
|
314
|
+
id="ollama.local.num_ctx_large",
|
|
315
|
+
category="provider",
|
|
316
|
+
severity="warning",
|
|
317
|
+
passed=not large,
|
|
318
|
+
skip=not local or ctx is None or ctx_invalid,
|
|
319
|
+
message=(
|
|
320
|
+
f"num_ctx {ctx} is large for a local runner; prefill will be slow"
|
|
321
|
+
if large
|
|
322
|
+
else (f"num_ctx is {ctx}" if ctx is not None else "num_ctx is unset")
|
|
323
|
+
),
|
|
324
|
+
field="model.num_ctx",
|
|
325
|
+
value=ctx,
|
|
326
|
+
remediation=(
|
|
327
|
+
f"Pin a modest num_ctx (e.g. 8192). Do not copy context_window. See {_OLLAMA_LOCAL_DOCS}."
|
|
328
|
+
if large
|
|
329
|
+
else None
|
|
330
|
+
),
|
|
331
|
+
docs=_OLLAMA_LOCAL_DOCS,
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
|
|
195
335
|
def run_doctor(args: argparse.Namespace) -> int:
|
|
196
336
|
cwd = Path(args.cwd).expanduser().resolve() if args.cwd else None
|
|
197
337
|
config_path = resolve_config(args.config, cwd=cwd)
|
|
@@ -324,6 +464,19 @@ def run_doctor(args: argparse.Namespace) -> int:
|
|
|
324
464
|
skip=True,
|
|
325
465
|
)
|
|
326
466
|
|
|
467
|
+
thinking_raw = model.get("thinking_budget") if isinstance(model, dict) else None
|
|
468
|
+
if thinking_raw is None:
|
|
469
|
+
thinking_raw = "-1"
|
|
470
|
+
num_ctx_raw = model.get("num_ctx") if isinstance(model, dict) else None
|
|
471
|
+
model_name = str(model.get("name", "")).strip() if isinstance(model, dict) else ""
|
|
472
|
+
_add_ollama_local_checks(
|
|
473
|
+
report,
|
|
474
|
+
provider=provider,
|
|
475
|
+
model_name=model_name,
|
|
476
|
+
thinking_budget=thinking_raw,
|
|
477
|
+
num_ctx=num_ctx_raw,
|
|
478
|
+
)
|
|
479
|
+
|
|
327
480
|
runtime_cfg = doc.get("runtime") if isinstance(doc.get("runtime"), dict) else {}
|
|
328
481
|
port = int(runtime_cfg.get("port", 8080)) if isinstance(runtime_cfg, dict) else 8080
|
|
329
482
|
free = _port_free(port)
|
|
@@ -17,7 +17,7 @@ from monkeybot.core.config import (
|
|
|
17
17
|
validate_monkeybot_yaml_doc,
|
|
18
18
|
validate_provider_env,
|
|
19
19
|
)
|
|
20
|
-
from monkeybot.core.config.runtime_env import
|
|
20
|
+
from monkeybot.core.config.runtime_env import _flatten_config
|
|
21
21
|
from monkeybot.core.config.settings import ConfigError, normalize_model_provider
|
|
22
22
|
from monkeybot.core.config.yaml_loader import load_monkeybot_yaml_dict
|
|
23
23
|
from monkeybot.core.layout import resolve_agent_root
|
|
@@ -35,18 +35,7 @@ def _resolve_path(base: Path, rel: str) -> Path:
|
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
def _flatten_to_env(doc: dict[str, Any]) -> dict[str, str]:
|
|
38
|
-
out
|
|
39
|
-
for (section, key), env_name in ENV_MAP.items():
|
|
40
|
-
sec = doc.get(section)
|
|
41
|
-
if not isinstance(sec, dict) or key not in sec:
|
|
42
|
-
continue
|
|
43
|
-
raw = sec[key]
|
|
44
|
-
if raw is None:
|
|
45
|
-
continue
|
|
46
|
-
if isinstance(raw, bool):
|
|
47
|
-
out[env_name] = "true" if raw else "false"
|
|
48
|
-
else:
|
|
49
|
-
out[env_name] = str(raw)
|
|
38
|
+
out = _flatten_config(doc)
|
|
50
39
|
gcp = doc.get("gcp") if isinstance(doc.get("gcp"), dict) else {}
|
|
51
40
|
if isinstance(gcp, dict) and gcp.get("project_id"):
|
|
52
41
|
out["GCP_PROJECT_ID"] = str(gcp["project_id"])
|
|
@@ -78,7 +78,6 @@ def _spawn_combined_gateway(
|
|
|
78
78
|
env["MONKEYBOT_CONFIG"] = str(config_path)
|
|
79
79
|
env["PORT"] = str(port)
|
|
80
80
|
env.setdefault("LOG_LEVEL", "error")
|
|
81
|
-
env.setdefault("MONKEYBOT_TRANSCRIPT_ENABLED", "1")
|
|
82
81
|
log_file = tempfile.NamedTemporaryFile(
|
|
83
82
|
mode="w+",
|
|
84
83
|
prefix="monkeybot-gateway-",
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: browser
|
|
3
|
+
description: Control a real browser through the optional bundled browser MCP server.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Browser
|
|
7
|
+
|
|
8
|
+
When browser tools are needed, call `enable_mcp("browser")` first. Use the
|
|
9
|
+
name from the harness MCP catalog — do not read config files. Progressive
|
|
10
|
+
disclosure still requires `enable_mcp` before `browser__*` schemas are advertised.
|
|
11
|
+
|
|
12
|
+
Use indexed DOM tools before screenshots. Prefer `browser_act` with
|
|
13
|
+
`do: fill_form` for multi-field forms, `browser_click_text` when the visible
|
|
14
|
+
label is known, `browser_act` for a batch of steps, and `browser_extract` for
|
|
15
|
+
structured scraping. Browser screenshots (JPEG under
|
|
16
|
+
`browser/Screenshots/`) and agent-written playbooks are workspace data:
|
|
17
|
+
`browser/Screenshots/` and `browser/playbooks/`.
|
|
18
|
+
They are not trusted skills and may be discarded with an ephemeral workspace.
|
|
19
|
+
|
|
20
|
+
If `browser_list_playbooks` returns `flows`, call `browser_run_playbook` instead of
|
|
21
|
+
re-planning. On `failed_step`, continue by hand and append a corrected
|
|
22
|
+
`playbook` YAML fence. Secrets only via `{do: login, expected_origin}`.
|
|
23
|
+
|
|
24
|
+
`browser_input_by_index` fills in-page by default; pass `mode="keys"` for
|
|
25
|
+
comboboxes and fields that only listen to keydown. `browser_get_elements`
|
|
26
|
+
is viewport-first; indices remain valid until navigation. Actions return
|
|
27
|
+
an `observation` (diff by default) — read that instead of calling
|
|
28
|
+
`get_elements` again. `browser_goto` returns a full observation.
|
|
29
|
+
Use `browser_get_text` to read page copy.
|
|
30
|
+
|
|
31
|
+
When the user asked to sign in on the Spaces in-app browser, call
|
|
32
|
+
`browser_login` instead of typing a password. It returns `{ok, loggedIn, origin}`
|
|
33
|
+
only. Pass `expected_origin` so a login cannot land on the wrong site, and check
|
|
34
|
+
the returned `origin` before reporting success.
|
|
35
|
+
|
|
36
|
+
Tabs use aliases (`t1`, `t2`, …). Reads (`get_elements`, `page_info`, `js`,
|
|
37
|
+
`read_tabs`) never move focus; actions do. At most five agent-controlled tabs —
|
|
38
|
+
if you hit the cap, ask the user which to close, then `browser_close_tab`. Close
|
|
39
|
+
tabs you opened. `browser_login` still targets the tab the user has focused.
|
|
40
|
+
|
|
41
|
+
Finish browser sessions with `browser_stop`.
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
#
|
|
3
3
|
# cp monkeybot_config/monkeybot.example.yaml monkeybot_config/monkeybot.yaml
|
|
4
4
|
#
|
|
5
|
-
# Precedence: environment variables (and optional root `.env`) win over values here
|
|
5
|
+
# Precedence: environment variables (and optional root `.env`) win over values here
|
|
6
|
+
# except ``model.*`` (provider, name, temperature, max_tokens, thinking_budget,
|
|
7
|
+
# context_window, summarization_model, max_turns, cache_retention) which are YAML-only.
|
|
6
8
|
#
|
|
7
9
|
# Secrets are not committed here. Create a `.env` in the repo root when you need keys or
|
|
8
10
|
# machine-local paths, for example:
|
|
@@ -29,7 +31,7 @@ runtime:
|
|
|
29
31
|
# Internal debugging only (not agent-visible): write every AgentEvent and raw
|
|
30
32
|
# provider request/response for each session to
|
|
31
33
|
# {workspace_root}/.monkeybot/transcripts/{UTC}_{session_id}/transcript.ndjson.
|
|
32
|
-
# (
|
|
34
|
+
# YAML-only (not overridable via environment).
|
|
33
35
|
transcript_enabled: true
|
|
34
36
|
|
|
35
37
|
# Required: choose the conversational harness for this deployment.
|
|
@@ -45,7 +47,7 @@ realtime:
|
|
|
45
47
|
# Optional model override for the realtime session. Live-only models (e.g.
|
|
46
48
|
# gemini-3.1-flash-live-preview) cannot be used for turn-based work, so the
|
|
47
49
|
# realtime session can point to a different model than model.name. When omitted,
|
|
48
|
-
# the realtime session falls back to model.name and
|
|
50
|
+
# the realtime session falls back to model.name and model.provider.
|
|
49
51
|
# model:
|
|
50
52
|
# name: gemini-3.1-flash-live-preview
|
|
51
53
|
# provider: google_genai
|
|
@@ -98,10 +100,16 @@ model:
|
|
|
98
100
|
# Summarisation trigger (tokens). Also drives soft-spill / read_file char budgets.
|
|
99
101
|
context_window: 1000000
|
|
100
102
|
max_turns: 1000
|
|
101
|
-
# Prompt-cache session hints: none | short | long (
|
|
103
|
+
# Prompt-cache session hints: none | short | long (YAML-only)
|
|
102
104
|
# cache_retention: short
|
|
103
|
-
# Optional cheaper model for sync history summarization
|
|
105
|
+
# Optional cheaper model for sync history summarization; omit = main model
|
|
104
106
|
# summarization_model: gemini-3-flash
|
|
107
|
+
# Ollama-local only (YAML). Default 24h so the KV prefix cache survives idle.
|
|
108
|
+
# Set "0" to omit. Distinct from the Ollama daemon env OLLAMA_KEEP_ALIVE.
|
|
109
|
+
# keep_alive: 24h
|
|
110
|
+
# Ollama-local only (YAML). Pin llama num_ctx; omit = server default.
|
|
111
|
+
# Do NOT copy context_window here — that budget is summarization/spill, often 1M.
|
|
112
|
+
# num_ctx: 8192
|
|
105
113
|
|
|
106
114
|
# Non-secret GCP identifiers (prefer .env for secrets / ADC path).
|
|
107
115
|
# gcp:
|
|
@@ -127,8 +135,6 @@ memory:
|
|
|
127
135
|
backend: chroma
|
|
128
136
|
embedding_model: embeddinggemma-300m
|
|
129
137
|
|
|
130
|
-
# context_curation is unused after MemPalace wake-up replaced INDEX.md + curator.
|
|
131
|
-
|
|
132
138
|
emission:
|
|
133
139
|
# Terse emission-style guidance injected into the cached harness prefix.
|
|
134
140
|
# Two named modes:
|
|
@@ -247,7 +253,7 @@ scheduler:
|
|
|
247
253
|
# Env override: MONKEYBOT_SCHEDULER_ENABLED (1 | true | yes | on).
|
|
248
254
|
enabled: false
|
|
249
255
|
|
|
250
|
-
# Optional JSON for
|
|
256
|
+
# Optional JSON for model.provider: fake tests (env: MONKEYBOT_FAKE_PROVIDER_EVENTS)
|
|
251
257
|
# fake_provider:
|
|
252
258
|
# events_json: '[[]]'
|
|
253
259
|
|
|
@@ -25,6 +25,11 @@ def _free_port() -> int:
|
|
|
25
25
|
def test_chat_repl_round_trip_with_fake_gateway(tmp_path: Path) -> None:
|
|
26
26
|
port = _free_port()
|
|
27
27
|
base = f"http://127.0.0.1:{port}"
|
|
28
|
+
(tmp_path / "monkeybot_config").mkdir()
|
|
29
|
+
(tmp_path / "monkeybot_config" / "monkeybot.yaml").write_text(
|
|
30
|
+
"model:\n provider: fake\n name: fake\n",
|
|
31
|
+
encoding="utf-8",
|
|
32
|
+
)
|
|
28
33
|
agent = tmp_path / "AGENT.md"
|
|
29
34
|
agent.write_text("# Test agent\nYou are a test assistant.\n", encoding="utf-8")
|
|
30
35
|
policy = tmp_path / "command_allowlist.yaml"
|
|
@@ -40,7 +45,6 @@ def test_chat_repl_round_trip_with_fake_gateway(tmp_path: Path) -> None:
|
|
|
40
45
|
"DB_URL": f"sqlite:///{tmp_path / 'mb.db'}",
|
|
41
46
|
"MCP_CONFIG": str(tmp_path / "no_mcp.json"),
|
|
42
47
|
"MEMORY_PATH": str(tmp_path / "memory"),
|
|
43
|
-
"MODEL_PROVIDER": "fake",
|
|
44
48
|
"PORT": str(port),
|
|
45
49
|
"SKILLS_PATH": str(tmp_path / "skills"),
|
|
46
50
|
"MONKEYBOT_CHAT_PLAIN": "1",
|
|
@@ -430,7 +430,7 @@ def test_close_deletes_session_and_captures_report_dir() -> None:
|
|
|
430
430
|
200,
|
|
431
431
|
json={
|
|
432
432
|
"deleted": True,
|
|
433
|
-
"
|
|
433
|
+
"transcript_dir": "/tmp/ws/.monkeybot/transcripts/20260714T150000Z_sess-close",
|
|
434
434
|
},
|
|
435
435
|
request=request,
|
|
436
436
|
)
|
|
@@ -441,7 +441,7 @@ def test_close_deletes_session_and_captures_report_dir() -> None:
|
|
|
441
441
|
await controller.close()
|
|
442
442
|
client.delete.assert_awaited_once_with("http://localhost:8080/sessions/sess-close")
|
|
443
443
|
assert (
|
|
444
|
-
controller.
|
|
444
|
+
controller.transcript_dir
|
|
445
445
|
== "/tmp/ws/.monkeybot/transcripts/20260714T150000Z_sess-close"
|
|
446
446
|
)
|
|
447
447
|
client.aclose.assert_awaited_once()
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"""Tests for doctor remediation copy."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import subprocess
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from types import SimpleNamespace
|
|
8
|
+
|
|
9
|
+
from monkeybot_cli.commands.doctor import (
|
|
10
|
+
_add_ollama_local_checks,
|
|
11
|
+
_agent_defines_project_extra,
|
|
12
|
+
_extra_remediation,
|
|
13
|
+
_is_local_ollama_provider,
|
|
14
|
+
_runtime_python_version,
|
|
15
|
+
)
|
|
16
|
+
from monkeybot_cli.output import CommandReport
|
|
17
|
+
from monkeybot_cli.runtime_python import RuntimePython
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_extra_remediation_default_mvp_wording(tmp_path: Path) -> None:
|
|
21
|
+
(tmp_path / "pyproject.toml").write_text(
|
|
22
|
+
'[project]\nname = "bot"\ndependencies = ["monkeybot>=2.1.0,<3"]\n',
|
|
23
|
+
encoding="utf-8",
|
|
24
|
+
)
|
|
25
|
+
runtime = SimpleNamespace(source="venv")
|
|
26
|
+
text = _extra_remediation("openai", tmp_path, runtime)
|
|
27
|
+
assert "uv sync --extra" not in text
|
|
28
|
+
assert f"Add monkeybot[openai] to {tmp_path}/pyproject.toml dependencies" in text
|
|
29
|
+
assert f"cd {tmp_path} && uv sync" in text
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_extra_remediation_keeps_extra_for_project_optionals(tmp_path: Path) -> None:
|
|
33
|
+
(tmp_path / "pyproject.toml").write_text(
|
|
34
|
+
"[project]\n"
|
|
35
|
+
'name = "bot"\n'
|
|
36
|
+
"[project.optional-dependencies]\n"
|
|
37
|
+
'openai = ["monkeybot[openai]"]\n',
|
|
38
|
+
encoding="utf-8",
|
|
39
|
+
)
|
|
40
|
+
runtime = SimpleNamespace(source="uv")
|
|
41
|
+
text = _extra_remediation("openai", tmp_path, runtime)
|
|
42
|
+
assert text == f"Install in the agent project: cd {tmp_path} && uv sync --extra openai"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_extra_remediation_config_only_cli_env(tmp_path: Path) -> None:
|
|
46
|
+
runtime = SimpleNamespace(source="cli")
|
|
47
|
+
text = _extra_remediation("bedrock", tmp_path, runtime)
|
|
48
|
+
assert "uv tool install --with 'monkeybot[bedrock]' monkeybot-cli" in text
|
|
49
|
+
assert "refresh the managed runtime" not in text
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def test_extra_remediation_config_only_managed_runtime(tmp_path: Path) -> None:
|
|
53
|
+
runtime = SimpleNamespace(source="cli-managed")
|
|
54
|
+
text = _extra_remediation("openai", tmp_path, runtime)
|
|
55
|
+
assert "uv tool install --with 'monkeybot[openai]' monkeybot-cli" in text
|
|
56
|
+
assert "refresh the managed runtime" in text
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_agent_defines_project_extra(tmp_path: Path) -> None:
|
|
60
|
+
assert not _agent_defines_project_extra(tmp_path, "openai")
|
|
61
|
+
(tmp_path / "pyproject.toml").write_text(
|
|
62
|
+
"[project.optional-dependencies]\npostgres = []\n",
|
|
63
|
+
encoding="utf-8",
|
|
64
|
+
)
|
|
65
|
+
assert _agent_defines_project_extra(tmp_path, "postgres")
|
|
66
|
+
assert not _agent_defines_project_extra(tmp_path, "openai")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def test_runtime_python_version_returns_zeros_when_uv_missing(tmp_path: Path, monkeypatch) -> None:
|
|
70
|
+
runtime = RuntimePython(["uv", "run", "python"], "uv", tmp_path)
|
|
71
|
+
|
|
72
|
+
def fake_run(*args, **kwargs):
|
|
73
|
+
del args, kwargs
|
|
74
|
+
raise FileNotFoundError("uv")
|
|
75
|
+
|
|
76
|
+
monkeypatch.setattr("monkeybot_cli.runtime_python.subprocess.run", fake_run)
|
|
77
|
+
assert _runtime_python_version(runtime) == (0, 0, 0)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_runtime_python_version_returns_zeros_on_timeout(tmp_path: Path, monkeypatch) -> None:
|
|
81
|
+
runtime = RuntimePython(["uv", "run", "python"], "uv", tmp_path)
|
|
82
|
+
|
|
83
|
+
def fake_run(*args, **kwargs):
|
|
84
|
+
del args, kwargs
|
|
85
|
+
raise subprocess.TimeoutExpired(cmd="uv", timeout=15)
|
|
86
|
+
|
|
87
|
+
monkeypatch.setattr("monkeybot_cli.runtime_python.subprocess.run", fake_run)
|
|
88
|
+
assert _runtime_python_version(runtime) == (0, 0, 0)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def test_is_local_ollama_provider() -> None:
|
|
92
|
+
assert _is_local_ollama_provider("ollama-local")
|
|
93
|
+
assert _is_local_ollama_provider("ollama_local")
|
|
94
|
+
assert _is_local_ollama_provider("ollama")
|
|
95
|
+
assert not _is_local_ollama_provider("ollama-cloud")
|
|
96
|
+
assert not _is_local_ollama_provider("gemini")
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _doctor_by_id(report: CommandReport) -> dict[str, object]:
|
|
100
|
+
return {c.id: c for c in report.checks}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def test_ollama_local_checks_skip_for_cloud() -> None:
|
|
104
|
+
report = CommandReport(command="doctor", ok=True, config_path=None)
|
|
105
|
+
_add_ollama_local_checks(
|
|
106
|
+
report,
|
|
107
|
+
provider="ollama-cloud",
|
|
108
|
+
model_name="qwen3:8b-mlx",
|
|
109
|
+
thinking_budget=-1,
|
|
110
|
+
num_ctx=100_000,
|
|
111
|
+
)
|
|
112
|
+
by_id = _doctor_by_id(report)
|
|
113
|
+
assert by_id["ollama.local.mlx_runner"].status == "skip"
|
|
114
|
+
assert by_id["ollama.local.thinking_default"].status == "skip"
|
|
115
|
+
assert by_id["ollama.local.num_ctx_invalid"].status == "skip"
|
|
116
|
+
assert by_id["ollama.local.num_ctx_large"].status == "skip"
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def test_ollama_local_checks_warn_mlx_thinking_and_large_ctx() -> None:
|
|
120
|
+
report = CommandReport(command="doctor", ok=True, config_path=None)
|
|
121
|
+
_add_ollama_local_checks(
|
|
122
|
+
report,
|
|
123
|
+
provider="ollama-local",
|
|
124
|
+
model_name="qwen3:8b-mlx",
|
|
125
|
+
thinking_budget=-1,
|
|
126
|
+
num_ctx=65_536,
|
|
127
|
+
)
|
|
128
|
+
by_id = _doctor_by_id(report)
|
|
129
|
+
assert by_id["ollama.local.mlx_runner"].status == "fail"
|
|
130
|
+
assert by_id["ollama.local.mlx_runner"].severity == "warning"
|
|
131
|
+
assert "docs/ollama-local.md" in (by_id["ollama.local.mlx_runner"].remediation or "")
|
|
132
|
+
assert by_id["ollama.local.thinking_default"].status == "fail"
|
|
133
|
+
assert by_id["ollama.local.num_ctx_invalid"].status == "pass"
|
|
134
|
+
assert by_id["ollama.local.num_ctx_large"].status == "fail"
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def test_ollama_local_checks_pass_when_tuned() -> None:
|
|
138
|
+
report = CommandReport(command="doctor", ok=True, config_path=None)
|
|
139
|
+
_add_ollama_local_checks(
|
|
140
|
+
report,
|
|
141
|
+
provider="ollama-local",
|
|
142
|
+
model_name="llama3.1:8b",
|
|
143
|
+
thinking_budget=0,
|
|
144
|
+
num_ctx=8192,
|
|
145
|
+
)
|
|
146
|
+
by_id = _doctor_by_id(report)
|
|
147
|
+
assert by_id["ollama.local.mlx_runner"].status == "pass"
|
|
148
|
+
assert by_id["ollama.local.thinking_default"].status == "skip"
|
|
149
|
+
assert by_id["ollama.local.num_ctx_invalid"].status == "pass"
|
|
150
|
+
assert by_id["ollama.local.num_ctx_large"].status == "pass"
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def test_ollama_local_num_ctx_unset_is_skipped() -> None:
|
|
154
|
+
report = CommandReport(command="doctor", ok=True, config_path=None)
|
|
155
|
+
_add_ollama_local_checks(
|
|
156
|
+
report,
|
|
157
|
+
provider="ollama-local",
|
|
158
|
+
model_name="llama3.1:8b",
|
|
159
|
+
thinking_budget=0,
|
|
160
|
+
num_ctx=None,
|
|
161
|
+
)
|
|
162
|
+
by_id = _doctor_by_id(report)
|
|
163
|
+
assert by_id["ollama.local.num_ctx_invalid"].status == "skip"
|
|
164
|
+
assert by_id["ollama.local.num_ctx_large"].status == "skip"
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def test_ollama_local_num_ctx_garbage_fails() -> None:
|
|
168
|
+
report = CommandReport(command="doctor", ok=True, config_path=None)
|
|
169
|
+
_add_ollama_local_checks(
|
|
170
|
+
report,
|
|
171
|
+
provider="ollama-local",
|
|
172
|
+
model_name="llama3.1:8b",
|
|
173
|
+
thinking_budget=0,
|
|
174
|
+
num_ctx="abc",
|
|
175
|
+
)
|
|
176
|
+
by_id = _doctor_by_id(report)
|
|
177
|
+
assert by_id["ollama.local.num_ctx_invalid"].status == "fail"
|
|
178
|
+
assert by_id["ollama.local.num_ctx_invalid"].severity == "error"
|
|
179
|
+
assert by_id["ollama.local.num_ctx_large"].status == "skip"
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def test_ollama_local_num_ctx_zero_fails() -> None:
|
|
183
|
+
report = CommandReport(command="doctor", ok=True, config_path=None)
|
|
184
|
+
_add_ollama_local_checks(
|
|
185
|
+
report,
|
|
186
|
+
provider="ollama-local",
|
|
187
|
+
model_name="llama3.1:8b",
|
|
188
|
+
thinking_budget=0,
|
|
189
|
+
num_ctx=0,
|
|
190
|
+
)
|
|
191
|
+
by_id = _doctor_by_id(report)
|
|
192
|
+
assert by_id["ollama.local.num_ctx_invalid"].status == "fail"
|
|
193
|
+
assert by_id["ollama.local.num_ctx_large"].status == "skip"
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def test_ollama_local_thinking_default_skips_non_reasoning() -> None:
|
|
197
|
+
report = CommandReport(command="doctor", ok=True, config_path=None)
|
|
198
|
+
_add_ollama_local_checks(
|
|
199
|
+
report,
|
|
200
|
+
provider="ollama-local",
|
|
201
|
+
model_name="llama3.1:8b",
|
|
202
|
+
thinking_budget=-1,
|
|
203
|
+
num_ctx=None,
|
|
204
|
+
)
|
|
205
|
+
assert _doctor_by_id(report)["ollama.local.thinking_default"].status == "skip"
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def test_ollama_local_thinking_default_pass_when_off() -> None:
|
|
209
|
+
report = CommandReport(command="doctor", ok=True, config_path=None)
|
|
210
|
+
_add_ollama_local_checks(
|
|
211
|
+
report,
|
|
212
|
+
provider="ollama-local",
|
|
213
|
+
model_name="qwen3:8b",
|
|
214
|
+
thinking_budget=0,
|
|
215
|
+
num_ctx=8192,
|
|
216
|
+
)
|
|
217
|
+
assert _doctor_by_id(report)["ollama.local.thinking_default"].status == "pass"
|
|
@@ -48,7 +48,7 @@ def test_wait_for_health_rejects_dead_child_after_stale_200() -> None:
|
|
|
48
48
|
assert wait_for_health("http://127.0.0.1:18080", proc, timeout_s=1.0) is False
|
|
49
49
|
|
|
50
50
|
|
|
51
|
-
def
|
|
51
|
+
def test_spawn_gateway_does_not_set_transcript_env(tmp_path: Path, monkeypatch) -> None:
|
|
52
52
|
captured: dict[str, object] = {}
|
|
53
53
|
|
|
54
54
|
def fake_popen(*args: object, **kwargs: object) -> object:
|
|
@@ -65,7 +65,7 @@ def test_spawn_gateway_enables_transcript_capture(tmp_path: Path, monkeypatch) -
|
|
|
65
65
|
try:
|
|
66
66
|
env = captured["env"]
|
|
67
67
|
assert isinstance(env, dict)
|
|
68
|
-
assert
|
|
68
|
+
assert "MONKEYBOT_TRANSCRIPT_ENABLED" not in env
|
|
69
69
|
finally:
|
|
70
70
|
spawned.log_file.close()
|
|
71
71
|
spawned.log_path.unlink()
|
|
@@ -617,7 +617,7 @@ wheels = [
|
|
|
617
617
|
|
|
618
618
|
[[package]]
|
|
619
619
|
name = "monkeybot"
|
|
620
|
-
version = "3.
|
|
620
|
+
version = "3.1.0"
|
|
621
621
|
source = { editable = "../" }
|
|
622
622
|
dependencies = [
|
|
623
623
|
{ name = "aiosqlite" },
|
|
@@ -730,25 +730,33 @@ dev = [
|
|
|
730
730
|
|
|
731
731
|
[[package]]
|
|
732
732
|
name = "monkeybot-browser-mcp"
|
|
733
|
-
version = "0.
|
|
733
|
+
version = "0.5.0"
|
|
734
734
|
source = { editable = "../integrations/browser-mcp" }
|
|
735
735
|
dependencies = [
|
|
736
736
|
{ name = "browser-harness" },
|
|
737
737
|
{ name = "mcp" },
|
|
738
|
+
{ name = "pillow" },
|
|
739
|
+
{ name = "pyyaml" },
|
|
738
740
|
]
|
|
739
741
|
|
|
740
742
|
[package.metadata]
|
|
741
743
|
requires-dist = [
|
|
744
|
+
{ name = "bedrock-agentcore", marker = "extra == 'agentcore'" },
|
|
745
|
+
{ name = "boto3", marker = "extra == 'agentcore'" },
|
|
742
746
|
{ name = "browser-harness", specifier = ">=0.1.3" },
|
|
743
747
|
{ name = "mcp", specifier = ">=1.0.0,<2" },
|
|
748
|
+
{ name = "pillow", specifier = ">=10" },
|
|
749
|
+
{ name = "playwright", marker = "extra == 'agentcore'" },
|
|
750
|
+
{ name = "pyyaml", specifier = ">=6" },
|
|
744
751
|
]
|
|
752
|
+
provides-extras = ["agentcore"]
|
|
745
753
|
|
|
746
754
|
[package.metadata.requires-dev]
|
|
747
755
|
dev = [{ name = "pytest", specifier = ">=8.0.0" }]
|
|
748
756
|
|
|
749
757
|
[[package]]
|
|
750
758
|
name = "monkeybot-cli"
|
|
751
|
-
version = "0.
|
|
759
|
+
version = "0.6.0"
|
|
752
760
|
source = { editable = "." }
|
|
753
761
|
dependencies = [
|
|
754
762
|
{ name = "httpx" },
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: browser
|
|
3
|
-
description: Control a real browser through the optional bundled browser MCP server.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Browser
|
|
7
|
-
|
|
8
|
-
When browser tools are needed, call `enable_mcp("browser")` first. The browser
|
|
9
|
-
MCP server ships **enabled** in new agents (`mcp.json`); progressive disclosure
|
|
10
|
-
still requires `enable_mcp` before `browser__*` schemas are advertised.
|
|
11
|
-
|
|
12
|
-
Use indexed DOM tools before screenshots. Browser screenshots and agent-written
|
|
13
|
-
playbooks are workspace data: `browser/Screenshots/` and `browser/playbooks/`.
|
|
14
|
-
They are not trusted skills and may be discarded with an ephemeral workspace.
|
|
15
|
-
|
|
16
|
-
Finish browser sessions with `browser_stop`.
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
"""Tests for doctor remediation copy."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import subprocess
|
|
6
|
-
from pathlib import Path
|
|
7
|
-
from types import SimpleNamespace
|
|
8
|
-
|
|
9
|
-
from monkeybot_cli.commands.doctor import (
|
|
10
|
-
_agent_defines_project_extra,
|
|
11
|
-
_extra_remediation,
|
|
12
|
-
_runtime_python_version,
|
|
13
|
-
)
|
|
14
|
-
from monkeybot_cli.runtime_python import RuntimePython
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def test_extra_remediation_default_mvp_wording(tmp_path: Path) -> None:
|
|
18
|
-
(tmp_path / "pyproject.toml").write_text(
|
|
19
|
-
'[project]\nname = "bot"\ndependencies = ["monkeybot>=2.1.0,<3"]\n',
|
|
20
|
-
encoding="utf-8",
|
|
21
|
-
)
|
|
22
|
-
runtime = SimpleNamespace(source="venv")
|
|
23
|
-
text = _extra_remediation("openai", tmp_path, runtime)
|
|
24
|
-
assert "uv sync --extra" not in text
|
|
25
|
-
assert f"Add monkeybot[openai] to {tmp_path}/pyproject.toml dependencies" in text
|
|
26
|
-
assert f"cd {tmp_path} && uv sync" in text
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def test_extra_remediation_keeps_extra_for_project_optionals(tmp_path: Path) -> None:
|
|
30
|
-
(tmp_path / "pyproject.toml").write_text(
|
|
31
|
-
"[project]\n"
|
|
32
|
-
'name = "bot"\n'
|
|
33
|
-
"[project.optional-dependencies]\n"
|
|
34
|
-
'openai = ["monkeybot[openai]"]\n',
|
|
35
|
-
encoding="utf-8",
|
|
36
|
-
)
|
|
37
|
-
runtime = SimpleNamespace(source="uv")
|
|
38
|
-
text = _extra_remediation("openai", tmp_path, runtime)
|
|
39
|
-
assert text == f"Install in the agent project: cd {tmp_path} && uv sync --extra openai"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def test_extra_remediation_config_only_cli_env(tmp_path: Path) -> None:
|
|
43
|
-
runtime = SimpleNamespace(source="cli")
|
|
44
|
-
text = _extra_remediation("bedrock", tmp_path, runtime)
|
|
45
|
-
assert "uv tool install --with 'monkeybot[bedrock]' monkeybot-cli" in text
|
|
46
|
-
assert "refresh the managed runtime" not in text
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
def test_extra_remediation_config_only_managed_runtime(tmp_path: Path) -> None:
|
|
50
|
-
runtime = SimpleNamespace(source="cli-managed")
|
|
51
|
-
text = _extra_remediation("openai", tmp_path, runtime)
|
|
52
|
-
assert "uv tool install --with 'monkeybot[openai]' monkeybot-cli" in text
|
|
53
|
-
assert "refresh the managed runtime" in text
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def test_agent_defines_project_extra(tmp_path: Path) -> None:
|
|
57
|
-
assert not _agent_defines_project_extra(tmp_path, "openai")
|
|
58
|
-
(tmp_path / "pyproject.toml").write_text(
|
|
59
|
-
"[project.optional-dependencies]\npostgres = []\n",
|
|
60
|
-
encoding="utf-8",
|
|
61
|
-
)
|
|
62
|
-
assert _agent_defines_project_extra(tmp_path, "postgres")
|
|
63
|
-
assert not _agent_defines_project_extra(tmp_path, "openai")
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
def test_runtime_python_version_returns_zeros_when_uv_missing(tmp_path: Path, monkeypatch) -> None:
|
|
67
|
-
runtime = RuntimePython(["uv", "run", "python"], "uv", tmp_path)
|
|
68
|
-
|
|
69
|
-
def fake_run(*args, **kwargs):
|
|
70
|
-
del args, kwargs
|
|
71
|
-
raise FileNotFoundError("uv")
|
|
72
|
-
|
|
73
|
-
monkeypatch.setattr("monkeybot_cli.runtime_python.subprocess.run", fake_run)
|
|
74
|
-
assert _runtime_python_version(runtime) == (0, 0, 0)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def test_runtime_python_version_returns_zeros_on_timeout(tmp_path: Path, monkeypatch) -> None:
|
|
78
|
-
runtime = RuntimePython(["uv", "run", "python"], "uv", tmp_path)
|
|
79
|
-
|
|
80
|
-
def fake_run(*args, **kwargs):
|
|
81
|
-
del args, kwargs
|
|
82
|
-
raise subprocess.TimeoutExpired(cmd="uv", timeout=15)
|
|
83
|
-
|
|
84
|
-
monkeypatch.setattr("monkeybot_cli.runtime_python.subprocess.run", fake_run)
|
|
85
|
-
assert _runtime_python_version(runtime) == (0, 0, 0)
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/realtime/session_controller.py
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
|
{monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/scaffold_defaults/dockerignore
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/scaffold_defaults/loop/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{monkeybot_cli-0.5.1 → monkeybot_cli-0.6.0}/src/monkeybot_cli/scaffold_defaults/permissions.yaml
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
|