neuroverse 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.
- package/LICENSE +19 -0
- package/dist/constants.d.ts +12 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +12 -0
- package/dist/constants.js.map +1 -0
- package/dist/core/intent.d.ts +18 -0
- package/dist/core/intent.d.ts.map +1 -0
- package/dist/core/intent.js +85 -0
- package/dist/core/intent.js.map +1 -0
- package/dist/core/language.d.ts +24 -0
- package/dist/core/language.d.ts.map +1 -0
- package/dist/core/language.js +120 -0
- package/dist/core/language.js.map +1 -0
- package/dist/core/memory.d.ts +29 -0
- package/dist/core/memory.d.ts.map +1 -0
- package/dist/core/memory.js +119 -0
- package/dist/core/memory.js.map +1 -0
- package/dist/core/router.d.ts +22 -0
- package/dist/core/router.d.ts.map +1 -0
- package/dist/core/router.js +118 -0
- package/dist/core/router.js.map +1 -0
- package/dist/core/safety.d.ts +23 -0
- package/dist/core/safety.d.ts.map +1 -0
- package/dist/core/safety.js +147 -0
- package/dist/core/safety.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +355 -0
- package/dist/index.js.map +1 -0
- package/dist/services/agent-router.d.ts +12 -0
- package/dist/services/agent-router.d.ts.map +1 -0
- package/dist/services/agent-router.js +36 -0
- package/dist/services/agent-router.js.map +1 -0
- package/dist/services/executor.d.ts +9 -0
- package/dist/services/executor.d.ts.map +1 -0
- package/dist/services/executor.js +63 -0
- package/dist/services/executor.js.map +1 -0
- package/dist/types.d.ts +85 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +32 -0
- package/dist/types.js.map +1 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
Copyright 2026 Joshua Ragiland M
|
|
8
|
+
|
|
9
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
you may not use this file except in compliance with the License.
|
|
11
|
+
You may obtain a copy of the License at
|
|
12
|
+
|
|
13
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
|
|
15
|
+
Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
See the License for the specific language governing permissions and
|
|
19
|
+
limitations under the License.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NeuroVerse — Shared constants.
|
|
3
|
+
*/
|
|
4
|
+
/** Maximum response size in characters. */
|
|
5
|
+
export declare const CHARACTER_LIMIT = 25000;
|
|
6
|
+
/** Maximum short-term memory entries per user. */
|
|
7
|
+
export declare const MAX_SHORT_TERM = 50;
|
|
8
|
+
/** Minimum importance score to persist episodic / semantic memories. */
|
|
9
|
+
export declare const IMPORTANCE_THRESHOLD = 0.4;
|
|
10
|
+
/** Default retry count for tool execution. */
|
|
11
|
+
export declare const MAX_RETRIES = 2;
|
|
12
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,2CAA2C;AAC3C,eAAO,MAAM,eAAe,QAAS,CAAC;AAEtC,kDAAkD;AAClD,eAAO,MAAM,cAAc,KAAK,CAAC;AAEjC,wEAAwE;AACxE,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC,8CAA8C;AAC9C,eAAO,MAAM,WAAW,IAAI,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NeuroVerse — Shared constants.
|
|
3
|
+
*/
|
|
4
|
+
/** Maximum response size in characters. */
|
|
5
|
+
export const CHARACTER_LIMIT = 25_000;
|
|
6
|
+
/** Maximum short-term memory entries per user. */
|
|
7
|
+
export const MAX_SHORT_TERM = 50;
|
|
8
|
+
/** Minimum importance score to persist episodic / semantic memories. */
|
|
9
|
+
export const IMPORTANCE_THRESHOLD = 0.4;
|
|
10
|
+
/** Default retry count for tool execution. */
|
|
11
|
+
export const MAX_RETRIES = 2;
|
|
12
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,2CAA2C;AAC3C,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC;AAEtC,kDAAkD;AAClD,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,CAAC;AAEjC,wEAAwE;AACxE,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,CAAC;AAExC,8CAA8C;AAC9C,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bodhi — Intent Extraction Engine.
|
|
3
|
+
*
|
|
4
|
+
* Strategy:
|
|
5
|
+
* 1. Try LLM extraction (if callable provided)
|
|
6
|
+
* 2. Fall back to rule-based deterministic parser
|
|
7
|
+
* 3. Always return a valid ExtractedIntent
|
|
8
|
+
*/
|
|
9
|
+
import type { ExtractedIntent, LLMCall } from "../types.js";
|
|
10
|
+
/**
|
|
11
|
+
* Rule-based intent extraction (deterministic fallback).
|
|
12
|
+
*/
|
|
13
|
+
export declare function ruleBasedExtract(text: string): ExtractedIntent;
|
|
14
|
+
/**
|
|
15
|
+
* Extract intent — LLM first, rule-based fallback.
|
|
16
|
+
*/
|
|
17
|
+
export declare function extractIntent(text: string, llmCall?: LLMCall): Promise<ExtractedIntent>;
|
|
18
|
+
//# sourceMappingURL=intent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intent.d.ts","sourceRoot":"","sources":["../../src/core/intent.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAkD5D;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAe9D;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,OAAO,GAChB,OAAO,CAAC,eAAe,CAAC,CA6B1B"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bodhi — Intent Extraction Engine.
|
|
3
|
+
*
|
|
4
|
+
* Strategy:
|
|
5
|
+
* 1. Try LLM extraction (if callable provided)
|
|
6
|
+
* 2. Fall back to rule-based deterministic parser
|
|
7
|
+
* 3. Always return a valid ExtractedIntent
|
|
8
|
+
*/
|
|
9
|
+
const RULE_PATTERNS = [
|
|
10
|
+
{ intent: "convert_format", keywords: ["convert", "transform", "change format", "export"], confidence: 0.75 },
|
|
11
|
+
{ intent: "summarize", keywords: ["summarize", "summarise", "summary", "brief", "tldr"], confidence: 0.8 },
|
|
12
|
+
{ intent: "generate_report", keywords: ["report", "generate report", "analytics"], confidence: 0.7 },
|
|
13
|
+
{ intent: "delete_data", keywords: ["delete", "remove", "drop", "clean", "erase", "destroy"], confidence: 0.85 },
|
|
14
|
+
{ intent: "query_data", keywords: ["query", "search", "find", "fetch", "get", "lookup", "look up"], confidence: 0.7 },
|
|
15
|
+
{ intent: "send_message", keywords: ["send", "share", "email", "notify", "message"], confidence: 0.7 },
|
|
16
|
+
{ intent: "explain", keywords: ["explain", "describe", "what is", "how to", "tell me about"], confidence: 0.7 },
|
|
17
|
+
];
|
|
18
|
+
// ─── Format heuristics ──────────────────────────────────────────────────
|
|
19
|
+
const FORMAT_KEYWORDS = ["csv", "json", "xml", "pdf", "excel", "xlsx", "yaml", "html", "markdown", "txt"];
|
|
20
|
+
function detectFormats(text) {
|
|
21
|
+
const lower = text.toLowerCase();
|
|
22
|
+
const params = {};
|
|
23
|
+
const found = FORMAT_KEYWORDS.filter((f) => lower.includes(f));
|
|
24
|
+
if (found.length >= 2) {
|
|
25
|
+
params["input_format"] = found[0];
|
|
26
|
+
params["output_format"] = found[1];
|
|
27
|
+
}
|
|
28
|
+
else if (found.length === 1) {
|
|
29
|
+
params["output_format"] = found[0];
|
|
30
|
+
}
|
|
31
|
+
return params;
|
|
32
|
+
}
|
|
33
|
+
// ─── LLM prompt ─────────────────────────────────────────────────────────
|
|
34
|
+
const LLM_PROMPT = (text) => `You are an intent extraction engine. Given the user input below, respond with ONLY valid JSON:
|
|
35
|
+
{"intent": "<canonical_intent>", "parameters": {}, "confidence": 0.0-1.0}
|
|
36
|
+
|
|
37
|
+
Canonical intents: convert_format, summarize, generate_report, delete_data, query_data, send_message, explain, unknown
|
|
38
|
+
|
|
39
|
+
User input: "${text}"`;
|
|
40
|
+
// ─── Public API ─────────────────────────────────────────────────────────
|
|
41
|
+
/**
|
|
42
|
+
* Rule-based intent extraction (deterministic fallback).
|
|
43
|
+
*/
|
|
44
|
+
export function ruleBasedExtract(text) {
|
|
45
|
+
const lower = text.toLowerCase();
|
|
46
|
+
for (const rule of RULE_PATTERNS) {
|
|
47
|
+
if (rule.keywords.some((kw) => lower.includes(kw))) {
|
|
48
|
+
return {
|
|
49
|
+
intent: rule.intent,
|
|
50
|
+
parameters: detectFormats(text),
|
|
51
|
+
confidence: rule.confidence,
|
|
52
|
+
source: "rule",
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return { intent: "unknown", parameters: {}, confidence: 0.1, source: "rule" };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Extract intent — LLM first, rule-based fallback.
|
|
60
|
+
*/
|
|
61
|
+
export async function extractIntent(text, llmCall) {
|
|
62
|
+
if (!text.trim()) {
|
|
63
|
+
return { intent: "unknown", parameters: {}, confidence: 0, source: "rule" };
|
|
64
|
+
}
|
|
65
|
+
// Try LLM
|
|
66
|
+
if (llmCall) {
|
|
67
|
+
try {
|
|
68
|
+
const raw = await llmCall(LLM_PROMPT(text));
|
|
69
|
+
const parsed = JSON.parse(raw.trim());
|
|
70
|
+
if (parsed.intent && (parsed.confidence ?? 0) >= 0.5) {
|
|
71
|
+
return {
|
|
72
|
+
intent: parsed.intent.toLowerCase().replace(/\s+/g, "_"),
|
|
73
|
+
parameters: { ...detectFormats(text), ...(parsed.parameters ?? {}) },
|
|
74
|
+
confidence: parsed.confidence ?? 0.5,
|
|
75
|
+
source: "llm",
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// LLM failed — fall through to rule-based
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return ruleBasedExtract(text);
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=intent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intent.js","sourceRoot":"","sources":["../../src/core/intent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vani — Multilingual Language Intelligence.
|
|
3
|
+
*
|
|
4
|
+
* Hybrid pipeline:
|
|
5
|
+
* 1. Rule-based keyword normalisation (Tamil, Hindi, Telugu, Kannada)
|
|
6
|
+
* 2. Heuristic language detection (trigram analysis)
|
|
7
|
+
* 3. Code-switch detection
|
|
8
|
+
*
|
|
9
|
+
* No external dependencies — pure TypeScript.
|
|
10
|
+
*/
|
|
11
|
+
import type { LanguageDetectionResult } from "../types.js";
|
|
12
|
+
/**
|
|
13
|
+
* Normalise domain-critical keywords while preserving the rest.
|
|
14
|
+
* NOT full translation — only maps action keywords.
|
|
15
|
+
*/
|
|
16
|
+
export declare function normaliseKeywords(text: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Detect language(s) from the input text.
|
|
19
|
+
*
|
|
20
|
+
* Uses a simple trigram-hit heuristic — no external dependencies.
|
|
21
|
+
* For production, swap in a proper detector (franc, cld3, etc.).
|
|
22
|
+
*/
|
|
23
|
+
export declare function detectLanguage(text: string): LanguageDetectionResult;
|
|
24
|
+
//# sourceMappingURL=language.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"language.d.ts","sourceRoot":"","sources":["../../src/core/language.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AA+C3D;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAItD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,uBAAuB,CA4DpE"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vani — Multilingual Language Intelligence.
|
|
3
|
+
*
|
|
4
|
+
* Hybrid pipeline:
|
|
5
|
+
* 1. Rule-based keyword normalisation (Tamil, Hindi, Telugu, Kannada)
|
|
6
|
+
* 2. Heuristic language detection (trigram analysis)
|
|
7
|
+
* 3. Code-switch detection
|
|
8
|
+
*
|
|
9
|
+
* No external dependencies — pure TypeScript.
|
|
10
|
+
*/
|
|
11
|
+
// ─── Keyword maps (Indian language → English canonical) ─────────────────
|
|
12
|
+
const KEYWORD_MAP = {
|
|
13
|
+
// Tamil
|
|
14
|
+
pannu: "do",
|
|
15
|
+
maathru: "change",
|
|
16
|
+
anuppu: "send",
|
|
17
|
+
kaattu: "show",
|
|
18
|
+
padi: "read",
|
|
19
|
+
edhu: "this",
|
|
20
|
+
adhu: "that",
|
|
21
|
+
indha: "this",
|
|
22
|
+
// Hindi
|
|
23
|
+
karo: "do",
|
|
24
|
+
banao: "create",
|
|
25
|
+
bhejo: "send",
|
|
26
|
+
dikhao: "show",
|
|
27
|
+
padho: "read",
|
|
28
|
+
hatao: "remove",
|
|
29
|
+
nikalo: "extract",
|
|
30
|
+
batao: "tell",
|
|
31
|
+
// Telugu
|
|
32
|
+
cheyyi: "do",
|
|
33
|
+
pampu: "send",
|
|
34
|
+
chupinchu: "show",
|
|
35
|
+
chaduvvu: "read",
|
|
36
|
+
teeyandi: "remove",
|
|
37
|
+
// Kannada
|
|
38
|
+
maadu: "do",
|
|
39
|
+
kalisu: "send",
|
|
40
|
+
toorisu: "show",
|
|
41
|
+
odigu: "read",
|
|
42
|
+
};
|
|
43
|
+
// ─── Common Indian-language trigrams for detection ──────────────────────
|
|
44
|
+
const LANGUAGE_TRIGRAMS = {
|
|
45
|
+
ta: ["anna", "indha", "pannu", "maathru", "anuppu", "kaattu", "romba", "naan"],
|
|
46
|
+
hi: ["karo", "banao", "bhejo", "dikhao", "yaar", "bhai", "mujhe", "kaise", "mein"],
|
|
47
|
+
te: ["cheyyi", "pampu", "chupinchu", "andi", "meeru", "nenu"],
|
|
48
|
+
kn: ["maadu", "kalisu", "toorisu", "guru", "nodu", "hege"],
|
|
49
|
+
};
|
|
50
|
+
// ─── Public API ─────────────────────────────────────────────────────────
|
|
51
|
+
/**
|
|
52
|
+
* Normalise domain-critical keywords while preserving the rest.
|
|
53
|
+
* NOT full translation — only maps action keywords.
|
|
54
|
+
*/
|
|
55
|
+
export function normaliseKeywords(text) {
|
|
56
|
+
if (!text)
|
|
57
|
+
return "";
|
|
58
|
+
const words = text.split(/\s+/);
|
|
59
|
+
return words.map((w) => KEYWORD_MAP[w.toLowerCase()] ?? w).join(" ");
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Detect language(s) from the input text.
|
|
63
|
+
*
|
|
64
|
+
* Uses a simple trigram-hit heuristic — no external dependencies.
|
|
65
|
+
* For production, swap in a proper detector (franc, cld3, etc.).
|
|
66
|
+
*/
|
|
67
|
+
export function detectLanguage(text) {
|
|
68
|
+
if (!text.trim()) {
|
|
69
|
+
return {
|
|
70
|
+
languages: ["en"],
|
|
71
|
+
confidence: 0,
|
|
72
|
+
isCodeSwitched: false,
|
|
73
|
+
originalText: text,
|
|
74
|
+
normalizedText: "",
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
const lower = text.toLowerCase();
|
|
78
|
+
const words = lower.split(/\s+/);
|
|
79
|
+
const detected = new Map();
|
|
80
|
+
// Check each word against trigram lists
|
|
81
|
+
for (const word of words) {
|
|
82
|
+
for (const [lang, trigrams] of Object.entries(LANGUAGE_TRIGRAMS)) {
|
|
83
|
+
if (trigrams.includes(word)) {
|
|
84
|
+
detected.set(lang, (detected.get(lang) ?? 0) + 1);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const languages = [];
|
|
89
|
+
let confidence = 0.5;
|
|
90
|
+
if (detected.size === 0) {
|
|
91
|
+
// Assume English
|
|
92
|
+
languages.push("en");
|
|
93
|
+
confidence = 0.7;
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
// Sort by hit count descending
|
|
97
|
+
const sorted = [...detected.entries()].sort((a, b) => b[1] - a[1]);
|
|
98
|
+
for (const [lang] of sorted) {
|
|
99
|
+
languages.push(lang);
|
|
100
|
+
}
|
|
101
|
+
// If there are English words too, add English
|
|
102
|
+
const hasEnglish = words.some((w) => !Object.values(LANGUAGE_TRIGRAMS).flat().includes(w) &&
|
|
103
|
+
!Object.keys(KEYWORD_MAP).includes(w) &&
|
|
104
|
+
w.length > 2);
|
|
105
|
+
if (hasEnglish && !languages.includes("en")) {
|
|
106
|
+
languages.push("en");
|
|
107
|
+
}
|
|
108
|
+
confidence = Math.min(0.95, 0.5 + sorted[0][1] * 0.15);
|
|
109
|
+
}
|
|
110
|
+
const isCodeSwitched = languages.length > 1;
|
|
111
|
+
const normalizedText = normaliseKeywords(text);
|
|
112
|
+
return {
|
|
113
|
+
languages,
|
|
114
|
+
confidence,
|
|
115
|
+
isCodeSwitched,
|
|
116
|
+
originalText: text,
|
|
117
|
+
normalizedText,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=language.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"language.js","sourceRoot":"","sources":["../../src/core/language.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smriti — Tiered Memory System.
|
|
3
|
+
*
|
|
4
|
+
* Tiers:
|
|
5
|
+
* short_term — in-process Map, capped at MAX_SHORT_TERM per user
|
|
6
|
+
* episodic — persistent (JSON file on disk)
|
|
7
|
+
* semantic — persistent (JSON file on disk)
|
|
8
|
+
*
|
|
9
|
+
* Node.js version uses JSON files instead of PostgreSQL for zero-dep operation.
|
|
10
|
+
* For production, swap in a real database adapter.
|
|
11
|
+
*/
|
|
12
|
+
import type { MemoryRecord, MemoryQuery } from "../types.js";
|
|
13
|
+
export declare function setDataDir(dir: string): void;
|
|
14
|
+
/**
|
|
15
|
+
* Store a memory record in the appropriate tier.
|
|
16
|
+
*/
|
|
17
|
+
export declare function storeMemory(record: Partial<MemoryRecord> & {
|
|
18
|
+
userId: string;
|
|
19
|
+
intent: string;
|
|
20
|
+
}): MemoryRecord;
|
|
21
|
+
/**
|
|
22
|
+
* Retrieve memory records matching the query.
|
|
23
|
+
*/
|
|
24
|
+
export declare function recallMemory(query: MemoryQuery): MemoryRecord[];
|
|
25
|
+
/**
|
|
26
|
+
* Clear short-term memory for a user.
|
|
27
|
+
*/
|
|
28
|
+
export declare function clearShortTerm(userId: string): void;
|
|
29
|
+
//# sourceMappingURL=memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/core/memory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAc,MAAM,aAAa,CAAC;AAUzE,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAE5C;AA6BD;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,YAAY,CAgC5G;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,GAAG,YAAY,EAAE,CAyB/D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAEnD"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smriti — Tiered Memory System.
|
|
3
|
+
*
|
|
4
|
+
* Tiers:
|
|
5
|
+
* short_term — in-process Map, capped at MAX_SHORT_TERM per user
|
|
6
|
+
* episodic — persistent (JSON file on disk)
|
|
7
|
+
* semantic — persistent (JSON file on disk)
|
|
8
|
+
*
|
|
9
|
+
* Node.js version uses JSON files instead of PostgreSQL for zero-dep operation.
|
|
10
|
+
* For production, swap in a real database adapter.
|
|
11
|
+
*/
|
|
12
|
+
import { randomUUID } from "node:crypto";
|
|
13
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
import { MAX_SHORT_TERM, IMPORTANCE_THRESHOLD } from "../constants.js";
|
|
16
|
+
// ─── In-process short-term store ────────────────────────────────────────
|
|
17
|
+
const shortTerm = new Map();
|
|
18
|
+
// ─── Data directory ─────────────────────────────────────────────────────
|
|
19
|
+
let dataDir = join(process.cwd(), "data", "memory");
|
|
20
|
+
export function setDataDir(dir) {
|
|
21
|
+
dataDir = dir;
|
|
22
|
+
}
|
|
23
|
+
function ensureDir() {
|
|
24
|
+
if (!existsSync(dataDir)) {
|
|
25
|
+
mkdirSync(dataDir, { recursive: true });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function persistPath() {
|
|
29
|
+
ensureDir();
|
|
30
|
+
return join(dataDir, "persistent.json");
|
|
31
|
+
}
|
|
32
|
+
function loadPersistent() {
|
|
33
|
+
const p = persistPath();
|
|
34
|
+
if (!existsSync(p))
|
|
35
|
+
return [];
|
|
36
|
+
try {
|
|
37
|
+
return JSON.parse(readFileSync(p, "utf-8"));
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function savePersistent(records) {
|
|
44
|
+
writeFileSync(persistPath(), JSON.stringify(records, null, 2), "utf-8");
|
|
45
|
+
}
|
|
46
|
+
// ─── Public API ─────────────────────────────────────────────────────────
|
|
47
|
+
/**
|
|
48
|
+
* Store a memory record in the appropriate tier.
|
|
49
|
+
*/
|
|
50
|
+
export function storeMemory(record) {
|
|
51
|
+
const now = new Date().toISOString();
|
|
52
|
+
const full = {
|
|
53
|
+
id: record.id ?? randomUUID(),
|
|
54
|
+
userId: record.userId,
|
|
55
|
+
tier: (record.tier ?? "short_term"),
|
|
56
|
+
intent: record.intent,
|
|
57
|
+
language: record.language ?? "en",
|
|
58
|
+
data: record.data ?? {},
|
|
59
|
+
importanceScore: record.importanceScore ?? 0.5,
|
|
60
|
+
createdAt: record.createdAt ?? now,
|
|
61
|
+
updatedAt: now,
|
|
62
|
+
};
|
|
63
|
+
if (full.tier === "short_term") {
|
|
64
|
+
const existing = shortTerm.get(full.userId) ?? [];
|
|
65
|
+
existing.push(full);
|
|
66
|
+
// Cap
|
|
67
|
+
if (existing.length > MAX_SHORT_TERM) {
|
|
68
|
+
existing.shift();
|
|
69
|
+
}
|
|
70
|
+
shortTerm.set(full.userId, existing);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
// Episodic / Semantic — persist only above threshold
|
|
74
|
+
if (full.importanceScore >= IMPORTANCE_THRESHOLD) {
|
|
75
|
+
const records = loadPersistent();
|
|
76
|
+
records.push(full);
|
|
77
|
+
savePersistent(records);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return full;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Retrieve memory records matching the query.
|
|
84
|
+
*/
|
|
85
|
+
export function recallMemory(query) {
|
|
86
|
+
const results = [];
|
|
87
|
+
// Check short-term
|
|
88
|
+
const stRecords = shortTerm.get(query.userId) ?? [];
|
|
89
|
+
for (const r of stRecords) {
|
|
90
|
+
if (query.tier && r.tier !== query.tier)
|
|
91
|
+
continue;
|
|
92
|
+
if (query.intent && r.intent !== query.intent)
|
|
93
|
+
continue;
|
|
94
|
+
results.push(r);
|
|
95
|
+
}
|
|
96
|
+
// Check persistent
|
|
97
|
+
if (!query.tier || query.tier !== "short_term") {
|
|
98
|
+
const persistent = loadPersistent();
|
|
99
|
+
for (const r of persistent) {
|
|
100
|
+
if (r.userId !== query.userId)
|
|
101
|
+
continue;
|
|
102
|
+
if (query.tier && r.tier !== query.tier)
|
|
103
|
+
continue;
|
|
104
|
+
if (query.intent && r.intent !== query.intent)
|
|
105
|
+
continue;
|
|
106
|
+
results.push(r);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Sort by createdAt descending, apply limit
|
|
110
|
+
results.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
111
|
+
return results.slice(0, query.limit);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Clear short-term memory for a user.
|
|
115
|
+
*/
|
|
116
|
+
export function clearShortTerm(userId) {
|
|
117
|
+
shortTerm.delete(userId);
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/core/memory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Marga — Multi-Model AI Router.
|
|
3
|
+
*
|
|
4
|
+
* Routes tasks to the best-suited LLM provider:
|
|
5
|
+
* multilingual → Sarvam AI
|
|
6
|
+
* reasoning → Anthropic / OpenAI
|
|
7
|
+
* local → Ollama
|
|
8
|
+
* general → best available
|
|
9
|
+
*/
|
|
10
|
+
import { TaskType } from "../types.js";
|
|
11
|
+
import type { ModelRoutingDecision } from "../types.js";
|
|
12
|
+
interface RouterConfig {
|
|
13
|
+
openaiApiKey?: string;
|
|
14
|
+
anthropicApiKey?: string;
|
|
15
|
+
sarvamApiKey?: string;
|
|
16
|
+
ollamaBaseUrl: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function configureRouter(cfg: Partial<RouterConfig>): void;
|
|
19
|
+
export declare function routeTask(taskType: TaskType): ModelRoutingDecision;
|
|
20
|
+
export declare function callLLM(prompt: string, taskType?: TaskType): Promise<string>;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=router.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/core/router.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAiB,QAAQ,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,KAAK,EAAE,oBAAoB,EAAW,MAAM,aAAa,CAAC;AAIjE,UAAU,YAAY;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;CACvB;AAMD,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,IAAI,CAEhE;AAaD,wBAAgB,SAAS,CAAC,QAAQ,EAAE,QAAQ,GAAG,oBAAoB,CAuClE;AAkBD,wBAAsB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAE,QAA2B,GAAG,OAAO,CAAC,MAAM,CAAC,CAGpG"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Marga — Multi-Model AI Router.
|
|
3
|
+
*
|
|
4
|
+
* Routes tasks to the best-suited LLM provider:
|
|
5
|
+
* multilingual → Sarvam AI
|
|
6
|
+
* reasoning → Anthropic / OpenAI
|
|
7
|
+
* local → Ollama
|
|
8
|
+
* general → best available
|
|
9
|
+
*/
|
|
10
|
+
import axios from "axios";
|
|
11
|
+
import { ModelProvider, TaskType } from "../types.js";
|
|
12
|
+
let config = {
|
|
13
|
+
ollamaBaseUrl: "http://localhost:11434",
|
|
14
|
+
};
|
|
15
|
+
export function configureRouter(cfg) {
|
|
16
|
+
config = { ...config, ...cfg };
|
|
17
|
+
}
|
|
18
|
+
// ─── Default models ─────────────────────────────────────────────────────
|
|
19
|
+
const DEFAULT_MODELS = {
|
|
20
|
+
[ModelProvider.OPENAI]: "gpt-4o",
|
|
21
|
+
[ModelProvider.ANTHROPIC]: "claude-sonnet-4-20250514",
|
|
22
|
+
[ModelProvider.OLLAMA]: "llama3",
|
|
23
|
+
[ModelProvider.SARVAM]: "sarvam-2b-v0.5",
|
|
24
|
+
};
|
|
25
|
+
// ─── Routing logic ──────────────────────────────────────────────────────
|
|
26
|
+
export function routeTask(taskType) {
|
|
27
|
+
if (taskType === TaskType.MULTILINGUAL) {
|
|
28
|
+
if (config.sarvamApiKey) {
|
|
29
|
+
return {
|
|
30
|
+
provider: ModelProvider.SARVAM,
|
|
31
|
+
modelName: DEFAULT_MODELS[ModelProvider.SARVAM],
|
|
32
|
+
reason: "Multilingual task — routing to Sarvam AI for Indian-language support.",
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
return fallbackDecision("Sarvam not configured; falling back for multilingual.");
|
|
36
|
+
}
|
|
37
|
+
if (taskType === TaskType.REASONING) {
|
|
38
|
+
if (config.anthropicApiKey) {
|
|
39
|
+
return {
|
|
40
|
+
provider: ModelProvider.ANTHROPIC,
|
|
41
|
+
modelName: DEFAULT_MODELS[ModelProvider.ANTHROPIC],
|
|
42
|
+
reason: "Reasoning task — routing to Anthropic for strong analytical capability.",
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
if (config.openaiApiKey) {
|
|
46
|
+
return {
|
|
47
|
+
provider: ModelProvider.OPENAI,
|
|
48
|
+
modelName: DEFAULT_MODELS[ModelProvider.OPENAI],
|
|
49
|
+
reason: "Reasoning task — routing to OpenAI (Anthropic unavailable).",
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
return fallbackDecision("No reasoning provider available.");
|
|
53
|
+
}
|
|
54
|
+
if (taskType === TaskType.LOCAL) {
|
|
55
|
+
return {
|
|
56
|
+
provider: ModelProvider.OLLAMA,
|
|
57
|
+
modelName: DEFAULT_MODELS[ModelProvider.OLLAMA],
|
|
58
|
+
reason: "Local task — routing to Ollama for on-device execution.",
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return fallbackDecision("General task — using best available provider.");
|
|
62
|
+
}
|
|
63
|
+
function fallbackDecision(reason) {
|
|
64
|
+
if (config.openaiApiKey) {
|
|
65
|
+
return { provider: ModelProvider.OPENAI, modelName: DEFAULT_MODELS[ModelProvider.OPENAI], reason };
|
|
66
|
+
}
|
|
67
|
+
if (config.anthropicApiKey) {
|
|
68
|
+
return { provider: ModelProvider.ANTHROPIC, modelName: DEFAULT_MODELS[ModelProvider.ANTHROPIC], reason };
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
provider: ModelProvider.OLLAMA,
|
|
72
|
+
modelName: DEFAULT_MODELS[ModelProvider.OLLAMA],
|
|
73
|
+
reason: reason + " Falling back to Ollama (local).",
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
// ─── Provider dispatch ──────────────────────────────────────────────────
|
|
77
|
+
export async function callLLM(prompt, taskType = TaskType.GENERAL) {
|
|
78
|
+
const decision = routeTask(taskType);
|
|
79
|
+
return dispatch(prompt, decision);
|
|
80
|
+
}
|
|
81
|
+
async function dispatch(prompt, decision) {
|
|
82
|
+
switch (decision.provider) {
|
|
83
|
+
case ModelProvider.OPENAI:
|
|
84
|
+
return callOpenAI(prompt, decision.modelName);
|
|
85
|
+
case ModelProvider.ANTHROPIC:
|
|
86
|
+
return callAnthropic(prompt, decision.modelName);
|
|
87
|
+
case ModelProvider.SARVAM:
|
|
88
|
+
return callSarvam(prompt, decision.modelName);
|
|
89
|
+
case ModelProvider.OLLAMA:
|
|
90
|
+
return callOllama(prompt, decision.modelName);
|
|
91
|
+
default:
|
|
92
|
+
throw new Error(`Unknown provider: ${decision.provider}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async function callOpenAI(prompt, model) {
|
|
96
|
+
const resp = await axios.post("https://api.openai.com/v1/chat/completions", { model, messages: [{ role: "user", content: prompt }], temperature: 0.3 }, { headers: { Authorization: `Bearer ${config.openaiApiKey}`, "Content-Type": "application/json" }, timeout: 60000 });
|
|
97
|
+
return resp.data.choices[0].message.content;
|
|
98
|
+
}
|
|
99
|
+
async function callAnthropic(prompt, model) {
|
|
100
|
+
const resp = await axios.post("https://api.anthropic.com/v1/messages", { model, max_tokens: 2048, messages: [{ role: "user", content: prompt }] }, {
|
|
101
|
+
headers: {
|
|
102
|
+
"x-api-key": config.anthropicApiKey ?? "",
|
|
103
|
+
"anthropic-version": "2023-06-01",
|
|
104
|
+
"Content-Type": "application/json",
|
|
105
|
+
},
|
|
106
|
+
timeout: 60000,
|
|
107
|
+
});
|
|
108
|
+
return resp.data.content[0].text;
|
|
109
|
+
}
|
|
110
|
+
async function callSarvam(prompt, model) {
|
|
111
|
+
const resp = await axios.post("https://api.sarvam.ai/v1/chat/completions", { model, messages: [{ role: "user", content: prompt }], temperature: 0.3 }, { headers: { Authorization: `Bearer ${config.sarvamApiKey}`, "Content-Type": "application/json" }, timeout: 60000 });
|
|
112
|
+
return resp.data.choices[0].message.content;
|
|
113
|
+
}
|
|
114
|
+
async function callOllama(prompt, model) {
|
|
115
|
+
const resp = await axios.post(`${config.ollamaBaseUrl}/api/generate`, { model, prompt, stream: false }, { timeout: 120000 });
|
|
116
|
+
return resp.data.response ?? "";
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/core/router.ts"],"names":[],"mappings":"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"}
|