morpheus-cli 0.5.2 → 0.5.4
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.
- package/README.md +75 -0
- package/dist/runtime/apoc.js +11 -10
- package/dist/runtime/tools/factory.js +18 -6
- package/dist/runtime/webhooks/dispatcher.js +9 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -64,6 +64,81 @@ morpheus session new
|
|
|
64
64
|
morpheus session status
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
+
## Docker
|
|
68
|
+
|
|
69
|
+
### Docker Compose (recommended)
|
|
70
|
+
|
|
71
|
+
**1. Create an `env.docker` file** (referenced by `docker-compose.yml`):
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
cp .env.example env.docker # or create manually
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Minimal `env.docker`:
|
|
78
|
+
|
|
79
|
+
```env
|
|
80
|
+
OPENAI_API_KEY=sk-...
|
|
81
|
+
THE_ARCHITECT_PASS=changeme
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**2. Run:**
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
docker compose up -d
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The dashboard will be available at `http://localhost:3333`.
|
|
91
|
+
|
|
92
|
+
**Useful commands:**
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
docker compose logs -f # follow logs
|
|
96
|
+
docker compose restart morpheus # restart the agent
|
|
97
|
+
docker compose down # stop
|
|
98
|
+
docker compose down -v # stop and remove persistent data
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Data persistence:** configuration and databases are stored in the `morpheus_data` Docker volume (`/root/.morpheus` inside the container). They survive container restarts and rebuilds.
|
|
102
|
+
|
|
103
|
+
**Override variables** at runtime via the `environment` block in `docker-compose.yml` or directly in `env.docker`. All `MORPHEUS_*` env vars work the same as in a native install. See the [Environment Variables](#environment-variables) section for the full list.
|
|
104
|
+
|
|
105
|
+
### Docker (standalone)
|
|
106
|
+
|
|
107
|
+
**Build:**
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
docker build -t morpheus .
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Run:**
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
docker run -d \
|
|
117
|
+
--name morpheus-agent \
|
|
118
|
+
-p 3333:3333 \
|
|
119
|
+
-e OPENAI_API_KEY=sk-... \
|
|
120
|
+
-e THE_ARCHITECT_PASS=changeme \
|
|
121
|
+
-v morpheus_data:/root/.morpheus \
|
|
122
|
+
morpheus
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**With Telegram:**
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
docker run -d \
|
|
129
|
+
--name morpheus-agent \
|
|
130
|
+
-p 3333:3333 \
|
|
131
|
+
-e OPENAI_API_KEY=sk-... \
|
|
132
|
+
-e THE_ARCHITECT_PASS=changeme \
|
|
133
|
+
-e MORPHEUS_TELEGRAM_ENABLED=true \
|
|
134
|
+
-e MORPHEUS_TELEGRAM_TOKEN=<bot-token> \
|
|
135
|
+
-e MORPHEUS_TELEGRAM_ALLOWED_USERS=123456789 \
|
|
136
|
+
-v morpheus_data:/root/.morpheus \
|
|
137
|
+
morpheus
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**Health check:** the container exposes `GET /health` and Docker will probe it every 30s (60s start period, 3 retries before marking unhealthy).
|
|
141
|
+
|
|
67
142
|
## Async Task Execution
|
|
68
143
|
|
|
69
144
|
Morpheus uses asynchronous delegation by default:
|
package/dist/runtime/apoc.js
CHANGED
|
@@ -185,21 +185,21 @@ PHASE 2 — Source Discovery
|
|
|
185
185
|
- Major authoritative publications
|
|
186
186
|
4. Reformulate query if necessary.
|
|
187
187
|
|
|
188
|
-
PHASE 3 — Source Validation
|
|
189
|
-
1.
|
|
190
|
-
2. Read actual page content.
|
|
191
|
-
3.
|
|
192
|
-
4.
|
|
188
|
+
PHASE 3 — Source Validation
|
|
189
|
+
1. Try to open at least 3 distinct URLs with browser_navigate.
|
|
190
|
+
2. Read actual page content from accessible pages.
|
|
191
|
+
3. Ignore inaccessible pages (timeouts, bot blocks, errors).
|
|
192
|
+
4. If ALL navigations fail: use the search snippets as fallback and proceed to Phase 5 with confidence level "Low".
|
|
193
193
|
|
|
194
194
|
PHASE 4 — Cross-Verification
|
|
195
|
-
1. Extract relevant information from each source.
|
|
195
|
+
1. Extract relevant information from each accessible source.
|
|
196
196
|
2. Compare findings:
|
|
197
197
|
- Agreement → verified
|
|
198
198
|
- Minor differences → report variation
|
|
199
199
|
- Conflict → report discrepancy
|
|
200
|
-
3.
|
|
201
|
-
4. If
|
|
202
|
-
"
|
|
200
|
+
3. Seek confirmation from at least 2 reliable sources when possible.
|
|
201
|
+
4. If confirmed by snippets only (all navigations failed), state:
|
|
202
|
+
"Based on search result snippets (page content could not be accessed)."
|
|
203
203
|
|
|
204
204
|
PHASE 5 — Structured Report
|
|
205
205
|
Include:
|
|
@@ -210,8 +210,9 @@ Include:
|
|
|
210
210
|
|
|
211
211
|
ANTI-HALLUCINATION RULES
|
|
212
212
|
- Never answer from prior knowledge without verification.
|
|
213
|
-
- Never stop after reading only one source.
|
|
213
|
+
- Never stop after reading only one source when navigation is successful.
|
|
214
214
|
- Treat time-sensitive information as volatile.
|
|
215
|
+
- NEVER say "no results found" when browser_search returned results — always report what was found, even if only from snippets.
|
|
215
216
|
|
|
216
217
|
|
|
217
218
|
|
|
@@ -40,6 +40,15 @@ function wrapToolWithSanitizedSchema(tool) {
|
|
|
40
40
|
}
|
|
41
41
|
return tool;
|
|
42
42
|
}
|
|
43
|
+
/** Timeout (ms) for connecting to each MCP server and fetching its tools list. */
|
|
44
|
+
const MCP_CONNECT_TIMEOUT_MS = 15_000;
|
|
45
|
+
/**
|
|
46
|
+
* Returns a promise that rejects after `ms` milliseconds with a timeout error.
|
|
47
|
+
* Used to guard `client.getTools()` against servers that never respond.
|
|
48
|
+
*/
|
|
49
|
+
function connectTimeout(serverName, ms) {
|
|
50
|
+
return new Promise((_, reject) => setTimeout(() => reject(new Error(`MCP server '${serverName}' timed out after ${ms}ms`)), ms));
|
|
51
|
+
}
|
|
43
52
|
export class Construtor {
|
|
44
53
|
static async probe() {
|
|
45
54
|
const mcpServers = await loadMCPConfig();
|
|
@@ -50,7 +59,10 @@ export class Construtor {
|
|
|
50
59
|
mcpServers: { [serverName]: serverConfig },
|
|
51
60
|
onConnectionError: "ignore",
|
|
52
61
|
});
|
|
53
|
-
const tools = await
|
|
62
|
+
const tools = await Promise.race([
|
|
63
|
+
client.getTools(),
|
|
64
|
+
connectTimeout(serverName, MCP_CONNECT_TIMEOUT_MS),
|
|
65
|
+
]);
|
|
54
66
|
results.push({ name: serverName, ok: true, toolCount: tools.length });
|
|
55
67
|
}
|
|
56
68
|
catch (error) {
|
|
@@ -63,7 +75,6 @@ export class Construtor {
|
|
|
63
75
|
const display = DisplayManager.getInstance();
|
|
64
76
|
const mcpServers = await loadMCPConfig();
|
|
65
77
|
const serverCount = Object.keys(mcpServers).length;
|
|
66
|
-
// console.log(mcpServers);
|
|
67
78
|
if (serverCount === 0) {
|
|
68
79
|
display.log('No MCP servers configured in mcps.json', { level: 'info', source: 'Construtor' });
|
|
69
80
|
return [];
|
|
@@ -78,13 +89,14 @@ export class Construtor {
|
|
|
78
89
|
onConnectionError: "ignore",
|
|
79
90
|
});
|
|
80
91
|
try {
|
|
81
|
-
const tools = await
|
|
92
|
+
const tools = await Promise.race([
|
|
93
|
+
client.getTools(),
|
|
94
|
+
connectTimeout(serverName, MCP_CONNECT_TIMEOUT_MS),
|
|
95
|
+
]);
|
|
82
96
|
// Rename tools to include server prefix to avoid collisions
|
|
83
97
|
tools.forEach(tool => {
|
|
84
|
-
const
|
|
85
|
-
const newName = `${serverName}_${originalName}`;
|
|
98
|
+
const newName = `${serverName}_${tool.name}`;
|
|
86
99
|
Object.defineProperty(tool, "name", { value: newName });
|
|
87
|
-
const shortDesc = tool.description && typeof tool.description === 'string' ? tool.description.slice(0, 100) + '...' : '';
|
|
88
100
|
display.log(`Loaded MCP tool: ${tool.name} (from ${serverName})`, { level: 'info', source: 'Construtor' });
|
|
89
101
|
});
|
|
90
102
|
// Sanitize tool schemas to remove fields not supported by Gemini
|
|
@@ -127,11 +127,16 @@ Analyze the payload above and follow the instructions provided. Be concise and a
|
|
|
127
127
|
payload = {};
|
|
128
128
|
}
|
|
129
129
|
display.log(`Re-dispatching stale notification ${notification.id} for webhook "${webhook.name}".`, { source: 'Webhooks' });
|
|
130
|
-
//
|
|
131
|
-
|
|
132
|
-
|
|
130
|
+
// Sequential await — recovery dispatches run one at a time.
|
|
131
|
+
// Firing all at once would flood Oracle and cause concurrent
|
|
132
|
+
// EmbeddingService initializations, leading to repeated ONNX errors.
|
|
133
|
+
try {
|
|
134
|
+
const dispatcher = new WebhookDispatcher();
|
|
135
|
+
await dispatcher.dispatch(webhook, payload, notification.id);
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
133
138
|
display.log(`Recovery dispatch error for notification ${notification.id}: ${err.message}`, { source: 'Webhooks', level: 'error' });
|
|
134
|
-
}
|
|
139
|
+
}
|
|
135
140
|
}
|
|
136
141
|
}
|
|
137
142
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "morpheus-cli",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.4",
|
|
4
4
|
"description": "Morpheus is a local AI agent for developers, running as a CLI daemon that connects to LLMs, local tools, and MCPs, enabling interaction via Terminal, Telegram, and Discord. Inspired by the character Morpheus from *The Matrix*, the project acts as an intelligent orchestrator, bridging the gap between the developer and complex systems.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"morpheus": "./bin/morpheus.js"
|