@denispro2006/duke-ai-kernel 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/README.md +81 -0
  2. package/config/prompts/default.txt +1 -0
  3. package/config/routing.json +24 -0
  4. package/dist/api/routes.d.ts +3 -0
  5. package/dist/api/routes.d.ts.map +1 -0
  6. package/dist/api/routes.js +114 -0
  7. package/dist/api/routes.js.map +1 -0
  8. package/dist/app.d.ts +7 -0
  9. package/dist/app.d.ts.map +1 -0
  10. package/dist/app.js +21 -0
  11. package/dist/app.js.map +1 -0
  12. package/dist/config/index.d.ts +50 -0
  13. package/dist/config/index.d.ts.map +1 -0
  14. package/dist/config/index.js +86 -0
  15. package/dist/config/index.js.map +1 -0
  16. package/dist/context/context-manager.d.ts +30 -0
  17. package/dist/context/context-manager.d.ts.map +1 -0
  18. package/dist/context/context-manager.js +77 -0
  19. package/dist/context/context-manager.js.map +1 -0
  20. package/dist/controllers/ai.controller.d.ts +3 -0
  21. package/dist/controllers/ai.controller.d.ts.map +1 -0
  22. package/dist/controllers/ai.controller.js +20 -0
  23. package/dist/controllers/ai.controller.js.map +1 -0
  24. package/dist/controllers/message.controller.d.ts +4 -0
  25. package/dist/controllers/message.controller.d.ts.map +1 -0
  26. package/dist/controllers/message.controller.js +28 -0
  27. package/dist/controllers/message.controller.js.map +1 -0
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +31 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/kernel/index.d.ts +17 -0
  33. package/dist/kernel/index.d.ts.map +1 -0
  34. package/dist/kernel/index.js +134 -0
  35. package/dist/kernel/index.js.map +1 -0
  36. package/dist/lib/logger.d.ts +3 -0
  37. package/dist/lib/logger.d.ts.map +1 -0
  38. package/dist/lib/logger.js +15 -0
  39. package/dist/lib/logger.js.map +1 -0
  40. package/dist/middleware/auth.middleware.d.ts +3 -0
  41. package/dist/middleware/auth.middleware.d.ts.map +1 -0
  42. package/dist/middleware/auth.middleware.js +24 -0
  43. package/dist/middleware/auth.middleware.js.map +1 -0
  44. package/dist/middleware/error.middleware.d.ts +6 -0
  45. package/dist/middleware/error.middleware.d.ts.map +1 -0
  46. package/dist/middleware/error.middleware.js +16 -0
  47. package/dist/middleware/error.middleware.js.map +1 -0
  48. package/dist/models/Message.d.ts +10 -0
  49. package/dist/models/Message.d.ts.map +1 -0
  50. package/dist/models/Message.js +3 -0
  51. package/dist/models/Message.js.map +1 -0
  52. package/dist/models/User.d.ts +7 -0
  53. package/dist/models/User.d.ts.map +1 -0
  54. package/dist/models/User.js +3 -0
  55. package/dist/models/User.js.map +1 -0
  56. package/dist/plugins/index.d.ts +10 -0
  57. package/dist/plugins/index.d.ts.map +1 -0
  58. package/dist/plugins/index.js +74 -0
  59. package/dist/plugins/index.js.map +1 -0
  60. package/dist/providers/anthropic.d.ts +3 -0
  61. package/dist/providers/anthropic.d.ts.map +1 -0
  62. package/dist/providers/anthropic.js +65 -0
  63. package/dist/providers/anthropic.js.map +1 -0
  64. package/dist/providers/index.d.ts +8 -0
  65. package/dist/providers/index.d.ts.map +1 -0
  66. package/dist/providers/index.js +38 -0
  67. package/dist/providers/index.js.map +1 -0
  68. package/dist/providers/ollama.d.ts +3 -0
  69. package/dist/providers/ollama.d.ts.map +1 -0
  70. package/dist/providers/ollama.js +77 -0
  71. package/dist/providers/ollama.js.map +1 -0
  72. package/dist/providers/openai.d.ts +3 -0
  73. package/dist/providers/openai.d.ts.map +1 -0
  74. package/dist/providers/openai.js +63 -0
  75. package/dist/providers/openai.js.map +1 -0
  76. package/dist/router/index.d.ts +13 -0
  77. package/dist/router/index.d.ts.map +1 -0
  78. package/dist/router/index.js +70 -0
  79. package/dist/router/index.js.map +1 -0
  80. package/dist/routes/ai.routes.d.ts +3 -0
  81. package/dist/routes/ai.routes.d.ts.map +1 -0
  82. package/dist/routes/ai.routes.js +9 -0
  83. package/dist/routes/ai.routes.js.map +1 -0
  84. package/dist/routes/index.d.ts +2 -0
  85. package/dist/routes/index.d.ts.map +1 -0
  86. package/dist/routes/index.js +6 -0
  87. package/dist/routes/index.js.map +1 -0
  88. package/dist/services/ai.service.d.ts +4 -0
  89. package/dist/services/ai.service.d.ts.map +1 -0
  90. package/dist/services/ai.service.js +28 -0
  91. package/dist/services/ai.service.js.map +1 -0
  92. package/dist/services/db.service.d.ts +3 -0
  93. package/dist/services/db.service.d.ts.map +1 -0
  94. package/dist/services/db.service.js +60 -0
  95. package/dist/services/db.service.js.map +1 -0
  96. package/dist/services/kernel.service.d.ts +4 -0
  97. package/dist/services/kernel.service.d.ts.map +1 -0
  98. package/dist/services/kernel.service.js +14 -0
  99. package/dist/services/kernel.service.js.map +1 -0
  100. package/dist/types.d.ts +72 -0
  101. package/dist/types.d.ts.map +1 -0
  102. package/dist/types.js +3 -0
  103. package/dist/types.js.map +1 -0
  104. package/dist/utils/helpers.d.ts +6 -0
  105. package/dist/utils/helpers.d.ts.map +1 -0
  106. package/dist/utils/helpers.js +24 -0
  107. package/dist/utils/helpers.js.map +1 -0
  108. package/dist/utils/logger.d.ts +2 -0
  109. package/dist/utils/logger.d.ts.map +1 -0
  110. package/dist/utils/logger.js +6 -0
  111. package/dist/utils/logger.js.map +1 -0
  112. package/dist/workers/aiWorker.d.ts +6 -0
  113. package/dist/workers/aiWorker.d.ts.map +1 -0
  114. package/dist/workers/aiWorker.js +42 -0
  115. package/dist/workers/aiWorker.js.map +1 -0
  116. package/dist/ws/gateway.d.ts +3 -0
  117. package/dist/ws/gateway.d.ts.map +1 -0
  118. package/dist/ws/gateway.js +110 -0
  119. package/dist/ws/gateway.js.map +1 -0
  120. package/package.json +68 -0
package/README.md ADDED
@@ -0,0 +1,81 @@
1
+ # duke-ai-kernel
2
+
3
+ AI kernel for the [duke-messenger](https://github.com/duke-messenger) platform. Handles LLM routing, context management, and real-time messaging via WebSocket.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ # 1. Clone and install
9
+ git clone https://github.com/duke-messenger/duke-ai-kernel
10
+ cd duke-ai-kernel
11
+ npm install
12
+
13
+ # 2. Configure environment
14
+ cp .env.example .env
15
+ # Edit .env with your API keys
16
+
17
+ # 3. Start the kernel
18
+ npm run dev
19
+ ```
20
+
21
+ The kernel starts on `http://localhost:3000` by default.
22
+
23
+ ## Features
24
+
25
+ - **Unified LLM routing** — route requests to OpenAI, Anthropic, or local Ollama models
26
+ - **Context management** — per-conversation history with configurable token-budget trimming
27
+ - **Real-time streaming** — stream responses to clients over WebSocket
28
+ - **Plugin pipeline** — extend with custom pre/post processors
29
+ - **Worker concurrency** — bounded async workers prevent rate-limit saturation
30
+
31
+ ## Stack
32
+
33
+ | Layer | Technology |
34
+ |-------|-----------|
35
+ | Runtime | Node.js 20+ |
36
+ | Framework | Express 5 |
37
+ | WebSocket | ws |
38
+ | Language | TypeScript |
39
+ | Testing | Vitest |
40
+
41
+ ## Scripts
42
+
43
+ ```bash
44
+ npm run dev # Start with hot reload
45
+ npm run build # Compile TypeScript
46
+ npm start # Run compiled output
47
+ npm run lint # Check code style
48
+ npm run typecheck # Type-check without building
49
+ npm test # Run all tests
50
+ npm run test:coverage # Run tests with coverage report
51
+ ```
52
+
53
+ ## Environment Variables
54
+
55
+ Copy `.env.example` to `.env`. At minimum you need:
56
+
57
+ ```
58
+ OPENAI_API_KEY=sk-...
59
+ AUTH_SECRET=your-secret-here
60
+ ```
61
+
62
+ See [Environment Variables](docs/api.md) for the full reference.
63
+
64
+ ## Docker
65
+
66
+ ```bash
67
+ # Start kernel + Redis
68
+ docker compose up -d
69
+
70
+ # Verify
71
+ curl http://localhost:3000/api/v1/healthz
72
+ ```
73
+
74
+ ## Documentation
75
+
76
+ - [API Reference](docs/api.md)
77
+ - [Architecture & Data Flow](docs/api.md)
78
+
79
+ ## License
80
+
81
+ MIT © duke-messenger contributors
@@ -0,0 +1 @@
1
+ You are a helpful assistant.
@@ -0,0 +1,24 @@
1
+ {
2
+ "rules": [
3
+ {
4
+ "if": { "tag": "reasoning" },
5
+ "use": "openai",
6
+ "model": "o1-mini"
7
+ },
8
+ {
9
+ "if": { "tag": "local" },
10
+ "use": "ollama",
11
+ "model": "llama3"
12
+ },
13
+ {
14
+ "if": { "tier": "low-cost" },
15
+ "use": "openai",
16
+ "model": "gpt-4o-mini"
17
+ },
18
+ {
19
+ "default": true,
20
+ "use": "openai",
21
+ "model": "gpt-4o-mini"
22
+ }
23
+ ]
24
+ }
@@ -0,0 +1,3 @@
1
+ declare const apiRouter: import("express-serve-static-core").Router;
2
+ export { apiRouter };
3
+ //# sourceMappingURL=routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/api/routes.ts"],"names":[],"mappings":"AASA,QAAA,MAAM,SAAS,4CAAW,CAAA;AAoH1B,OAAO,EAAE,SAAS,EAAE,CAAA"}
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.apiRouter = void 0;
4
+ const express_1 = require("express");
5
+ const zod_1 = require("zod");
6
+ const kernel_1 = require("../kernel");
7
+ const context_manager_1 = require("../context/context-manager");
8
+ const router_1 = require("../router");
9
+ const helpers_1 = require("../utils/helpers");
10
+ const logger_1 = require("../lib/logger");
11
+ const config_1 = require("../config");
12
+ const apiRouter = (0, express_1.Router)();
13
+ exports.apiRouter = apiRouter;
14
+ const MessageSchema = zod_1.z.object({
15
+ role: zod_1.z.enum(['user', 'assistant', 'system']),
16
+ content: zod_1.z.string(),
17
+ });
18
+ const CompleteSchema = zod_1.z.object({
19
+ model: zod_1.z.string().optional(),
20
+ conversationId: zod_1.z.string().optional(),
21
+ messages: zod_1.z.array(MessageSchema).min(1),
22
+ options: zod_1.z
23
+ .object({
24
+ temperature: zod_1.z.number().min(0).max(2).optional(),
25
+ maxTokens: zod_1.z.number().int().positive().optional(),
26
+ tag: zod_1.z.string().optional(),
27
+ tier: zod_1.z.string().optional(),
28
+ })
29
+ .optional(),
30
+ });
31
+ const ConversationCreateSchema = zod_1.z.object({
32
+ systemPrompt: zod_1.z.string().optional(),
33
+ maxContextTokens: zod_1.z.number().int().positive().optional(),
34
+ metadata: zod_1.z.record(zod_1.z.unknown()).optional(),
35
+ });
36
+ apiRouter.get('/healthz', (_req, res) => {
37
+ res.json({
38
+ status: 'ok',
39
+ uptime: Math.floor(process.uptime()),
40
+ version: '1.0.0',
41
+ });
42
+ });
43
+ apiRouter.post('/complete', async (req, res) => {
44
+ const parsed = CompleteSchema.safeParse(req.body);
45
+ if (!parsed.success) {
46
+ res.status(400).json({ error: 'VALIDATION_ERROR', message: parsed.error.message });
47
+ return;
48
+ }
49
+ const { model, conversationId, messages, options } = parsed.data;
50
+ const convId = conversationId ?? (0, helpers_1.generateId)('conv');
51
+ try {
52
+ const response = await kernel_1.kernel.process({
53
+ id: (0, helpers_1.generateId)('req'),
54
+ conversationId: convId,
55
+ messages,
56
+ model: model ?? config_1.config.providers.defaultModel,
57
+ options,
58
+ });
59
+ res.json({
60
+ id: response.id,
61
+ conversationId: convId,
62
+ message: response.message,
63
+ usage: response.usage,
64
+ model: response.model,
65
+ finishReason: response.finishReason,
66
+ });
67
+ }
68
+ catch (err) {
69
+ logger_1.logger.error({ err, conversationId: convId }, 'Completion failed');
70
+ res.status(502).json({ error: 'PROVIDER_ERROR', message: err.message });
71
+ }
72
+ });
73
+ apiRouter.get('/conversations/:id', async (req, res) => {
74
+ const id = req.params['id'];
75
+ const entry = await context_manager_1.contextManager.getEntry(id);
76
+ if (!entry) {
77
+ res.status(404).json({ error: 'NOT_FOUND', message: `Conversation ${id} does not exist.` });
78
+ return;
79
+ }
80
+ const tokenCount = context_manager_1.contextManager.estimateTokens(entry.messages);
81
+ res.json({
82
+ conversationId: id,
83
+ messages: entry.messages,
84
+ createdAt: entry.createdAt,
85
+ updatedAt: entry.updatedAt,
86
+ tokenCount,
87
+ });
88
+ });
89
+ apiRouter.delete('/conversations/:id', async (req, res) => {
90
+ const id = req.params['id'];
91
+ await context_manager_1.contextManager.clear(id);
92
+ res.status(204).send();
93
+ });
94
+ apiRouter.post('/conversations', async (req, res) => {
95
+ const parsed = ConversationCreateSchema.safeParse(req.body);
96
+ if (!parsed.success) {
97
+ res.status(400).json({ error: 'VALIDATION_ERROR', message: parsed.error.message });
98
+ return;
99
+ }
100
+ const conversationId = (0, helpers_1.generateId)('conv');
101
+ await context_manager_1.contextManager.create(conversationId, {
102
+ systemPrompt: parsed.data.systemPrompt,
103
+ maxContextTokens: parsed.data.maxContextTokens,
104
+ });
105
+ res.status(201).json({
106
+ conversationId,
107
+ createdAt: new Date(),
108
+ });
109
+ });
110
+ apiRouter.get('/models', (_req, res) => {
111
+ const models = router_1.router.getAvailableModels();
112
+ res.json({ models });
113
+ });
114
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/api/routes.ts"],"names":[],"mappings":"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"}
package/dist/app.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import { Express } from 'express';
2
+ type AppOptions = {
3
+ authBypass?: boolean;
4
+ };
5
+ export declare function buildApp(_options?: AppOptions): Express;
6
+ export {};
7
+ //# sourceMappingURL=app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAO1C,KAAK,UAAU,GAAG;IAChB,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB,CAAA;AAED,wBAAgB,QAAQ,CAAC,QAAQ,GAAE,UAAe,GAAG,OAAO,CAW3D"}
package/dist/app.js ADDED
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.buildApp = buildApp;
7
+ const express_1 = __importDefault(require("express"));
8
+ const pino_http_1 = __importDefault(require("pino-http"));
9
+ const routes_1 = require("./api/routes");
10
+ const auth_middleware_1 = require("./middleware/auth.middleware");
11
+ const error_middleware_1 = require("./middleware/error.middleware");
12
+ const logger_1 = require("./lib/logger");
13
+ function buildApp(_options = {}) {
14
+ const app = (0, express_1.default)();
15
+ app.use(express_1.default.json());
16
+ app.use((0, pino_http_1.default)({ logger: logger_1.logger }));
17
+ app.use('/api/v1', auth_middleware_1.authMiddleware, routes_1.apiRouter);
18
+ app.use(error_middleware_1.errorMiddleware);
19
+ return app;
20
+ }
21
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":";;;;;AAWA,4BAWC;AAtBD,sDAA0C;AAC1C,0DAAgC;AAChC,yCAAwC;AACxC,kEAA6D;AAC7D,oEAA+D;AAC/D,yCAAqC;AAMrC,SAAgB,QAAQ,CAAC,WAAuB,EAAE;IAChD,MAAM,GAAG,GAAG,IAAA,iBAAO,GAAE,CAAA;IAErB,GAAG,CAAC,GAAG,CAAC,iBAAO,CAAC,IAAI,EAAE,CAAC,CAAA;IACvB,GAAG,CAAC,GAAG,CAAC,IAAA,mBAAQ,EAAC,EAAE,MAAM,EAAN,eAAM,EAAE,CAAC,CAAC,CAAA;IAE7B,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,gCAAc,EAAE,kBAAS,CAAC,CAAA;IAE7C,GAAG,CAAC,GAAG,CAAC,kCAA8C,CAAC,CAAA;IAEvD,OAAO,GAAG,CAAA;AACZ,CAAC"}
@@ -0,0 +1,50 @@
1
+ import 'dotenv/config';
2
+ export declare const config: {
3
+ readonly port: number;
4
+ readonly nodeEnv: string;
5
+ readonly logLevel: string;
6
+ readonly auth: {
7
+ readonly secret: string;
8
+ readonly tokenTtl: number;
9
+ readonly bypass: boolean;
10
+ };
11
+ readonly providers: {
12
+ readonly openai: {
13
+ readonly apiKey: string | undefined;
14
+ readonly baseUrl: string | undefined;
15
+ };
16
+ readonly anthropic: {
17
+ readonly apiKey: string | undefined;
18
+ };
19
+ readonly ollama: {
20
+ readonly baseUrl: string;
21
+ };
22
+ readonly defaultModel: string;
23
+ };
24
+ readonly worker: {
25
+ readonly concurrency: number;
26
+ readonly retryLimit: number;
27
+ readonly retryDelayMs: number;
28
+ readonly timeoutMs: number;
29
+ };
30
+ readonly context: {
31
+ readonly store: "memory" | "redis";
32
+ readonly redisUrl: string;
33
+ readonly maxTokens: number;
34
+ readonly ttl: number;
35
+ };
36
+ readonly rateLimit: {
37
+ readonly enabled: boolean;
38
+ readonly rpm: number;
39
+ readonly store: "memory" | "redis";
40
+ };
41
+ readonly db: {
42
+ readonly enabled: boolean;
43
+ readonly url: string | undefined;
44
+ };
45
+ readonly systemPrompt: {
46
+ readonly text: string;
47
+ readonly file: string | undefined;
48
+ };
49
+ };
50
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAA;AAqCtB,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAiCkC,QAAQ,GAAG,OAAO;;;;;;;;wBASf,QAAQ,GAAG,OAAO;;;;;;;;;;CAYhE,CAAA"}
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.config = void 0;
4
+ require("dotenv/config");
5
+ function requireEnv(name) {
6
+ const val = process.env[name];
7
+ if (!val)
8
+ throw new Error(`Missing required env var: ${name}`);
9
+ return val;
10
+ }
11
+ function optionalEnv(name, fallback) {
12
+ return process.env[name] ?? fallback;
13
+ }
14
+ function optionalBool(name, fallback) {
15
+ const val = process.env[name];
16
+ if (val === undefined)
17
+ return fallback;
18
+ return val === 'true';
19
+ }
20
+ function optionalInt(name, fallback) {
21
+ const val = process.env[name];
22
+ if (val === undefined)
23
+ return fallback;
24
+ const parsed = parseInt(val, 10);
25
+ if (isNaN(parsed))
26
+ throw new Error(`Env var ${name} must be an integer, got: ${val}`);
27
+ return parsed;
28
+ }
29
+ if (!optionalBool('AUTH_BYPASS', false)) {
30
+ requireEnv('AUTH_SECRET');
31
+ }
32
+ const hasOpenAI = !!process.env['OPENAI_API_KEY'];
33
+ const hasAnthropic = !!process.env['ANTHROPIC_API_KEY'];
34
+ const hasOllama = !!process.env['OLLAMA_BASE_URL'];
35
+ if (!hasOpenAI && !hasAnthropic && !hasOllama) {
36
+ throw new Error('At least one LLM provider key must be configured (OPENAI_API_KEY, ANTHROPIC_API_KEY, or OLLAMA_BASE_URL)');
37
+ }
38
+ exports.config = {
39
+ port: optionalInt('PORT', 3000),
40
+ nodeEnv: optionalEnv('NODE_ENV', 'development'),
41
+ logLevel: optionalEnv('LOG_LEVEL', 'info'),
42
+ auth: {
43
+ secret: process.env['AUTH_SECRET'] ?? '',
44
+ tokenTtl: optionalInt('AUTH_TOKEN_TTL', 86400),
45
+ bypass: optionalBool('AUTH_BYPASS', false),
46
+ },
47
+ providers: {
48
+ openai: {
49
+ apiKey: process.env['OPENAI_API_KEY'],
50
+ baseUrl: process.env['OPENAI_BASE_URL'],
51
+ },
52
+ anthropic: {
53
+ apiKey: process.env['ANTHROPIC_API_KEY'],
54
+ },
55
+ ollama: {
56
+ baseUrl: optionalEnv('OLLAMA_BASE_URL', 'http://localhost:11434'),
57
+ },
58
+ defaultModel: optionalEnv('DEFAULT_MODEL', 'gpt-4o-mini'),
59
+ },
60
+ worker: {
61
+ concurrency: optionalInt('WORKER_CONCURRENCY', 5),
62
+ retryLimit: optionalInt('WORKER_RETRY_LIMIT', 3),
63
+ retryDelayMs: optionalInt('WORKER_RETRY_DELAY_MS', 1000),
64
+ timeoutMs: optionalInt('WORKER_TIMEOUT_MS', 60000),
65
+ },
66
+ context: {
67
+ store: optionalEnv('CONTEXT_STORE', 'memory'),
68
+ redisUrl: optionalEnv('REDIS_URL', 'redis://localhost:6379'),
69
+ maxTokens: optionalInt('CONTEXT_MAX_TOKENS', 4096),
70
+ ttl: optionalInt('CONTEXT_TTL', 3600),
71
+ },
72
+ rateLimit: {
73
+ enabled: optionalBool('RATE_LIMIT_ENABLED', true),
74
+ rpm: optionalInt('RATE_LIMIT_RPM', 60),
75
+ store: optionalEnv('RATE_LIMIT_STORE', 'memory'),
76
+ },
77
+ db: {
78
+ enabled: optionalBool('ENABLE_DB_PERSISTENCE', false),
79
+ url: process.env['DATABASE_URL'],
80
+ },
81
+ systemPrompt: {
82
+ text: optionalEnv('SYSTEM_PROMPT', 'You are a helpful assistant.'),
83
+ file: process.env['SYSTEM_PROMPT_FILE'],
84
+ },
85
+ };
86
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { Message } from '../types';
2
+ type ContextEntry = {
3
+ messages: Message[];
4
+ createdAt: Date;
5
+ updatedAt: Date;
6
+ maxTokens?: number;
7
+ systemPrompt?: string;
8
+ };
9
+ export declare class ContextManager {
10
+ private store;
11
+ get(conversationId: string): Promise<Message[]>;
12
+ getEntry(conversationId: string): Promise<ContextEntry | undefined>;
13
+ create(conversationId: string, options?: {
14
+ systemPrompt?: string;
15
+ maxContextTokens?: number;
16
+ }): Promise<void>;
17
+ append(conversationId: string, messages: Message[]): Promise<void>;
18
+ clear(conversationId: string): Promise<void>;
19
+ trim(messages: Message[], maxTokens: number): Promise<Message[]>;
20
+ getForRequest(conversationId: string): Promise<{
21
+ messages: Message[];
22
+ systemPrompt?: string;
23
+ }>;
24
+ has(conversationId: string): boolean;
25
+ estimateTokens(messages: Message[]): number;
26
+ getAll(): Map<string, ContextEntry>;
27
+ }
28
+ export declare const contextManager: ContextManager;
29
+ export {};
30
+ //# sourceMappingURL=context-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-manager.d.ts","sourceRoot":"","sources":["../../src/context/context-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAIlC,KAAK,YAAY,GAAG;IAClB,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,SAAS,EAAE,IAAI,CAAA;IACf,SAAS,EAAE,IAAI,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAuC;IAE9C,GAAG,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAK/C,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC;IAInE,MAAM,CACV,cAAc,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,GAC7D,OAAO,CAAC,IAAI,CAAC;IAYV,MAAM,CAAC,cAAc,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAWlE,KAAK,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5C,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAwBhE,aAAa,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAOpG,GAAG,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO;IAIpC,cAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM;IAM3C,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC;CAGpC;AAED,eAAO,MAAM,cAAc,gBAAuB,CAAA"}
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.contextManager = exports.ContextManager = void 0;
4
+ const logger_1 = require("../lib/logger");
5
+ const config_1 = require("../config");
6
+ class ContextManager {
7
+ store = new Map();
8
+ async get(conversationId) {
9
+ const entry = this.store.get(conversationId);
10
+ return entry ? [...entry.messages] : [];
11
+ }
12
+ async getEntry(conversationId) {
13
+ return this.store.get(conversationId);
14
+ }
15
+ async create(conversationId, options) {
16
+ const now = new Date();
17
+ this.store.set(conversationId, {
18
+ messages: [],
19
+ createdAt: now,
20
+ updatedAt: now,
21
+ maxTokens: options?.maxContextTokens,
22
+ systemPrompt: options?.systemPrompt,
23
+ });
24
+ logger_1.logger.debug({ conversationId }, 'Context created');
25
+ }
26
+ async append(conversationId, messages) {
27
+ let entry = this.store.get(conversationId);
28
+ if (!entry) {
29
+ await this.create(conversationId);
30
+ entry = this.store.get(conversationId);
31
+ }
32
+ entry.messages.push(...messages);
33
+ entry.updatedAt = new Date();
34
+ logger_1.logger.debug({ conversationId, added: messages.length }, 'Context appended');
35
+ }
36
+ async clear(conversationId) {
37
+ this.store.delete(conversationId);
38
+ logger_1.logger.debug({ conversationId }, 'Context cleared');
39
+ }
40
+ async trim(messages, maxTokens) {
41
+ const pinned = messages.filter((m) => m.metadata?.['pinned'] === true);
42
+ const unpinned = messages.filter((m) => m.metadata?.['pinned'] !== true);
43
+ let tokenCount = this.estimateTokens(pinned);
44
+ const kept = [];
45
+ for (let i = unpinned.length - 1; i >= 0; i--) {
46
+ const msg = unpinned[i];
47
+ const msgTokens = this.estimateTokens([msg]);
48
+ if (tokenCount + msgTokens <= maxTokens) {
49
+ kept.unshift(msg);
50
+ tokenCount += msgTokens;
51
+ }
52
+ }
53
+ const result = [...pinned, ...kept];
54
+ logger_1.logger.debug({ original: messages.length, trimmed: result.length, tokens: tokenCount }, 'Context trimmed');
55
+ return result;
56
+ }
57
+ async getForRequest(conversationId) {
58
+ const entry = this.store.get(conversationId);
59
+ const maxTokens = entry?.maxTokens ?? config_1.config.context.maxTokens;
60
+ const messages = entry ? await this.trim(entry.messages, maxTokens) : [];
61
+ return { messages, systemPrompt: entry?.systemPrompt };
62
+ }
63
+ has(conversationId) {
64
+ return this.store.has(conversationId);
65
+ }
66
+ estimateTokens(messages) {
67
+ return messages.reduce((sum, m) => {
68
+ return sum + Math.ceil(m.content.length / 4) + 4;
69
+ }, 0);
70
+ }
71
+ getAll() {
72
+ return this.store;
73
+ }
74
+ }
75
+ exports.ContextManager = ContextManager;
76
+ exports.contextManager = new ContextManager();
77
+ //# sourceMappingURL=context-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-manager.js","sourceRoot":"","sources":["../../src/context/context-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Request, Response } from 'express';
2
+ export declare function handleComplete(req: Request, res: Response): Promise<void>;
3
+ //# sourceMappingURL=ai.controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/ai.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAK3C,wBAAsB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAkB/E"}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleComplete = handleComplete;
4
+ const ai_service_1 = require("../services/ai.service");
5
+ const helpers_1 = require("../utils/helpers");
6
+ const logger_1 = require("../lib/logger");
7
+ async function handleComplete(req, res) {
8
+ const { conversationId, messages, model, options } = req.body;
9
+ const convId = conversationId ?? (0, helpers_1.generateId)('conv');
10
+ const userMessage = messages.find((m) => m.role === 'user')?.content ?? '';
11
+ try {
12
+ const response = await (0, ai_service_1.complete)(convId, userMessage, model, options);
13
+ res.json(response);
14
+ }
15
+ catch (err) {
16
+ logger_1.logger.error({ err }, 'Controller: completion failed');
17
+ res.status(502).json({ error: 'PROVIDER_ERROR', message: err.message });
18
+ }
19
+ }
20
+ //# sourceMappingURL=ai.controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai.controller.js","sourceRoot":"","sources":["../../src/controllers/ai.controller.ts"],"names":[],"mappings":";;AAKA,wCAkBC;AAtBD,uDAAiD;AACjD,8CAA6C;AAC7C,0CAAsC;AAE/B,KAAK,UAAU,cAAc,CAAC,GAAY,EAAE,GAAa;IAC9D,MAAM,EAAE,cAAc,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,GAAG,CAAC,IAKxD,CAAA;IAED,MAAM,MAAM,GAAG,cAAc,IAAI,IAAA,oBAAU,EAAC,MAAM,CAAC,CAAA;IACnD,MAAM,WAAW,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,EAAE,OAAO,IAAI,EAAE,CAAA;IAE1E,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,IAAA,qBAAQ,EAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,OAA8C,CAAC,CAAA;QAC3G,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IACpB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,eAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,+BAA+B,CAAC,CAAA;QACtD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAG,GAAa,CAAC,OAAO,EAAE,CAAC,CAAA;IACpF,CAAC;AACH,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { Request, Response } from 'express';
2
+ export declare function getConversation(req: Request, res: Response): Promise<void>;
3
+ export declare function deleteConversation(req: Request, res: Response): Promise<void>;
4
+ //# sourceMappingURL=message.controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/message.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAI3C,wBAAsB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBhF;AAED,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAKnF"}
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getConversation = getConversation;
4
+ exports.deleteConversation = deleteConversation;
5
+ const context_manager_1 = require("../context/context-manager");
6
+ const logger_1 = require("../lib/logger");
7
+ async function getConversation(req, res) {
8
+ const id = req.params['id'];
9
+ const entry = await context_manager_1.contextManager.getEntry(id);
10
+ if (!entry) {
11
+ res.status(404).json({ error: 'NOT_FOUND', message: `Conversation ${id} does not exist.` });
12
+ return;
13
+ }
14
+ res.json({
15
+ conversationId: id,
16
+ messages: entry.messages,
17
+ createdAt: entry.createdAt,
18
+ updatedAt: entry.updatedAt,
19
+ tokenCount: context_manager_1.contextManager.estimateTokens(entry.messages),
20
+ });
21
+ }
22
+ async function deleteConversation(req, res) {
23
+ const id = req.params['id'];
24
+ await context_manager_1.contextManager.clear(id);
25
+ logger_1.logger.debug({ conversationId: id }, 'Conversation deleted');
26
+ res.status(204).send();
27
+ }
28
+ //# sourceMappingURL=message.controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message.controller.js","sourceRoot":"","sources":["../../src/controllers/message.controller.ts"],"names":[],"mappings":";;AAIA,0CAgBC;AAED,gDAKC;AA1BD,gEAA2D;AAC3D,0CAAsC;AAE/B,KAAK,UAAU,eAAe,CAAC,GAAY,EAAE,GAAa;IAC/D,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAW,CAAA;IACrC,MAAM,KAAK,GAAG,MAAM,gCAAc,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;IAE/C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,CAAC,CAAA;QAC3F,OAAM;IACR,CAAC;IAED,GAAG,CAAC,IAAI,CAAC;QACP,cAAc,EAAE,EAAE;QAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,UAAU,EAAE,gCAAc,CAAC,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC;KAC1D,CAAC,CAAA;AACJ,CAAC;AAEM,KAAK,UAAU,kBAAkB,CAAC,GAAY,EAAE,GAAa;IAClE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAW,CAAA;IACrC,MAAM,gCAAc,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;IAC9B,eAAM,CAAC,KAAK,CAAC,EAAE,cAAc,EAAE,EAAE,EAAE,EAAE,sBAAsB,CAAC,CAAA;IAC5D,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAA;AACxB,CAAC"}
@@ -0,0 +1,2 @@
1
+ import 'dotenv/config';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAA"}