morpheus-cli 0.4.8 → 0.4.10
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.
|
@@ -356,9 +356,18 @@ export class TelegramAdapter {
|
|
|
356
356
|
await fs.writeFile(filePath, buffer);
|
|
357
357
|
return filePath;
|
|
358
358
|
}
|
|
359
|
+
/**
|
|
360
|
+
* Escapes a string for Telegram MarkdownV2 format.
|
|
361
|
+
* All special characters outside code spans must be escaped with a backslash.
|
|
362
|
+
*/
|
|
363
|
+
escapeMarkdownV2(text) {
|
|
364
|
+
// Characters that must be escaped in MarkdownV2 outside of code/pre blocks
|
|
365
|
+
return text.replace(/([_*[\]()~`>#+\-=|{}.!\\])/g, '\\$1');
|
|
366
|
+
}
|
|
359
367
|
/**
|
|
360
368
|
* Sends a proactive message to all allowed Telegram users.
|
|
361
369
|
* Used by the webhook notification system to push results.
|
|
370
|
+
* Tries plain text first to avoid Markdown parse errors from LLM output.
|
|
362
371
|
*/
|
|
363
372
|
async sendMessage(text) {
|
|
364
373
|
if (!this.isConnected || !this.bot) {
|
|
@@ -370,9 +379,14 @@ export class TelegramAdapter {
|
|
|
370
379
|
this.display.log('No allowed Telegram users configured — skipping notification.', { source: 'Telegram', level: 'warning' });
|
|
371
380
|
return;
|
|
372
381
|
}
|
|
382
|
+
// Truncate to Telegram's 4096 char limit
|
|
383
|
+
const MAX_LEN = 4096;
|
|
384
|
+
const safeText = text.length > MAX_LEN ? text.slice(0, MAX_LEN - 3) + '...' : text;
|
|
373
385
|
for (const userId of allowedUsers) {
|
|
374
386
|
try {
|
|
375
|
-
|
|
387
|
+
// Send as plain text — LLM output often has unbalanced markdown that
|
|
388
|
+
// causes "Can't find end of entity" errors with parse_mode: 'Markdown'.
|
|
389
|
+
await this.bot.telegram.sendMessage(userId, safeText);
|
|
376
390
|
}
|
|
377
391
|
catch (err) {
|
|
378
392
|
this.display.log(`Failed to send message to Telegram user ${userId}: ${err.message}`, { source: 'Telegram', level: 'error' });
|
package/dist/runtime/apoc.js
CHANGED
|
@@ -4,6 +4,7 @@ import { ProviderFactory } from "./providers/factory.js";
|
|
|
4
4
|
import { ProviderError } from "./errors.js";
|
|
5
5
|
import { DisplayManager } from "./display.js";
|
|
6
6
|
import { buildDevKit } from "../devkit/index.js";
|
|
7
|
+
import { SQLiteChatMessageHistory } from "./memory/sqlite.js";
|
|
7
8
|
/**
|
|
8
9
|
* Apoc is a subagent of Oracle specialized in devtools operations.
|
|
9
10
|
* It receives delegated tasks from Oracle and executes them using DevKit tools
|
|
@@ -15,12 +16,20 @@ import { buildDevKit } from "../devkit/index.js";
|
|
|
15
16
|
*/
|
|
16
17
|
export class Apoc {
|
|
17
18
|
static instance = null;
|
|
19
|
+
static currentSessionId = undefined;
|
|
18
20
|
agent;
|
|
19
21
|
config;
|
|
20
22
|
display = DisplayManager.getInstance();
|
|
21
23
|
constructor(config) {
|
|
22
24
|
this.config = config || ConfigManager.getInstance().get();
|
|
23
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Called by Oracle before each chat() so Apoc knows which session to
|
|
28
|
+
* attribute its token usage to.
|
|
29
|
+
*/
|
|
30
|
+
static setSessionId(sessionId) {
|
|
31
|
+
Apoc.currentSessionId = sessionId;
|
|
32
|
+
}
|
|
24
33
|
static getInstance(config) {
|
|
25
34
|
if (!Apoc.instance) {
|
|
26
35
|
Apoc.instance = new Apoc(config);
|
|
@@ -54,8 +63,9 @@ export class Apoc {
|
|
|
54
63
|
* Execute a devtools task delegated by Oracle.
|
|
55
64
|
* @param task Natural language task description
|
|
56
65
|
* @param context Optional additional context from the ongoing conversation
|
|
66
|
+
* @param sessionId Session to attribute token usage to (defaults to 'apoc')
|
|
57
67
|
*/
|
|
58
|
-
async execute(task, context) {
|
|
68
|
+
async execute(task, context, sessionId) {
|
|
59
69
|
if (!this.agent) {
|
|
60
70
|
await this.initialize();
|
|
61
71
|
}
|
|
@@ -90,6 +100,23 @@ ${context ? `CONTEXT FROM ORACLE:\n${context}` : ""}
|
|
|
90
100
|
const messages = [systemMessage, userMessage];
|
|
91
101
|
try {
|
|
92
102
|
const response = await this.agent.invoke({ messages });
|
|
103
|
+
// Persist Apoc-generated messages so token usage is tracked in short-memory.db.
|
|
104
|
+
// Use the caller's session when provided, then the static session set by Oracle,
|
|
105
|
+
// otherwise fall back to 'apoc'.
|
|
106
|
+
const apocConfig = this.config.apoc || this.config.llm;
|
|
107
|
+
const newMessages = response.messages.slice(messages.length);
|
|
108
|
+
if (newMessages.length > 0) {
|
|
109
|
+
const targetSession = sessionId ?? Apoc.currentSessionId ?? 'apoc';
|
|
110
|
+
const history = new SQLiteChatMessageHistory({ sessionId: targetSession });
|
|
111
|
+
for (const msg of newMessages) {
|
|
112
|
+
msg.provider_metadata = {
|
|
113
|
+
provider: apocConfig.provider,
|
|
114
|
+
model: apocConfig.model,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
await history.addMessages(newMessages);
|
|
118
|
+
history.close();
|
|
119
|
+
}
|
|
93
120
|
const lastMessage = response.messages[response.messages.length - 1];
|
|
94
121
|
const content = typeof lastMessage.content === "string"
|
|
95
122
|
? lastMessage.content
|
package/dist/runtime/oracle.js
CHANGED
|
@@ -6,6 +6,7 @@ import { ProviderError } from "./errors.js";
|
|
|
6
6
|
import { DisplayManager } from "./display.js";
|
|
7
7
|
import { SQLiteChatMessageHistory } from "./memory/sqlite.js";
|
|
8
8
|
import { SatiMemoryMiddleware } from "./memory/sati/index.js";
|
|
9
|
+
import { Apoc } from "./apoc.js";
|
|
9
10
|
export class Oracle {
|
|
10
11
|
provider;
|
|
11
12
|
config;
|
|
@@ -208,6 +209,11 @@ You maintain intent until resolution.
|
|
|
208
209
|
}
|
|
209
210
|
messages.push(...previousMessages);
|
|
210
211
|
messages.push(userMessage);
|
|
212
|
+
// Propagate current session to Apoc so its token usage lands in the right session
|
|
213
|
+
const currentSessionId = (this.history instanceof SQLiteChatMessageHistory)
|
|
214
|
+
? this.history.currentSessionId
|
|
215
|
+
: undefined;
|
|
216
|
+
Apoc.setSessionId(currentSessionId);
|
|
211
217
|
const response = await this.provider.invoke({ messages });
|
|
212
218
|
// Identify new messages generated during the interaction
|
|
213
219
|
// The `messages` array passed to invoke had length `messages.length`
|
|
@@ -229,9 +235,6 @@ You maintain intent until resolution.
|
|
|
229
235
|
const lastMessage = response.messages[response.messages.length - 1];
|
|
230
236
|
const responseContent = (typeof lastMessage.content === 'string') ? lastMessage.content : JSON.stringify(lastMessage.content);
|
|
231
237
|
// Sati Middleware: Evaluation (Fire and forget)
|
|
232
|
-
const currentSessionId = (this.history instanceof SQLiteChatMessageHistory)
|
|
233
|
-
? this.history.currentSessionId
|
|
234
|
-
: undefined;
|
|
235
238
|
this.satiMiddleware.afterAgent(responseContent, [...previousMessages, userMessage], currentSessionId)
|
|
236
239
|
.catch((e) => this.display.log(`Sati memory evaluation failed: ${e.message}`, { source: 'Sati' }));
|
|
237
240
|
return responseContent;
|
|
@@ -85,7 +85,7 @@ Analyze the payload above and follow the instructions provided. Be concise and a
|
|
|
85
85
|
try {
|
|
86
86
|
const icon = status === 'completed' ? '✅' : '❌';
|
|
87
87
|
const truncated = result.length > 3500 ? result.slice(0, 3500) + '…' : result;
|
|
88
|
-
const message = `${icon}
|
|
88
|
+
const message = `${icon} Webhook: ${webhookName}\n\n${truncated}`;
|
|
89
89
|
await adapter.sendMessage(message);
|
|
90
90
|
}
|
|
91
91
|
catch (err) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "morpheus-cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.10",
|
|
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"
|