morpheus-cli 0.9.12 → 0.9.20
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 +49 -18
- package/dist/channels/discord.js +93 -6
- package/dist/channels/telegram.js +112 -12
- package/dist/cli/commands/restart.js +2 -2
- package/dist/cli/commands/start.js +17 -2
- package/dist/config/manager.js +20 -1
- package/dist/config/paths.js +4 -0
- package/dist/config/schemas.js +15 -0
- package/dist/http/api.js +7 -3
- package/dist/http/routers/agents.js +9 -0
- package/dist/http/routers/danger.js +4 -5
- package/dist/http/routers/link.js +4 -4
- package/dist/runtime/__tests__/telephonist-tts.test.js +84 -0
- package/dist/runtime/adapters/AuditRepositoryAdapter.js +6 -0
- package/dist/runtime/adapters/ChannelNotifierAdapter.js +9 -0
- package/dist/runtime/adapters/LangChainProviderAdapter.js +9 -0
- package/dist/runtime/adapters/SQLiteChatHistoryAdapter.js +15 -0
- package/dist/runtime/adapters/SQLiteTaskEnqueuerAdapter.js +6 -0
- package/dist/runtime/adapters/index.js +5 -0
- package/dist/runtime/audit/repository.js +6 -2
- package/dist/runtime/chronos/repository.js +7 -5
- package/dist/runtime/chronos/worker.js +27 -4
- package/dist/runtime/chronos/worker.test.js +3 -2
- package/dist/runtime/container.js +50 -0
- package/dist/runtime/hot-reload.js +6 -9
- package/dist/runtime/memory/backfill-embeddings.js +2 -3
- package/dist/runtime/memory/sati/repository.js +3 -3
- package/dist/runtime/memory/sqlite.js +40 -14
- package/dist/runtime/memory/trinity-db.js +2 -2
- package/dist/runtime/oracle.js +78 -43
- package/dist/runtime/ports/IChatHistory.js +1 -0
- package/dist/runtime/ports/ILLMProviderFactory.js +1 -0
- package/dist/runtime/ports/INotifier.js +1 -0
- package/dist/runtime/ports/ITaskEnqueuer.js +1 -0
- package/dist/runtime/ports/index.js +1 -0
- package/dist/runtime/providers/factory.js +8 -52
- package/dist/runtime/providers/strategies.js +66 -0
- package/dist/runtime/setup/repository.js +2 -2
- package/dist/runtime/subagents/ISubagent.js +1 -0
- package/dist/runtime/{apoc.js → subagents/apoc.js} +20 -7
- package/dist/runtime/{devkit-instrument.js → subagents/devkit-instrument.js} +1 -1
- package/dist/runtime/subagents/index.js +12 -0
- package/dist/runtime/{link.js → subagents/link/link.js} +24 -10
- package/dist/runtime/{link-repository.js → subagents/link/repository.js} +4 -4
- package/dist/runtime/{link-search.js → subagents/link/search.js} +3 -3
- package/dist/runtime/{link-worker.js → subagents/link/worker.js} +9 -9
- package/dist/runtime/{neo.js → subagents/neo.js} +24 -10
- package/dist/runtime/subagents/registry.js +134 -0
- package/dist/runtime/{trinity.js → subagents/trinity/trinity.js} +23 -9
- package/dist/runtime/{subagent-utils.js → subagents/utils.js} +2 -2
- package/dist/runtime/tasks/repository.js +2 -2
- package/dist/runtime/tasks/worker.js +6 -70
- package/dist/runtime/telephonist.js +160 -0
- package/dist/runtime/tools/chronos-tools.js +1 -0
- package/dist/runtime/tools/delegation-utils.js +5 -7
- package/dist/runtime/tools/morpheus-tools.js +9 -10
- package/dist/runtime/tools/smith-tool.js +5 -7
- package/dist/runtime/webhooks/dispatcher.js +4 -0
- package/dist/runtime/webhooks/repository.js +2 -2
- package/dist/types/config.js +6 -0
- package/dist/ui/assets/AuditDashboard-Cu33zb_7.js +1 -0
- package/dist/ui/assets/Chat-mt1j5V55.js +41 -0
- package/dist/ui/assets/{Chronos-D1yAb4M5.js → Chronos-Bq_h41cw.js} +1 -1
- package/dist/ui/assets/{ConfirmationModal-DxUHZgTy.js → ConfirmationModal-CxLP8iC6.js} +1 -1
- package/dist/ui/assets/{Dashboard-BzxmcHaS.js → Dashboard-D0LAlHtG.js} +1 -1
- package/dist/ui/assets/{DeleteConfirmationModal-CqNXT_YQ.js → DeleteConfirmationModal-kZ_c3sFk.js} +1 -1
- package/dist/ui/assets/{Documents-DLFZdmim.js → Documents-nlQNoUcq.js} +1 -1
- package/dist/ui/assets/{Logs-B1Bpy9dB.js → Logs-C1tlg574.js} +1 -1
- package/dist/ui/assets/{MCPManager-BbUDMh5Q.js → MCPManager-Do7isizG.js} +1 -1
- package/dist/ui/assets/ModelPricing-BeJ7oXBA.js +1 -0
- package/dist/ui/assets/{Notifications-8Cqj-mNp.js → Notifications-Cg5CMlY0.js} +1 -1
- package/dist/ui/assets/{SatiMemories-CdHUe6di.js → SatiMemories-D9l6s8Pc.js} +1 -1
- package/dist/ui/assets/SessionAudit-Da1ySlYg.js +9 -0
- package/dist/ui/assets/Settings-DpXwpEhO.js +49 -0
- package/dist/ui/assets/{Skills-0k7A2T5_.js → Skills-DaqCY8QH.js} +1 -1
- package/dist/ui/assets/Smiths-DA-x4KFT.js +1 -0
- package/dist/ui/assets/Switch-CJTE4ZQm.js +1 -0
- package/dist/ui/assets/Tasks-DU49M9U-.js +1 -0
- package/dist/ui/assets/{TrinityDatabases-CGna6IMX.js → TrinityDatabases-CoKzKTL-.js} +1 -1
- package/dist/ui/assets/{UsageStats-B7EzZlZe.js → UsageStats-cds352Pj.js} +1 -1
- package/dist/ui/assets/{WebhookManager-Bb7KiucS.js → WebhookManager-DdAdHQUk.js} +1 -1
- package/dist/ui/assets/agents-B1z_dlQC.js +1 -0
- package/dist/ui/assets/{audit-CJ2Ms81U.js → audit-BAhaGrKY.js} +1 -1
- package/dist/ui/assets/{chronos-Bm68OSy4.js → chronos-DGD_Md9M.js} +1 -1
- package/dist/ui/assets/config-BwTXe5M2.js +1 -0
- package/dist/ui/assets/{index-BxN2w9sY.js → index-BcX5O7kY.js} +2 -2
- package/dist/ui/assets/index-Cjli-AD7.css +1 -0
- package/dist/ui/assets/{mcp-BE_OVkBe.js → mcp-BlkruPaA.js} +1 -1
- package/dist/ui/assets/{skills-Dt0qU4gH.js → skills-CtCb-52u.js} +1 -1
- package/dist/ui/assets/{stats-Bmdps1LR.js → stats-BiPI2kaw.js} +1 -1
- package/dist/ui/assets/useCurrency-BCdG-pHx.js +1 -0
- package/dist/ui/index.html +2 -2
- package/dist/ui/sw.js +1 -1
- package/package.json +1 -1
- package/dist/ui/assets/AuditDashboard-CM1YN1uk.js +0 -1
- package/dist/ui/assets/Chat-D4y-g6Tw.js +0 -41
- package/dist/ui/assets/ModelPricing-DCl-2_eJ.js +0 -1
- package/dist/ui/assets/SessionAudit-CtVHK_IH.js +0 -9
- package/dist/ui/assets/Settings-Clge45Z0.js +0 -49
- package/dist/ui/assets/Smiths-gjgBMN1F.js +0 -1
- package/dist/ui/assets/Tasks-AQ3MrrMp.js +0 -1
- package/dist/ui/assets/config-C88yQ_CP.js +0 -1
- package/dist/ui/assets/index-C3Ff736M.css +0 -1
- /package/dist/runtime/{ISubagent.js → ports/IAuditEmitter.js} +0 -0
- /package/dist/runtime/{link-chunker.js → subagents/link/chunker.js} +0 -0
- /package/dist/runtime/{trinity-connector.js → subagents/trinity/connector.js} +0 -0
package/dist/runtime/oracle.js
CHANGED
|
@@ -5,12 +5,9 @@ import { ProviderError } from "./errors.js";
|
|
|
5
5
|
import { DisplayManager } from "./display.js";
|
|
6
6
|
import { SQLiteChatMessageHistory } from "./memory/sqlite.js";
|
|
7
7
|
import { SatiMemoryMiddleware } from "./memory/sati/index.js";
|
|
8
|
-
import { Apoc } from "./
|
|
8
|
+
import { Apoc, Neo, Trinity, Link, SubagentRegistry, emitToolAuditEvents } from "./subagents/index.js";
|
|
9
9
|
import { TaskRequestContext } from "./tasks/context.js";
|
|
10
10
|
import { TaskRepository } from "./tasks/repository.js";
|
|
11
|
-
import { Neo } from "./neo.js";
|
|
12
|
-
import { Trinity } from "./trinity.js";
|
|
13
|
-
import { Link } from "./link.js";
|
|
14
11
|
import { SmithDelegateTool } from "./tools/smith-tool.js";
|
|
15
12
|
import { TaskQueryTool, chronosTools, timeVerifierTool } from "./tools/index.js";
|
|
16
13
|
import { Construtor } from "./tools/factory.js";
|
|
@@ -20,12 +17,9 @@ import { SmithRegistry } from "./smiths/registry.js";
|
|
|
20
17
|
import { AuditRepository } from "./audit/repository.js";
|
|
21
18
|
import { SetupRepository } from './setup/repository.js';
|
|
22
19
|
import { buildSetupTool } from './tools/setup-tool.js';
|
|
23
|
-
import {
|
|
20
|
+
import { SmithDelegator } from "./smiths/delegator.js";
|
|
24
21
|
import { PATHS } from "../config/paths.js";
|
|
25
22
|
import { writeFileSync } from "fs";
|
|
26
|
-
const ORACLE_DELEGATION_TOOLS = new Set([
|
|
27
|
-
'apoc_delegate', 'neo_delegate', 'trinity_delegate', 'smith_delegate', 'link_delegate',
|
|
28
|
-
]);
|
|
29
23
|
export class Oracle {
|
|
30
24
|
provider;
|
|
31
25
|
config;
|
|
@@ -40,6 +34,48 @@ export class Oracle {
|
|
|
40
34
|
this.config = config || ConfigManager.getInstance().get();
|
|
41
35
|
this.databasePath = overrides?.databasePath;
|
|
42
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Registers Smith in the SubagentRegistry if Smiths are configured and enabled.
|
|
39
|
+
* Smith is special — it uses a standalone tool (SmithDelegateTool) and SmithDelegator
|
|
40
|
+
* rather than implementing ISubagent, so we create a minimal registration.
|
|
41
|
+
*/
|
|
42
|
+
registerSmithIfEnabled() {
|
|
43
|
+
const smithsConfig = ConfigManager.getInstance().getSmithsConfig();
|
|
44
|
+
if (!smithsConfig.enabled || smithsConfig.entries.length === 0)
|
|
45
|
+
return;
|
|
46
|
+
if (SubagentRegistry.get('smith'))
|
|
47
|
+
return; // already registered
|
|
48
|
+
const delegator = SmithDelegator.getInstance();
|
|
49
|
+
SubagentRegistry.register({
|
|
50
|
+
agentKey: 'smith', auditAgent: 'smith', label: 'Smith',
|
|
51
|
+
delegateToolName: 'smith_delegate', emoji: '🕶️', color: 'gray',
|
|
52
|
+
description: 'Remote DevKit execution',
|
|
53
|
+
colorClass: 'text-gray-500 dark:text-gray-400',
|
|
54
|
+
bgClass: 'bg-gray-50 dark:bg-zinc-900',
|
|
55
|
+
badgeClass: 'bg-gray-200 text-gray-700 dark:bg-gray-700/60 dark:text-gray-300',
|
|
56
|
+
instance: {
|
|
57
|
+
initialize: async () => { },
|
|
58
|
+
execute: async (task, context) => delegator.delegate('unknown', task, context),
|
|
59
|
+
reload: async () => { },
|
|
60
|
+
createDelegateTool: () => SmithDelegateTool,
|
|
61
|
+
},
|
|
62
|
+
hasDynamicDescription: false,
|
|
63
|
+
isMultiInstance: true,
|
|
64
|
+
executeTask: async (task) => {
|
|
65
|
+
let smithName = 'unknown';
|
|
66
|
+
if (task.context) {
|
|
67
|
+
try {
|
|
68
|
+
const parsed = JSON.parse(task.context);
|
|
69
|
+
smithName = parsed.smith_name || parsed.smith || 'unknown';
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
smithName = task.context;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return delegator.delegate(smithName, task.input, task.context ?? undefined);
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
43
79
|
buildDelegationFailureResponse() {
|
|
44
80
|
return "Task enqueue could not be confirmed in the database. No task was created. Please retry.";
|
|
45
81
|
}
|
|
@@ -115,13 +151,16 @@ export class Oracle {
|
|
|
115
151
|
return valid;
|
|
116
152
|
}
|
|
117
153
|
hasDelegationToolCall(messages) {
|
|
154
|
+
const delegationTools = SubagentRegistry.getDelegationToolNames();
|
|
155
|
+
// Also include smith_delegate which may not be in registry if smiths are disabled
|
|
156
|
+
delegationTools.add('smith_delegate');
|
|
118
157
|
for (const msg of messages) {
|
|
119
158
|
if (!(msg instanceof AIMessage))
|
|
120
159
|
continue;
|
|
121
160
|
const toolCalls = msg.tool_calls ?? [];
|
|
122
161
|
if (!Array.isArray(toolCalls))
|
|
123
162
|
continue;
|
|
124
|
-
if (toolCalls.some((tc) => tc?.name
|
|
163
|
+
if (toolCalls.some((tc) => delegationTools.has(tc?.name))) {
|
|
125
164
|
return true;
|
|
126
165
|
}
|
|
127
166
|
}
|
|
@@ -152,27 +191,30 @@ export class Oracle {
|
|
|
152
191
|
// Note: API Key validation is delegated to ProviderFactory or the Provider itself
|
|
153
192
|
// to allow for Environment Variable fallback supported by LangChain.
|
|
154
193
|
try {
|
|
155
|
-
//
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
//
|
|
194
|
+
// Ensure subagents are instantiated and self-registered before using the registry.
|
|
195
|
+
Apoc.getInstance();
|
|
196
|
+
Neo.getInstance();
|
|
197
|
+
Trinity.getInstance();
|
|
198
|
+
Link.getInstance();
|
|
199
|
+
// Register Smith in the registry if configured
|
|
200
|
+
this.registerSmithIfEnabled();
|
|
201
|
+
// Refresh dynamic tool catalogs so delegate descriptions contain runtime info.
|
|
202
|
+
await SubagentRegistry.refreshAllCatalogs();
|
|
161
203
|
// Initialize setup repository (creates table if needed)
|
|
162
204
|
SetupRepository.getInstance();
|
|
163
205
|
const coreTools = [
|
|
164
206
|
buildSetupTool(),
|
|
165
207
|
TaskQueryTool,
|
|
166
|
-
|
|
167
|
-
Apoc.getInstance().createDelegateTool(),
|
|
168
|
-
Trinity.getInstance().createDelegateTool(),
|
|
169
|
-
Link.getInstance().createDelegateTool(),
|
|
208
|
+
...SubagentRegistry.getDelegationTools(),
|
|
170
209
|
createLoadSkillTool(),
|
|
171
210
|
timeVerifierTool,
|
|
172
211
|
...chronosTools,
|
|
173
212
|
];
|
|
213
|
+
// Smith's tool is already included via SubagentRegistry.getDelegationTools()
|
|
214
|
+
// if registerSmithIfEnabled() registered it. Only add it if Smith is enabled
|
|
215
|
+
// but NOT yet in the registry (shouldn't happen, but defensive).
|
|
174
216
|
const smithsConfig = ConfigManager.getInstance().getSmithsConfig();
|
|
175
|
-
if (smithsConfig.enabled && smithsConfig.entries.length > 0) {
|
|
217
|
+
if (smithsConfig.enabled && smithsConfig.entries.length > 0 && !SubagentRegistry.get('smith')) {
|
|
176
218
|
coreTools.push(SmithDelegateTool);
|
|
177
219
|
}
|
|
178
220
|
this.provider = await ProviderFactory.create(this.config.llm, coreTools);
|
|
@@ -225,12 +267,14 @@ export class Oracle {
|
|
|
225
267
|
provider: isTelephonist ? this.config.audio?.provider : this.config.llm.provider,
|
|
226
268
|
model: isTelephonist ? this.config.audio?.model : this.config.llm.model
|
|
227
269
|
};
|
|
228
|
-
// Inject source metadata for automated origins (webhook, chronos)
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
270
|
+
// Inject source metadata for automated origins (webhook, chronos).
|
|
271
|
+
// Prefer explicit taskContext.source (set by Chronos even when origin_channel
|
|
272
|
+
// points to a specific notification channel like 'telegram').
|
|
273
|
+
const messageSource = taskContext?.source ?? (taskContext?.origin_channel === 'webhook' ? 'webhook'
|
|
274
|
+
: taskContext?.origin_channel === 'chronos' ? 'chronos'
|
|
275
|
+
: null);
|
|
276
|
+
if (messageSource) {
|
|
277
|
+
userMessage.source_metadata = { source: messageSource };
|
|
234
278
|
}
|
|
235
279
|
// Attach extra usage (e.g. from Audio) to the user message to be persisted
|
|
236
280
|
if (extraUsage) {
|
|
@@ -465,10 +509,7 @@ Use it to inform your response and tool selection (if needed), but do not assume
|
|
|
465
509
|
}
|
|
466
510
|
messages.push(...previousMessages);
|
|
467
511
|
messages.push(userMessage);
|
|
468
|
-
|
|
469
|
-
Neo.setSessionId(currentSessionId);
|
|
470
|
-
Trinity.setSessionId(currentSessionId);
|
|
471
|
-
Link.setSessionId(currentSessionId);
|
|
512
|
+
SubagentRegistry.setAllSessionIds(currentSessionId);
|
|
472
513
|
const invokeContext = {
|
|
473
514
|
origin_channel: taskContext?.origin_channel ?? "api",
|
|
474
515
|
session_id: taskContext?.session_id ?? currentSessionId ?? "default",
|
|
@@ -514,8 +555,10 @@ Use it to inform your response and tool selection (if needed), but do not assume
|
|
|
514
555
|
// Emit tool_call audit events for Oracle's independent tool calls.
|
|
515
556
|
// Delegation tools (apoc/neo/trinity/smith/skill/link) are already audited
|
|
516
557
|
// inside buildDelegationTool or the task system — skip them here.
|
|
558
|
+
const delegationToolNames = SubagentRegistry.getDelegationToolNames();
|
|
559
|
+
delegationToolNames.add('smith_delegate');
|
|
517
560
|
emitToolAuditEvents(newGeneratedMessages, currentSessionId ?? 'default', 'oracle', {
|
|
518
|
-
skipTools:
|
|
561
|
+
skipTools: delegationToolNames,
|
|
519
562
|
});
|
|
520
563
|
// Inject provider/model metadata and duration into all new AI messages
|
|
521
564
|
for (const msg of newGeneratedMessages) {
|
|
@@ -694,24 +737,16 @@ Use it to inform your response and tool selection (if needed), but do not assume
|
|
|
694
737
|
}
|
|
695
738
|
// Reload MCP tool cache from servers (slow path)
|
|
696
739
|
await Construtor.reload();
|
|
697
|
-
await
|
|
698
|
-
await Trinity.refreshDelegateCatalog().catch(() => { });
|
|
699
|
-
await Link.refreshDelegateCatalog().catch(() => { });
|
|
740
|
+
await SubagentRegistry.refreshAllCatalogs();
|
|
700
741
|
this.provider = await ProviderFactory.create(this.config.llm, [
|
|
701
742
|
buildSetupTool(),
|
|
702
743
|
TaskQueryTool,
|
|
703
|
-
|
|
704
|
-
Apoc.getInstance().createDelegateTool(),
|
|
705
|
-
Trinity.getInstance().createDelegateTool(),
|
|
706
|
-
Link.getInstance().createDelegateTool(),
|
|
744
|
+
...SubagentRegistry.getDelegationTools(),
|
|
707
745
|
createLoadSkillTool(),
|
|
708
746
|
timeVerifierTool,
|
|
709
747
|
...chronosTools,
|
|
710
748
|
]);
|
|
711
|
-
await
|
|
712
|
-
|
|
713
|
-
await Trinity.getInstance().reload();
|
|
714
|
-
await Link.getInstance().reload();
|
|
715
|
-
this.display.log(`Oracle and Neo tools reloaded`, { source: 'Oracle' });
|
|
749
|
+
await SubagentRegistry.reloadAll();
|
|
750
|
+
this.display.log(`Oracle and subagent tools reloaded`, { source: 'Oracle' });
|
|
716
751
|
}
|
|
717
752
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
import { ChatOpenAI } from "@langchain/openai";
|
|
2
|
-
import { ChatAnthropic } from "@langchain/anthropic";
|
|
3
|
-
import { ChatOllama } from "@langchain/ollama";
|
|
4
|
-
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
|
|
5
1
|
import { ProviderError } from "../errors.js";
|
|
6
2
|
import { createAgent, createMiddleware } from "langchain";
|
|
7
3
|
import { DisplayManager } from "../display.js";
|
|
8
|
-
import { getUsableApiKey } from "../trinity-crypto.js";
|
|
9
4
|
import { ConfigManager } from "../../config/manager.js";
|
|
10
5
|
import { TaskRequestContext } from "../tasks/context.js";
|
|
11
6
|
import { ChannelRegistry } from "../../channels/registry.js";
|
|
7
|
+
import { getStrategy, registerStrategy } from "./strategies.js";
|
|
12
8
|
/** Channels that should NOT receive verbose tool notifications */
|
|
13
9
|
const SILENT_CHANNELS = new Set(['api', 'ui']);
|
|
10
|
+
export { registerStrategy };
|
|
14
11
|
export class ProviderFactory {
|
|
15
12
|
static buildMonitoringMiddleware() {
|
|
16
13
|
const display = DisplayManager.getInstance();
|
|
@@ -41,44 +38,11 @@ export class ProviderFactory {
|
|
|
41
38
|
});
|
|
42
39
|
}
|
|
43
40
|
static buildModel(config) {
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
return new ChatOpenAI({
|
|
48
|
-
modelName: config.model,
|
|
49
|
-
temperature: config.temperature,
|
|
50
|
-
apiKey: process.env.OPENAI_API_KEY || usableApiKey,
|
|
51
|
-
});
|
|
52
|
-
case 'anthropic':
|
|
53
|
-
return new ChatAnthropic({
|
|
54
|
-
modelName: config.model,
|
|
55
|
-
temperature: config.temperature,
|
|
56
|
-
apiKey: process.env.ANTHROPIC_API_KEY || usableApiKey,
|
|
57
|
-
});
|
|
58
|
-
case 'openrouter':
|
|
59
|
-
return new ChatOpenAI({
|
|
60
|
-
modelName: config.model,
|
|
61
|
-
temperature: config.temperature,
|
|
62
|
-
apiKey: process.env.OPENROUTER_API_KEY || usableApiKey,
|
|
63
|
-
configuration: {
|
|
64
|
-
baseURL: config.base_url || 'https://openrouter.ai/api/v1'
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
case 'ollama':
|
|
68
|
-
return new ChatOllama({
|
|
69
|
-
model: config.model,
|
|
70
|
-
temperature: config.temperature,
|
|
71
|
-
baseUrl: config.base_url || usableApiKey,
|
|
72
|
-
});
|
|
73
|
-
case 'gemini':
|
|
74
|
-
return new ChatGoogleGenerativeAI({
|
|
75
|
-
model: config.model,
|
|
76
|
-
temperature: config.temperature,
|
|
77
|
-
apiKey: process.env.GOOGLE_API_KEY || usableApiKey
|
|
78
|
-
});
|
|
79
|
-
default:
|
|
80
|
-
throw new Error(`Unsupported provider: ${config.provider}`);
|
|
41
|
+
const strategy = getStrategy(config.provider);
|
|
42
|
+
if (!strategy) {
|
|
43
|
+
throw new Error(`Unsupported provider: ${config.provider}`);
|
|
81
44
|
}
|
|
45
|
+
return strategy.build(config);
|
|
82
46
|
}
|
|
83
47
|
static handleProviderError(config, error) {
|
|
84
48
|
let suggestion = "Check your configuration and API keys.";
|
|
@@ -114,14 +78,6 @@ export class ProviderFactory {
|
|
|
114
78
|
ProviderFactory.handleProviderError(config, error);
|
|
115
79
|
}
|
|
116
80
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
const model = ProviderFactory.buildModel(config);
|
|
120
|
-
const middleware = ProviderFactory.buildMonitoringMiddleware();
|
|
121
|
-
return createAgent({ model, tools, middleware: [middleware] });
|
|
122
|
-
}
|
|
123
|
-
catch (error) {
|
|
124
|
-
ProviderFactory.handleProviderError(config, error);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
81
|
+
/** Alias for createBare — both methods are identical. */
|
|
82
|
+
static create = ProviderFactory.createBare;
|
|
127
83
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { ChatOpenAI } from "@langchain/openai";
|
|
2
|
+
import { ChatAnthropic } from "@langchain/anthropic";
|
|
3
|
+
import { ChatOllama } from "@langchain/ollama";
|
|
4
|
+
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
|
|
5
|
+
import { getUsableApiKey } from "../trinity-crypto.js";
|
|
6
|
+
class OpenAIStrategy {
|
|
7
|
+
build(config) {
|
|
8
|
+
return new ChatOpenAI({
|
|
9
|
+
modelName: config.model,
|
|
10
|
+
temperature: config.temperature,
|
|
11
|
+
apiKey: process.env.OPENAI_API_KEY || getUsableApiKey(config.api_key),
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
class AnthropicStrategy {
|
|
16
|
+
build(config) {
|
|
17
|
+
return new ChatAnthropic({
|
|
18
|
+
modelName: config.model,
|
|
19
|
+
temperature: config.temperature,
|
|
20
|
+
apiKey: process.env.ANTHROPIC_API_KEY || getUsableApiKey(config.api_key),
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
class OpenRouterStrategy {
|
|
25
|
+
build(config) {
|
|
26
|
+
return new ChatOpenAI({
|
|
27
|
+
modelName: config.model,
|
|
28
|
+
temperature: config.temperature,
|
|
29
|
+
apiKey: process.env.OPENROUTER_API_KEY || getUsableApiKey(config.api_key),
|
|
30
|
+
configuration: {
|
|
31
|
+
baseURL: config.base_url || 'https://openrouter.ai/api/v1'
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
class OllamaStrategy {
|
|
37
|
+
build(config) {
|
|
38
|
+
return new ChatOllama({
|
|
39
|
+
model: config.model,
|
|
40
|
+
temperature: config.temperature,
|
|
41
|
+
baseUrl: config.base_url || getUsableApiKey(config.api_key),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
class GeminiStrategy {
|
|
46
|
+
build(config) {
|
|
47
|
+
return new ChatGoogleGenerativeAI({
|
|
48
|
+
model: config.model,
|
|
49
|
+
temperature: config.temperature,
|
|
50
|
+
apiKey: process.env.GOOGLE_API_KEY || getUsableApiKey(config.api_key),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const strategies = new Map([
|
|
55
|
+
['openai', new OpenAIStrategy()],
|
|
56
|
+
['anthropic', new AnthropicStrategy()],
|
|
57
|
+
['openrouter', new OpenRouterStrategy()],
|
|
58
|
+
['ollama', new OllamaStrategy()],
|
|
59
|
+
['gemini', new GeminiStrategy()],
|
|
60
|
+
]);
|
|
61
|
+
export function registerStrategy(provider, strategy) {
|
|
62
|
+
strategies.set(provider, strategy);
|
|
63
|
+
}
|
|
64
|
+
export function getStrategy(provider) {
|
|
65
|
+
return strategies.get(provider);
|
|
66
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import Database from 'better-sqlite3';
|
|
2
2
|
import fs from 'fs-extra';
|
|
3
3
|
import path from 'path';
|
|
4
|
-
import { homedir } from 'os';
|
|
5
4
|
import { ConfigManager } from '../../config/manager.js';
|
|
5
|
+
import { PATHS } from '../../config/paths.js';
|
|
6
6
|
export class SetupRepository {
|
|
7
7
|
static instance = null;
|
|
8
8
|
db;
|
|
9
9
|
constructor(dbPath) {
|
|
10
|
-
const resolvedPath = dbPath ??
|
|
10
|
+
const resolvedPath = dbPath ?? PATHS.shortMemoryDb;
|
|
11
11
|
fs.ensureDirSync(path.dirname(resolvedPath));
|
|
12
12
|
this.db = new Database(resolvedPath, { timeout: 5000 });
|
|
13
13
|
this.db.pragma('journal_mode = WAL');
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { HumanMessage, SystemMessage, AIMessage } from "@langchain/core/messages";
|
|
2
|
-
import { ConfigManager } from "
|
|
3
|
-
import {
|
|
4
|
-
import { ProviderError } from "
|
|
5
|
-
import { DisplayManager } from "
|
|
2
|
+
import { ConfigManager } from "../../config/manager.js";
|
|
3
|
+
import { ServiceContainer, SERVICE_KEYS } from "../container.js";
|
|
4
|
+
import { ProviderError } from "../errors.js";
|
|
5
|
+
import { DisplayManager } from "../display.js";
|
|
6
6
|
import { buildDevKit } from "morpheus-devkit";
|
|
7
7
|
import { instrumentDevKitTools } from "./devkit-instrument.js";
|
|
8
|
-
import { extractRawUsage, persistAgentMessage, buildAgentResult, emitToolAuditEvents } from "./
|
|
9
|
-
import { buildDelegationTool } from "
|
|
8
|
+
import { extractRawUsage, persistAgentMessage, buildAgentResult, emitToolAuditEvents } from "./utils.js";
|
|
9
|
+
import { buildDelegationTool } from "../tools/delegation-utils.js";
|
|
10
|
+
import { SubagentRegistry } from "./registry.js";
|
|
10
11
|
/**
|
|
11
12
|
* Apoc is a subagent of Oracle specialized in devtools operations.
|
|
12
13
|
* It receives delegated tasks from Oracle and executes them using DevKit tools
|
|
@@ -36,6 +37,18 @@ export class Apoc {
|
|
|
36
37
|
static getInstance(config) {
|
|
37
38
|
if (!Apoc.instance) {
|
|
38
39
|
Apoc.instance = new Apoc(config);
|
|
40
|
+
SubagentRegistry.register({
|
|
41
|
+
agentKey: 'apoc', auditAgent: 'apoc', label: 'Apoc',
|
|
42
|
+
delegateToolName: 'apoc_delegate', emoji: '🧑🔬', color: 'amber',
|
|
43
|
+
description: 'Filesystem, shell & browser',
|
|
44
|
+
colorClass: 'text-amber-600 dark:text-amber-400',
|
|
45
|
+
bgClass: 'bg-amber-50 dark:bg-amber-900/10',
|
|
46
|
+
badgeClass: 'bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-300',
|
|
47
|
+
instance: Apoc.instance,
|
|
48
|
+
hasDynamicDescription: false,
|
|
49
|
+
isMultiInstance: false,
|
|
50
|
+
setSessionId: (id) => Apoc.setSessionId(id),
|
|
51
|
+
});
|
|
39
52
|
}
|
|
40
53
|
return Apoc.instance;
|
|
41
54
|
}
|
|
@@ -65,7 +78,7 @@ export class Apoc {
|
|
|
65
78
|
const tools = instrumentDevKitTools(rawTools, () => Apoc.currentSessionId, () => 'apoc');
|
|
66
79
|
this.display.log(`Apoc initialized with ${tools.length} DevKit tools (sandbox_dir: ${devkit.sandbox_dir}, personality: ${personality})`, { source: "Apoc" });
|
|
67
80
|
try {
|
|
68
|
-
this.agent = await
|
|
81
|
+
this.agent = await ServiceContainer.get(SERVICE_KEYS.providerFactory).createBare(apocConfig, tools);
|
|
69
82
|
}
|
|
70
83
|
catch (err) {
|
|
71
84
|
throw new ProviderError(apocConfig.provider, err, "Apoc subagent initialization failed");
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Re-exports for convenient external access
|
|
2
|
+
export { Apoc } from './apoc.js';
|
|
3
|
+
export { Neo } from './neo.js';
|
|
4
|
+
export { Trinity } from './trinity/trinity.js';
|
|
5
|
+
export { Link } from './link/link.js';
|
|
6
|
+
export { SubagentRegistry, SYSTEM_AGENTS } from './registry.js';
|
|
7
|
+
export { extractRawUsage, persistAgentMessage, buildAgentResult, emitToolAuditEvents } from './utils.js';
|
|
8
|
+
export { LinkRepository } from './link/repository.js';
|
|
9
|
+
export { LinkWorker } from './link/worker.js';
|
|
10
|
+
export { LinkSearch } from './link/search.js';
|
|
11
|
+
export { instrumentDevKitTools } from './devkit-instrument.js';
|
|
12
|
+
export { testConnection, introspectSchema, executeQuery } from './trinity/connector.js';
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { HumanMessage, SystemMessage, AIMessage } from "@langchain/core/messages";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { DynamicStructuredTool } from "@langchain/core/tools";
|
|
4
|
-
import { ConfigManager } from '
|
|
5
|
-
import { LinkRepository } from './
|
|
6
|
-
import { LinkSearch } from './
|
|
7
|
-
import {
|
|
8
|
-
import { ProviderError } from '
|
|
9
|
-
import { DisplayManager } from '
|
|
10
|
-
import { TaskRequestContext } from '
|
|
11
|
-
import { extractRawUsage, persistAgentMessage, buildAgentResult, emitToolAuditEvents } from '
|
|
12
|
-
import { buildDelegationTool } from '
|
|
4
|
+
import { ConfigManager } from '../../../config/manager.js';
|
|
5
|
+
import { LinkRepository } from './repository.js';
|
|
6
|
+
import { LinkSearch } from './search.js';
|
|
7
|
+
import { ServiceContainer, SERVICE_KEYS } from '../../container.js';
|
|
8
|
+
import { ProviderError } from '../../errors.js';
|
|
9
|
+
import { DisplayManager } from '../../display.js';
|
|
10
|
+
import { TaskRequestContext } from '../../tasks/context.js';
|
|
11
|
+
import { extractRawUsage, persistAgentMessage, buildAgentResult, emitToolAuditEvents } from '../utils.js';
|
|
12
|
+
import { buildDelegationTool } from '../../tools/delegation-utils.js';
|
|
13
|
+
import { SubagentRegistry } from '../registry.js';
|
|
13
14
|
const LINK_BASE_DESCRIPTION = `Delegate to Link, the documentation specialist subagent.
|
|
14
15
|
|
|
15
16
|
Link has access to indexed user documents (PDFs, Markdown, TXT, DOCX) stored in ~/.morpheus/docs.
|
|
@@ -58,6 +59,19 @@ export class Link {
|
|
|
58
59
|
config = ConfigManager.getInstance().get();
|
|
59
60
|
}
|
|
60
61
|
Link.instance = new Link(config);
|
|
62
|
+
SubagentRegistry.register({
|
|
63
|
+
agentKey: 'link', auditAgent: 'link', label: 'Link',
|
|
64
|
+
delegateToolName: 'link_delegate', emoji: '🕵️♂️', color: 'indigo',
|
|
65
|
+
description: 'Document search & RAG',
|
|
66
|
+
colorClass: 'text-indigo-600 dark:text-indigo-400',
|
|
67
|
+
bgClass: 'bg-indigo-50 dark:bg-indigo-900/10',
|
|
68
|
+
badgeClass: 'bg-indigo-100 text-indigo-700 dark:bg-indigo-900/40 dark:text-indigo-300',
|
|
69
|
+
instance: Link.instance,
|
|
70
|
+
hasDynamicDescription: true,
|
|
71
|
+
isMultiInstance: false,
|
|
72
|
+
setSessionId: (id) => Link.setSessionId(id),
|
|
73
|
+
refreshCatalog: () => Link.refreshDelegateCatalog(),
|
|
74
|
+
});
|
|
61
75
|
}
|
|
62
76
|
return Link.instance;
|
|
63
77
|
}
|
|
@@ -254,7 +268,7 @@ export class Link {
|
|
|
254
268
|
}
|
|
255
269
|
this.display.log(`Link initialized with personality: ${personality}.`, { source: 'Link' });
|
|
256
270
|
try {
|
|
257
|
-
this.agent = await
|
|
271
|
+
this.agent = await ServiceContainer.get(SERVICE_KEYS.providerFactory).create(linkConfig, tools);
|
|
258
272
|
}
|
|
259
273
|
catch (err) {
|
|
260
274
|
throw new ProviderError(linkConfig.provider, err, 'Link subagent initialization failed');
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import Database from 'better-sqlite3';
|
|
2
2
|
import fs from 'fs-extra';
|
|
3
3
|
import path from 'path';
|
|
4
|
-
import { homedir } from 'os';
|
|
5
4
|
import { randomUUID } from 'crypto';
|
|
6
|
-
import loadVecExtension from '
|
|
7
|
-
import { DisplayManager } from '
|
|
5
|
+
import loadVecExtension from '../../memory/sqlite-vec.js';
|
|
6
|
+
import { DisplayManager } from '../../display.js';
|
|
7
|
+
import { PATHS } from '../../../config/paths.js';
|
|
8
8
|
// ─── Repository ──────────────────────────────────────────────────────────────
|
|
9
9
|
const EMBEDDING_DIM = 384;
|
|
10
10
|
export class LinkRepository {
|
|
@@ -13,7 +13,7 @@ export class LinkRepository {
|
|
|
13
13
|
dbPath;
|
|
14
14
|
display = DisplayManager.getInstance();
|
|
15
15
|
constructor(dbPath) {
|
|
16
|
-
this.dbPath = dbPath ||
|
|
16
|
+
this.dbPath = dbPath || PATHS.linkDb;
|
|
17
17
|
}
|
|
18
18
|
static getInstance(dbPath) {
|
|
19
19
|
if (!LinkRepository.instance) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { LinkRepository } from './
|
|
2
|
-
import { ConfigManager } from '
|
|
3
|
-
import { EmbeddingService } from '
|
|
1
|
+
import { LinkRepository } from './repository.js';
|
|
2
|
+
import { ConfigManager } from '../../../config/manager.js';
|
|
3
|
+
import { EmbeddingService } from '../../memory/embedding.service.js';
|
|
4
4
|
/**
|
|
5
5
|
* LinkSearch - Hybrid search for Link documents
|
|
6
6
|
*
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { homedir } from 'os';
|
|
2
|
-
import path from 'path';
|
|
3
1
|
import fs from 'fs-extra';
|
|
4
2
|
import fsSync from 'fs';
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { LinkRepository } from './repository.js';
|
|
5
|
+
import { LinkSearch } from './search.js';
|
|
6
|
+
import { hashFile, processDocument, isSupportedFormat } from './chunker.js';
|
|
7
|
+
import { EmbeddingService } from '../../memory/embedding.service.js';
|
|
8
|
+
import { ConfigManager } from '../../../config/manager.js';
|
|
9
|
+
import { DisplayManager } from '../../display.js';
|
|
10
|
+
import { PATHS } from '../../../config/paths.js';
|
|
11
11
|
/**
|
|
12
12
|
* LinkWorker - Background worker for document indexing
|
|
13
13
|
*
|
|
@@ -26,7 +26,7 @@ export class LinkWorker {
|
|
|
26
26
|
constructor() {
|
|
27
27
|
this.repository = LinkRepository.getInstance();
|
|
28
28
|
this.search = LinkSearch.getInstance();
|
|
29
|
-
this.docsPath =
|
|
29
|
+
this.docsPath = PATHS.docs;
|
|
30
30
|
}
|
|
31
31
|
static getInstance() {
|
|
32
32
|
if (!LinkWorker.instance) {
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { HumanMessage, SystemMessage, AIMessage } from "@langchain/core/messages";
|
|
2
|
-
import { ConfigManager } from "
|
|
3
|
-
import {
|
|
4
|
-
import { ProviderError } from "
|
|
5
|
-
import { DisplayManager } from "
|
|
6
|
-
import { Construtor } from "
|
|
7
|
-
import { morpheusTools } from "
|
|
8
|
-
import { TaskRequestContext } from "
|
|
9
|
-
import { extractRawUsage, persistAgentMessage, buildAgentResult, emitToolAuditEvents } from "./
|
|
10
|
-
import { buildDelegationTool } from "
|
|
2
|
+
import { ConfigManager } from "../../config/manager.js";
|
|
3
|
+
import { ServiceContainer, SERVICE_KEYS } from "../container.js";
|
|
4
|
+
import { ProviderError } from "../errors.js";
|
|
5
|
+
import { DisplayManager } from "../display.js";
|
|
6
|
+
import { Construtor } from "../tools/factory.js";
|
|
7
|
+
import { morpheusTools } from "../tools/index.js";
|
|
8
|
+
import { TaskRequestContext } from "../tasks/context.js";
|
|
9
|
+
import { extractRawUsage, persistAgentMessage, buildAgentResult, emitToolAuditEvents } from "./utils.js";
|
|
10
|
+
import { buildDelegationTool } from "../tools/delegation-utils.js";
|
|
11
|
+
import { SubagentRegistry } from "./registry.js";
|
|
11
12
|
// Internal Morpheus tools get 'tool_call' event type; MCP tools get 'mcp_tool'
|
|
12
13
|
const MORPHEUS_TOOL_NAMES = new Set(morpheusTools.map((t) => t.name));
|
|
13
14
|
const NEO_BUILTIN_CAPABILITIES = `
|
|
@@ -61,6 +62,19 @@ export class Neo {
|
|
|
61
62
|
static getInstance(config) {
|
|
62
63
|
if (!Neo.instance) {
|
|
63
64
|
Neo.instance = new Neo(config);
|
|
65
|
+
SubagentRegistry.register({
|
|
66
|
+
agentKey: 'neo', auditAgent: 'neo', label: 'Neo',
|
|
67
|
+
delegateToolName: 'neo_delegate', emoji: '🥷', color: 'violet',
|
|
68
|
+
description: 'MCP tool orchestration',
|
|
69
|
+
colorClass: 'text-violet-600 dark:text-violet-400',
|
|
70
|
+
bgClass: 'bg-violet-50 dark:bg-violet-900/10',
|
|
71
|
+
badgeClass: 'bg-purple-100 text-purple-700 dark:bg-purple-900/40 dark:text-purple-300',
|
|
72
|
+
instance: Neo.instance,
|
|
73
|
+
hasDynamicDescription: true,
|
|
74
|
+
isMultiInstance: false,
|
|
75
|
+
setSessionId: (id) => Neo.setSessionId(id),
|
|
76
|
+
refreshCatalog: () => Neo.refreshDelegateCatalog(),
|
|
77
|
+
});
|
|
64
78
|
}
|
|
65
79
|
return Neo.instance;
|
|
66
80
|
}
|
|
@@ -87,7 +101,7 @@ export class Neo {
|
|
|
87
101
|
}
|
|
88
102
|
this.display.log(`Neo initialized with ${tools.length} tools (personality: ${personality}).`, { source: "Neo" });
|
|
89
103
|
try {
|
|
90
|
-
this.agent = await
|
|
104
|
+
this.agent = await ServiceContainer.get(SERVICE_KEYS.providerFactory).create(neoConfig, tools);
|
|
91
105
|
}
|
|
92
106
|
catch (err) {
|
|
93
107
|
throw new ProviderError(neoConfig.provider, err, "Neo subagent initialization failed");
|