morpheus-cli 0.4.9 → 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.
@@ -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
@@ -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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "morpheus-cli",
3
- "version": "0.4.9",
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"