maple-mcp 0.1.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.
- maple_mcp-0.1.0/.env.example +16 -0
- maple_mcp-0.1.0/.github/workflows/publish.yml +22 -0
- maple_mcp-0.1.0/.github/workflows/test.yml +68 -0
- maple_mcp-0.1.0/.gitignore +37 -0
- maple_mcp-0.1.0/LICENSE +21 -0
- maple_mcp-0.1.0/PKG-INFO +162 -0
- maple_mcp-0.1.0/README.md +118 -0
- maple_mcp-0.1.0/docker-compose.ci.yaml +100 -0
- maple_mcp-0.1.0/examples/block_sorting/.env.example +18 -0
- maple_mcp-0.1.0/examples/block_sorting/README.md +99 -0
- maple_mcp-0.1.0/examples/block_sorting/default.node.info.yaml +124 -0
- maple_mcp-0.1.0/examples/block_sorting/default.node.yaml +7 -0
- maple_mcp-0.1.0/examples/block_sorting/maple.config.yaml +26 -0
- maple_mcp-0.1.0/examples/block_sorting/mock_agent.py +208 -0
- maple_mcp-0.1.0/examples/block_sorting/stub_node.py +166 -0
- maple_mcp-0.1.0/examples/block_sorting/vision.py +54 -0
- maple_mcp-0.1.0/figures/architecture-1.png +0 -0
- maple_mcp-0.1.0/figures/architecture.tex +62 -0
- maple_mcp-0.1.0/maple/__init__.py +3 -0
- maple_mcp-0.1.0/maple/attach.py +128 -0
- maple_mcp-0.1.0/maple/auth.py +63 -0
- maple_mcp-0.1.0/maple/cli.py +220 -0
- maple_mcp-0.1.0/maple/config.py +189 -0
- maple_mcp-0.1.0/maple/hooks.py +37 -0
- maple_mcp-0.1.0/maple/middleware.py +42 -0
- maple_mcp-0.1.0/maple/models.py +40 -0
- maple_mcp-0.1.0/maple/operator/__init__.py +1 -0
- maple_mcp-0.1.0/maple/operator/agent.py +292 -0
- maple_mcp-0.1.0/maple/operator/prompt.md +48 -0
- maple_mcp-0.1.0/maple/operator/server.py +511 -0
- maple_mcp-0.1.0/maple/overseer/__init__.py +1 -0
- maple_mcp-0.1.0/maple/overseer/agent.py +213 -0
- maple_mcp-0.1.0/maple/overseer/prompt.md +56 -0
- maple_mcp-0.1.0/maple/overseer/server.py +429 -0
- maple_mcp-0.1.0/maple/services.py +229 -0
- maple_mcp-0.1.0/maple/sessions.py +184 -0
- maple_mcp-0.1.0/maple/tui.py +273 -0
- maple_mcp-0.1.0/maple/vision.py +58 -0
- maple_mcp-0.1.0/maple.config.example.yaml +24 -0
- maple_mcp-0.1.0/pyproject.toml +74 -0
- maple_mcp-0.1.0/tests/__init__.py +0 -0
- maple_mcp-0.1.0/tests/conftest.py +73 -0
- maple_mcp-0.1.0/tests/fixtures/custom_prompt.md +2 -0
- maple_mcp-0.1.0/tests/fixtures/custom_tool.py +10 -0
- maple_mcp-0.1.0/tests/fixtures/maple.config.yaml +10 -0
- maple_mcp-0.1.0/tests/test_cli.py +81 -0
- maple_mcp-0.1.0/tests/test_config.py +159 -0
- maple_mcp-0.1.0/tests/test_integration_custom.py +105 -0
- maple_mcp-0.1.0/tests/test_integration_full.py +371 -0
- maple_mcp-0.1.0/tests/test_integration_stub.py +227 -0
- maple_mcp-0.1.0/tests/test_overseer.py +117 -0
- maple_mcp-0.1.0/tests/test_sessions.py +210 -0
- maple_mcp-0.1.0/tests/test_tui.py +41 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# MADSci Service URLs
|
|
2
|
+
WORKCELL_SERVER_URL=http://localhost:8005/
|
|
3
|
+
DATA_SERVER_URL=http://localhost:8004/
|
|
4
|
+
EVENT_SERVER_URL=http://localhost:8001/
|
|
5
|
+
EXPERIMENT_SERVER_URL=http://localhost:8002/
|
|
6
|
+
|
|
7
|
+
# LLM Backend (pick one)
|
|
8
|
+
MODEL_PROVIDER=openai
|
|
9
|
+
OPENAI_API_KEY=sk-...
|
|
10
|
+
# MODEL_PROVIDER=anthropic
|
|
11
|
+
# ANTHROPIC_API_KEY=sk-ant-...
|
|
12
|
+
# MODEL_PROVIDER=ollama
|
|
13
|
+
# OLLAMA_HOST=http://localhost:11434
|
|
14
|
+
|
|
15
|
+
# Agent model (override per-agent if needed)
|
|
16
|
+
EXECUTOR_AGENT_MODEL=gpt-4o
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
permissions:
|
|
11
|
+
id-token: write
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
- uses: actions/setup-python@v5
|
|
15
|
+
with:
|
|
16
|
+
python-version: "3.11"
|
|
17
|
+
- name: Install build tools
|
|
18
|
+
run: pip install build
|
|
19
|
+
- name: Build package
|
|
20
|
+
run: python -m build
|
|
21
|
+
- name: Publish to PyPI
|
|
22
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths-ignore:
|
|
7
|
+
- '**.md'
|
|
8
|
+
- 'figures/**'
|
|
9
|
+
- 'LICENSE'
|
|
10
|
+
pull_request:
|
|
11
|
+
branches: [main]
|
|
12
|
+
paths-ignore:
|
|
13
|
+
- '**.md'
|
|
14
|
+
- 'figures/**'
|
|
15
|
+
- 'LICENSE'
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
unit:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
strategy:
|
|
21
|
+
matrix:
|
|
22
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v4
|
|
25
|
+
- uses: actions/setup-python@v5
|
|
26
|
+
with:
|
|
27
|
+
python-version: ${{ matrix.python-version }}
|
|
28
|
+
- name: Install dependencies
|
|
29
|
+
run: pip install -e ".[dev]"
|
|
30
|
+
- name: Run unit tests
|
|
31
|
+
run: pytest -m "not integration" --tb=short
|
|
32
|
+
|
|
33
|
+
integration:
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
needs: unit
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v4
|
|
38
|
+
- uses: actions/setup-python@v5
|
|
39
|
+
with:
|
|
40
|
+
python-version: "3.11"
|
|
41
|
+
- name: Install dependencies
|
|
42
|
+
run: pip install -e ".[dev]"
|
|
43
|
+
|
|
44
|
+
- name: Start MADSci services
|
|
45
|
+
run: |
|
|
46
|
+
docker compose -f docker-compose.ci.yaml up -d
|
|
47
|
+
echo "Waiting for services to be ready..."
|
|
48
|
+
sleep 20
|
|
49
|
+
|
|
50
|
+
- name: Verify services are up
|
|
51
|
+
run: |
|
|
52
|
+
curl -sf http://localhost:8001/health || (echo "Event Manager not ready" && exit 1)
|
|
53
|
+
curl -sf http://localhost:8005/health || (echo "Workcell Manager not ready" && exit 1)
|
|
54
|
+
echo "✓ MADSci services ready"
|
|
55
|
+
|
|
56
|
+
- name: Create .env for integration tests
|
|
57
|
+
run: |
|
|
58
|
+
printf 'WORKCELL_SERVER_URL=http://localhost:8005/\nEXPERIMENT_SERVER_URL=http://localhost:8002/\nEVENT_SERVER_URL=http://localhost:8001/\nDATA_SERVER_URL=http://localhost:8004/\nRESOURCE_SERVER_URL=http://localhost:8003/\nLOCATION_SERVER_URL=http://localhost:8006/\nMCP_OPERATOR_URL=http://localhost:8102/mcp\n' > examples/block_sorting/.env
|
|
59
|
+
cp examples/block_sorting/.env .env
|
|
60
|
+
|
|
61
|
+
- name: Run integration tests
|
|
62
|
+
run: pytest -m integration --tb=short
|
|
63
|
+
|
|
64
|
+
- name: Tear down
|
|
65
|
+
if: always()
|
|
66
|
+
run: |
|
|
67
|
+
maple down
|
|
68
|
+
docker compose -f docker-compose.ci.yaml down -v
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Specs (internal planning docs)
|
|
2
|
+
specs/
|
|
3
|
+
|
|
4
|
+
# Python
|
|
5
|
+
__pycache__/
|
|
6
|
+
*.py[cod]
|
|
7
|
+
*$py.class
|
|
8
|
+
*.egg-info/
|
|
9
|
+
dist/
|
|
10
|
+
build/
|
|
11
|
+
.eggs/
|
|
12
|
+
|
|
13
|
+
# Virtual environment
|
|
14
|
+
.venv/
|
|
15
|
+
venv/
|
|
16
|
+
env/
|
|
17
|
+
|
|
18
|
+
# IDE
|
|
19
|
+
.idea/
|
|
20
|
+
.vscode/
|
|
21
|
+
*.swp
|
|
22
|
+
*.swo
|
|
23
|
+
|
|
24
|
+
# OS
|
|
25
|
+
.DS_Store
|
|
26
|
+
Thumbs.db
|
|
27
|
+
|
|
28
|
+
# Environment
|
|
29
|
+
.env
|
|
30
|
+
|
|
31
|
+
# Sessions
|
|
32
|
+
sessions/
|
|
33
|
+
|
|
34
|
+
# Test artifacts
|
|
35
|
+
.pytest_cache/
|
|
36
|
+
.coverage
|
|
37
|
+
htmlcov/
|
maple_mcp-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Gabriel Ferrer
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
maple_mcp-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: maple-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Model-Agnostic Platform for Laboratory Experiments — LLM agents for autonomous MADSci experiments via MCP
|
|
5
|
+
Project-URL: Homepage, https://github.com/gabrielferrer/maple-mcp
|
|
6
|
+
Project-URL: Repository, https://github.com/gabrielferrer/maple-mcp
|
|
7
|
+
Project-URL: Issues, https://github.com/gabrielferrer/maple-mcp/issues
|
|
8
|
+
Author: Gabriel Ferrer
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: agents,autonomous-lab,llm,madsci,mcp,robotics
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Requires-Dist: fastapi>=0.100.0
|
|
22
|
+
Requires-Dist: fastmcp>=2.0.0
|
|
23
|
+
Requires-Dist: httpx>=0.24.0
|
|
24
|
+
Requires-Dist: madsci-client<0.6.0,>=0.5.0
|
|
25
|
+
Requires-Dist: madsci-common<0.6.0,>=0.5.0
|
|
26
|
+
Requires-Dist: madsci-experiment-application<0.6.0,>=0.5.0
|
|
27
|
+
Requires-Dist: madsci-node-module<0.6.0,>=0.5.0
|
|
28
|
+
Requires-Dist: numpy>=1.24.0
|
|
29
|
+
Requires-Dist: openai>=1.0.0
|
|
30
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
31
|
+
Requires-Dist: pyyaml>=6.0
|
|
32
|
+
Requires-Dist: rich>=13.0.0
|
|
33
|
+
Requires-Dist: strands-agents[anthropic,ollama]>=1.0.0
|
|
34
|
+
Requires-Dist: textual>=4.0.0
|
|
35
|
+
Requires-Dist: typer>=0.9.0
|
|
36
|
+
Requires-Dist: uvicorn>=0.20.0
|
|
37
|
+
Requires-Dist: watchfiles>=0.20.0
|
|
38
|
+
Provides-Extra: dev
|
|
39
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
|
40
|
+
Requires-Dist: pytest-mock>=3.10.0; extra == 'dev'
|
|
41
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
42
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
43
|
+
Description-Content-Type: text/markdown
|
|
44
|
+
|
|
45
|
+
# MAPLE
|
|
46
|
+
|
|
47
|
+
**Model-Agnostic Platform for Laboratory Experiments**
|
|
48
|
+
|
|
49
|
+
MAPLE adds LLM agent capabilities to any [MADSci](https://github.com/AD-SDL/MADSci)-powered laboratory (v0.5.x) via MCP. Two agents — an **Operator** for experiment execution and an **Overseer** for lab monitoring — connect to your lab through configurable MCP servers.
|
|
50
|
+
|
|
51
|
+
## Architecture
|
|
52
|
+
|
|
53
|
+

|
|
54
|
+
|
|
55
|
+
## Quick Start
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install maple-mcp
|
|
59
|
+
cd your-experiment/
|
|
60
|
+
cp .env.example .env # Configure MADSci URLs + model provider
|
|
61
|
+
maple serve stub # Start demo (no LLM needed)
|
|
62
|
+
maple chat operator # Open TUI — type anything
|
|
63
|
+
maple down # Stop all services
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
For a real LLM experiment:
|
|
67
|
+
```bash
|
|
68
|
+
maple serve operator # Start with your configured model
|
|
69
|
+
maple chat operator # Run an experiment
|
|
70
|
+
maple chat operator --resume # Pick up where you left off
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
See [`examples/block_sorting/`](examples/block_sorting/) for a complete walkthrough.
|
|
74
|
+
|
|
75
|
+
## Installation
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
pip install maple-mcp
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Requires Python 3.10+ and a running [MADSci](https://github.com/AD-SDL/MADSci) lab (v0.5.x).
|
|
82
|
+
|
|
83
|
+
## CLI
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
maple serve {all, operator, overseer, stub, mock} [--dev]
|
|
87
|
+
maple chat {operator, overseer} [--resume]
|
|
88
|
+
maple down
|
|
89
|
+
maple status
|
|
90
|
+
maple logs
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Configuration
|
|
94
|
+
|
|
95
|
+
One `maple.config.yaml` per experiment:
|
|
96
|
+
|
|
97
|
+
```yaml
|
|
98
|
+
experiment:
|
|
99
|
+
name: My Experiment
|
|
100
|
+
objective: Sort samples by type
|
|
101
|
+
constraints:
|
|
102
|
+
- "Only handle one sample at a time"
|
|
103
|
+
|
|
104
|
+
operator:
|
|
105
|
+
vision_backend: "vision:MyVision"
|
|
106
|
+
custom_tools:
|
|
107
|
+
- "my_tools:prepare_sample"
|
|
108
|
+
post_action_hooks:
|
|
109
|
+
- node: AnalysisNode
|
|
110
|
+
action: verify_placement
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Infrastructure goes in `.env` (IPs, API keys, model provider).
|
|
114
|
+
|
|
115
|
+
## Extending MAPLE
|
|
116
|
+
|
|
117
|
+
| Extension Point | Mechanism | Config Key |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| Vision detection | Subclass `VisionBackend` | `operator.vision_backend` |
|
|
120
|
+
| MCP tools | `@mcp.tool` decorator | `operator.custom_tools` / `overseer.custom_tools` |
|
|
121
|
+
| Agent hooks | `extra_hooks` param on factory | Programmatic |
|
|
122
|
+
| Post-action hooks | YAML (no code) | `operator.post_action_hooks` |
|
|
123
|
+
| System prompts | Markdown file | `operator.prompt` / `overseer.prompt` |
|
|
124
|
+
|
|
125
|
+
## Supported Models
|
|
126
|
+
|
|
127
|
+
| Provider | Environment Variable |
|
|
128
|
+
|---|---|
|
|
129
|
+
| OpenAI | `MODEL_PROVIDER=openai` |
|
|
130
|
+
| Anthropic | `MODEL_PROVIDER=anthropic` |
|
|
131
|
+
| Ollama (local, free) | `MODEL_PROVIDER=ollama` |
|
|
132
|
+
|
|
133
|
+
## Multi-User
|
|
134
|
+
|
|
135
|
+
Each device auto-generates a unique identity token. Multiple users can run experiments simultaneously — sessions are isolated automatically.
|
|
136
|
+
|
|
137
|
+
## Programmatic Usage
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
from maple.operator.agent import create_operator_agent
|
|
141
|
+
|
|
142
|
+
agent = create_operator_agent("my-session")
|
|
143
|
+
result = agent("Sort the colored blocks by color.")
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Testing
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
pytest -m "not integration" # Unit tests (no network)
|
|
150
|
+
docker compose -f docker-compose.ci.yaml up -d # Start MADSci
|
|
151
|
+
pytest -m integration # Integration tests
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Compatibility
|
|
155
|
+
|
|
156
|
+
- Python 3.10+
|
|
157
|
+
- MADSci >=0.5.0, <0.6.0
|
|
158
|
+
- FastMCP 3.x
|
|
159
|
+
|
|
160
|
+
## License
|
|
161
|
+
|
|
162
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# MAPLE
|
|
2
|
+
|
|
3
|
+
**Model-Agnostic Platform for Laboratory Experiments**
|
|
4
|
+
|
|
5
|
+
MAPLE adds LLM agent capabilities to any [MADSci](https://github.com/AD-SDL/MADSci)-powered laboratory (v0.5.x) via MCP. Two agents — an **Operator** for experiment execution and an **Overseer** for lab monitoring — connect to your lab through configurable MCP servers.
|
|
6
|
+
|
|
7
|
+
## Architecture
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install maple-mcp
|
|
15
|
+
cd your-experiment/
|
|
16
|
+
cp .env.example .env # Configure MADSci URLs + model provider
|
|
17
|
+
maple serve stub # Start demo (no LLM needed)
|
|
18
|
+
maple chat operator # Open TUI — type anything
|
|
19
|
+
maple down # Stop all services
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
For a real LLM experiment:
|
|
23
|
+
```bash
|
|
24
|
+
maple serve operator # Start with your configured model
|
|
25
|
+
maple chat operator # Run an experiment
|
|
26
|
+
maple chat operator --resume # Pick up where you left off
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
See [`examples/block_sorting/`](examples/block_sorting/) for a complete walkthrough.
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install maple-mcp
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Requires Python 3.10+ and a running [MADSci](https://github.com/AD-SDL/MADSci) lab (v0.5.x).
|
|
38
|
+
|
|
39
|
+
## CLI
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
maple serve {all, operator, overseer, stub, mock} [--dev]
|
|
43
|
+
maple chat {operator, overseer} [--resume]
|
|
44
|
+
maple down
|
|
45
|
+
maple status
|
|
46
|
+
maple logs
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Configuration
|
|
50
|
+
|
|
51
|
+
One `maple.config.yaml` per experiment:
|
|
52
|
+
|
|
53
|
+
```yaml
|
|
54
|
+
experiment:
|
|
55
|
+
name: My Experiment
|
|
56
|
+
objective: Sort samples by type
|
|
57
|
+
constraints:
|
|
58
|
+
- "Only handle one sample at a time"
|
|
59
|
+
|
|
60
|
+
operator:
|
|
61
|
+
vision_backend: "vision:MyVision"
|
|
62
|
+
custom_tools:
|
|
63
|
+
- "my_tools:prepare_sample"
|
|
64
|
+
post_action_hooks:
|
|
65
|
+
- node: AnalysisNode
|
|
66
|
+
action: verify_placement
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Infrastructure goes in `.env` (IPs, API keys, model provider).
|
|
70
|
+
|
|
71
|
+
## Extending MAPLE
|
|
72
|
+
|
|
73
|
+
| Extension Point | Mechanism | Config Key |
|
|
74
|
+
|---|---|---|
|
|
75
|
+
| Vision detection | Subclass `VisionBackend` | `operator.vision_backend` |
|
|
76
|
+
| MCP tools | `@mcp.tool` decorator | `operator.custom_tools` / `overseer.custom_tools` |
|
|
77
|
+
| Agent hooks | `extra_hooks` param on factory | Programmatic |
|
|
78
|
+
| Post-action hooks | YAML (no code) | `operator.post_action_hooks` |
|
|
79
|
+
| System prompts | Markdown file | `operator.prompt` / `overseer.prompt` |
|
|
80
|
+
|
|
81
|
+
## Supported Models
|
|
82
|
+
|
|
83
|
+
| Provider | Environment Variable |
|
|
84
|
+
|---|---|
|
|
85
|
+
| OpenAI | `MODEL_PROVIDER=openai` |
|
|
86
|
+
| Anthropic | `MODEL_PROVIDER=anthropic` |
|
|
87
|
+
| Ollama (local, free) | `MODEL_PROVIDER=ollama` |
|
|
88
|
+
|
|
89
|
+
## Multi-User
|
|
90
|
+
|
|
91
|
+
Each device auto-generates a unique identity token. Multiple users can run experiments simultaneously — sessions are isolated automatically.
|
|
92
|
+
|
|
93
|
+
## Programmatic Usage
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
from maple.operator.agent import create_operator_agent
|
|
97
|
+
|
|
98
|
+
agent = create_operator_agent("my-session")
|
|
99
|
+
result = agent("Sort the colored blocks by color.")
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Testing
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
pytest -m "not integration" # Unit tests (no network)
|
|
106
|
+
docker compose -f docker-compose.ci.yaml up -d # Start MADSci
|
|
107
|
+
pytest -m integration # Integration tests
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Compatibility
|
|
111
|
+
|
|
112
|
+
- Python 3.10+
|
|
113
|
+
- MADSci >=0.5.0, <0.6.0
|
|
114
|
+
- FastMCP 3.x
|
|
115
|
+
|
|
116
|
+
## License
|
|
117
|
+
|
|
118
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
name: maple_ci
|
|
2
|
+
|
|
3
|
+
# Minimal MADSci stack for MAPLE integration tests.
|
|
4
|
+
# No lab dashboard, no minio — just the managers needed for E2E testing.
|
|
5
|
+
|
|
6
|
+
x-madsci-service: &madsci-service
|
|
7
|
+
image: ghcr.io/ad-sdl/madsci:v0.5.0
|
|
8
|
+
network_mode: host
|
|
9
|
+
extra_hosts:
|
|
10
|
+
- "host.docker.internal:host-gateway"
|
|
11
|
+
environment:
|
|
12
|
+
- USER_ID=1000
|
|
13
|
+
- GROUP_ID=1000
|
|
14
|
+
restart: "no"
|
|
15
|
+
|
|
16
|
+
services:
|
|
17
|
+
# === DATABASES ===
|
|
18
|
+
|
|
19
|
+
mongodb:
|
|
20
|
+
container_name: mongodb
|
|
21
|
+
image: mongo:8.0
|
|
22
|
+
network_mode: host
|
|
23
|
+
volumes:
|
|
24
|
+
- mongodb_data:/data/db
|
|
25
|
+
|
|
26
|
+
redis:
|
|
27
|
+
container_name: redis
|
|
28
|
+
image: redis:7.4
|
|
29
|
+
network_mode: host
|
|
30
|
+
command: redis-server --appendonly yes
|
|
31
|
+
|
|
32
|
+
postgres:
|
|
33
|
+
container_name: postgres
|
|
34
|
+
image: postgres:17
|
|
35
|
+
network_mode: host
|
|
36
|
+
environment:
|
|
37
|
+
- POSTGRES_USER=madsci
|
|
38
|
+
- POSTGRES_PASSWORD=madsci
|
|
39
|
+
- POSTGRES_DB=resources
|
|
40
|
+
|
|
41
|
+
# === MANAGERS ===
|
|
42
|
+
|
|
43
|
+
event_manager:
|
|
44
|
+
<<: *madsci-service
|
|
45
|
+
container_name: event_manager
|
|
46
|
+
command: python -m madsci.event_manager.event_server --host 0.0.0.0 --port 8001
|
|
47
|
+
depends_on:
|
|
48
|
+
- mongodb
|
|
49
|
+
|
|
50
|
+
resource_manager:
|
|
51
|
+
<<: *madsci-service
|
|
52
|
+
container_name: resource_manager
|
|
53
|
+
command: python -m madsci.resource_manager.resource_server --host 0.0.0.0 --port 8003
|
|
54
|
+
depends_on:
|
|
55
|
+
- postgres
|
|
56
|
+
- event_manager
|
|
57
|
+
|
|
58
|
+
data_manager:
|
|
59
|
+
<<: *madsci-service
|
|
60
|
+
container_name: data_manager
|
|
61
|
+
command: python -m madsci.data_manager.data_server --host 0.0.0.0 --port 8004
|
|
62
|
+
depends_on:
|
|
63
|
+
- mongodb
|
|
64
|
+
- event_manager
|
|
65
|
+
|
|
66
|
+
experiment_manager:
|
|
67
|
+
<<: *madsci-service
|
|
68
|
+
container_name: experiment_manager
|
|
69
|
+
command: python -m madsci.experiment_manager.experiment_server --host 0.0.0.0 --port 8002
|
|
70
|
+
depends_on:
|
|
71
|
+
- mongodb
|
|
72
|
+
- event_manager
|
|
73
|
+
|
|
74
|
+
workcell_manager:
|
|
75
|
+
<<: *madsci-service
|
|
76
|
+
container_name: workcell_manager
|
|
77
|
+
command: python -m madsci.workcell_manager.workcell_server --host 0.0.0.0 --port 8005
|
|
78
|
+
environment:
|
|
79
|
+
- USER_ID=1000
|
|
80
|
+
- GROUP_ID=1000
|
|
81
|
+
- LOCATION_SERVER_URL=http://localhost:8006/
|
|
82
|
+
- RESOURCE_SERVER_URL=http://localhost:8003/
|
|
83
|
+
- EVENT_SERVER_URL=http://localhost:8001/
|
|
84
|
+
- DATA_SERVER_URL=http://localhost:8004/
|
|
85
|
+
depends_on:
|
|
86
|
+
- redis
|
|
87
|
+
- mongodb
|
|
88
|
+
- resource_manager
|
|
89
|
+
- event_manager
|
|
90
|
+
- postgres
|
|
91
|
+
|
|
92
|
+
location_manager:
|
|
93
|
+
<<: *madsci-service
|
|
94
|
+
container_name: location_manager
|
|
95
|
+
command: python -m madsci.location_manager.location_server --host 0.0.0.0 --port 8006
|
|
96
|
+
depends_on:
|
|
97
|
+
- redis
|
|
98
|
+
|
|
99
|
+
volumes:
|
|
100
|
+
mongodb_data:
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Environment variables for the block sorting demo.
|
|
2
|
+
# Copy to .env and adjust as needed.
|
|
3
|
+
|
|
4
|
+
# MADSci service URLs
|
|
5
|
+
WORKCELL_SERVER_URL=http://localhost:8005/
|
|
6
|
+
EXPERIMENT_SERVER_URL=http://localhost:8002/
|
|
7
|
+
EVENT_SERVER_URL=http://localhost:8001/
|
|
8
|
+
DATA_SERVER_URL=http://localhost:8004/
|
|
9
|
+
RESOURCE_SERVER_URL=http://localhost:8003/
|
|
10
|
+
LOCATION_SERVER_URL=http://localhost:8006/
|
|
11
|
+
|
|
12
|
+
# MCP server URL (Operator)
|
|
13
|
+
MCP_OPERATOR_URL=http://localhost:8102/mcp
|
|
14
|
+
|
|
15
|
+
# Model provider (not needed for mock agent demo)
|
|
16
|
+
# MODEL_PROVIDER=ollama
|
|
17
|
+
# OLLAMA_HOST=http://localhost:11434
|
|
18
|
+
# OPERATOR_MODEL=qwen3:8b
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Block Sorting Demo
|
|
2
|
+
|
|
3
|
+
A self-contained example demonstrating the full MAPLE pipeline. Uses a stub robot node, mock agent (no LLM needed), and an example VisionBackend.
|
|
4
|
+
|
|
5
|
+
## What's Included
|
|
6
|
+
|
|
7
|
+
| File | Purpose |
|
|
8
|
+
|------|---------|
|
|
9
|
+
| `vision.py` | `ExampleVision` — hardcoded VisionBackend (3 blocks, always sorted) |
|
|
10
|
+
| `stub_node.py` | Minimal MADSci node with `pick_and_place` action |
|
|
11
|
+
| `mock_agent.py` | Scripted agent — walks through full experiment without an LLM |
|
|
12
|
+
| `maple.config.yaml` | MAPLE config pointing to `vision:ExampleVision` |
|
|
13
|
+
| `.env.example` | Template for service URLs |
|
|
14
|
+
|
|
15
|
+
## Prerequisites
|
|
16
|
+
|
|
17
|
+
- Python 3.10+
|
|
18
|
+
- `pip install maple-mcp`
|
|
19
|
+
- A running MADSci lab (real or example lab via `docker compose`)
|
|
20
|
+
|
|
21
|
+
## Setup
|
|
22
|
+
|
|
23
|
+
### 1. Configure environment
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
cd examples/block_sorting
|
|
27
|
+
cp .env.example .env
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Edit `.env` with your MADSci service URLs. Set `NODE_URL` to the address the Workcell Manager can reach your stub node at.
|
|
31
|
+
|
|
32
|
+
### 2. Start the stub node
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
python stub_node.py
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
You should see:
|
|
39
|
+
```
|
|
40
|
+
✓ Registered StubBot at <NODE_URL> with Workcell Manager
|
|
41
|
+
INFO: Uvicorn running on http://0.0.0.0:2000
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 3. Start the mock agent
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
python mock_agent.py
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 4. Launch the TUI
|
|
51
|
+
|
|
52
|
+
In a separate terminal:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
maple chat --agent operator
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Type anything (e.g., "sort the blocks") and press Enter. The mock agent streams a scripted experiment:
|
|
59
|
+
|
|
60
|
+
1. Registers the experiment
|
|
61
|
+
2. Detects 3 blocks (2 red, 1 blue)
|
|
62
|
+
3. Sorts each block with `pick_and_place`
|
|
63
|
+
4. Verifies all blocks sorted
|
|
64
|
+
5. Ends the experiment
|
|
65
|
+
|
|
66
|
+
Press Enter again to exit.
|
|
67
|
+
|
|
68
|
+
## Cleanup
|
|
69
|
+
|
|
70
|
+
The stub node registers as non-permanent. To remove it, restart the Workcell Manager:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
docker restart workcell_manager
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Going Live
|
|
77
|
+
|
|
78
|
+
To use a real LLM instead of the mock agent:
|
|
79
|
+
|
|
80
|
+
1. Install Ollama: `curl -fsSL https://ollama.com/install.sh | sh`
|
|
81
|
+
2. Pull a model: `ollama pull qwen3:8b`
|
|
82
|
+
3. Add to `.env`:
|
|
83
|
+
```
|
|
84
|
+
MODEL_PROVIDER=ollama
|
|
85
|
+
OLLAMA_HOST=http://localhost:11434
|
|
86
|
+
OPERATOR_MODEL=qwen3:8b
|
|
87
|
+
```
|
|
88
|
+
4. Skip the mock agent — use `maple serve --agent operator --config maple.config.yaml` instead
|
|
89
|
+
5. Run `maple chat --agent operator` and tell it: "Sort the blocks by color"
|
|
90
|
+
|
|
91
|
+
To use real hardware, replace `ExampleVision` with your own `VisionBackend` subclass and update `vision_backend` in `maple.config.yaml`.
|
|
92
|
+
|
|
93
|
+
## Troubleshooting
|
|
94
|
+
|
|
95
|
+
| Problem | Solution |
|
|
96
|
+
|---------|----------|
|
|
97
|
+
| StubBot shows `ready=False` | Check the Workcell Manager can reach NODE_URL |
|
|
98
|
+
| Workflow stuck in "Queued" | Node isn't ready. Verify with `get_nodes()` |
|
|
99
|
+
| Node name already exists | Restart Workcell Manager to clear non-permanent nodes |
|