morpheus-cli 0.6.9 → 0.7.0

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.
@@ -167,7 +167,8 @@ export class ConfigManager {
167
167
  base_url: config.apoc.base_url || config.llm.base_url,
168
168
  context_window: config.apoc.context_window !== undefined ? resolveNumeric('MORPHEUS_APOC_CONTEXT_WINDOW', config.apoc.context_window, config.apoc.context_window) : llmConfig.context_window,
169
169
  working_dir: resolveString('MORPHEUS_APOC_WORKING_DIR', config.apoc.working_dir, process.cwd()),
170
- timeout_ms: config.apoc.timeout_ms !== undefined ? resolveNumeric('MORPHEUS_APOC_TIMEOUT_MS', config.apoc.timeout_ms, 30_000) : 30_000
170
+ timeout_ms: config.apoc.timeout_ms !== undefined ? resolveNumeric('MORPHEUS_APOC_TIMEOUT_MS', config.apoc.timeout_ms, 30_000) : 30_000,
171
+ personality: resolveString('MORPHEUS_APOC_PERSONALITY', config.apoc.personality, 'pragmatic_dev'),
171
172
  };
172
173
  }
173
174
  // Apply precedence to Neo config
@@ -207,6 +208,7 @@ export class ConfigManager {
207
208
  api_key: resolveApiKey(neoProvider, 'MORPHEUS_NEO_API_KEY', config.neo?.api_key || llmConfig.api_key),
208
209
  base_url: neoBaseUrl || undefined,
209
210
  context_window: resolveOptionalNumeric('MORPHEUS_NEO_CONTEXT_WINDOW', config.neo?.context_window, neoContextWindowFallback),
211
+ personality: resolveString('MORPHEUS_NEO_PERSONALITY', config.neo?.personality, 'analytical_engineer'),
210
212
  };
211
213
  }
212
214
  // Apply precedence to Trinity config
@@ -230,6 +232,7 @@ export class ConfigManager {
230
232
  api_key: resolveApiKey(trinityProvider, 'MORPHEUS_TRINITY_API_KEY', config.trinity?.api_key || llmConfig.api_key),
231
233
  base_url: config.trinity?.base_url || config.llm.base_url,
232
234
  context_window: resolveOptionalNumeric('MORPHEUS_TRINITY_CONTEXT_WINDOW', config.trinity?.context_window, trinityContextWindowFallback),
235
+ personality: resolveString('MORPHEUS_TRINITY_PERSONALITY', config.trinity?.personality, 'data_specialist'),
233
236
  };
234
237
  }
235
238
  // Apply precedence to audio config
@@ -210,6 +210,8 @@ export function getActiveEnvOverrides() {
210
210
  overrides['neo.temperature'] = true;
211
211
  if (isEnvVarSet('MORPHEUS_NEO_API_KEY'))
212
212
  overrides['neo.api_key'] = true;
213
+ if (isEnvVarSet('MORPHEUS_NEO_PERSONALITY'))
214
+ overrides['neo.personality'] = true;
213
215
  // Apoc
214
216
  if (isEnvVarSet('MORPHEUS_APOC_PROVIDER'))
215
217
  overrides['apoc.provider'] = true;
@@ -223,6 +225,8 @@ export function getActiveEnvOverrides() {
223
225
  overrides['apoc.working_dir'] = true;
224
226
  if (isEnvVarSet('MORPHEUS_APOC_TIMEOUT_MS'))
225
227
  overrides['apoc.timeout_ms'] = true;
228
+ if (isEnvVarSet('MORPHEUS_APOC_PERSONALITY'))
229
+ overrides['apoc.personality'] = true;
226
230
  // Trinity
227
231
  if (isEnvVarSet('MORPHEUS_TRINITY_PROVIDER'))
228
232
  overrides['trinity.provider'] = true;
@@ -232,6 +236,8 @@ export function getActiveEnvOverrides() {
232
236
  overrides['trinity.temperature'] = true;
233
237
  if (isEnvVarSet('MORPHEUS_TRINITY_API_KEY'))
234
238
  overrides['trinity.api_key'] = true;
239
+ if (isEnvVarSet('MORPHEUS_TRINITY_PERSONALITY'))
240
+ overrides['trinity.personality'] = true;
235
241
  // Audio
236
242
  if (isEnvVarSet('MORPHEUS_AUDIO_PROVIDER'))
237
243
  overrides['audio.provider'] = true;
@@ -44,6 +44,7 @@ export class Apoc {
44
44
  // console.log(`Apoc configuration: ${JSON.stringify(apocConfig)}`);
45
45
  const working_dir = this.config.apoc?.working_dir || process.cwd();
46
46
  const timeout_ms = this.config.apoc?.timeout_ms || 30_000;
47
+ const personality = this.config.apoc?.personality || 'pragmatic_dev';
47
48
  // Import all devkit tool factories (side-effect registration)
48
49
  await import("../devkit/index.js");
49
50
  const tools = buildDevKit({
@@ -51,7 +52,7 @@ export class Apoc {
51
52
  allowed_commands: [], // no restriction — Oracle is trusted orchestrator
52
53
  timeout_ms,
53
54
  });
54
- this.display.log(`Apoc initialized with ${tools.length} DevKit tools (working_dir: ${working_dir})`, { source: "Apoc" });
55
+ this.display.log(`Apoc initialized with ${tools.length} DevKit tools (working_dir: ${working_dir}, personality: ${personality})`, { source: "Apoc" });
55
56
  try {
56
57
  this.agent = await ProviderFactory.createBare(apocConfig, tools);
57
58
  }
@@ -72,8 +73,9 @@ export class Apoc {
72
73
  this.display.log(`Executing delegated task: ${task.slice(0, 80)}...`, {
73
74
  source: "Apoc",
74
75
  });
76
+ const personality = this.config.apoc?.personality || 'pragmatic_dev';
75
77
  const systemMessage = new SystemMessage(`
76
- You are Apoc, a high-reliability execution and verification subagent inside the Morpheus system.
78
+ You are Apoc, ${personality === 'pragmatic_dev' ? 'a pragmatic and methodical developer' : personality}, a high-reliability execution and verification subagent inside the Morpheus system.
77
79
 
78
80
  You are NOT a conversational assistant.
79
81
  You are a task executor, evidence collector, and autonomous verifier.
@@ -35,10 +35,11 @@ export class Neo {
35
35
  }
36
36
  async initialize() {
37
37
  const neoConfig = this.config.neo || this.config.llm;
38
+ const personality = this.config.neo?.personality || 'analytical_engineer';
38
39
  const mcpTools = await Construtor.create();
39
40
  const tools = [...mcpTools, ...morpheusTools];
40
41
  updateNeoDelegateToolDescription(mcpTools);
41
- this.display.log(`Neo initialized with ${tools.length} tools.`, { source: "Neo" });
42
+ this.display.log(`Neo initialized with ${tools.length} tools (personality: ${personality}).`, { source: "Neo" });
42
43
  try {
43
44
  this.agent = await ProviderFactory.create(neoConfig, tools);
44
45
  }
@@ -54,8 +55,9 @@ export class Neo {
54
55
  this.display.log(`Executing delegated task in Neo: ${task.slice(0, 80)}...`, {
55
56
  source: "Neo",
56
57
  });
58
+ const personality = this.config.neo?.personality || 'analytical_engineer';
57
59
  const systemMessage = new SystemMessage(`
58
- You are Neo, an execution subagent in Morpheus.
60
+ You are Neo, ${personality === 'analytical_engineer' ? 'an analytical and precise engineer' : personality}, an execution subagent in Morpheus.
59
61
 
60
62
  You execute tasks using MCP and internal tools.
61
63
  Focus on verifiable execution and return objective results.
@@ -40,14 +40,18 @@ 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;
43
+ /**
44
+ * Timeout (ms) for connecting to each MCP server and fetching its tools list.
45
+ * Increased to 60s to allow time for npx to download and install packages.
46
+ * First connection may take longer as npx downloads the package.
47
+ */
48
+ const MCP_CONNECT_TIMEOUT_MS = 60_000;
45
49
  /**
46
50
  * Returns a promise that rejects after `ms` milliseconds with a timeout error.
47
51
  * Used to guard `client.getTools()` against servers that never respond.
48
52
  */
49
53
  function connectTimeout(serverName, ms) {
50
- return new Promise((_, reject) => setTimeout(() => reject(new Error(`MCP server '${serverName}' timed out after ${ms}ms`)), ms));
54
+ return new Promise((_, reject) => setTimeout(() => reject(new Error(`MCP server '${serverName}' timed out after ${ms}ms. If using 'npx', first run may take longer to download packages.`)), ms));
51
55
  }
52
56
  export class Construtor {
53
57
  static async probe() {
@@ -89,6 +93,11 @@ export class Construtor {
89
93
  onConnectionError: "ignore",
90
94
  });
91
95
  try {
96
+ display.log(`Connecting to MCP server '${serverName}'... (timeout: ${MCP_CONNECT_TIMEOUT_MS / 1000}s)`, {
97
+ level: 'info',
98
+ source: 'Construtor',
99
+ meta: { server: serverName, transport: serverConfig.transport }
100
+ });
92
101
  const tools = await Promise.race([
93
102
  client.getTools(),
94
103
  connectTimeout(serverName, MCP_CONNECT_TIMEOUT_MS),
@@ -102,6 +111,7 @@ export class Construtor {
102
111
  // Sanitize tool schemas to remove fields not supported by Gemini
103
112
  const sanitizedTools = tools.map(tool => wrapToolWithSanitizedSchema(tool));
104
113
  allTools.push(...sanitizedTools);
114
+ display.log(`Successfully loaded ${tools.length} tools from MCP server '${serverName}'`, { level: 'info', source: 'Construtor' });
105
115
  }
106
116
  catch (error) {
107
117
  display.log(`Failed to initialize MCP tools for server '${serverName}': ${error}`, { level: 'warning', source: 'Construtor' });
@@ -159,8 +159,9 @@ export class Trinity {
159
159
  }
160
160
  async initialize() {
161
161
  const trinityConfig = this.config.trinity || this.config.llm;
162
+ const personality = this.config.trinity?.personality || 'data_specialist';
162
163
  const tools = this.buildTrinityTools();
163
- this.display.log(`Trinity initialized with ${tools.length} tools.`, { source: 'Trinity' });
164
+ this.display.log(`Trinity initialized with ${tools.length} tools (personality: ${personality}).`, { source: 'Trinity' });
164
165
  try {
165
166
  this.agent = await ProviderFactory.createBare(trinityConfig, tools);
166
167
  }
@@ -183,8 +184,9 @@ export class Trinity {
183
184
  return `- [${db.id}] ${db.name} (${db.type}): ${tables}`;
184
185
  }).join('\n')
185
186
  : ' (no databases registered)';
187
+ const personality = this.config.trinity?.personality || 'data_specialist';
186
188
  const systemMessage = new SystemMessage(`
187
- You are Trinity, a specialized database subagent within the Morpheus system.
189
+ You are Trinity, ${personality === 'data_specialist' ? 'a meticulous data specialist' : personality}, a specialized database subagent within the Morpheus system.
188
190
 
189
191
  You receive natural-language database tasks from Oracle and execute them using your available tools.
190
192
 
@@ -50,10 +50,18 @@ export const DEFAULT_CONFIG = {
50
50
  model: 'gpt-4',
51
51
  temperature: 0.2,
52
52
  timeout_ms: 30000,
53
+ personality: 'pragmatic_dev',
53
54
  },
54
55
  neo: {
55
56
  provider: 'openai',
56
57
  model: 'gpt-4',
57
58
  temperature: 0.2,
59
+ personality: 'analytical_engineer',
60
+ },
61
+ trinity: {
62
+ provider: 'openai',
63
+ model: 'gpt-4',
64
+ temperature: 0.2,
65
+ personality: 'data_specialist',
58
66
  }
59
67
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "morpheus-cli",
3
- "version": "0.6.9",
3
+ "version": "0.7.0",
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"