@chozzz/vargos 2.0.6 → 2.0.8
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/dist/cli.js +14 -5
- package/dist/cli.js.map +1 -1
- package/dist/edge/mcp/index.d.ts +33 -0
- package/dist/edge/mcp/index.d.ts.map +1 -0
- package/dist/edge/mcp/index.js +217 -0
- package/dist/edge/mcp/index.js.map +1 -0
- package/dist/edge/webhooks/index.d.ts +33 -0
- package/dist/edge/webhooks/index.d.ts.map +1 -0
- package/dist/edge/webhooks/index.js +231 -0
- package/dist/edge/webhooks/index.js.map +1 -0
- package/dist/edge/webhooks/transform.d.ts +8 -0
- package/dist/edge/webhooks/transform.d.ts.map +1 -0
- package/dist/edge/webhooks/transform.js +29 -0
- package/dist/edge/webhooks/transform.js.map +1 -0
- package/dist/gateway/bus.d.ts +48 -0
- package/dist/gateway/bus.d.ts.map +1 -0
- package/dist/gateway/bus.js +2 -0
- package/dist/gateway/bus.js.map +1 -0
- package/dist/gateway/decorators.d.ts +40 -0
- package/dist/gateway/decorators.d.ts.map +1 -0
- package/dist/gateway/decorators.js +43 -0
- package/dist/gateway/decorators.js.map +1 -0
- package/dist/gateway/emitter.d.ts +42 -0
- package/dist/gateway/emitter.d.ts.map +1 -0
- package/dist/gateway/emitter.js +259 -0
- package/dist/gateway/emitter.js.map +1 -0
- package/dist/gateway/events.d.ts +343 -0
- package/dist/gateway/events.d.ts.map +1 -0
- package/dist/gateway/events.js +7 -0
- package/dist/gateway/events.js.map +1 -0
- package/dist/gateway/tcp-server.d.ts +7 -0
- package/dist/gateway/tcp-server.d.ts.map +1 -0
- package/dist/gateway/tcp-server.js +115 -0
- package/dist/gateway/tcp-server.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +74 -0
- package/dist/index.js.map +1 -0
- package/dist/scripts/migrate-cron-sessions.d.ts +10 -0
- package/dist/scripts/migrate-cron-sessions.d.ts.map +1 -0
- package/dist/scripts/migrate-cron-sessions.js +139 -0
- package/dist/scripts/migrate-cron-sessions.js.map +1 -0
- package/dist/scripts/seed.d.ts +2 -0
- package/dist/scripts/seed.d.ts.map +1 -0
- package/dist/scripts/seed.js +4 -0
- package/dist/scripts/seed.js.map +1 -0
- package/dist/services/agent/directives.d.ts +14 -0
- package/dist/services/agent/directives.d.ts.map +1 -0
- package/dist/services/agent/directives.js +32 -0
- package/dist/services/agent/directives.js.map +1 -0
- package/dist/services/agent/index.d.ts +104 -0
- package/dist/services/agent/index.d.ts.map +1 -0
- package/dist/services/agent/index.js +534 -0
- package/dist/services/agent/index.js.map +1 -0
- package/dist/services/agent/persona.d.ts +15 -0
- package/dist/services/agent/persona.d.ts.map +1 -0
- package/dist/services/agent/persona.js +63 -0
- package/dist/services/agent/persona.js.map +1 -0
- package/dist/services/agent/prompt-interpolate.d.ts +41 -0
- package/dist/services/agent/prompt-interpolate.d.ts.map +1 -0
- package/dist/services/agent/prompt-interpolate.js +102 -0
- package/dist/services/agent/prompt-interpolate.js.map +1 -0
- package/dist/services/agent/schema.d.ts +10 -0
- package/dist/services/agent/schema.d.ts.map +1 -0
- package/dist/services/agent/schema.js +5 -0
- package/dist/services/agent/schema.js.map +1 -0
- package/dist/services/agent/tools.d.ts +26 -0
- package/dist/services/agent/tools.d.ts.map +1 -0
- package/dist/services/agent/tools.js +85 -0
- package/dist/services/agent/tools.js.map +1 -0
- package/dist/services/channels/base-adapter.d.ts +61 -0
- package/dist/services/channels/base-adapter.d.ts.map +1 -0
- package/dist/services/channels/base-adapter.js +181 -0
- package/dist/services/channels/base-adapter.js.map +1 -0
- package/dist/services/channels/contracts.d.ts +75 -0
- package/dist/services/channels/contracts.d.ts.map +1 -0
- package/dist/services/channels/contracts.js +6 -0
- package/dist/services/channels/contracts.js.map +1 -0
- package/dist/services/channels/debounce.d.ts +22 -0
- package/dist/services/channels/debounce.d.ts.map +1 -0
- package/dist/services/channels/debounce.js +53 -0
- package/dist/services/channels/debounce.js.map +1 -0
- package/dist/services/channels/dedupe.d.ts +19 -0
- package/dist/services/channels/dedupe.d.ts.map +1 -0
- package/dist/services/channels/dedupe.js +52 -0
- package/dist/services/channels/dedupe.js.map +1 -0
- package/dist/services/channels/delivery.d.ts +12 -0
- package/dist/services/channels/delivery.d.ts.map +1 -0
- package/dist/services/channels/delivery.js +53 -0
- package/dist/services/channels/delivery.js.map +1 -0
- package/dist/services/channels/index.d.ts +53 -0
- package/dist/services/channels/index.d.ts.map +1 -0
- package/dist/services/channels/index.js +405 -0
- package/dist/services/channels/index.js.map +1 -0
- package/dist/services/channels/link-expand.d.ts +8 -0
- package/dist/services/channels/link-expand.d.ts.map +1 -0
- package/dist/services/channels/link-expand.js +28 -0
- package/dist/services/channels/link-expand.js.map +1 -0
- package/dist/services/channels/media-extract.d.ts +7 -0
- package/dist/services/channels/media-extract.d.ts.map +1 -0
- package/dist/services/channels/media-extract.js +31 -0
- package/dist/services/channels/media-extract.js.map +1 -0
- package/dist/services/channels/pipeline.d.ts +29 -0
- package/dist/services/channels/pipeline.d.ts.map +1 -0
- package/dist/services/channels/pipeline.js +120 -0
- package/dist/services/channels/pipeline.js.map +1 -0
- package/dist/services/channels/provider-loader.d.ts +7 -0
- package/dist/services/channels/provider-loader.d.ts.map +1 -0
- package/dist/services/channels/provider-loader.js +13 -0
- package/dist/services/channels/provider-loader.js.map +1 -0
- package/dist/services/channels/providers/telegram/adapter.d.ts +34 -0
- package/dist/services/channels/providers/telegram/adapter.d.ts.map +1 -0
- package/dist/services/channels/providers/telegram/adapter.js +278 -0
- package/dist/services/channels/providers/telegram/adapter.js.map +1 -0
- package/dist/services/channels/providers/telegram/index.d.ts +11 -0
- package/dist/services/channels/providers/telegram/index.d.ts.map +1 -0
- package/dist/services/channels/providers/telegram/index.js +11 -0
- package/dist/services/channels/providers/telegram/index.js.map +1 -0
- package/dist/services/channels/providers/telegram/normalizer.d.ts +12 -0
- package/dist/services/channels/providers/telegram/normalizer.d.ts.map +1 -0
- package/dist/services/channels/providers/telegram/normalizer.js +50 -0
- package/dist/services/channels/providers/telegram/normalizer.js.map +1 -0
- package/dist/services/channels/providers/telegram/types.d.ts +72 -0
- package/dist/services/channels/providers/telegram/types.d.ts.map +1 -0
- package/dist/services/channels/providers/telegram/types.js +3 -0
- package/dist/services/channels/providers/telegram/types.js.map +1 -0
- package/dist/services/channels/providers/whatsapp/adapter.d.ts +36 -0
- package/dist/services/channels/providers/whatsapp/adapter.d.ts.map +1 -0
- package/dist/services/channels/providers/whatsapp/adapter.js +261 -0
- package/dist/services/channels/providers/whatsapp/adapter.js.map +1 -0
- package/dist/services/channels/providers/whatsapp/index.d.ts +11 -0
- package/dist/services/channels/providers/whatsapp/index.d.ts.map +1 -0
- package/dist/services/channels/providers/whatsapp/index.js +11 -0
- package/dist/services/channels/providers/whatsapp/index.js.map +1 -0
- package/dist/services/channels/providers/whatsapp/normalizer.d.ts +11 -0
- package/dist/services/channels/providers/whatsapp/normalizer.d.ts.map +1 -0
- package/dist/services/channels/providers/whatsapp/normalizer.js +47 -0
- package/dist/services/channels/providers/whatsapp/normalizer.js.map +1 -0
- package/dist/services/channels/providers/whatsapp/session.d.ts +9 -0
- package/dist/services/channels/providers/whatsapp/session.d.ts.map +1 -0
- package/dist/services/channels/providers/whatsapp/session.js +118 -0
- package/dist/services/channels/providers/whatsapp/session.js.map +1 -0
- package/dist/services/channels/providers/whatsapp/types.d.ts +23 -0
- package/dist/services/channels/providers/whatsapp/types.d.ts.map +1 -0
- package/dist/services/channels/providers/whatsapp/types.js +3 -0
- package/dist/services/channels/providers/whatsapp/types.js.map +1 -0
- package/dist/services/channels/reconnect.d.ts +23 -0
- package/dist/services/channels/reconnect.d.ts.map +1 -0
- package/dist/services/channels/reconnect.js +32 -0
- package/dist/services/channels/reconnect.js.map +1 -0
- package/dist/services/channels/status-reactions.d.ts +27 -0
- package/dist/services/channels/status-reactions.d.ts.map +1 -0
- package/dist/services/channels/status-reactions.js +63 -0
- package/dist/services/channels/status-reactions.js.map +1 -0
- package/dist/services/channels/types.d.ts +16 -0
- package/dist/services/channels/types.d.ts.map +1 -0
- package/dist/services/channels/types.js +2 -0
- package/dist/services/channels/types.js.map +1 -0
- package/dist/services/channels/typing-state.d.ts +22 -0
- package/dist/services/channels/typing-state.d.ts.map +1 -0
- package/dist/services/channels/typing-state.js +88 -0
- package/dist/services/channels/typing-state.js.map +1 -0
- package/dist/services/config/index.d.ts +2426 -0
- package/dist/services/config/index.d.ts.map +1 -0
- package/dist/services/config/index.js +232 -0
- package/dist/services/config/index.js.map +1 -0
- package/dist/services/config/schemas/agent.d.ts +720 -0
- package/dist/services/config/schemas/agent.d.ts.map +1 -0
- package/dist/services/config/schemas/agent.js +86 -0
- package/dist/services/config/schemas/agent.js.map +1 -0
- package/dist/services/config/schemas/auth.d.ts +60 -0
- package/dist/services/config/schemas/auth.d.ts.map +1 -0
- package/dist/services/config/schemas/auth.js +18 -0
- package/dist/services/config/schemas/auth.js.map +1 -0
- package/dist/services/config/schemas/channels.d.ts +117 -0
- package/dist/services/config/schemas/channels.d.ts.map +1 -0
- package/dist/services/config/schemas/channels.js +22 -0
- package/dist/services/config/schemas/channels.js.map +1 -0
- package/dist/services/config/schemas/cron.d.ts +97 -0
- package/dist/services/config/schemas/cron.d.ts.map +1 -0
- package/dist/services/config/schemas/cron.js +18 -0
- package/dist/services/config/schemas/cron.js.map +1 -0
- package/dist/services/config/schemas/features.d.ts +43 -0
- package/dist/services/config/schemas/features.d.ts.map +1 -0
- package/dist/services/config/schemas/features.js +20 -0
- package/dist/services/config/schemas/features.js.map +1 -0
- package/dist/services/config/schemas/index.d.ts +24 -0
- package/dist/services/config/schemas/index.d.ts.map +1 -0
- package/dist/services/config/schemas/index.js +24 -0
- package/dist/services/config/schemas/index.js.map +1 -0
- package/dist/services/config/schemas/mcp.d.ts +31 -0
- package/dist/services/config/schemas/mcp.d.ts.map +1 -0
- package/dist/services/config/schemas/mcp.js +39 -0
- package/dist/services/config/schemas/mcp.js.map +1 -0
- package/dist/services/config/schemas/primitives.d.ts +13 -0
- package/dist/services/config/schemas/primitives.d.ts.map +1 -0
- package/dist/services/config/schemas/primitives.js +17 -0
- package/dist/services/config/schemas/primitives.js.map +1 -0
- package/dist/services/config/schemas/providers.d.ts +335 -0
- package/dist/services/config/schemas/providers.d.ts.map +1 -0
- package/dist/services/config/schemas/providers.js +27 -0
- package/dist/services/config/schemas/providers.js.map +1 -0
- package/dist/services/config/schemas/storage.d.ts +16 -0
- package/dist/services/config/schemas/storage.d.ts.map +1 -0
- package/dist/services/config/schemas/storage.js +9 -0
- package/dist/services/config/schemas/storage.js.map +1 -0
- package/dist/services/config/schemas/webhooks.d.ts +25 -0
- package/dist/services/config/schemas/webhooks.d.ts.map +1 -0
- package/dist/services/config/schemas/webhooks.js +12 -0
- package/dist/services/config/schemas/webhooks.js.map +1 -0
- package/dist/services/cron/index.d.ts +50 -0
- package/dist/services/cron/index.d.ts.map +1 -0
- package/dist/services/cron/index.js +460 -0
- package/dist/services/cron/index.js.map +1 -0
- package/dist/services/log/index.d.ts +14 -0
- package/dist/services/log/index.d.ts.map +1 -0
- package/dist/services/log/index.js +137 -0
- package/dist/services/log/index.js.map +1 -0
- package/dist/services/mcp-client/index.d.ts +37 -0
- package/dist/services/mcp-client/index.d.ts.map +1 -0
- package/dist/services/mcp-client/index.js +258 -0
- package/dist/services/mcp-client/index.js.map +1 -0
- package/dist/services/media/extract-document.d.ts +8 -0
- package/dist/services/media/extract-document.d.ts.map +1 -0
- package/dist/services/media/extract-document.js +85 -0
- package/dist/services/media/extract-document.js.map +1 -0
- package/dist/services/media/index.d.ts +21 -0
- package/dist/services/media/index.d.ts.map +1 -0
- package/dist/services/media/index.js +116 -0
- package/dist/services/media/index.js.map +1 -0
- package/dist/services/media/providers/anthropic.d.ts +6 -0
- package/dist/services/media/providers/anthropic.d.ts.map +1 -0
- package/dist/services/media/providers/anthropic.js +38 -0
- package/dist/services/media/providers/anthropic.js.map +1 -0
- package/dist/services/media/providers/index.d.ts +6 -0
- package/dist/services/media/providers/index.d.ts.map +1 -0
- package/dist/services/media/providers/index.js +15 -0
- package/dist/services/media/providers/index.js.map +1 -0
- package/dist/services/media/providers/openai.d.ts +6 -0
- package/dist/services/media/providers/openai.d.ts.map +1 -0
- package/dist/services/media/providers/openai.js +48 -0
- package/dist/services/media/providers/openai.js.map +1 -0
- package/dist/services/media/providers/provider.d.ts +5 -0
- package/dist/services/media/providers/provider.d.ts.map +1 -0
- package/dist/services/media/providers/provider.js +2 -0
- package/dist/services/media/providers/provider.js.map +1 -0
- package/dist/services/memory/chunker.d.ts +7 -0
- package/dist/services/memory/chunker.d.ts.map +1 -0
- package/dist/services/memory/chunker.js +46 -0
- package/dist/services/memory/chunker.js.map +1 -0
- package/dist/services/memory/context.d.ts +68 -0
- package/dist/services/memory/context.d.ts.map +1 -0
- package/dist/services/memory/context.js +223 -0
- package/dist/services/memory/context.js.map +1 -0
- package/dist/services/memory/embedding.d.ts +9 -0
- package/dist/services/memory/embedding.d.ts.map +1 -0
- package/dist/services/memory/embedding.js +49 -0
- package/dist/services/memory/embedding.js.map +1 -0
- package/dist/services/memory/index.d.ts +24 -0
- package/dist/services/memory/index.d.ts.map +1 -0
- package/dist/services/memory/index.js +140 -0
- package/dist/services/memory/index.js.map +1 -0
- package/dist/services/memory/session-indexer.d.ts +5 -0
- package/dist/services/memory/session-indexer.d.ts.map +1 -0
- package/dist/services/memory/session-indexer.js +62 -0
- package/dist/services/memory/session-indexer.js.map +1 -0
- package/dist/services/memory/sqlite-storage.d.ts +23 -0
- package/dist/services/memory/sqlite-storage.d.ts.map +1 -0
- package/dist/services/memory/sqlite-storage.js +75 -0
- package/dist/services/memory/sqlite-storage.js.map +1 -0
- package/dist/services/memory/types.d.ts +31 -0
- package/dist/services/memory/types.d.ts.map +1 -0
- package/dist/services/memory/types.js +2 -0
- package/dist/services/memory/types.js.map +1 -0
- package/dist/services/web/index.d.ts +9 -0
- package/dist/services/web/index.d.ts.map +1 -0
- package/dist/services/web/index.js +101 -0
- package/dist/services/web/index.js.map +1 -0
- package/dist/vitest.config.d.ts +3 -0
- package/dist/vitest.config.d.ts.map +1 -0
- package/dist/vitest.config.js +9 -0
- package/dist/vitest.config.js.map +1 -0
- package/package.json +2 -8
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP client service — loads external MCP servers and exposes them as bus events.
|
|
3
|
+
*
|
|
4
|
+
* Inverse of edge/mcp:
|
|
5
|
+
* edge/mcp exports bus events as MCP tools to external clients (outbound)
|
|
6
|
+
* this service imports external MCP servers as bus events (inbound)
|
|
7
|
+
*
|
|
8
|
+
* MCP servers are configured in ~/.vargos/agent/mcp.json:
|
|
9
|
+
* {
|
|
10
|
+
* "mcpServers": {
|
|
11
|
+
* "server-name": { command: "node server.js" },
|
|
12
|
+
* }
|
|
13
|
+
* }
|
|
14
|
+
*
|
|
15
|
+
* Tools become callable events: mcp.server-name.toolName on the bus
|
|
16
|
+
*/
|
|
17
|
+
import type { Bus } from '../../gateway/bus.js';
|
|
18
|
+
import type { AppConfig } from '../../services/config/index.js';
|
|
19
|
+
export declare class McpClientService {
|
|
20
|
+
private readonly bus;
|
|
21
|
+
private readonly config;
|
|
22
|
+
private servers;
|
|
23
|
+
constructor(bus: Bus, config: AppConfig);
|
|
24
|
+
start(): Promise<void>;
|
|
25
|
+
private connectServer;
|
|
26
|
+
/**
|
|
27
|
+
* Convert JSON Schema to Zod schema.
|
|
28
|
+
* Handles common JSON Schema properties like type, properties, required, etc.
|
|
29
|
+
*/
|
|
30
|
+
private jsonSchemaToZod;
|
|
31
|
+
private registerToolHandler;
|
|
32
|
+
stop(): Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
export declare function boot(bus: Bus): Promise<{
|
|
35
|
+
stop(): Promise<void>;
|
|
36
|
+
}>;
|
|
37
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../services/mcp-client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAQH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAehE,qBAAa,gBAAgB;IAIzB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJzB,OAAO,CAAC,OAAO,CAA0C;gBAGtC,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,SAAS;IAG9B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAsDd,aAAa;IA6D3B;;;OAGG;IAEH,OAAO,CAAC,eAAe;IAwDvB,OAAO,CAAC,mBAAmB;IA+CrB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAiB5B;AAID,wBAAsB,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC;IAAE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAAC,CAKvE"}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP client service — loads external MCP servers and exposes them as bus events.
|
|
3
|
+
*
|
|
4
|
+
* Inverse of edge/mcp:
|
|
5
|
+
* edge/mcp exports bus events as MCP tools to external clients (outbound)
|
|
6
|
+
* this service imports external MCP servers as bus events (inbound)
|
|
7
|
+
*
|
|
8
|
+
* MCP servers are configured in ~/.vargos/agent/mcp.json:
|
|
9
|
+
* {
|
|
10
|
+
* "mcpServers": {
|
|
11
|
+
* "server-name": { command: "node server.js" },
|
|
12
|
+
* }
|
|
13
|
+
* }
|
|
14
|
+
*
|
|
15
|
+
* Tools become callable events: mcp.server-name.toolName on the bus
|
|
16
|
+
*/
|
|
17
|
+
import { z } from 'zod';
|
|
18
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
19
|
+
import path from 'node:path';
|
|
20
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
21
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
22
|
+
import { createLogger } from '../../lib/logger.js';
|
|
23
|
+
import { toMessage } from '../../lib/error.js';
|
|
24
|
+
import { getDataPaths } from '../../lib/paths.js';
|
|
25
|
+
const log = createLogger('mcp-client');
|
|
26
|
+
// ── McpClientService ──────────────────────────────────────────────────────────
|
|
27
|
+
export class McpClientService {
|
|
28
|
+
bus;
|
|
29
|
+
config;
|
|
30
|
+
servers = new Map();
|
|
31
|
+
constructor(bus, config) {
|
|
32
|
+
this.bus = bus;
|
|
33
|
+
this.config = config;
|
|
34
|
+
}
|
|
35
|
+
async start() {
|
|
36
|
+
const { dataDir } = getDataPaths();
|
|
37
|
+
const mcpConfigPath = path.join(dataDir, 'agent', 'mcp.json');
|
|
38
|
+
let mcpServers = this.config.mcpServers || {};
|
|
39
|
+
// Load from agent/mcp.json if it exists (merged with config.mcpServers)
|
|
40
|
+
if (existsSync(mcpConfigPath)) {
|
|
41
|
+
try {
|
|
42
|
+
const content = readFileSync(mcpConfigPath, 'utf8');
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
44
|
+
const mcpConfig = JSON.parse(content);
|
|
45
|
+
if (mcpConfig.mcpServers) {
|
|
46
|
+
mcpServers = { ...mcpServers, ...mcpConfig.mcpServers };
|
|
47
|
+
log.info(`loaded MCP servers from agent/mcp.json`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
log.warn(`failed to load agent/mcp.json: ${toMessage(err)}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (!mcpServers || Object.keys(mcpServers).length === 0) {
|
|
55
|
+
log.debug('no MCP servers configured');
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
for (const [name, serverConfig] of Object.entries(mcpServers)) {
|
|
59
|
+
// Skip disabled servers
|
|
60
|
+
if (serverConfig.enabled === false) {
|
|
61
|
+
log.debug(`MCP server disabled: ${name}`);
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
await Promise.race([
|
|
66
|
+
this.connectServer(name, serverConfig),
|
|
67
|
+
// 5 second timeout per server to avoid hanging on unavailable servers
|
|
68
|
+
new Promise((_resolve, reject) => {
|
|
69
|
+
setTimeout(() => reject(new Error('connection timeout')), 5000);
|
|
70
|
+
}),
|
|
71
|
+
]);
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
log.warn(`MCP server ${name}: ${toMessage(err)}`);
|
|
75
|
+
// Continue with other servers even if one fails
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (this.servers.size > 0) {
|
|
79
|
+
log.info(`connected ${this.servers.size} MCP server(s)`);
|
|
80
|
+
}
|
|
81
|
+
else if (Object.keys(mcpServers).length > 0) {
|
|
82
|
+
log.debug(`no MCP servers available (${Object.keys(mcpServers).length} configured but not connectable)`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async connectServer(name, config) {
|
|
86
|
+
const transport = config.transport || 'stdio';
|
|
87
|
+
if (transport !== 'stdio') {
|
|
88
|
+
throw new Error(`transport not supported: ${transport} (only stdio supported currently)`);
|
|
89
|
+
}
|
|
90
|
+
// Support both "command" string and "command/args" format
|
|
91
|
+
const cmdStr = config.command;
|
|
92
|
+
if (!cmdStr)
|
|
93
|
+
throw new Error(`server ${name}: stdio transport requires command`);
|
|
94
|
+
let cmd;
|
|
95
|
+
let args;
|
|
96
|
+
if (Array.isArray(config.args)) {
|
|
97
|
+
// Separate command and args arrays
|
|
98
|
+
cmd = cmdStr;
|
|
99
|
+
args = config.args;
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
// Parse command string with space-separated args
|
|
103
|
+
const parts = cmdStr.split(' ');
|
|
104
|
+
cmd = parts[0];
|
|
105
|
+
args = parts.slice(1);
|
|
106
|
+
}
|
|
107
|
+
// Extract optional env vars
|
|
108
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
109
|
+
const env = config.env || {};
|
|
110
|
+
const clientTransport = new StdioClientTransport({
|
|
111
|
+
command: cmd,
|
|
112
|
+
args,
|
|
113
|
+
env: Object.keys(env).length > 0 ? { ...process.env, ...env } : undefined,
|
|
114
|
+
});
|
|
115
|
+
const client = new Client({
|
|
116
|
+
name: `vargos-mcp-client-${name}`,
|
|
117
|
+
version: '1.0.0',
|
|
118
|
+
});
|
|
119
|
+
try {
|
|
120
|
+
await client.connect(clientTransport);
|
|
121
|
+
const { tools } = await client.listTools();
|
|
122
|
+
const toolMap = new Map(tools.map(t => [t.name, t]));
|
|
123
|
+
const registeredTools = new Set();
|
|
124
|
+
this.servers.set(name, { client, tools: toolMap, registeredTools });
|
|
125
|
+
log.info(`MCP server connected: ${name} (${tools.length} tools)`);
|
|
126
|
+
// Dynamically register each tool as a bus callable event
|
|
127
|
+
for (const tool of tools) {
|
|
128
|
+
this.registerToolHandler(name, tool, registeredTools);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
133
|
+
await clientTransport.close?.();
|
|
134
|
+
throw err;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Convert JSON Schema to Zod schema.
|
|
139
|
+
* Handles common JSON Schema properties like type, properties, required, etc.
|
|
140
|
+
*/
|
|
141
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
142
|
+
jsonSchemaToZod(jsonSchema) {
|
|
143
|
+
if (!jsonSchema || typeof jsonSchema !== 'object') {
|
|
144
|
+
return z.any();
|
|
145
|
+
}
|
|
146
|
+
const { type, properties, required, items, enum: enumValues } = jsonSchema;
|
|
147
|
+
// Handle enum
|
|
148
|
+
if (enumValues && Array.isArray(enumValues) && enumValues.length > 0) {
|
|
149
|
+
return z.enum(enumValues);
|
|
150
|
+
}
|
|
151
|
+
// Handle array
|
|
152
|
+
if (type === 'array' || Array.isArray(type) && type.includes('array')) {
|
|
153
|
+
const itemSchema = items ? this.jsonSchemaToZod(items) : z.any();
|
|
154
|
+
return z.array(itemSchema);
|
|
155
|
+
}
|
|
156
|
+
// Handle object
|
|
157
|
+
if (type === 'object' || type === undefined || (Array.isArray(type) && type.includes('object'))) {
|
|
158
|
+
if (properties && typeof properties === 'object') {
|
|
159
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
160
|
+
const zodProperties = {};
|
|
161
|
+
for (const [key, prop] of Object.entries(properties)) {
|
|
162
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
163
|
+
zodProperties[key] = this.jsonSchemaToZod(prop);
|
|
164
|
+
// Make fields optional unless explicitly required
|
|
165
|
+
if (!required || !required.includes(key)) {
|
|
166
|
+
zodProperties[key] = zodProperties[key].optional();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return z.object(zodProperties).passthrough();
|
|
170
|
+
}
|
|
171
|
+
// No properties specified — accept any object
|
|
172
|
+
return z.object({}).passthrough();
|
|
173
|
+
}
|
|
174
|
+
// Handle primitives
|
|
175
|
+
switch (type) {
|
|
176
|
+
case 'string':
|
|
177
|
+
return z.string();
|
|
178
|
+
case 'number':
|
|
179
|
+
return z.number();
|
|
180
|
+
case 'integer':
|
|
181
|
+
return z.number().int();
|
|
182
|
+
case 'boolean':
|
|
183
|
+
return z.boolean();
|
|
184
|
+
case 'null':
|
|
185
|
+
return z.null();
|
|
186
|
+
default:
|
|
187
|
+
return z.any();
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
registerToolHandler(serverName, tool, registeredTools) {
|
|
191
|
+
const eventName = `mcp.${serverName}.${tool.name}`;
|
|
192
|
+
// Dynamically register the tool as a callable event
|
|
193
|
+
const handler = async (params) => {
|
|
194
|
+
const connection = this.servers.get(serverName);
|
|
195
|
+
if (!connection)
|
|
196
|
+
throw new Error(`MCP server not connected: ${serverName}`);
|
|
197
|
+
try {
|
|
198
|
+
const result = await connection.client.callTool({
|
|
199
|
+
name: tool.name,
|
|
200
|
+
arguments: params,
|
|
201
|
+
});
|
|
202
|
+
// Convert MCP response to bus event result
|
|
203
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
204
|
+
const content = result.content || [];
|
|
205
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
206
|
+
if (result.isError) {
|
|
207
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
208
|
+
const textContent = content.find((c) => c.type === 'text');
|
|
209
|
+
throw new Error(textContent?.text || 'Tool error');
|
|
210
|
+
}
|
|
211
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
212
|
+
const textContent = content.find((c) => c.type === 'text');
|
|
213
|
+
return textContent
|
|
214
|
+
? { text: textContent.text }
|
|
215
|
+
: { content };
|
|
216
|
+
}
|
|
217
|
+
catch (err) {
|
|
218
|
+
log.error(`tool call failed: ${serverName}.${tool.name}: ${toMessage(err)}`);
|
|
219
|
+
throw err;
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
// Register with bus using the public registerTool API
|
|
223
|
+
// Convert MCP JSON Schema to Zod schema for introspection
|
|
224
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
225
|
+
const zodSchema = this.jsonSchemaToZod(tool.inputSchema);
|
|
226
|
+
const toolSchema = {
|
|
227
|
+
description: tool.description || `MCP tool: ${tool.name}`,
|
|
228
|
+
schema: zodSchema,
|
|
229
|
+
};
|
|
230
|
+
this.bus.registerTool(eventName, handler, toolSchema);
|
|
231
|
+
registeredTools.add(eventName);
|
|
232
|
+
}
|
|
233
|
+
async stop() {
|
|
234
|
+
for (const { client, registeredTools } of this.servers.values()) {
|
|
235
|
+
// Unregister all tools
|
|
236
|
+
for (const eventName of registeredTools) {
|
|
237
|
+
this.bus.unregisterTool(eventName);
|
|
238
|
+
}
|
|
239
|
+
registeredTools.clear();
|
|
240
|
+
// Close MCP client
|
|
241
|
+
try {
|
|
242
|
+
await client.close?.();
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
// best effort
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
this.servers.clear();
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
// ── Boot ───────────────────────────────────────────────────────────────────────
|
|
252
|
+
export async function boot(bus) {
|
|
253
|
+
const config = await bus.call('config.get', {});
|
|
254
|
+
const svc = new McpClientService(bus, config);
|
|
255
|
+
await svc.start();
|
|
256
|
+
return { stop: () => svc.stop() };
|
|
257
|
+
}
|
|
258
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../services/mcp-client/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local document text extraction — PDF, DOCX, XLSX, TXT, MD
|
|
3
|
+
* No external API calls, pure Node.js library-based extraction
|
|
4
|
+
*/
|
|
5
|
+
export declare function extractDocument(filePath: string, mimeType: string): Promise<{
|
|
6
|
+
text: string;
|
|
7
|
+
}>;
|
|
8
|
+
//# sourceMappingURL=extract-document.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract-document.d.ts","sourceRoot":"","sources":["../../../services/media/extract-document.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA8CH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAkD3B"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local document text extraction — PDF, DOCX, XLSX, TXT, MD
|
|
3
|
+
* No external API calls, pure Node.js library-based extraction
|
|
4
|
+
*/
|
|
5
|
+
import { readFile, lstat } from 'node:fs/promises';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { PDFParse } from 'pdf-parse';
|
|
8
|
+
import * as mammoth from 'mammoth';
|
|
9
|
+
import XLSX from 'xlsx';
|
|
10
|
+
import { createLogger } from '../../lib/logger.js';
|
|
11
|
+
import { toMessage } from '../../lib/error.js';
|
|
12
|
+
import { getDataPaths } from '../../lib/paths.js';
|
|
13
|
+
const log = createLogger('media');
|
|
14
|
+
const MAX_DOCUMENT_SIZE = 50 * 1024 * 1024; // 50 MB
|
|
15
|
+
const MAX_TEXT_SIZE = 1 * 1024 * 1024; // 1 MB for text files (token cost)
|
|
16
|
+
/**
|
|
17
|
+
* Validate and resolve document path to prevent traversal attacks
|
|
18
|
+
*/
|
|
19
|
+
async function validatePath(filePath) {
|
|
20
|
+
const dataDir = getDataPaths().dataDir;
|
|
21
|
+
const resolved = path.resolve(filePath);
|
|
22
|
+
const rel = path.relative(dataDir, resolved);
|
|
23
|
+
if (rel.startsWith('..') || path.isAbsolute(rel)) {
|
|
24
|
+
throw new Error(`Path outside workspace: ${filePath}`);
|
|
25
|
+
}
|
|
26
|
+
const fileStats = await lstat(resolved);
|
|
27
|
+
if (fileStats.isSymbolicLink()) {
|
|
28
|
+
throw new Error(`Symlinks not allowed: ${filePath}`);
|
|
29
|
+
}
|
|
30
|
+
if (!fileStats.isFile()) {
|
|
31
|
+
throw new Error(`Not a regular file: ${filePath}`);
|
|
32
|
+
}
|
|
33
|
+
const ext = path.extname(resolved).toLowerCase();
|
|
34
|
+
const maxSize = ext === '.txt' || ext === '.md' ? MAX_TEXT_SIZE : MAX_DOCUMENT_SIZE;
|
|
35
|
+
if (fileStats.size > maxSize) {
|
|
36
|
+
throw new Error(`Document too large: ${fileStats.size} bytes (max ${maxSize})`);
|
|
37
|
+
}
|
|
38
|
+
return resolved;
|
|
39
|
+
}
|
|
40
|
+
export async function extractDocument(filePath, mimeType) {
|
|
41
|
+
try {
|
|
42
|
+
const validatedPath = await validatePath(filePath);
|
|
43
|
+
const ext = path.extname(validatedPath).toLowerCase();
|
|
44
|
+
const normalizedMime = mimeType.split(';')[0].trim().toLowerCase();
|
|
45
|
+
// Plain text formats
|
|
46
|
+
if (normalizedMime === 'text/plain' || normalizedMime === 'text/markdown' || ext === '.txt' || ext === '.md') {
|
|
47
|
+
const text = await readFile(validatedPath, 'utf-8').then(t => t.replace(/^\uFEFF/, ''));
|
|
48
|
+
return { text };
|
|
49
|
+
}
|
|
50
|
+
// PDF extraction
|
|
51
|
+
if (normalizedMime === 'application/pdf' || ext === '.pdf') {
|
|
52
|
+
const buffer = await readFile(validatedPath);
|
|
53
|
+
const parser = new PDFParse({ data: buffer });
|
|
54
|
+
const result = await parser.getText();
|
|
55
|
+
return { text: result.text };
|
|
56
|
+
}
|
|
57
|
+
// DOCX extraction
|
|
58
|
+
if (normalizedMime === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' || ext === '.docx') {
|
|
59
|
+
const result = await mammoth.extractRawText({ path: validatedPath });
|
|
60
|
+
return { text: result.value };
|
|
61
|
+
}
|
|
62
|
+
// XLSX extraction
|
|
63
|
+
if (normalizedMime === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' || ext === '.xlsx') {
|
|
64
|
+
const buffer = await readFile(validatedPath);
|
|
65
|
+
const workbook = XLSX.read(buffer, { type: 'buffer' });
|
|
66
|
+
const sheets = workbook.SheetNames;
|
|
67
|
+
const texts = [];
|
|
68
|
+
for (const sheet of sheets) {
|
|
69
|
+
texts.push(`## Sheet: ${sheet}\n`);
|
|
70
|
+
const csv = XLSX.utils.sheet_to_csv(workbook.Sheets[sheet]);
|
|
71
|
+
texts.push(csv);
|
|
72
|
+
}
|
|
73
|
+
return { text: texts.join('\n') };
|
|
74
|
+
}
|
|
75
|
+
// Fallback: try to read as text
|
|
76
|
+
const text = await readFile(validatedPath, 'utf-8');
|
|
77
|
+
return { text };
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
const errorMsg = toMessage(err);
|
|
81
|
+
log.error(`Document extraction failed for ${filePath}: ${errorMsg}`);
|
|
82
|
+
throw new Error(`Failed to extract document: ${errorMsg}`, { cause: err });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=extract-document.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract-document.js","sourceRoot":"","sources":["../../../services/media/extract-document.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AACnC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;AAElC,MAAM,iBAAiB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,QAAQ;AACpD,MAAM,aAAa,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,mCAAmC;AAE1E;;GAEG;AACH,KAAK,UAAU,YAAY,CAAC,QAAgB;IAC1C,MAAM,OAAO,GAAG,YAAY,EAAE,CAAC,OAAO,CAAC;IACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAExC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC7C,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,2BAA2B,QAAQ,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAC;IACxC,IAAI,SAAS,CAAC,cAAc,EAAE,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,yBAAyB,QAAQ,EAAE,CAAC,CAAC;IACvD,CAAC;IAED,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,uBAAuB,QAAQ,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IACjD,MAAM,OAAO,GAAG,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,iBAAiB,CAAC;IACpF,IAAI,SAAS,CAAC,IAAI,GAAG,OAAO,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,uBAAuB,SAAS,CAAC,IAAI,eAAe,OAAO,GAAG,CAAC,CAAC;IAClF,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAAgB,EAChB,QAAgB;IAEhB,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC;QACnD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,WAAW,EAAE,CAAC;QACtD,MAAM,cAAc,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAEnE,qBAAqB;QACrB,IAAI,cAAc,KAAK,YAAY,IAAI,cAAc,KAAK,eAAe,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,KAAK,EAAE,CAAC;YAC7G,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC;YACxF,OAAO,EAAE,IAAI,EAAE,CAAC;QAClB,CAAC;QAED,iBAAiB;QACjB,IAAI,cAAc,KAAK,iBAAiB,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;YAC3D,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,aAAa,CAAC,CAAC;YAC7C,MAAM,MAAM,GAAG,IAAI,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;YAC9C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;YACtC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;QAC/B,CAAC;QAED,kBAAkB;QAClB,IAAI,cAAc,KAAK,yEAAyE,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;YACpH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC;YACrE,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;QAChC,CAAC;QAED,kBAAkB;QAClB,IAAI,cAAc,KAAK,mEAAmE,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;YAC9G,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,aAAa,CAAC,CAAC;YAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;YACvD,MAAM,MAAM,GAAG,QAAQ,CAAC,UAAU,CAAC;YACnC,MAAM,KAAK,GAAa,EAAE,CAAC;YAE3B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,KAAK,CAAC,IAAI,CAAC,aAAa,KAAK,IAAI,CAAC,CAAC;gBACnC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAE,CAAC,CAAC;gBAC7D,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAClB,CAAC;YAED,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,CAAC;QAED,gCAAgC;QAChC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QACpD,OAAO,EAAE,IAAI,EAAE,CAAC;IAClB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;QAChC,GAAG,CAAC,KAAK,CAAC,kCAAkC,QAAQ,KAAK,QAAQ,EAAE,CAAC,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,+BAA+B,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;IAC7E,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Media service — audio transcription, image description, and document extraction
|
|
3
|
+
*
|
|
4
|
+
* Callable: media.transcribeAudio, media.describeImage, media.extractDocument
|
|
5
|
+
*/
|
|
6
|
+
import type { Bus } from '../../gateway/bus.js';
|
|
7
|
+
import type { EventMap } from '../../gateway/events.js';
|
|
8
|
+
import type { AppConfig } from '../../services/config/index.js';
|
|
9
|
+
export declare class MediaService {
|
|
10
|
+
private readonly bus;
|
|
11
|
+
private readonly config;
|
|
12
|
+
constructor(bus: Bus, config: AppConfig);
|
|
13
|
+
private resolveProviderConfig;
|
|
14
|
+
transcribeAudio(params: EventMap['media.transcribeAudio']['params']): Promise<EventMap['media.transcribeAudio']['result']>;
|
|
15
|
+
describeImage(params: EventMap['media.describeImage']['params']): Promise<EventMap['media.describeImage']['result']>;
|
|
16
|
+
extractDocument(params: EventMap['media.extractDocument']['params']): Promise<EventMap['media.extractDocument']['result']>;
|
|
17
|
+
}
|
|
18
|
+
export declare function boot(bus: Bus): Promise<{
|
|
19
|
+
stop?(): void;
|
|
20
|
+
}>;
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../services/media/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAOhE,qBAAa,YAAY;IAErB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,SAAS;IAIpC,OAAO,CAAC,qBAAqB;IAavB,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,uBAAuB,CAAC,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAC,QAAQ,CAAC,CAAC;IAa1H,aAAa,CAAC,MAAM,EAAE,QAAQ,CAAC,qBAAqB,CAAC,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC,QAAQ,CAAC,CAAC;IAapH,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,uBAAuB,CAAC,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAC,QAAQ,CAAC,CAAC;CAGjI;AAED,wBAAsB,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC;IAAE,IAAI,CAAC,IAAI,IAAI,CAAA;CAAE,CAAC,CAM/D"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Media service — audio transcription, image description, and document extraction
|
|
3
|
+
*
|
|
4
|
+
* Callable: media.transcribeAudio, media.describeImage, media.extractDocument
|
|
5
|
+
*/
|
|
6
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
7
|
+
var useValue = arguments.length > 2;
|
|
8
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
9
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
10
|
+
}
|
|
11
|
+
return useValue ? value : void 0;
|
|
12
|
+
};
|
|
13
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
14
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
15
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
16
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
17
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
18
|
+
var _, done = false;
|
|
19
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
20
|
+
var context = {};
|
|
21
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
22
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
23
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
24
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
25
|
+
if (kind === "accessor") {
|
|
26
|
+
if (result === void 0) continue;
|
|
27
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
28
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
29
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
30
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
31
|
+
}
|
|
32
|
+
else if (_ = accept(result)) {
|
|
33
|
+
if (kind === "field") initializers.unshift(_);
|
|
34
|
+
else descriptor[key] = _;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
38
|
+
done = true;
|
|
39
|
+
};
|
|
40
|
+
import { z } from 'zod';
|
|
41
|
+
import { register } from '../../gateway/decorators.js';
|
|
42
|
+
import { createLogger } from '../../lib/logger.js';
|
|
43
|
+
import { createProvider } from './providers/index.js';
|
|
44
|
+
import { extractDocument } from './extract-document.js';
|
|
45
|
+
const log = createLogger('media');
|
|
46
|
+
let MediaService = (() => {
|
|
47
|
+
let _instanceExtraInitializers = [];
|
|
48
|
+
let _transcribeAudio_decorators;
|
|
49
|
+
let _describeImage_decorators;
|
|
50
|
+
let _extractDocument_decorators;
|
|
51
|
+
return class MediaService {
|
|
52
|
+
static {
|
|
53
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
54
|
+
_transcribeAudio_decorators = [register('media.transcribeAudio', {
|
|
55
|
+
description: 'Transcribe an audio file to text using configured audio model.',
|
|
56
|
+
schema: z.object({ filePath: z.string() }),
|
|
57
|
+
})];
|
|
58
|
+
_describeImage_decorators = [register('media.describeImage', {
|
|
59
|
+
description: 'Describe an image using configured vision model.',
|
|
60
|
+
schema: z.object({ filePath: z.string() }),
|
|
61
|
+
})];
|
|
62
|
+
_extractDocument_decorators = [register('media.extractDocument', {
|
|
63
|
+
description: 'Extract text from documents (PDF, DOCX, XLSX, TXT, MD).',
|
|
64
|
+
schema: z.object({ filePath: z.string(), mimeType: z.string() }),
|
|
65
|
+
})];
|
|
66
|
+
__esDecorate(this, null, _transcribeAudio_decorators, { kind: "method", name: "transcribeAudio", static: false, private: false, access: { has: obj => "transcribeAudio" in obj, get: obj => obj.transcribeAudio }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
67
|
+
__esDecorate(this, null, _describeImage_decorators, { kind: "method", name: "describeImage", static: false, private: false, access: { has: obj => "describeImage" in obj, get: obj => obj.describeImage }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
68
|
+
__esDecorate(this, null, _extractDocument_decorators, { kind: "method", name: "extractDocument", static: false, private: false, access: { has: obj => "extractDocument" in obj, get: obj => obj.extractDocument }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
69
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
70
|
+
}
|
|
71
|
+
bus = __runInitializers(this, _instanceExtraInitializers);
|
|
72
|
+
config;
|
|
73
|
+
constructor(bus, config) {
|
|
74
|
+
this.bus = bus;
|
|
75
|
+
this.config = config;
|
|
76
|
+
}
|
|
77
|
+
resolveProviderConfig(ref) {
|
|
78
|
+
const [provider, model] = ref.split(':');
|
|
79
|
+
if (!provider || !model)
|
|
80
|
+
throw new Error('Invalid config format (expected "provider:model")');
|
|
81
|
+
const authEntry = this.config.auth?.[provider];
|
|
82
|
+
const apiKey = authEntry && 'key' in authEntry ? authEntry.key : null;
|
|
83
|
+
if (!apiKey)
|
|
84
|
+
throw new Error(`No API key configured for ${provider}`);
|
|
85
|
+
return { provider, model, apiKey, baseUrl: this.config.providers?.[provider]?.baseUrl };
|
|
86
|
+
}
|
|
87
|
+
async transcribeAudio(params) {
|
|
88
|
+
const audioRef = this.config.agent?.media?.audio;
|
|
89
|
+
if (!audioRef)
|
|
90
|
+
throw new Error('No audio model configured (agent.media.audio)');
|
|
91
|
+
const { provider, model, apiKey, baseUrl } = this.resolveProviderConfig(audioRef);
|
|
92
|
+
const text = await createProvider(provider).transcribeAudio(params.filePath, model, apiKey, baseUrl);
|
|
93
|
+
return { text };
|
|
94
|
+
}
|
|
95
|
+
async describeImage(params) {
|
|
96
|
+
const imgRef = this.config.agent?.media?.image;
|
|
97
|
+
if (!imgRef)
|
|
98
|
+
throw new Error('No image model configured (agent.media.image)');
|
|
99
|
+
const { provider, model, apiKey, baseUrl } = this.resolveProviderConfig(imgRef);
|
|
100
|
+
const description = await createProvider(provider).describeImage(params.filePath, model, apiKey, baseUrl);
|
|
101
|
+
return { description };
|
|
102
|
+
}
|
|
103
|
+
async extractDocument(params) {
|
|
104
|
+
return extractDocument(params.filePath, params.mimeType);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
})();
|
|
108
|
+
export { MediaService };
|
|
109
|
+
export async function boot(bus) {
|
|
110
|
+
const config = await bus.call('config.get', {});
|
|
111
|
+
const svc = new MediaService(bus, config);
|
|
112
|
+
bus.bootstrap(svc);
|
|
113
|
+
log.debug('media service initialized');
|
|
114
|
+
return {};
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../services/media/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { MediaProvider } from './provider.js';
|
|
2
|
+
export declare class AnthropicProvider implements MediaProvider {
|
|
3
|
+
transcribeAudio(): Promise<string>;
|
|
4
|
+
describeImage(filePath: string, model: string, apiKey: string, baseUrl?: string): Promise<string>;
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=anthropic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../../../services/media/providers/anthropic.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,qBAAa,iBAAkB,YAAW,aAAa;IAC/C,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC;IAIlC,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CA8BxG"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { getMimeTypeFromExt } from '../../../lib/media-transcribe.js';
|
|
4
|
+
export class AnthropicProvider {
|
|
5
|
+
async transcribeAudio() {
|
|
6
|
+
throw new Error('Anthropic does not support audio transcription. Use openai provider.');
|
|
7
|
+
}
|
|
8
|
+
async describeImage(filePath, model, apiKey, baseUrl) {
|
|
9
|
+
const buffer = await readFile(filePath);
|
|
10
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
11
|
+
const mimeType = getMimeTypeFromExt(ext);
|
|
12
|
+
const imageData = buffer.toString('base64');
|
|
13
|
+
const res = await fetch(`${baseUrl ?? 'https://api.anthropic.com'}/v1/messages`, {
|
|
14
|
+
method: 'POST',
|
|
15
|
+
headers: {
|
|
16
|
+
'x-api-key': apiKey,
|
|
17
|
+
'anthropic-version': '2023-06-01',
|
|
18
|
+
'Content-Type': 'application/json',
|
|
19
|
+
},
|
|
20
|
+
body: JSON.stringify({
|
|
21
|
+
model,
|
|
22
|
+
max_tokens: 1024,
|
|
23
|
+
messages: [{
|
|
24
|
+
role: 'user',
|
|
25
|
+
content: [
|
|
26
|
+
{ type: 'image', source: { type: 'base64', media_type: mimeType, data: imageData } },
|
|
27
|
+
{ type: 'text', text: 'Describe this image concisely.' },
|
|
28
|
+
],
|
|
29
|
+
}],
|
|
30
|
+
}),
|
|
31
|
+
});
|
|
32
|
+
if (!res.ok)
|
|
33
|
+
throw new Error(`Anthropic Vision ${res.status}: ${(await res.text()).slice(0, 100)}`);
|
|
34
|
+
const data = (await res.json());
|
|
35
|
+
return data.content.find(b => b.type === 'text')?.text ?? '';
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=anthropic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../../services/media/providers/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAGtE,MAAM,OAAO,iBAAiB;IAC5B,KAAK,CAAC,eAAe;QACnB,MAAM,IAAI,KAAK,CAAC,sEAAsE,CAAC,CAAC;IAC1F,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,QAAgB,EAAE,KAAa,EAAE,MAAc,EAAE,OAAgB;QACnF,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACxC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;QACjD,MAAM,QAAQ,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;QACzC,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAE5C,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,IAAI,2BAA2B,cAAc,EAAE;YAC/E,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,WAAW,EAAE,MAAM;gBACnB,mBAAmB,EAAE,YAAY;gBACjC,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK;gBACL,UAAU,EAAE,IAAI;gBAChB,QAAQ,EAAE,CAAC;wBACT,IAAI,EAAE,MAAM;wBACZ,OAAO,EAAE;4BACP,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE;4BACpF,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,gCAAgC,EAAE;yBACzD;qBACF,CAAC;aACH,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,GAAG,CAAC,MAAM,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;QACpG,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAwD,CAAC;QACvF,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;IAC/D,CAAC;CACF"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { type MediaProvider } from './provider.js';
|
|
2
|
+
export { OpenAIProvider } from './openai.js';
|
|
3
|
+
export { AnthropicProvider } from './anthropic.js';
|
|
4
|
+
import type { MediaProvider } from './provider.js';
|
|
5
|
+
export declare function createProvider(name: string): MediaProvider;
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../services/media/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAInD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAS1D"}
|