morpheus-cli 0.9.13 → 0.9.22

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.
Files changed (102) hide show
  1. package/README.md +48 -17
  2. package/dist/channels/discord.js +93 -6
  3. package/dist/channels/telegram.js +109 -9
  4. package/dist/cli/commands/start.js +15 -0
  5. package/dist/config/manager.js +20 -1
  6. package/dist/config/paths.js +4 -0
  7. package/dist/config/schemas.js +15 -0
  8. package/dist/http/api.js +5 -1
  9. package/dist/http/middleware/auth.js +2 -1
  10. package/dist/http/routers/danger.js +4 -5
  11. package/dist/http/routers/display.js +33 -0
  12. package/dist/http/routers/link.js +2 -2
  13. package/dist/runtime/__tests__/telephonist-tts.test.js +84 -0
  14. package/dist/runtime/adapters/AuditRepositoryAdapter.js +6 -0
  15. package/dist/runtime/adapters/ChannelNotifierAdapter.js +9 -0
  16. package/dist/runtime/adapters/LangChainProviderAdapter.js +9 -0
  17. package/dist/runtime/adapters/SQLiteChatHistoryAdapter.js +15 -0
  18. package/dist/runtime/adapters/SQLiteTaskEnqueuerAdapter.js +6 -0
  19. package/dist/runtime/adapters/index.js +5 -0
  20. package/dist/runtime/audit/repository.js +6 -2
  21. package/dist/runtime/chronos/repository.js +2 -2
  22. package/dist/runtime/container.js +50 -0
  23. package/dist/runtime/display.js +17 -2
  24. package/dist/runtime/hot-reload.js +6 -9
  25. package/dist/runtime/memory/backfill-embeddings.js +2 -3
  26. package/dist/runtime/memory/sati/repository.js +3 -3
  27. package/dist/runtime/memory/sqlite.js +3 -3
  28. package/dist/runtime/memory/trinity-db.js +2 -2
  29. package/dist/runtime/ports/IAuditEmitter.js +1 -0
  30. package/dist/runtime/ports/IChatHistory.js +1 -0
  31. package/dist/runtime/ports/ILLMProviderFactory.js +1 -0
  32. package/dist/runtime/ports/INotifier.js +1 -0
  33. package/dist/runtime/ports/ITaskEnqueuer.js +1 -0
  34. package/dist/runtime/ports/index.js +1 -0
  35. package/dist/runtime/providers/factory.js +8 -52
  36. package/dist/runtime/providers/strategies.js +66 -0
  37. package/dist/runtime/setup/repository.js +2 -2
  38. package/dist/runtime/subagents/apoc.js +2 -2
  39. package/dist/runtime/subagents/link/link.js +2 -2
  40. package/dist/runtime/subagents/link/repository.js +2 -2
  41. package/dist/runtime/subagents/link/worker.js +3 -3
  42. package/dist/runtime/subagents/neo.js +2 -2
  43. package/dist/runtime/subagents/trinity/trinity.js +2 -2
  44. package/dist/runtime/tasks/repository.js +2 -2
  45. package/dist/runtime/telephonist.js +160 -0
  46. package/dist/runtime/tools/delegation-utils.js +5 -7
  47. package/dist/runtime/tools/morpheus-tools.js +6 -7
  48. package/dist/runtime/tools/smith-tool.js +5 -7
  49. package/dist/runtime/webhooks/repository.js +2 -2
  50. package/dist/types/config.js +6 -0
  51. package/dist/ui/assets/AuditDashboard-z3OBbJ8I.js +1 -0
  52. package/dist/ui/assets/{Chat-UVoDlqqM.js → Chat-aFz9FjrD.js} +7 -7
  53. package/dist/ui/assets/{Chronos-Dfs_pOsc.js → Chronos-MP_NCj2A.js} +1 -1
  54. package/dist/ui/assets/{ConfirmationModal-BBIjVef7.js → ConfirmationModal-B3gHIVKY.js} +1 -1
  55. package/dist/ui/assets/Dashboard-OyZXnj44.js +4120 -0
  56. package/dist/ui/assets/{DeleteConfirmationModal-Du85q5u2.js → DeleteConfirmationModal-D8QsQzwP.js} +1 -1
  57. package/dist/ui/assets/{Documents-DguILrI8.js → Documents-B8g_yv4f.js} +1 -1
  58. package/dist/ui/assets/{Logs-BDup2FET.js → Logs-BWufAtHa.js} +1 -1
  59. package/dist/ui/assets/{MCPManager-WBdh1rum.js → MCPManager-lLoGEyBy.js} +1 -1
  60. package/dist/ui/assets/ModelPricing-CuYIUwXt.js +1 -0
  61. package/dist/ui/assets/Notifications-nI--fmYx.js +1 -0
  62. package/dist/ui/assets/{Pagination-BHZKk42X.js → Pagination-D4ShqUKO.js} +1 -1
  63. package/dist/ui/assets/SatiMemories-DO3JDQBi.js +1 -0
  64. package/dist/ui/assets/{SelectInput-KVLsnfra.js → SelectInput-BPDcd3y7.js} +1 -1
  65. package/dist/ui/assets/SessionAudit-BWtJRkj1.js +9 -0
  66. package/dist/ui/assets/Settings-CblauAVd.js +49 -0
  67. package/dist/ui/assets/Skills-Dw6G5c8W.js +7 -0
  68. package/dist/ui/assets/Smiths-B6-CnRMv.js +1 -0
  69. package/dist/ui/assets/Switch-C7TxLq0E.js +1 -0
  70. package/dist/ui/assets/Tasks-DzUyw5z3.js +1 -0
  71. package/dist/ui/assets/{TrinityDatabases-DYHJunk7.js → TrinityDatabases-DCjdwnLH.js} +1 -1
  72. package/dist/ui/assets/{UsageStats-BpGXaHgW.js → UsageStats-VajzjndO.js} +1 -1
  73. package/dist/ui/assets/{WebhookManager-D2muhYy9.js → WebhookManager-BbfMCiy-.js} +2 -2
  74. package/dist/ui/assets/{agents-CgqJea9n.js → agents-CN_AKX_I.js} +1 -1
  75. package/dist/ui/assets/{audit-Dc3YW0-4.js → audit-M-5UGwoK.js} +1 -1
  76. package/dist/ui/assets/{chronos-CZvGhZQB.js → chronos-mZ0RIvh4.js} +1 -1
  77. package/dist/ui/assets/config-7LGRnJ26.js +1 -0
  78. package/dist/ui/assets/index-Bko2TlZY.css +1 -0
  79. package/dist/ui/assets/{index-Bta9YXEm.js → index-Db1XEN8v.js} +3 -3
  80. package/dist/ui/assets/{mcp-vIffcwd6.js → mcp-YiYC-9IH.js} +1 -1
  81. package/dist/ui/assets/{skills-wANsorUj.js → skills-dc6Xqqhb.js} +1 -1
  82. package/dist/ui/assets/{stats-xnlA4NwX.js → stats-BzqxCDuj.js} +1 -1
  83. package/dist/ui/assets/useCurrency-CEc5edm2.js +1 -0
  84. package/dist/ui/assets/vendor-icons-DE7PWdkN.js +1 -0
  85. package/dist/ui/assets/vendor-utils-BIYveU_1.js +39 -0
  86. package/dist/ui/index.html +4 -4
  87. package/dist/ui/sw.js +1 -1
  88. package/package.json +1 -1
  89. package/dist/ui/assets/AuditDashboard-BVyKnpVm.js +0 -1
  90. package/dist/ui/assets/Dashboard-BdSQDB14.js +0 -1
  91. package/dist/ui/assets/ModelPricing-BQPw0r6z.js +0 -1
  92. package/dist/ui/assets/Notifications-BslO2Ect.js +0 -1
  93. package/dist/ui/assets/SatiMemories-DzaLaZ6M.js +0 -1
  94. package/dist/ui/assets/SessionAudit-CBDThjBi.js +0 -9
  95. package/dist/ui/assets/Settings-JPTCA7C7.js +0 -49
  96. package/dist/ui/assets/Skills-BnDg1HCb.js +0 -7
  97. package/dist/ui/assets/Smiths-DR6g_o3D.js +0 -1
  98. package/dist/ui/assets/Tasks-BuoNCvI-.js +0 -1
  99. package/dist/ui/assets/config-pKL8Y4V9.js +0 -1
  100. package/dist/ui/assets/index-Cjli-AD7.css +0 -1
  101. package/dist/ui/assets/vendor-icons-NHF9HNeN.js +0 -1
  102. package/dist/ui/assets/vendor-utils-D4NnWbOU.js +0 -39
@@ -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';
3
+ import path from 'path';
5
4
  import { LinkRepository } from './repository.js';
6
5
  import { LinkSearch } from './search.js';
7
6
  import { hashFile, processDocument, isSupportedFormat } from './chunker.js';
8
7
  import { EmbeddingService } from '../../memory/embedding.service.js';
9
8
  import { ConfigManager } from '../../../config/manager.js';
10
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 = path.join(homedir(), '.morpheus', 'docs');
29
+ this.docsPath = PATHS.docs;
30
30
  }
31
31
  static getInstance() {
32
32
  if (!LinkWorker.instance) {
@@ -1,6 +1,6 @@
1
1
  import { HumanMessage, SystemMessage, AIMessage } from "@langchain/core/messages";
2
2
  import { ConfigManager } from "../../config/manager.js";
3
- import { ProviderFactory } from "../providers/factory.js";
3
+ import { ServiceContainer, SERVICE_KEYS } from "../container.js";
4
4
  import { ProviderError } from "../errors.js";
5
5
  import { DisplayManager } from "../display.js";
6
6
  import { Construtor } from "../tools/factory.js";
@@ -101,7 +101,7 @@ export class Neo {
101
101
  }
102
102
  this.display.log(`Neo initialized with ${tools.length} tools (personality: ${personality}).`, { source: "Neo" });
103
103
  try {
104
- this.agent = await ProviderFactory.create(neoConfig, tools);
104
+ this.agent = await ServiceContainer.get(SERVICE_KEYS.providerFactory).create(neoConfig, tools);
105
105
  }
106
106
  catch (err) {
107
107
  throw new ProviderError(neoConfig.provider, err, "Neo subagent initialization failed");
@@ -2,7 +2,7 @@ import { HumanMessage, SystemMessage, AIMessage } from "@langchain/core/messages
2
2
  import { tool } from "@langchain/core/tools";
3
3
  import { z } from "zod";
4
4
  import { ConfigManager } from "../../../config/manager.js";
5
- import { ProviderFactory } from "../../providers/factory.js";
5
+ import { ServiceContainer, SERVICE_KEYS } from "../../container.js";
6
6
  import { ProviderError } from "../../errors.js";
7
7
  import { DisplayManager } from "../../display.js";
8
8
  import { DatabaseRegistry } from "../../memory/trinity-db.js";
@@ -204,7 +204,7 @@ export class Trinity {
204
204
  const tools = this.buildTrinityTools();
205
205
  this.display.log(`Trinity initialized with ${tools.length} tools (personality: ${personality}).`, { source: 'Trinity' });
206
206
  try {
207
- this.agent = await ProviderFactory.createBare(trinityConfig, tools);
207
+ this.agent = await ServiceContainer.get(SERVICE_KEYS.providerFactory).createBare(trinityConfig, tools);
208
208
  }
209
209
  catch (err) {
210
210
  throw new ProviderError(trinityConfig.provider, err, 'Trinity subagent initialization failed');
@@ -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 { randomUUID } from 'crypto';
5
+ import { PATHS } from '../../config/paths.js';
6
6
  export class TaskRepository {
7
7
  static instance = null;
8
8
  db;
9
9
  constructor() {
10
- const dbPath = path.join(homedir(), '.morpheus', 'memory', 'short-memory.db');
10
+ const dbPath = PATHS.shortMemoryDb;
11
11
  fs.ensureDirSync(path.dirname(dbPath));
12
12
  this.db = new Database(dbPath, { timeout: 5000 });
13
13
  this.db.pragma('journal_mode = WAL');
@@ -2,6 +2,9 @@ import { GoogleGenAI } from '@google/genai';
2
2
  import OpenAI from 'openai';
3
3
  import { OpenRouter } from '@openrouter/sdk';
4
4
  import fs from 'fs';
5
+ import fsExtra from 'fs-extra';
6
+ import path from 'path';
7
+ import os from 'os';
5
8
  import { parseFile } from 'music-metadata';
6
9
  /**
7
10
  * Returns the actual audio duration in seconds by parsing the file header.
@@ -25,6 +28,7 @@ async function getAudioDurationSeconds(filePath) {
25
28
  return 0;
26
29
  }
27
30
  }
31
+ export const TTS_MAX_CHARS = 4096;
28
32
  class GeminiTelephonist {
29
33
  model;
30
34
  constructor(model) {
@@ -187,6 +191,162 @@ export function createTelephonist(config) {
187
191
  throw new Error(`Unsupported audio provider: '${config.provider}'. Supported: google, openai, openrouter, ollama.`);
188
192
  }
189
193
  }
194
+ // ─── TTS Implementations ─────────────────────────────────────────────────────
195
+ function truncateForTts(text) {
196
+ if (text.length <= TTS_MAX_CHARS)
197
+ return text;
198
+ console.warn(`[Telephonist] TTS input truncated from ${text.length} to ${TTS_MAX_CHARS} chars.`);
199
+ return text.slice(0, TTS_MAX_CHARS);
200
+ }
201
+ function mimeTypeToExt(mimeType) {
202
+ if (mimeType.includes('ogg'))
203
+ return '.ogg';
204
+ if (mimeType.includes('mp3') || mimeType.includes('mpeg'))
205
+ return '.mp3';
206
+ if (mimeType.includes('wav'))
207
+ return '.wav';
208
+ if (mimeType.includes('aac'))
209
+ return '.aac';
210
+ return '.audio';
211
+ }
212
+ async function writeTempAudio(buffer, ext) {
213
+ const filePath = path.join(os.tmpdir(), `morpheus-tts-${Date.now()}${ext}`);
214
+ await fsExtra.writeFile(filePath, buffer);
215
+ return filePath;
216
+ }
217
+ /**
218
+ * Wraps raw PCM data in a WAV container header.
219
+ * Gemini TTS returns audio/pcm at 24000Hz, 16-bit, mono.
220
+ */
221
+ function pcmToWav(pcmBuffer, sampleRate = 24000, channels = 1, bitDepth = 16) {
222
+ const header = Buffer.alloc(44);
223
+ const dataSize = pcmBuffer.length;
224
+ const byteRate = sampleRate * channels * (bitDepth / 8);
225
+ const blockAlign = channels * (bitDepth / 8);
226
+ header.write('RIFF', 0);
227
+ header.writeUInt32LE(36 + dataSize, 4);
228
+ header.write('WAVE', 8);
229
+ header.write('fmt ', 12);
230
+ header.writeUInt32LE(16, 16); // PCM chunk size
231
+ header.writeUInt16LE(1, 20); // PCM format
232
+ header.writeUInt16LE(channels, 22);
233
+ header.writeUInt32LE(sampleRate, 24);
234
+ header.writeUInt32LE(byteRate, 28);
235
+ header.writeUInt16LE(blockAlign, 32);
236
+ header.writeUInt16LE(bitDepth, 34);
237
+ header.write('data', 36);
238
+ header.writeUInt32LE(dataSize, 40);
239
+ return Buffer.concat([header, pcmBuffer]);
240
+ }
241
+ class OpenAITtsTelephonist {
242
+ model;
243
+ defaultVoice;
244
+ constructor(model, defaultVoice) {
245
+ this.model = model;
246
+ this.defaultVoice = defaultVoice;
247
+ }
248
+ async transcribe() {
249
+ throw new Error('OpenAITtsTelephonist does not support transcription.');
250
+ }
251
+ async synthesize(text, apiKey, voice, stylePrompt) {
252
+ const client = new OpenAI({ apiKey });
253
+ const raw = stylePrompt ? `${stylePrompt}: ${text}` : text;
254
+ const input = truncateForTts(raw);
255
+ const response = await client.audio.speech.create({
256
+ model: this.model,
257
+ voice: (voice || this.defaultVoice),
258
+ input,
259
+ response_format: 'mp3',
260
+ });
261
+ const buffer = Buffer.from(await response.arrayBuffer());
262
+ const filePath = await writeTempAudio(buffer, '.mp3');
263
+ return {
264
+ filePath,
265
+ mimeType: 'audio/mpeg',
266
+ usage: {
267
+ input_tokens: 0,
268
+ output_tokens: 0,
269
+ total_tokens: 0,
270
+ audio_duration_seconds: 0,
271
+ },
272
+ };
273
+ }
274
+ }
275
+ class GeminiTtsTelephonist {
276
+ model;
277
+ defaultVoice;
278
+ constructor(model, defaultVoice) {
279
+ this.model = model;
280
+ this.defaultVoice = defaultVoice;
281
+ }
282
+ async transcribe() {
283
+ throw new Error('GeminiTtsTelephonist does not support transcription.');
284
+ }
285
+ async synthesize(text, apiKey, voice, stylePrompt) {
286
+ const ai = new GoogleGenAI({ apiKey });
287
+ const raw = stylePrompt ? `${stylePrompt}: ${text}` : text;
288
+ const input = truncateForTts(raw);
289
+ const response = await ai.models.generateContent({
290
+ model: this.model,
291
+ contents: [{ role: 'user', parts: [{ text: input }] }],
292
+ config: {
293
+ responseModalities: ['AUDIO'],
294
+ speechConfig: {
295
+ voiceConfig: {
296
+ prebuiltVoiceConfig: { voiceName: voice || this.defaultVoice },
297
+ },
298
+ },
299
+ },
300
+ });
301
+ const audioPart = response.candidates?.[0]?.content?.parts?.find((p) => p.inlineData?.mimeType?.startsWith('audio/'));
302
+ if (!audioPart?.inlineData?.data) {
303
+ throw new Error('Gemini TTS: no audio data in response');
304
+ }
305
+ const rawMimeType = audioPart.inlineData.mimeType ?? 'audio/pcm';
306
+ const rawBuffer = Buffer.from(audioPart.inlineData.data, 'base64');
307
+ let mimeType = rawMimeType;
308
+ let buffer;
309
+ // Gemini returns raw PCM — wrap it in a WAV container
310
+ if (rawMimeType.includes('pcm') || rawMimeType.includes('l16')) {
311
+ // Parse sample rate from mimeType params e.g. "audio/pcm;rate=24000"
312
+ const rateMatch = rawMimeType.match(/rate=(\d+)/i);
313
+ const sampleRate = rateMatch ? parseInt(rateMatch[1], 10) : 24000;
314
+ buffer = pcmToWav(rawBuffer, sampleRate);
315
+ mimeType = 'audio/wav';
316
+ }
317
+ else {
318
+ buffer = rawBuffer;
319
+ }
320
+ const ext = mimeTypeToExt(mimeType);
321
+ const filePath = await writeTempAudio(buffer, ext);
322
+ const usage = response.usageMetadata;
323
+ return {
324
+ filePath,
325
+ mimeType,
326
+ usage: {
327
+ input_tokens: usage?.promptTokenCount ?? 0,
328
+ output_tokens: usage?.candidatesTokenCount ?? 0,
329
+ total_tokens: usage?.totalTokenCount ?? 0,
330
+ audio_duration_seconds: 0,
331
+ },
332
+ };
333
+ }
334
+ }
335
+ /**
336
+ * Factory that creates an ITelephonist with TTS (synthesize) support.
337
+ * Supports providers: openai, google.
338
+ */
339
+ export function createTtsTelephonist(config) {
340
+ switch (config.provider) {
341
+ case 'openai':
342
+ return new OpenAITtsTelephonist(config.model, config.voice);
343
+ case 'google':
344
+ return new GeminiTtsTelephonist(config.model, config.voice);
345
+ default:
346
+ throw new Error(`Unsupported TTS provider: '${config.provider}'. Supported: openai, google.`);
347
+ }
348
+ }
349
+ // ─── Legacy export for backward compatibility ─────────────────────────────────
190
350
  // Legacy export for backward compatibility
191
351
  export class Telephonist {
192
352
  delegate;
@@ -1,11 +1,9 @@
1
1
  import { tool } from "@langchain/core/tools";
2
2
  import { z } from "zod";
3
- import { TaskRepository } from "../tasks/repository.js";
4
3
  import { TaskRequestContext } from "../tasks/context.js";
5
4
  import { compositeDelegationError, isLikelyCompositeDelegationTask } from "./delegation-guard.js";
6
5
  import { DisplayManager } from "../display.js";
7
- import { ChannelRegistry } from "../../channels/registry.js";
8
- import { AuditRepository } from "../audit/repository.js";
6
+ import { ServiceContainer, SERVICE_KEYS } from "../container.js";
9
7
  /**
10
8
  * Factory that builds a delegation StructuredTool for Apoc/Neo/Trinity.
11
9
  * Handles: composite guard, sync branch (notify→execute→audit→increment),
@@ -33,7 +31,8 @@ export function buildDelegationTool(opts) {
33
31
  const ctx = TaskRequestContext.get();
34
32
  const sessionId = ctx?.session_id ?? "default";
35
33
  if (ctx?.origin_channel && ctx.origin_user_id && ctx.origin_channel !== 'api' && ctx.origin_channel !== 'ui') {
36
- ChannelRegistry.sendToUser(ctx.origin_channel, ctx.origin_user_id, notifyText)
34
+ ServiceContainer.get(SERVICE_KEYS.notifier)
35
+ .sendToUser(ctx.origin_channel, ctx.origin_user_id, notifyText)
37
36
  .catch(() => { });
38
37
  }
39
38
  try {
@@ -41,7 +40,7 @@ export function buildDelegationTool(opts) {
41
40
  TaskRequestContext.incrementSyncDelegation();
42
41
  display.log(`${agentLabel} sync execution completed.`, { source, level: "info" });
43
42
  if (result.usage) {
44
- AuditRepository.getInstance().insert({
43
+ ServiceContainer.get(SERVICE_KEYS.auditEmitter).emit({
45
44
  session_id: sessionId,
46
45
  event_type: 'llm_call',
47
46
  agent: auditAgent,
@@ -76,8 +75,7 @@ export function buildDelegationTool(opts) {
76
75
  return "Delegation limit reached for this user turn. Split the request or wait for current tasks.";
77
76
  }
78
77
  const ctx = TaskRequestContext.get();
79
- const repository = TaskRepository.getInstance();
80
- const created = repository.createTask({
78
+ const created = ServiceContainer.get(SERVICE_KEYS.taskEnqueuer).enqueue({
81
79
  agent: agentKey,
82
80
  input: task,
83
81
  context: context ?? null,
@@ -2,14 +2,13 @@ import { tool } from "@langchain/core/tools";
2
2
  import { z } from "zod";
3
3
  import { ConfigManager } from "../../config/manager.js";
4
4
  import { promises as fsPromises } from "fs";
5
- import path from "path";
6
- import { homedir } from "os";
7
5
  import Database from "better-sqlite3";
6
+ import { PATHS } from "../../config/paths.js";
8
7
  import { TaskRepository } from "../tasks/repository.js";
9
8
  import { TaskRequestContext } from "../tasks/context.js";
10
9
  import { isEnvVarSet } from "../../config/precedence.js";
11
10
  // ─── Shared ───────────────────────────────────────────────────────────────────
12
- const shortMemoryDbPath = path.join(homedir(), ".morpheus", "memory", "short-memory.db");
11
+ const shortMemoryDbPath = PATHS.shortMemoryDb;
13
12
  /**
14
13
  * Map of config paths to their corresponding environment variable names.
15
14
  * Used to check if a config field is being overridden by an env var.
@@ -145,7 +144,7 @@ export const DiagnosticTool = tool(async () => {
145
144
  try {
146
145
  const timestamp = new Date().toISOString();
147
146
  const components = {};
148
- const morpheusRoot = path.join(homedir(), ".morpheus");
147
+ const morpheusRoot = PATHS.root;
149
148
  // Configuration
150
149
  try {
151
150
  const configManager = ConfigManager.getInstance();
@@ -198,7 +197,7 @@ export const DiagnosticTool = tool(async () => {
198
197
  }
199
198
  // Short-term memory DB
200
199
  try {
201
- const dbPath = path.join(morpheusRoot, "memory", "short-memory.db");
200
+ const dbPath = PATHS.shortMemoryDb;
202
201
  await fsPromises.access(dbPath);
203
202
  const stat = await fsPromises.stat(dbPath);
204
203
  components.shortMemoryDb = {
@@ -216,7 +215,7 @@ export const DiagnosticTool = tool(async () => {
216
215
  }
217
216
  // Sati long-term memory DB
218
217
  try {
219
- const satiDbPath = path.join(morpheusRoot, "memory", "sati-memory.db");
218
+ const satiDbPath = PATHS.satiDb;
220
219
  await fsPromises.access(satiDbPath);
221
220
  const stat = await fsPromises.stat(satiDbPath);
222
221
  components.satiMemoryDb = {
@@ -266,7 +265,7 @@ export const DiagnosticTool = tool(async () => {
266
265
  };
267
266
  // Logs directory
268
267
  try {
269
- const logsDir = path.join(morpheusRoot, "logs");
268
+ const logsDir = PATHS.logs;
270
269
  await fsPromises.access(logsDir);
271
270
  components.logs = {
272
271
  status: "healthy",
@@ -1,13 +1,11 @@
1
1
  import { tool } from "@langchain/core/tools";
2
2
  import { z } from "zod";
3
- import { TaskRepository } from "../tasks/repository.js";
4
3
  import { TaskRequestContext } from "../tasks/context.js";
5
4
  import { DisplayManager } from "../display.js";
6
5
  import { ConfigManager } from "../../config/manager.js";
7
6
  import { SmithDelegator } from "../smiths/delegator.js";
8
7
  import { SmithRegistry } from "../smiths/registry.js";
9
- import { ChannelRegistry } from "../../channels/registry.js";
10
- import { AuditRepository } from "../audit/repository.js";
8
+ import { ServiceContainer, SERVICE_KEYS } from "../container.js";
11
9
  /**
12
10
  * Returns true when Smiths are configured in sync mode (inline execution).
13
11
  */
@@ -43,7 +41,8 @@ export const SmithDelegateTool = tool(async ({ smith, task, context }) => {
43
41
  const sessionId = ctx?.session_id ?? 'default';
44
42
  // Notify originating channel
45
43
  if (ctx?.origin_channel && ctx.origin_user_id && ctx.origin_channel !== 'api' && ctx.origin_channel !== 'ui') {
46
- ChannelRegistry.sendToUser(ctx.origin_channel, ctx.origin_user_id, `🕶️ Smith '${smith}' is executing your request...`)
44
+ ServiceContainer.get(SERVICE_KEYS.notifier)
45
+ .sendToUser(ctx.origin_channel, ctx.origin_user_id, `🕶️ Smith '${smith}' is executing your request...`)
47
46
  .catch(() => { });
48
47
  }
49
48
  try {
@@ -55,7 +54,7 @@ export const SmithDelegateTool = tool(async ({ smith, task, context }) => {
55
54
  level: "info",
56
55
  });
57
56
  if (result.usage) {
58
- AuditRepository.getInstance().insert({
57
+ ServiceContainer.get(SERVICE_KEYS.auditEmitter).emit({
59
58
  session_id: sessionId,
60
59
  event_type: 'llm_call',
61
60
  agent: 'smith',
@@ -96,8 +95,7 @@ export const SmithDelegateTool = tool(async ({ smith, task, context }) => {
96
95
  return "Delegation limit reached for this user turn. Split the request or wait for current tasks.";
97
96
  }
98
97
  const ctx = TaskRequestContext.get();
99
- const repository = TaskRepository.getInstance();
100
- const created = repository.createTask({
98
+ const created = ServiceContainer.get(SERVICE_KEYS.taskEnqueuer).enqueue({
101
99
  agent: "smith",
102
100
  input: task,
103
101
  context: context ? JSON.stringify({ smith_name: smith, context }) : JSON.stringify({ smith_name: smith }),
@@ -1,13 +1,13 @@
1
1
  import Database from 'better-sqlite3';
2
2
  import path from 'path';
3
- import { homedir } from 'os';
4
3
  import fs from 'fs-extra';
5
4
  import { randomUUID } from 'crypto';
5
+ import { PATHS } from '../../config/paths.js';
6
6
  export class WebhookRepository {
7
7
  static instance = null;
8
8
  db;
9
9
  constructor() {
10
- const dbPath = path.join(homedir(), '.morpheus', 'memory', 'short-memory.db');
10
+ const dbPath = PATHS.shortMemoryDb;
11
11
  fs.ensureDirSync(path.dirname(dbPath));
12
12
  this.db = new Database(dbPath, { timeout: 5000 });
13
13
  this.db.pragma('journal_mode = WAL');
@@ -14,6 +14,12 @@ export const DEFAULT_CONFIG = {
14
14
  enabled: true,
15
15
  maxDurationSeconds: 300,
16
16
  supportedMimeTypes: ['audio/ogg', 'audio/mp3', 'audio/mpeg', 'audio/wav'],
17
+ tts: {
18
+ enabled: false,
19
+ provider: 'google',
20
+ model: 'gemini-2.5-flash-preview-tts',
21
+ voice: 'Kore',
22
+ },
17
23
  },
18
24
  memory: {
19
25
  limit: 100
@@ -0,0 +1 @@
1
+ import{j as e,m as o}from"./vendor-motion-C3CZ8ZlO.js";import{L as E,r as B}from"./vendor-react-DikRIOlj.js";import{a as D}from"./audit-M-5UGwoK.js";import{u as R}from"./agents-CN_AKX_I.js";import{u as O}from"./useCurrency-CEc5edm2.js";import{Y as _,V as F,h as L,i as I,au as v,I as j,o as N,A as z,g as S,ay as U,k as W,N as w,az as V,O as A,r as P,ak as H}from"./vendor-icons-DE7PWdkN.js";import"./vendor-utils-BIYveU_1.js";import"./index-Db1XEN8v.js";import"./config-7LGRnJ26.js";function m(r){return r>=1e6?`${(r/1e6).toFixed(1)}M`:r>=1e3?`${(r/1e3).toFixed(1)}k`:String(r)}function k(r){if(r<1e3)return`${r}ms`;if(r<6e4)return`${(r/1e3).toFixed(1)}s`;const i=Math.floor(r/6e4),l=Math.floor(r%6e4/1e3);return`${i}m ${l}s`}function G(r){return r?new Date(r).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"}):"—"}function T(r,i){return i?`${Math.round(r/i*100)}%`:"0%"}function J({data:r,fmtCost:i}){const[l,d]=B.useState(null);if(!r.length)return e.jsx("p",{className:"text-xs text-gray-400 dark:text-matrix-secondary/50 py-4",children:"No activity in the last 30 days."});const s=Math.max(...r.map(a=>a.eventCount),1);return e.jsx("div",{className:"flex items-end gap-0.5 h-24 w-full relative",children:r.map((a,g)=>{const y=Math.max(4,Math.round(a.eventCount/s*88)),p=l===g;return e.jsxs("div",{className:"flex-1 flex flex-col items-center justify-end group",onMouseEnter:()=>d(g),onMouseLeave:()=>d(null),children:[p&&e.jsxs("div",{className:"absolute -top-10 left-1/2 -translate-x-1/2 z-10 bg-gray-900 dark:bg-zinc-800 text-white text-[10px] rounded px-2 py-1 whitespace-nowrap pointer-events-none shadow-lg",children:[a.date,": ",a.eventCount," events · ",i(a.estimatedCostUsd)]}),e.jsx("div",{style:{height:y},className:`w-full rounded-t transition-colors ${p?"bg-blue-500 dark:bg-matrix-highlight":"bg-blue-300/70 dark:bg-matrix-highlight/40 group-hover:bg-blue-400 dark:group-hover:bg-matrix-highlight/60"}`})]},a.date)})})}function h({icon:r,label:i,value:l,sub:d,color:s="blue"}){const a={blue:"bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400 border-blue-200 dark:border-blue-800/40",green:"bg-green-50 dark:bg-green-900/20 text-green-600 dark:text-matrix-highlight border-green-200 dark:border-green-800/40",amber:"bg-amber-50 dark:bg-amber-900/20 text-amber-600 dark:text-amber-400 border-amber-200 dark:border-amber-800/40",purple:"bg-purple-50 dark:bg-purple-900/20 text-purple-600 dark:text-purple-400 border-purple-200 dark:border-purple-800/40",rose:"bg-rose-50 dark:bg-rose-900/20 text-rose-600 dark:text-rose-400 border-rose-200 dark:border-rose-800/40",teal:"bg-teal-50 dark:bg-teal-900/20 text-teal-600 dark:text-teal-400 border-teal-200 dark:border-teal-800/40"};return e.jsxs("div",{className:`rounded-lg border p-4 flex gap-3 items-start ${a[s]}`,children:[e.jsx("div",{className:"mt-0.5 flex-shrink-0",children:r}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("p",{className:"text-xs font-medium opacity-70 uppercase tracking-wider mb-0.5",children:i}),e.jsx("p",{className:"text-xl font-bold font-mono leading-tight",children:l}),d&&e.jsx("div",{className:"text-[11px] opacity-60 mt-0.5 leading-snug",children:d})]})]})}function x({title:r,icon:i,children:l}){return e.jsxs("div",{className:"rounded-lg border border-gray-200 dark:border-matrix-primary overflow-hidden bg-white dark:bg-zinc-900 shadow-sm",children:[e.jsxs("div",{className:"px-4 py-3 bg-gray-50 dark:bg-zinc-900 border-b border-gray-200 dark:border-matrix-primary flex items-center gap-2",children:[e.jsx("span",{className:"text-gray-500 dark:text-matrix-secondary/70",children:i}),e.jsx("h2",{className:"text-sm font-semibold text-gray-700 dark:text-matrix-secondary uppercase tracking-wider",children:r})]}),e.jsx("div",{className:"p-4",children:l})]})}function M({agent:r}){const{getByKey:i}=R(),l=i(r);return e.jsxs("span",{className:`inline-flex items-center gap-1 text-[11px] font-semibold px-1.5 py-0.5 rounded ${l.badgeClass}`,children:[l.emoji," ",r.toUpperCase()]})}function K({status:r}){const i={active:"bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-matrix-highlight",paused:"bg-gray-100 text-gray-600 dark:bg-zinc-800 dark:text-matrix-secondary",archived:"bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-300",deleted:"bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400",unknown:"bg-gray-100 text-gray-500 dark:bg-zinc-800 dark:text-matrix-secondary/60"};return e.jsx("span",{className:`text-[10px] font-semibold uppercase px-1.5 py-0.5 rounded ${i[r]??i.unknown}`,children:r})}const Y={llm_call:e.jsx(v,{size:13}),tool_call:e.jsx(j,{size:13}),mcp_tool:e.jsxs("svg",{width:"13",height:"13",viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:[e.jsx("path",{d:"M3.49994 11.7501L11.6717 3.57855C12.7762 2.47398 14.5672 2.47398 15.6717 3.57855C16.7762 4.68312 16.7762 6.47398 15.6717 7.57855M15.6717 7.57855L9.49994 13.7501M15.6717 7.57855C16.7762 6.47398 18.5672 6.47398 19.6717 7.57855C20.7762 8.68312 20.7762 10.474 19.6717 11.5785L12.7072 18.543C12.3167 18.9335 12.3167 19.5667 12.7072 19.9572L13.9999 21.2499",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"}),e.jsx("path",{d:"M17.4999 9.74921L11.3282 15.921C10.2237 17.0255 8.43272 17.0255 7.32823 15.921C6.22373 14.8164 6.22373 13.0255 7.32823 11.921L13.4999 5.74939",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})]}),memory_recovery:e.jsx(N,{size:13}),memory_persist:e.jsx(N,{size:13}),telephonist:e.jsx(A,{size:13}),skill_loaded:e.jsx(w,{size:13}),chronos_job:e.jsx(S,{size:13}),task_created:e.jsx(H,{size:13}),task_completed:e.jsx(P,{size:13})},Z={llm_call:"text-blue-500 dark:text-blue-400",tool_call:"text-amber-500 dark:text-amber-400",mcp_tool:"text-purple-500 dark:text-purple-400",memory_recovery:"text-emerald-500 dark:text-emerald-400",memory_persist:"text-violet-500 dark:text-violet-400",telephonist:"text-rose-500 dark:text-rose-400",skill_loaded:"text-teal-500 dark:text-teal-400",chronos_job:"text-orange-500 dark:text-orange-400",task_created:"text-gray-500 dark:text-matrix-secondary",task_completed:"text-green-600 dark:text-matrix-highlight"};function q({eventType:r}){return r==="mcp_tool"?e.jsx("span",{className:"flex-shrink-0 text-purple-500 dark:text-purple-400",children:e.jsxs("svg",{width:"13",height:"13",viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:[e.jsx("path",{d:"M3.49994 11.7501L11.6717 3.57855C12.7762 2.47398 14.5672 2.47398 15.6717 3.57855C16.7762 4.68312 16.7762 6.47398 15.6717 7.57855M15.6717 7.57855L9.49994 13.7501M15.6717 7.57855C16.7762 6.47398 18.5672 6.47398 19.6717 7.57855C20.7762 8.68312 20.7762 10.474 19.6717 11.5785L12.7072 18.543C12.3167 18.9335 12.3167 19.5667 12.7072 19.9572L13.9999 21.2499",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"}),e.jsx("path",{d:"M17.4999 9.74921L11.3282 15.921C10.2237 17.0255 8.43272 17.0255 7.32823 15.921C6.22373 14.8164 6.22373 13.0255 7.32823 11.921L13.4999 5.74939",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})]})}):e.jsx(j,{size:13,className:"flex-shrink-0 text-amber-500 dark:text-amber-400"})}const Q={llm_call:"bg-blue-400 dark:bg-blue-500",tool_call:"bg-amber-400 dark:bg-amber-500",mcp_tool:"bg-purple-400 dark:bg-purple-500",memory_recovery:"bg-emerald-400 dark:bg-emerald-500",memory_persist:"bg-violet-400 dark:bg-violet-500",telephonist:"bg-rose-400 dark:bg-rose-500",skill_loaded:"bg-teal-400 dark:bg-teal-500",chronos_job:"bg-orange-400 dark:bg-orange-500",task_created:"bg-gray-300 dark:bg-matrix-secondary/50",task_completed:"bg-green-400 dark:bg-matrix-highlight/70"},X={hidden:{opacity:0},show:{opacity:1,transition:{staggerChildren:.04}}},c={hidden:{opacity:0,y:12},show:{opacity:1,y:0}},oe=()=>{const{data:r,isLoading:i,mutate:l}=D(),{fmtCost:d}=O();if(i)return e.jsxs("div",{className:"flex items-center justify-center h-64 gap-3 text-gray-400 dark:text-matrix-secondary",children:[e.jsx(_,{size:20,className:"animate-spin"}),e.jsx("span",{className:"text-sm font-mono",children:"Loading audit data…"})]});if(!r)return e.jsxs("div",{className:"flex flex-col items-center justify-center h-64 gap-2 text-gray-400 dark:text-matrix-secondary",children:[e.jsx(F,{size:24}),e.jsx("span",{className:"text-sm",children:"Failed to load audit data."})]});const{sessions:s,totals:a,byAgent:g,byModel:y,topTools:p,recentSessions:f,dailyActivity:b}=r,C=[["llm_call",a.llmCallCount],["tool_call",a.toolCallCount],["mcp_tool",a.mcpToolCount],["memory_recovery",a.memoryRecoveryCount],["memory_persist",a.memoryPersistCount],["telephonist",a.telephonistCount],["skill_loaded",a.skillCount],["chronos_job",a.chronosJobCount],["task_created",a.taskCreatedCount],["task_completed",a.taskCompletedCount]].filter(([,t])=>t>0).sort((t,n)=>n[1]-t[1]),$=Math.max(...C.map(([,t])=>t),1);return e.jsxs(o.div,{variants:X,initial:"hidden",animate:"show",className:"space-y-6",children:[e.jsxs(o.div,{variants:c,className:"flex items-center justify-between flex-wrap gap-3",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"w-10 h-10 rounded-lg bg-blue-500/10 dark:bg-blue-500/20 border border-blue-200 dark:border-blue-800/40 flex items-center justify-center",children:e.jsx(L,{className:"w-5 h-5 text-blue-600 dark:text-blue-400"})}),e.jsxs("div",{children:[e.jsx("h1",{className:"text-xl font-bold text-gray-900 dark:text-matrix-highlight",children:"Global Audit"}),e.jsxs("p",{className:"text-sm text-gray-500 dark:text-matrix-secondary/60 mt-0.5",children:[s.withAudit," sessions with audit data · ",a.totalEventCount.toLocaleString()," events total"]})]})]}),e.jsxs("button",{onClick:()=>l(),className:"flex items-center gap-2 px-3 py-2 rounded-lg border border-gray-200 dark:border-matrix-primary text-sm text-gray-500 dark:text-matrix-secondary hover:bg-gray-50 dark:hover:bg-zinc-900 transition-colors",children:[e.jsx(_,{size:14})," Refresh"]})]}),e.jsxs(o.div,{variants:c,className:"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-3",children:[e.jsx(h,{icon:e.jsx(I,{size:16}),label:"Total Cost",value:d(a.estimatedCostUsd),color:"green"}),e.jsx(h,{icon:e.jsx(v,{size:16}),label:"LLM Calls",value:a.llmCallCount.toLocaleString(),color:"blue"}),e.jsx(h,{icon:e.jsx(j,{size:16}),label:"Tool Calls",value:(a.toolCallCount+a.mcpToolCount).toLocaleString(),sub:e.jsxs(e.Fragment,{children:[e.jsxs("span",{children:[a.toolCallCount," native"]}),e.jsx("br",{}),e.jsxs("span",{children:[a.mcpToolCount," MCP"]})]}),color:"amber"}),e.jsx(h,{icon:e.jsx(N,{size:16}),label:"Memory Hits",value:a.memoryRecoveryCount.toLocaleString(),color:"teal"}),e.jsx(h,{icon:e.jsx(z,{size:16}),label:"Total Tokens",value:m(a.totalInputTokens+a.totalOutputTokens),sub:e.jsxs(e.Fragment,{children:[e.jsxs("span",{children:["↑",m(a.totalInputTokens)," in"]}),e.jsx("br",{}),e.jsxs("span",{children:["↓",m(a.totalOutputTokens)," out"]})]}),color:"purple"}),e.jsx(h,{icon:e.jsx(S,{size:16}),label:"Total Time",value:k(a.totalDurationMs),color:"rose"})]}),e.jsxs(o.div,{variants:c,className:"grid grid-cols-1 md:grid-cols-2 gap-6",children:[e.jsxs(x,{title:"Sessions",icon:e.jsx(U,{size:14}),children:[e.jsx("div",{className:"grid grid-cols-2 gap-3 mb-4",children:[{label:"Total",value:s.total,cls:"text-gray-700 dark:text-matrix-secondary"},{label:"With Audit",value:s.withAudit,cls:"text-blue-600 dark:text-blue-400"},{label:"Active",value:s.active,cls:"text-green-600 dark:text-matrix-highlight"},{label:"Paused",value:s.paused,cls:"text-gray-500 dark:text-matrix-secondary"},{label:"Archived",value:s.archived,cls:"text-amber-600 dark:text-amber-400"},{label:"Deleted",value:s.deleted,cls:"text-red-500 dark:text-red-400"}].map(({label:t,value:n,cls:u})=>e.jsxs("div",{className:"flex flex-col",children:[e.jsx("span",{className:"text-[10px] uppercase tracking-widest text-gray-400 dark:text-matrix-secondary/50",children:t}),e.jsx("span",{className:`text-2xl font-bold font-mono ${u}`,children:n})]},t))}),s.total>0&&e.jsxs("div",{className:"h-2 rounded-full overflow-hidden flex gap-px",children:[s.active>0&&e.jsx("div",{className:"bg-green-400 dark:bg-matrix-highlight/70",style:{flex:s.active}}),s.paused>0&&e.jsx("div",{className:"bg-gray-300 dark:bg-matrix-primary/50",style:{flex:s.paused}}),s.archived>0&&e.jsx("div",{className:"bg-amber-400 dark:bg-amber-500/70",style:{flex:s.archived}}),s.deleted>0&&e.jsx("div",{className:"bg-red-400 dark:bg-red-500/70",style:{flex:s.deleted}})]})]}),e.jsxs(x,{title:"Activity — Last 30 Days",icon:e.jsx(W,{size:14}),children:[e.jsx(J,{data:b,fmtCost:d}),b.length>0&&e.jsxs("div",{className:"flex gap-4 mt-2 text-[11px] text-gray-400 dark:text-matrix-secondary/50 font-mono",children:[e.jsx("span",{children:b[0]?.date}),e.jsx("span",{className:"flex-1 text-right",children:b[b.length-1]?.date})]})]})]}),e.jsx(o.div,{variants:c,children:e.jsx(x,{title:"Events by Type",icon:e.jsx(z,{size:14}),children:e.jsx("div",{className:"space-y-2",children:C.map(([t,n])=>e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:`flex-shrink-0 w-5 flex justify-center ${Z[t]??"text-gray-400"}`,children:Y[t]}),e.jsx("span",{className:"text-xs font-mono text-gray-600 dark:text-matrix-secondary w-32 flex-shrink-0",children:t}),e.jsx("div",{className:"flex-1 h-2 bg-gray-100 dark:bg-zinc-800 rounded-full overflow-hidden",children:e.jsx("div",{className:`h-full rounded-full transition-all ${Q[t]??"bg-gray-400"}`,style:{width:T(n,$)}})}),e.jsx("span",{className:"text-xs font-mono text-gray-500 dark:text-matrix-secondary w-16 text-right",children:n.toLocaleString()}),e.jsx("span",{className:"text-[10px] text-gray-400 dark:text-matrix-secondary/50 w-10 text-right",children:T(n,a.totalEventCount)})]},t))})})}),e.jsxs(o.div,{variants:c,className:"grid grid-cols-1 lg:grid-cols-2 gap-6",children:[e.jsx(x,{title:"By Agent",icon:e.jsx(w,{size:14}),children:g.length===0?e.jsx("p",{className:"text-sm text-gray-400 dark:text-matrix-secondary/50",children:"No agent data."}):e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-xs font-mono",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-[10px] uppercase tracking-wider text-gray-400 dark:text-matrix-secondary/50 border-b border-gray-100 dark:border-matrix-primary/30",children:[e.jsx("th",{className:"pb-2 text-left",children:"Agent"}),e.jsx("th",{className:"pb-2 text-right",children:"LLM"}),e.jsx("th",{className:"pb-2 text-right",children:"Tools"}),e.jsx("th",{className:"pb-2 text-right",children:"Tokens"}),e.jsx("th",{className:"pb-2 text-right",children:"Time"}),e.jsx("th",{className:"pb-2 text-right",children:"Cost"})]})}),e.jsx("tbody",{className:"divide-y divide-gray-50 dark:divide-matrix-primary/20",children:g.map(t=>e.jsxs("tr",{className:"hover:bg-gray-50 dark:hover:bg-zinc-900/50",children:[e.jsx("td",{className:"py-1.5",children:e.jsx(M,{agent:t.agent})}),e.jsx("td",{className:"py-1.5 text-right text-gray-600 dark:text-matrix-secondary",children:t.llmCalls.toLocaleString()}),e.jsx("td",{className:"py-1.5 text-right text-gray-600 dark:text-matrix-secondary",children:t.toolCalls.toLocaleString()}),e.jsxs("td",{className:"py-1.5 text-right text-gray-500 dark:text-matrix-secondary/70",children:["↑",m(t.inputTokens)," ↓",m(t.outputTokens)]}),e.jsx("td",{className:"py-1.5 text-right text-gray-500 dark:text-matrix-secondary/70",children:k(t.totalDurationMs)}),e.jsx("td",{className:"py-1.5 text-right font-semibold text-gray-700 dark:text-matrix-secondary",children:d(t.estimatedCostUsd)})]},t.agent))})]})})}),e.jsx(x,{title:"By Model",icon:e.jsx(v,{size:14}),children:y.length===0?e.jsx("p",{className:"text-sm text-gray-400 dark:text-matrix-secondary/50",children:"No model data."}):e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-xs font-mono",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-[10px] uppercase tracking-wider text-gray-400 dark:text-matrix-secondary/50 border-b border-gray-100 dark:border-matrix-primary/30",children:[e.jsx("th",{className:"pb-2 text-left",children:"Model"}),e.jsx("th",{className:"pb-2 text-right",children:"Calls"}),e.jsx("th",{className:"pb-2 text-right",children:"In"}),e.jsx("th",{className:"pb-2 text-right",children:"Out"}),e.jsx("th",{className:"pb-2 text-right",children:"Cost"})]})}),e.jsx("tbody",{className:"divide-y divide-gray-50 dark:divide-matrix-primary/20",children:y.map(t=>e.jsxs("tr",{className:"hover:bg-gray-50 dark:hover:bg-zinc-900/50",children:[e.jsxs("td",{className:"py-1.5",children:[e.jsx("div",{className:"text-gray-700 dark:text-matrix-secondary break-all leading-tight",children:t.model}),e.jsx("div",{className:"text-[10px] text-gray-400 dark:text-matrix-secondary/40",children:t.provider})]}),e.jsx("td",{className:"py-1.5 text-right text-gray-600 dark:text-matrix-secondary",children:t.calls.toLocaleString()}),e.jsx("td",{className:"py-1.5 text-right text-gray-500 dark:text-matrix-secondary/70",children:m(t.inputTokens)}),e.jsx("td",{className:"py-1.5 text-right text-gray-500 dark:text-matrix-secondary/70",children:m(t.outputTokens)}),e.jsx("td",{className:"py-1.5 text-right font-semibold text-gray-700 dark:text-matrix-secondary",children:d(t.estimatedCostUsd)})]},`${t.provider}/${t.model}`))})]})})})]}),p.length>0&&e.jsx(o.div,{variants:c,children:e.jsx(x,{title:"Top Tools",icon:e.jsx(j,{size:14}),children:e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-xs font-mono",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-[10px] uppercase tracking-wider text-gray-400 dark:text-matrix-secondary/50 border-b border-gray-100 dark:border-matrix-primary/30",children:[e.jsx("th",{className:"pb-2 text-left",children:"Tool"}),e.jsx("th",{className:"pb-2 text-left",children:"Agent"}),e.jsx("th",{className:"pb-2 text-right",children:"Calls"}),e.jsx("th",{className:"pb-2 text-right",children:"Errors"}),e.jsx("th",{className:"pb-2 text-right",children:"Error rate"})]})}),e.jsx("tbody",{className:"divide-y divide-gray-50 dark:divide-matrix-primary/20",children:p.map((t,n)=>{const u=t.count?t.errorCount/t.count:0;return e.jsxs("tr",{className:"hover:bg-gray-50 dark:hover:bg-zinc-900/50",children:[e.jsx("td",{className:"py-1.5",children:e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx(q,{eventType:t.event_type}),e.jsx("span",{className:"text-gray-700 dark:text-matrix-secondary break-all",children:t.tool_name})]})}),e.jsx("td",{className:"py-1.5",children:t.agent?e.jsx(M,{agent:t.agent}):e.jsx("span",{className:"text-gray-400",children:"—"})}),e.jsx("td",{className:"py-1.5 text-right text-gray-600 dark:text-matrix-secondary",children:t.count.toLocaleString()}),e.jsx("td",{className:"py-1.5 text-right",children:e.jsx("span",{className:t.errorCount>0?"text-red-500 dark:text-red-400":"text-gray-400 dark:text-matrix-secondary/50",children:t.errorCount})}),e.jsx("td",{className:"py-1.5 text-right",children:e.jsx("span",{className:u>.1?"text-red-500 dark:text-red-400":u>0?"text-amber-500 dark:text-amber-400":"text-gray-400 dark:text-matrix-secondary/50",children:t.count>0?`${Math.round(u*100)}%`:"—"})})]},n)})})]})})})}),e.jsx(o.div,{variants:c,children:e.jsx(x,{title:"Recent Sessions with Audit",icon:e.jsx(L,{size:14}),children:f.length===0?e.jsx("p",{className:"text-sm text-gray-400 dark:text-matrix-secondary/50",children:"No sessions with audit data yet."}):e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-xs font-mono",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-[10px] uppercase tracking-wider text-gray-400 dark:text-matrix-secondary/50 border-b border-gray-100 dark:border-matrix-primary/30",children:[e.jsx("th",{className:"pb-2 text-left",children:"Session"}),e.jsx("th",{className:"pb-2 text-left",children:"Status"}),e.jsx("th",{className:"pb-2 text-right",children:"Events"}),e.jsx("th",{className:"pb-2 text-right",children:"LLM"}),e.jsx("th",{className:"pb-2 text-right",children:"Duration"}),e.jsx("th",{className:"pb-2 text-right",children:"Cost"}),e.jsx("th",{className:"pb-2"})]})}),e.jsx("tbody",{className:"divide-y divide-gray-50 dark:divide-matrix-primary/20",children:f.map(t=>e.jsxs("tr",{className:"hover:bg-gray-50 dark:hover:bg-zinc-900/50",children:[e.jsxs("td",{className:"py-2",children:[e.jsx("div",{className:"text-gray-700 dark:text-matrix-secondary truncate max-w-[160px]",title:t.title??t.session_id,children:t.title??e.jsxs("span",{className:"text-gray-400 dark:text-matrix-secondary/40 font-mono text-[10px]",children:[t.session_id.slice(0,12),"…"]})}),t.started_at&&e.jsx("div",{className:"text-[10px] text-gray-400 dark:text-matrix-secondary/40",children:G(t.started_at)})]}),e.jsx("td",{className:"py-2",children:e.jsx(K,{status:t.status})}),e.jsx("td",{className:"py-2 text-right text-gray-600 dark:text-matrix-secondary",children:t.event_count.toLocaleString()}),e.jsx("td",{className:"py-2 text-right text-gray-500 dark:text-matrix-secondary/70",children:t.llmCallCount.toLocaleString()}),e.jsx("td",{className:"py-2 text-right text-gray-500 dark:text-matrix-secondary/70",children:k(t.totalDurationMs)}),e.jsx("td",{className:"py-2 text-right font-semibold text-gray-700 dark:text-matrix-secondary",children:d(t.estimatedCostUsd)}),e.jsx("td",{className:"py-2 text-right",children:e.jsx(E,{to:`/sessions/${t.session_id}/audit`,className:"inline-flex items-center gap-1 px-2 py-1 rounded border border-gray-200 dark:border-matrix-primary text-gray-400 dark:text-matrix-secondary hover:text-blue-600 dark:hover:text-matrix-highlight hover:border-blue-300 dark:hover:border-matrix-highlight/50 transition-colors",title:"View session audit",children:e.jsx(V,{size:11})})})]},t.session_id))})]})})})}),a.telephonistCount>0&&e.jsx(o.div,{variants:c,children:e.jsx(x,{title:"Audio / Telephonist",icon:e.jsx(A,{size:14}),children:e.jsxs("div",{className:"flex flex-wrap gap-8",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-[10px] uppercase tracking-widest text-gray-400 dark:text-matrix-secondary/50 mb-0.5",children:"Calls"}),e.jsx("p",{className:"text-2xl font-bold font-mono text-rose-500 dark:text-rose-400",children:a.telephonistCount.toLocaleString()})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-[10px] uppercase tracking-widest text-gray-400 dark:text-matrix-secondary/50 mb-0.5",children:"Total Audio"}),e.jsx("p",{className:"text-2xl font-bold font-mono text-rose-500 dark:text-rose-400",children:a.totalAudioSeconds<60?`${a.totalAudioSeconds.toFixed(1)}s`:`${(a.totalAudioSeconds/60).toFixed(1)}m`})]})]})})})]})};export{oe as AuditDashboard};