monkeybot-cli 0.2.1__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.
- monkeybot_cli/__init__.py +3 -0
- monkeybot_cli/chat_renderer.py +87 -0
- monkeybot_cli/chat_session.py +911 -0
- monkeybot_cli/chat_status_bar.py +205 -0
- monkeybot_cli/chat_theme.py +91 -0
- monkeybot_cli/chat_tool_display.py +334 -0
- monkeybot_cli/chat_tui.py +1491 -0
- monkeybot_cli/chat_tui_widgets.py +996 -0
- monkeybot_cli/commands/__init__.py +1 -0
- monkeybot_cli/commands/chat.py +817 -0
- monkeybot_cli/commands/doctor.py +293 -0
- monkeybot_cli/commands/loop.py +207 -0
- monkeybot_cli/commands/new.py +207 -0
- monkeybot_cli/commands/run_cmd.py +41 -0
- monkeybot_cli/commands/talk.py +102 -0
- monkeybot_cli/commands/validate.py +385 -0
- monkeybot_cli/compat.py +7 -0
- monkeybot_cli/config_resolve.py +55 -0
- monkeybot_cli/exit_commands.py +13 -0
- monkeybot_cli/extras_catalog.py +95 -0
- monkeybot_cli/gateway_health.py +34 -0
- monkeybot_cli/main.py +38 -0
- monkeybot_cli/opensandbox_lifecycle.py +314 -0
- monkeybot_cli/output.py +110 -0
- monkeybot_cli/providers.py +112 -0
- monkeybot_cli/realtime/__init__.py +13 -0
- monkeybot_cli/realtime/audio_io.py +147 -0
- monkeybot_cli/realtime/client.py +17 -0
- monkeybot_cli/realtime/gateway_manager.py +142 -0
- monkeybot_cli/realtime/push_to_talk.py +128 -0
- monkeybot_cli/realtime/session.py +256 -0
- monkeybot_cli/realtime/session_controller.py +501 -0
- monkeybot_cli/realtime/talk_ui.py +243 -0
- monkeybot_cli/realtime/wire_encode.py +39 -0
- monkeybot_cli/runtime_python.py +91 -0
- monkeybot_cli/scaffold.py +287 -0
- monkeybot_cli/scaffold_defaults/AGENT.md +56 -0
- monkeybot_cli/scaffold_defaults/__init__.py +1 -0
- monkeybot_cli/scaffold_defaults/command_allowlist.yaml +57 -0
- monkeybot_cli/scaffold_defaults/env.example +35 -0
- monkeybot_cli/scaffold_defaults/mcp.json +49 -0
- monkeybot_cli/scaffold_defaults/monkeybot.example.yaml +191 -0
- monkeybot_cli/scaffold_defaults/otel-collector.example.yaml +57 -0
- monkeybot_cli/scaffold_defaults/permissions.yaml +32 -0
- monkeybot_cli/scaffold_defaults/setup-workspace.sh +24 -0
- monkeybot_cli/session_controller.py +7 -0
- monkeybot_cli/terminal_markdown.py +48 -0
- monkeybot_cli-0.2.1.dist-info/METADATA +10 -0
- monkeybot_cli-0.2.1.dist-info/RECORD +51 -0
- monkeybot_cli-0.2.1.dist-info/WHEEL +4 -0
- monkeybot_cli-0.2.1.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Identity
|
|
2
|
+
|
|
3
|
+
You are a capable agent running inside **monkeybot** — not a generic chatbot in a browser. You pair with the user to get work done: research, writing, analysis, file and code work, and everyday tasks. You have a **writable workspace** and tools every turn; use them.
|
|
4
|
+
|
|
5
|
+
Act like someone the user can rely on: do the work, give a real answer, and stop. You are not a demo, a script, or a tool-calling showcase.
|
|
6
|
+
|
|
7
|
+
The **monkeybot harness (fixed)** section appended each turn defines exact tool names, path rules, and invocation protocol. When it conflicts with anything below, follow the harness — this file is about judgment, not mechanics.
|
|
8
|
+
|
|
9
|
+
# How you work
|
|
10
|
+
|
|
11
|
+
- **Understand the request before acting.** If ambiguity would change the outcome, ask one focused question. If intent is clear, proceed — don't stall on trivia.
|
|
12
|
+
- **Use tools for outcomes that live outside this message** — a file on disk, live data, a command result, fetched content. Text in chat is not a substitute for a deliverable the user asked for.
|
|
13
|
+
- **One good result ends the search.** When you have enough to answer — from a tool, a file, or verified knowledge — stop gathering. Extra "just in case" calls usually waste time.
|
|
14
|
+
- **Match effort to the task.** Quick questions get quick answers. Multi-file work, ambiguous design, or conflicting sources earn more steps and explanation.
|
|
15
|
+
- **Say what you don't know.** If a tool failed, access is missing, or a fact is unverified, say so plainly and state what would resolve it. Don't guess and present it as fact.
|
|
16
|
+
|
|
17
|
+
# Making files and code changes
|
|
18
|
+
|
|
19
|
+
When the user asks you to **build, create, edit, or save** a file, use workspace tools (`write_file`, `replace_in_file`, or `run_command` when appropriate). **Do not paste full file contents and tell them to save manually** unless they explicitly asked to see the code in chat.
|
|
20
|
+
|
|
21
|
+
- **New file or full rewrite** → `write_file`.
|
|
22
|
+
- **Targeted change to an existing file** → `read_file` then `replace_in_file`.
|
|
23
|
+
- **Deliverables live in the workspace.** After writing, give the workspace-relative path (e.g. `code/lumina/index.html`) so they can open it.
|
|
24
|
+
- **Never claim you cannot create files** because of "chat limitations" or "no access to the hard drive" when workspace tools are available — check the active tool list and harness paths first.
|
|
25
|
+
- **Don't output long code blocks in chat** when the request was to produce a file. A short snippet for explanation is fine; the full artifact belongs on disk.
|
|
26
|
+
|
|
27
|
+
# Choosing and using tools
|
|
28
|
+
|
|
29
|
+
Pick the narrowest tool that satisfies the request.
|
|
30
|
+
|
|
31
|
+
- **Live or external content** (website, app, current info): fetch with browser/MCP or web search — don't guess from memory.
|
|
32
|
+
- **Web search**: when you need information you don't have and can't get more directly.
|
|
33
|
+
- **Memory / past context**: when the user references prior conversations or saved notes. Use a specific query — not a fragment of your own last message.
|
|
34
|
+
- **Commands**: when the task requires running something, within what's permitted. Don't run commands to narrate progress.
|
|
35
|
+
- **After a failure**: check for `ok: false`, non-zero exit codes, or empty results. Don't retry the identical call; fix the cause or report the blocker.
|
|
36
|
+
|
|
37
|
+
# Communication
|
|
38
|
+
|
|
39
|
+
- **Answer first.** Lead with the takeaway or result; add detail only if useful.
|
|
40
|
+
- **Be concise by default.** Expand when asked for depth — not before.
|
|
41
|
+
- **One coherent outcome per turn** — a clear result or one focused follow-up, not an unprompted menu.
|
|
42
|
+
- **Don't name tools to the user** unless they ask; say what you're doing ("I'll create the landing page file") not which API you call.
|
|
43
|
+
- **Formatting aids reading, not decoration.** Never fabricate tool output — only show what actually ran or exists.
|
|
44
|
+
|
|
45
|
+
# Honesty, including about yourself
|
|
46
|
+
|
|
47
|
+
- **Be accurate about your own actions.** If asked what you did or whether you used a tool, check the actual record — don't reconstruct from assumption or prior claims.
|
|
48
|
+
- **Own mistakes plainly.** If you should have written a file and pasted code instead, say so and fix it with the right tool.
|
|
49
|
+
- **Never fabricate** tool results, file contents, command output, or citations.
|
|
50
|
+
|
|
51
|
+
# Judgment and safety
|
|
52
|
+
|
|
53
|
+
- Don't help with harm intended against systems the user doesn't own, malware, or deceiving real people — say briefly why.
|
|
54
|
+
- Treat credentials and secrets as sensitive; suggest proper secret storage if shared in chat.
|
|
55
|
+
- Don't promise outcomes this setup can't deliver (e.g. production deployment when not configured). Writing files under the workspace **is** in scope.
|
|
56
|
+
- Before destructive or irreversible operations, say what you're about to do and why.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Packaged default ``monkeybot_config/`` files copied by ``monkeybot new``."""
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# run_command: binary allowlist (enforced at execution).
|
|
2
|
+
allowed_commands:
|
|
3
|
+
- cat
|
|
4
|
+
- ls
|
|
5
|
+
- grep
|
|
6
|
+
- echo
|
|
7
|
+
- python
|
|
8
|
+
- python3
|
|
9
|
+
- uv
|
|
10
|
+
- git
|
|
11
|
+
- gh
|
|
12
|
+
- bash
|
|
13
|
+
|
|
14
|
+
# Path prefixes permitted in run_command argv (./ and / arguments).
|
|
15
|
+
allowed_path_prefixes:
|
|
16
|
+
- ./data/memory/
|
|
17
|
+
- ./data/memory
|
|
18
|
+
- ./skills/
|
|
19
|
+
- ./skills
|
|
20
|
+
- ./test-data/
|
|
21
|
+
- ./code/
|
|
22
|
+
- ./code
|
|
23
|
+
|
|
24
|
+
# Optional: regexes matched against the normalized invocation (deny wins).
|
|
25
|
+
# Omit this key to use built-in DEFAULT_DENY_PATTERNS (install blocking).
|
|
26
|
+
deny_patterns:
|
|
27
|
+
- "pip3?\\s+install"
|
|
28
|
+
- "python3?\\s+-m\\s+pip\\s+install"
|
|
29
|
+
- "(^|\\s)uv\\s+(add|remove|sync|pip\\s+install|pip\\s+sync)"
|
|
30
|
+
- "(^|\\s)poetry\\s+(add|install)"
|
|
31
|
+
- "(^|\\s)conda\\s+install"
|
|
32
|
+
- "(^|\\s)(npm|pnpm|yarn)\\s+(install|add|i)(\\s|$)"
|
|
33
|
+
- "(^|\\s)(apt|apt-get)\\s+install"
|
|
34
|
+
- "(^|\\s)brew\\s+install"
|
|
35
|
+
- "^curl\\s+"
|
|
36
|
+
- "^wget\\s+"
|
|
37
|
+
- "^rm\\s+-rf"
|
|
38
|
+
- "^sudo\\s+"
|
|
39
|
+
- ".*>\\s*/etc/.*"
|
|
40
|
+
|
|
41
|
+
# Per-tool output shaping (token optimization). Merged with built-in defaults for
|
|
42
|
+
# run_command and web_search when keys are omitted here.
|
|
43
|
+
tool_output:
|
|
44
|
+
run_command:
|
|
45
|
+
content_type: logs
|
|
46
|
+
max_output_lines: 400
|
|
47
|
+
collapse_repeated: true
|
|
48
|
+
keep_patterns:
|
|
49
|
+
- "(?i)\\berror\\b"
|
|
50
|
+
- "(?i)\\bfatal\\b"
|
|
51
|
+
- "(?i)traceback"
|
|
52
|
+
- "(?i)\\bexception\\b"
|
|
53
|
+
web_search:
|
|
54
|
+
content_type: json
|
|
55
|
+
max_array_items: 30
|
|
56
|
+
read_file:
|
|
57
|
+
content_type: code
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Copy to .env and fill in secrets / machine-local values only.
|
|
2
|
+
|
|
3
|
+
# Conversation history — SQLite is fine for single-agent dev.
|
|
4
|
+
DB_URL=sqlite:///data/monkeybot.db
|
|
5
|
+
# DB_URL=postgresql://postgres:postgres@localhost:5432/monkeybot
|
|
6
|
+
# DB_URL=firestore://your-gcp-project/(default)
|
|
7
|
+
|
|
8
|
+
# Gemini / Vertex (pick one approach)
|
|
9
|
+
# GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json
|
|
10
|
+
# GCP_PROJECT_ID=your-gcp-project
|
|
11
|
+
# GOOGLE_CLOUD_PROJECT=your-gcp-project
|
|
12
|
+
# GEMINI_API_KEY=
|
|
13
|
+
|
|
14
|
+
# OpenAI
|
|
15
|
+
# OPENAI_API_KEY=
|
|
16
|
+
|
|
17
|
+
# Anthropic
|
|
18
|
+
# ANTHROPIC_API_KEY=
|
|
19
|
+
|
|
20
|
+
# Vertex Claude
|
|
21
|
+
# ANTHROPIC_VERTEX_PROJECT_ID=
|
|
22
|
+
# ANTHROPIC_VERTEX_REGION=us-east5
|
|
23
|
+
|
|
24
|
+
# AWS Bedrock
|
|
25
|
+
# AWS_REGION=us-east-1
|
|
26
|
+
|
|
27
|
+
# Hugging Face
|
|
28
|
+
# HF_TOKEN=
|
|
29
|
+
|
|
30
|
+
# Ollama (local models — no API key needed)
|
|
31
|
+
# OLLAMA_BASE_URL=http://localhost:11434
|
|
32
|
+
|
|
33
|
+
# Optional web search
|
|
34
|
+
# TAVILY_API_KEY=
|
|
35
|
+
# FIRECRAWL_API_KEY=
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mcpServers": {
|
|
3
|
+
"filesystem": {
|
|
4
|
+
"command": "npx",
|
|
5
|
+
"args": [
|
|
6
|
+
"-y",
|
|
7
|
+
"@modelcontextprotocol/server-filesystem",
|
|
8
|
+
"/path/to/workspace-readable-by-this-server"
|
|
9
|
+
],
|
|
10
|
+
"env": {
|
|
11
|
+
"NODE_ENV": "production",
|
|
12
|
+
"EXAMPLE_SECRET": "${MY_SECRET_ENV_VAR}"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"remote-http": {
|
|
16
|
+
"url": "https://your-mcp-host.example.com/mcp",
|
|
17
|
+
"headers": {
|
|
18
|
+
"Authorization": "Bearer ${MY_STATIC_BEARER_TOKEN}"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"remote-oauth": {
|
|
22
|
+
"url": "https://your-mcp-host.example.com/mcp",
|
|
23
|
+
"auth": {
|
|
24
|
+
"flow": "client_credentials",
|
|
25
|
+
"token_url": "https://identity.provider.example.com/oauth2/token",
|
|
26
|
+
"client_id": "${OAUTH_CLIENT_ID}",
|
|
27
|
+
"client_secret": "${OAUTH_CLIENT_SECRET}",
|
|
28
|
+
"scope": "read:tools write:tools",
|
|
29
|
+
"client_auth_method": "body"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"browser": {
|
|
33
|
+
"command": "uv",
|
|
34
|
+
"args": [
|
|
35
|
+
"run",
|
|
36
|
+
"--project",
|
|
37
|
+
"/path/to/monkeybot/integrations/browser-mcp",
|
|
38
|
+
"python",
|
|
39
|
+
"-m",
|
|
40
|
+
"browser_mcp.server"
|
|
41
|
+
],
|
|
42
|
+
"env": {
|
|
43
|
+
"BU_NAME": "monkeybot",
|
|
44
|
+
"BROWSER_MCP_PLAYBOOKS_DIR": "./workspace/skills/browser/playbooks",
|
|
45
|
+
"BROWSER_MCP_SCREENSHOTS_DIR": "${MONKEYBOT_WORKSPACE_ROOT}/browser/Screenshots"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# monkeybot harness — copy to monkeybot.yaml and edit (paths relative to process cwd).
|
|
2
|
+
#
|
|
3
|
+
# cp monkeybot_config/monkeybot.example.yaml monkeybot_config/monkeybot.yaml
|
|
4
|
+
#
|
|
5
|
+
# Precedence: environment variables (and optional `.env` in cwd) win over values here.
|
|
6
|
+
#
|
|
7
|
+
# Secrets are not committed here. Create a `.env` in the repo root when you need keys or
|
|
8
|
+
# machine-local paths, for example:
|
|
9
|
+
# GOOGLE_APPLICATION_CREDENTIALS, VERTEX_AI_PROJECT_ID, GCP_PROJECT_ID, GOOGLE_CLOUD_PROJECT,
|
|
10
|
+
# VERTEX_AI_LOCATION, GOOGLE_CLOUD_LOCATION, GEMINI_API_KEY,
|
|
11
|
+
# OPENAI_API_KEY, ANTHROPIC_API_KEY,
|
|
12
|
+
# ANTHROPIC_VERTEX_PROJECT_ID, ANTHROPIC_VERTEX_REGION,
|
|
13
|
+
# OLLAMA_BASE_URL (default http://localhost:11434, no API key needed),
|
|
14
|
+
# NVIDIA_API_KEY (free key from https://build.nvidia.com),
|
|
15
|
+
# TAVILY_API_KEY, FIRECRAWL_API_KEY, SANDBOX_API_KEY,
|
|
16
|
+
# MONKEYBOT_TOOL_DENIED_PATTERNS, MONKEYBOT_CORS_ALLOW_ORIGINS, MONKEYBOT_CONFIG, …
|
|
17
|
+
#
|
|
18
|
+
# Optional fragments: add top-level ``includes: [includes/extra.yaml]`` (paths relative
|
|
19
|
+
# to this file’s directory); later files deep-merge over earlier ones.
|
|
20
|
+
#
|
|
21
|
+
# Env-only overrides (not in this YAML schema) still work when set in the shell or `.env`.
|
|
22
|
+
|
|
23
|
+
runtime:
|
|
24
|
+
# DEBUG | INFO | WARNING | ERROR
|
|
25
|
+
log_level: INFO
|
|
26
|
+
port: 8080
|
|
27
|
+
# Optional second port env (same as PORT if unset in code paths that read GATEWAY_PORT)
|
|
28
|
+
# gateway_port: 8080
|
|
29
|
+
# Internal debugging only (not agent-visible): write every AgentEvent and raw
|
|
30
|
+
# provider request/response for each session to
|
|
31
|
+
# {workspace_root}/.monkeybot/transcripts/{session_id}.ndjson. Opt-in; default off.
|
|
32
|
+
# (env: MONKEYBOT_TRANSCRIPT_ENABLED)
|
|
33
|
+
transcript_enabled: false
|
|
34
|
+
|
|
35
|
+
# Required: choose the conversational harness for this deployment.
|
|
36
|
+
# turn_based - existing HTTP POST /reply + SSE (default, backwards-compatible)
|
|
37
|
+
# realtime - WebSocket /realtime with full-duplex audio/text (requires monkeybot[realtime])
|
|
38
|
+
harness:
|
|
39
|
+
mode: turn_based
|
|
40
|
+
|
|
41
|
+
# Realtime settings are validated at startup even when mode is turn_based, but only
|
|
42
|
+
# take effect when harness.mode is realtime. Requires monkeybot[realtime] (or the
|
|
43
|
+
# vendor-specific extra, e.g. monkeybot[realtime-gemini]).
|
|
44
|
+
realtime:
|
|
45
|
+
# Optional model override for the realtime session. Live-only models (e.g.
|
|
46
|
+
# gemini-3.1-flash-live-preview) cannot be used for turn-based work, so the
|
|
47
|
+
# realtime session can point to a different model than model.name. When omitted,
|
|
48
|
+
# the realtime session falls back to model.name and MODEL_PROVIDER.
|
|
49
|
+
# model:
|
|
50
|
+
# name: gemini-3.1-flash-live-preview
|
|
51
|
+
# provider: google_genai
|
|
52
|
+
websocket:
|
|
53
|
+
enabled: true
|
|
54
|
+
# port defaults to runtime.port when unset
|
|
55
|
+
# port: 8080
|
|
56
|
+
audio:
|
|
57
|
+
input_format: pcm_s16le_24khz_mono
|
|
58
|
+
output_format: pcm_s16le_24khz_mono
|
|
59
|
+
chunk_ms: 200
|
|
60
|
+
max_utterance_sec: 60
|
|
61
|
+
session:
|
|
62
|
+
max_duration_sec: 1800
|
|
63
|
+
idle_timeout_sec: 120
|
|
64
|
+
max_response_turn_sec: 300
|
|
65
|
+
max_concurrent_sessions: 100
|
|
66
|
+
metrics:
|
|
67
|
+
emit_summary_on_close: true
|
|
68
|
+
|
|
69
|
+
paths:
|
|
70
|
+
agent_md: ./monkeybot_config/AGENT.md
|
|
71
|
+
memory_storage_uri: local://./data/memory
|
|
72
|
+
skills_path: ./skills
|
|
73
|
+
db_url: sqlite:///data/monkeybot.db
|
|
74
|
+
# Apply SQLite/Postgres DDL on startup (true | false). Default true. Set false when migrations own the schema.
|
|
75
|
+
auto_schema: true
|
|
76
|
+
mcp_config: ./monkeybot_config/mcp.json
|
|
77
|
+
command_allowlist_config: ./monkeybot_config/command_allowlist.yaml
|
|
78
|
+
# Soft permission ruleset (allow/ask/deny). Hard allowlists stay in command_allowlist.yaml.
|
|
79
|
+
permission_config: ./monkeybot_config/permissions.yaml
|
|
80
|
+
workspace_root: ./workspace
|
|
81
|
+
|
|
82
|
+
model:
|
|
83
|
+
# gemini | openai | anthropic | vertex-claude | huggingface | ollama | nvidia | aws_bedrock | fake
|
|
84
|
+
provider: gemini
|
|
85
|
+
name: gemini-3.1-flash-live-preview
|
|
86
|
+
temperature: 0.7
|
|
87
|
+
max_tokens: 60000
|
|
88
|
+
# Gemini: -1 = model default, 0 = off, N = token budget
|
|
89
|
+
# Ollama (Gemma 4, Qwen3, …): -1 = server default, 0 = off (reasoning_effort: none)
|
|
90
|
+
thinking_budget: -1
|
|
91
|
+
# Summarisation trigger (tokens)
|
|
92
|
+
context_window: 1000000
|
|
93
|
+
max_turns: 50
|
|
94
|
+
# Prompt-cache session hints: none | short | long (env: MODEL_CACHE_RETENTION)
|
|
95
|
+
# cache_retention: short
|
|
96
|
+
# Optional cheaper model for sync history summarization (env: CONTEXT_SUMMARIZATION_MODEL); omit = main model
|
|
97
|
+
# summarization_model: gemini-3-flash
|
|
98
|
+
|
|
99
|
+
# Non-secret GCP identifiers (prefer .env for secrets / ADC path).
|
|
100
|
+
# gcp:
|
|
101
|
+
# project_id: your-gcp-project
|
|
102
|
+
# location: us-central1
|
|
103
|
+
|
|
104
|
+
# anthropic_vertex:
|
|
105
|
+
# project_id: your-gcp-project
|
|
106
|
+
# region: us-east5
|
|
107
|
+
|
|
108
|
+
gateway:
|
|
109
|
+
pending_response_timeout_sec: 300
|
|
110
|
+
sse_replay_max: 256
|
|
111
|
+
graceful_shutdown_timeout_sec: 5
|
|
112
|
+
# FastAPI CORS allow_origins (comma-separated, or "*" for any origin). Sets MONKEYBOT_CORS_ALLOW_ORIGINS.
|
|
113
|
+
# Default in code when unset: http://localhost:5173 (Vite dev). Add http://127.0.0.1:5173 if needed.
|
|
114
|
+
cors_allow_origins: "http://localhost:5173"
|
|
115
|
+
|
|
116
|
+
context_curation:
|
|
117
|
+
# When false, curation is skipped (env: CONTEXT_CURATION_ENABLED)
|
|
118
|
+
enabled: true
|
|
119
|
+
# Recent INDEX lines injected by default; also caps curator-selected lines
|
|
120
|
+
memory_window_lines: 12
|
|
121
|
+
memory_index_cap: 200
|
|
122
|
+
# Call LLM curator when estimated memory-index tokens exceed this
|
|
123
|
+
# (env: CONTEXT_CURATION_MEMORY_TOKEN_THRESHOLD). Below this, use the window only.
|
|
124
|
+
memory_token_threshold: 2000
|
|
125
|
+
# Separate small model for curator (env: CONTEXT_CURATOR_MODEL); empty uses main model id
|
|
126
|
+
curator_model: gemini-3-flash
|
|
127
|
+
timeout_sec: 10
|
|
128
|
+
|
|
129
|
+
emission:
|
|
130
|
+
# Terse emission-style guidance injected into the cached harness prefix.
|
|
131
|
+
# Two named modes:
|
|
132
|
+
# off (default) — no prompt change. Use for conversational / user-facing
|
|
133
|
+
# agents where warmth and explanation are the deliverable.
|
|
134
|
+
# terse — cut model output volume (less code, less prose). When the
|
|
135
|
+
# `task` tool is active, also requests dense, minified
|
|
136
|
+
# agent-to-agent handoffs (Lever 3).
|
|
137
|
+
# Env override: MONKEYBOT_EMISSION_STYLE — accepts off | terse | true | 1 | on | yes
|
|
138
|
+
# (any value other than the terse-set means off).
|
|
139
|
+
style: off
|
|
140
|
+
|
|
141
|
+
memory_hook:
|
|
142
|
+
enabled: true
|
|
143
|
+
|
|
144
|
+
subagent:
|
|
145
|
+
timeout_sec: 600
|
|
146
|
+
max_turns: 25
|
|
147
|
+
# Gemini only: enable native google_search grounding for subagent task runs.
|
|
148
|
+
# Config-file only (no env var override). Defaults to false.
|
|
149
|
+
vertex_google_search: false
|
|
150
|
+
# Default AGENT.md for task calls with no subagent_type (relative to bot project root).
|
|
151
|
+
agent_md: ./monkeybot_config/AGENT.md
|
|
152
|
+
|
|
153
|
+
# Named subagent personas — parent selects via task(subagent_type=...).
|
|
154
|
+
# Add entries and matching AGENT.md files under monkeybot_config/agents/ when needed.
|
|
155
|
+
# subagents:
|
|
156
|
+
# - name: researcher
|
|
157
|
+
# description: "Deep-dives a topic and returns a structured summary."
|
|
158
|
+
# agent_md: ./monkeybot_config/agents/researcher.md
|
|
159
|
+
|
|
160
|
+
tools:
|
|
161
|
+
# List of substrings blocked in tool args (also env MONKEYBOT_TOOL_DENIED_PATTERNS as comma-separated)
|
|
162
|
+
# denied_patterns:
|
|
163
|
+
# - "rm -rf"
|
|
164
|
+
# read_max_lines: 50000
|
|
165
|
+
# read_default_lines: 20000
|
|
166
|
+
# spill_read_max_lines: 50000
|
|
167
|
+
# spill_min_chars: 8000
|
|
168
|
+
# result_budget_fraction: 0.8
|
|
169
|
+
# result_budget_floor_tokens: 2000
|
|
170
|
+
|
|
171
|
+
web_search:
|
|
172
|
+
# duckduckgo | tavily | firecrawl | none (Tavily/Firecrawl need keys in .env)
|
|
173
|
+
backend: duckduckgo
|
|
174
|
+
max_results: 5
|
|
175
|
+
# Gemini only, additive to `backend` above (both can be on at once): enables Vertex
|
|
176
|
+
# Gemini's native `google_search` grounding tool. Ignored for other model providers.
|
|
177
|
+
# Config-file only (no env var override).
|
|
178
|
+
vertex_google_search: false
|
|
179
|
+
|
|
180
|
+
sandbox:
|
|
181
|
+
enabled: false
|
|
182
|
+
server_url: http://localhost:8080
|
|
183
|
+
image: python:3.12
|
|
184
|
+
ttl_seconds: 1800
|
|
185
|
+
|
|
186
|
+
# Optional JSON for MODEL_PROVIDER=fake tests (env: MONKEYBOT_FAKE_PROVIDER_EVENTS)
|
|
187
|
+
# fake_provider:
|
|
188
|
+
# events_json: '[[]]'
|
|
189
|
+
|
|
190
|
+
# includes:
|
|
191
|
+
# - includes/local.yaml
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# OpenTelemetry Collector — dual export (Phoenix + Langfuse)
|
|
2
|
+
#
|
|
3
|
+
# Prerequisites:
|
|
4
|
+
# - otel/opentelemetry-collector-contrib image (or core collector with otlphttp)
|
|
5
|
+
# - Langfuse: set LANGFUSE_OTEL_BASIC_AUTH to "Basic <base64(public_key:secret_key)>"
|
|
6
|
+
# (same value you would put in OTEL_EXPORTER_OTLP_HEADERS for direct export)
|
|
7
|
+
# - Phoenix: substitute PHOENIX_HOST (local Docker often phoenix:6006 or localhost:6006)
|
|
8
|
+
#
|
|
9
|
+
# Run collector (adjust mount path):
|
|
10
|
+
# docker run --rm -p 4318:4318 \
|
|
11
|
+
# -e LANGFUSE_OTEL_BASIC_AUTH \
|
|
12
|
+
# -v "$(pwd)/monkeybot_config/otel-collector.example.yaml:/etc/otelcol/config.yaml:ro" \
|
|
13
|
+
# otel/opentelemetry-collector-contrib:latest \
|
|
14
|
+
# --config=/etc/otelcol/config.yaml
|
|
15
|
+
#
|
|
16
|
+
# Point monkeybot at the collector (HTTP/protobuf, no path suffix on endpoint):
|
|
17
|
+
# export MONKEYBOT_OTEL_ENABLED=true
|
|
18
|
+
# export OTEL_TRACES_EXPORTER=otlp
|
|
19
|
+
# export OTEL_METRICS_EXPORTER=none
|
|
20
|
+
# export OTEL_LOGS_EXPORTER=none
|
|
21
|
+
# export OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4318
|
|
22
|
+
#
|
|
23
|
+
# Optional: gRPC ingest on 4317 — add protocols.grpc.endpoint: 0.0.0.0:4317 under receivers.otlp
|
|
24
|
+
# Manual verification (AC-012): send one chat turn; confirm the same trace in Phoenix and Langfuse UIs.
|
|
25
|
+
|
|
26
|
+
receivers:
|
|
27
|
+
otlp:
|
|
28
|
+
protocols:
|
|
29
|
+
http:
|
|
30
|
+
endpoint: 0.0.0.0:4318
|
|
31
|
+
# grpc:
|
|
32
|
+
# endpoint: 0.0.0.0:4317
|
|
33
|
+
|
|
34
|
+
processors:
|
|
35
|
+
batch: {}
|
|
36
|
+
# memory_limiter: # enable if large batches cause OOM on small hosts
|
|
37
|
+
# check_interval: 1s
|
|
38
|
+
# limit_mib: 512
|
|
39
|
+
|
|
40
|
+
exporters:
|
|
41
|
+
otlphttp/phoenix:
|
|
42
|
+
# otlphttp appends /v1/traces — do not include it in endpoint
|
|
43
|
+
endpoint: http://PHOENIX_HOST:6006
|
|
44
|
+
# Local Phoenix often needs no auth; Phoenix Cloud may use OTEL_EXPORTER_OTLP_HEADERS on the collector.
|
|
45
|
+
|
|
46
|
+
otlphttp/langfuse:
|
|
47
|
+
endpoint: https://cloud.langfuse.com/api/public/otel
|
|
48
|
+
# Self-hosted: e.g. https://langfuse.example.com/api/public/otel
|
|
49
|
+
headers:
|
|
50
|
+
Authorization: ${env:LANGFUSE_OTEL_BASIC_AUTH}
|
|
51
|
+
|
|
52
|
+
service:
|
|
53
|
+
pipelines:
|
|
54
|
+
traces:
|
|
55
|
+
receivers: [otlp]
|
|
56
|
+
processors: [batch]
|
|
57
|
+
exporters: [otlphttp/phoenix, otlphttp/langfuse]
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Soft permission ruleset (last-match-wins). Hard execution constraints remain in
|
|
2
|
+
# command_allowlist.yaml (allowed_commands / allowed_path_prefixes) + sandbox.
|
|
3
|
+
#
|
|
4
|
+
# Effects: allow | ask | deny
|
|
5
|
+
# Patterns: fnmatch wildcards (*, ?) against tool name and a normalized resource
|
|
6
|
+
# (run_command line, path arg, or str(args) fallback).
|
|
7
|
+
#
|
|
8
|
+
# default: applied when no rule matches.
|
|
9
|
+
default: allow
|
|
10
|
+
|
|
11
|
+
rules: []
|
|
12
|
+
|
|
13
|
+
# Examples (replace rules: [] with a list to enable):
|
|
14
|
+
# rules:
|
|
15
|
+
# - tool: read_file
|
|
16
|
+
# pattern: "*"
|
|
17
|
+
# effect: allow
|
|
18
|
+
# - tool: run_command
|
|
19
|
+
# pattern: "git *"
|
|
20
|
+
# effect: allow
|
|
21
|
+
# - tool: run_command
|
|
22
|
+
# pattern: "rm *"
|
|
23
|
+
# effect: deny
|
|
24
|
+
# message: "Destructive rm is blocked by permissions.yaml"
|
|
25
|
+
# - tool: write_file
|
|
26
|
+
# pattern: "*"
|
|
27
|
+
# effect: ask
|
|
28
|
+
# message: "Approve writing this file?"
|
|
29
|
+
# - tool: "*__*"
|
|
30
|
+
# pattern: "*"
|
|
31
|
+
# effect: ask
|
|
32
|
+
# message: "Approve this MCP tool call?"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Ensure workspace/ exists and workspace/skills points at skills/ (for read_file in sandbox).
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
5
|
+
WS="$ROOT/workspace"
|
|
6
|
+
SKILLS_SRC="$ROOT/skills"
|
|
7
|
+
LINK="$WS/skills"
|
|
8
|
+
|
|
9
|
+
mkdir -p "$WS"
|
|
10
|
+
touch "$WS/.gitkeep"
|
|
11
|
+
mkdir -p "$SKILLS_SRC"
|
|
12
|
+
|
|
13
|
+
if [[ -L "$LINK" ]]; then
|
|
14
|
+
echo "workspace/skills symlink already exists"
|
|
15
|
+
exit 0
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
if [[ -e "$LINK" ]]; then
|
|
19
|
+
echo "error: $LINK exists and is not a symlink — remove it or run from a clean scaffold" >&2
|
|
20
|
+
exit 1
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
ln -sfn "../skills" "$LINK"
|
|
24
|
+
echo "Created workspace/skills -> ../skills"
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Plain-text rendering for streamed assistant markdown in the terminal."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
_HEADER = re.compile(r"^#{1,6}\s+")
|
|
8
|
+
_BOLD = re.compile(r"\*\*(.+?)\*\*")
|
|
9
|
+
_ITALIC = re.compile(r"(?<!\*)\*([^*\n]+)\*(?!\*)")
|
|
10
|
+
_BULLET = re.compile(r"^(\s*)[\*\-]\s+")
|
|
11
|
+
_CODE = re.compile(r"`([^`]+)`")
|
|
12
|
+
_ORPHAN_MARKERS = re.compile(r"\*+")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def plain_text_markdown_line(line: str) -> str:
|
|
16
|
+
"""Strip common inline markdown markers from a single line."""
|
|
17
|
+
text = _HEADER.sub("", line)
|
|
18
|
+
text = _BOLD.sub(r"\1", text)
|
|
19
|
+
text = _ITALIC.sub(r"\1", text)
|
|
20
|
+
text = _BULLET.sub(r"\1• ", text)
|
|
21
|
+
text = _CODE.sub(r"\1", text)
|
|
22
|
+
text = _ORPHAN_MARKERS.sub("", text)
|
|
23
|
+
return text
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class MarkdownPlainStream:
|
|
27
|
+
"""Buffer streamed assistant text and emit line-wise plain text."""
|
|
28
|
+
|
|
29
|
+
def __init__(self) -> None:
|
|
30
|
+
self._pending = ""
|
|
31
|
+
|
|
32
|
+
def feed(self, chunk: str) -> str:
|
|
33
|
+
if not chunk:
|
|
34
|
+
return ""
|
|
35
|
+
self._pending += chunk
|
|
36
|
+
parts: list[str] = []
|
|
37
|
+
while "\n" in self._pending:
|
|
38
|
+
line, self._pending = self._pending.split("\n", 1)
|
|
39
|
+
parts.append(plain_text_markdown_line(line))
|
|
40
|
+
parts.append("\n")
|
|
41
|
+
return "".join(parts)
|
|
42
|
+
|
|
43
|
+
def flush(self) -> str:
|
|
44
|
+
if not self._pending:
|
|
45
|
+
return ""
|
|
46
|
+
rendered = plain_text_markdown_line(self._pending)
|
|
47
|
+
self._pending = ""
|
|
48
|
+
return rendered
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: monkeybot-cli
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: CLI to create, configure, validate, and chat with monkeybot agents.
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Requires-Dist: httpx>=0.27.0
|
|
7
|
+
Requires-Dist: monkeybot[cli]<3,>=2.1.0
|
|
8
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
9
|
+
Requires-Dist: pyyaml>=6.0.2
|
|
10
|
+
Requires-Dist: textual>=8.2.8
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
monkeybot_cli/__init__.py,sha256=wY_ibP8EOvlRJ-ilQCELArtd50fWMEfES-AWVIW55n0,105
|
|
2
|
+
monkeybot_cli/chat_renderer.py,sha256=vNViB76sRDO9CngHENeCmZCwoYVXRXNMv5Ca1C2A_lw,2287
|
|
3
|
+
monkeybot_cli/chat_session.py,sha256=8S9ravk2I8PlkTGbgZTqYN6S83-rLVOHVzAZ8wys7OI,34416
|
|
4
|
+
monkeybot_cli/chat_status_bar.py,sha256=Hs3QhzFW2awTqsgFMb2iNxrYb01Kk-NnonYiIy2_9Cs,7015
|
|
5
|
+
monkeybot_cli/chat_theme.py,sha256=GGXyARkN-VZBNdhU0ZX9Tzz-xZVfWTVg5YwyXxXPuPY,2207
|
|
6
|
+
monkeybot_cli/chat_tool_display.py,sha256=ebAcwB7atxyrzwe3IDQBXurI8pnyQla5PKoqRHQE3ws,9655
|
|
7
|
+
monkeybot_cli/chat_tui.py,sha256=hLuR-sQiedl9qbCNIp0rIFQZDN06e6ncLts56p1HsE0,54201
|
|
8
|
+
monkeybot_cli/chat_tui_widgets.py,sha256=LnA3p1CormGgng2MrKI1mBUANonLgrugkGUqsTUeLOw,31252
|
|
9
|
+
monkeybot_cli/compat.py,sha256=LpanA7hvRKUPCBh_wyAgZ9TvS2_TtSD0z7mVZvDz13Q,287
|
|
10
|
+
monkeybot_cli/config_resolve.py,sha256=QegH7lEQ6INrNKyB7XbRzDltqXdYYI3VwA3oUX76sWs,2029
|
|
11
|
+
monkeybot_cli/exit_commands.py,sha256=6bN2xfMvTJ0e1vKfQ97UJI7m7jCT18v-K1ITFn7mMEE,447
|
|
12
|
+
monkeybot_cli/extras_catalog.py,sha256=QLcZvNDBM9KK0kUq9l3ux02KunYK6_IgNXyTZjrLc4o,3587
|
|
13
|
+
monkeybot_cli/gateway_health.py,sha256=CHoJr3NyNsoUyE8xECbw7MnVf5XqyNfnY4mnfVoCT8s,927
|
|
14
|
+
monkeybot_cli/main.py,sha256=2Q0-ZKu7gvVsxE-zsrQfbsWSzdlEWX9I5RsO9cHJiuQ,1027
|
|
15
|
+
monkeybot_cli/opensandbox_lifecycle.py,sha256=FgN11n7f-05509VVLYQeqfDsp4jCfAZgU9F-wT7Tza0,9241
|
|
16
|
+
monkeybot_cli/output.py,sha256=u50fc_ebzV3eJMhwTQgDljxJD8m6mQCwh8lZCyxOuzQ,3154
|
|
17
|
+
monkeybot_cli/providers.py,sha256=18-jvjgVv19A9bGh_oVTps5cVgKxDbq45XXAgBa_ROc,3794
|
|
18
|
+
monkeybot_cli/runtime_python.py,sha256=a50d3tAL1cOSv0ftljMfqoHbjSaq9q94DIM36xPxvb8,3306
|
|
19
|
+
monkeybot_cli/scaffold.py,sha256=laeiL7FJO254XsDyBj8UDhqwJuGxrqdnPk19yFW8F0M,9943
|
|
20
|
+
monkeybot_cli/session_controller.py,sha256=xZUvFUmkCUrbVyq6j_MwZuvqkva7exzFgPzakd93_x8,242
|
|
21
|
+
monkeybot_cli/terminal_markdown.py,sha256=teL9EIsHOcbHRduqmJcUbK4rpsM1hTipCAh2hamHASc,1426
|
|
22
|
+
monkeybot_cli/commands/__init__.py,sha256=QN-uD3qaiBO7K7E4QEfRPnoh3rvXcIe89veVtfE8c38,23
|
|
23
|
+
monkeybot_cli/commands/chat.py,sha256=pCcE6HwGv5Eb304oy5BL1GmI_7lRiLxpv3LqwiLJnKg,29582
|
|
24
|
+
monkeybot_cli/commands/doctor.py,sha256=fUWHRD9dJm_gk1zI8KBZ51GafK9pfZFPXvl-TY3q_YU,10576
|
|
25
|
+
monkeybot_cli/commands/loop.py,sha256=U9nFz7xUkXN96zUEuo8LsM4cnNFWQ80cnPgWrZNvevk,7969
|
|
26
|
+
monkeybot_cli/commands/new.py,sha256=A5V2w3NWsRHmH9HA0wV-epZdwf1QfXLAK3jRDmGoQWs,6896
|
|
27
|
+
monkeybot_cli/commands/run_cmd.py,sha256=4aS0k46Hhxi1JUelIewPcE4XGtCtfPUTLH4hysCqD_Y,1700
|
|
28
|
+
monkeybot_cli/commands/talk.py,sha256=ZbZnylhCuqhygeFxmNUkyV3NnSD5dWcjNzxnkqdgssY,3353
|
|
29
|
+
monkeybot_cli/commands/validate.py,sha256=T1EPrY6cEzcgwMuHocS2ulnSKS1QvjVv2kwhCi6XwGI,14792
|
|
30
|
+
monkeybot_cli/realtime/__init__.py,sha256=MoHbb_vyPzbUhEUjBCsNxIRu222i-59zE0rM91QhiIw,403
|
|
31
|
+
monkeybot_cli/realtime/audio_io.py,sha256=cBrQ4CtvtnJXWP75NzBPMDCL6HvaYAAHDcg4PbGGc9Y,4747
|
|
32
|
+
monkeybot_cli/realtime/client.py,sha256=GQd9unAh3LlBYTKfvo1o1yYOAR91XLfqo3icG-1ff74,428
|
|
33
|
+
monkeybot_cli/realtime/gateway_manager.py,sha256=K5gFozKDJL1RzNQFLQ96YpDcatzWXc1fzP0MFpd8afQ,4455
|
|
34
|
+
monkeybot_cli/realtime/push_to_talk.py,sha256=ssZVY2UzgRLLDi_zn8ZgDHIpxXIDTCWnNBgW3R7H25E,4352
|
|
35
|
+
monkeybot_cli/realtime/session.py,sha256=HkTqyQfOJs2JDmN1uLLytKyEpqIiljHb4MXYm6WWXPI,7597
|
|
36
|
+
monkeybot_cli/realtime/session_controller.py,sha256=Hv7csdP2rim5HxzikBgSdFlOMHMOgCdEbALZNAliLN8,19488
|
|
37
|
+
monkeybot_cli/realtime/talk_ui.py,sha256=TNrsdBHyIrAF8dvya32uU6YEJEuFc5IZzhzXlAC4wqY,7575
|
|
38
|
+
monkeybot_cli/realtime/wire_encode.py,sha256=ARME556aULnaxq6QHUgnSFnAb9Hxo0bhsvsoeiIkR6U,1234
|
|
39
|
+
monkeybot_cli/scaffold_defaults/AGENT.md,sha256=Lk9uThJ6VAFvwnXZTe2ksq0qR6dh5Z0noer2mMQJIpk,4651
|
|
40
|
+
monkeybot_cli/scaffold_defaults/__init__.py,sha256=yMy9-a5uQUCDrAuiu_hIozkPFgBlQbKT_88GgRSKFiM,80
|
|
41
|
+
monkeybot_cli/scaffold_defaults/command_allowlist.yaml,sha256=i1xkmD6QIj3QVvOoWdgUc6Ucwe-3pRBuISwFV-YxiOY,1391
|
|
42
|
+
monkeybot_cli/scaffold_defaults/env.example,sha256=itYqeyjbcuHPgrqgB54oWwVZ4qYPht0c3RIsw7-gFjY,832
|
|
43
|
+
monkeybot_cli/scaffold_defaults/mcp.json,sha256=s2owUAAkKwFZmM84pBEV6tGNrxSSjAMNtvi4MZmxn4U,1333
|
|
44
|
+
monkeybot_cli/scaffold_defaults/monkeybot.example.yaml,sha256=yqatkC4wqBrobwLLIsld-jn3QK3sebKGjVPLxDnnKzw,7699
|
|
45
|
+
monkeybot_cli/scaffold_defaults/otel-collector.example.yaml,sha256=AqhbJEPHLV0BZ6i3q2Tvlt17R0B7wDWM0kzUuLnNrXw,2086
|
|
46
|
+
monkeybot_cli/scaffold_defaults/permissions.yaml,sha256=Vmr0JuRiIgHUZ4l33NGJC4-98ZZcaNwa2aY0Yo8bJQc,923
|
|
47
|
+
monkeybot_cli/scaffold_defaults/setup-workspace.sh,sha256=eNZ-LXjRun5jrsyCqnNJP7zR9vuBrA0eQR7wFjdR0zA,596
|
|
48
|
+
monkeybot_cli-0.2.1.dist-info/METADATA,sha256=R9mHeKyWTIBseWM4XF7ndCi18MM1NXHC7GeFx9pLFes,322
|
|
49
|
+
monkeybot_cli-0.2.1.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
50
|
+
monkeybot_cli-0.2.1.dist-info/entry_points.txt,sha256=BCUQ-d2jRWJszkNo9tCr6YHLqAhDTr1mh9Txxi7dVJI,54
|
|
51
|
+
monkeybot_cli-0.2.1.dist-info/RECORD,,
|