@dungle-scrubs/hippo 0.1.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 +21 -0
- package/README.md +439 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +559 -0
- package/dist/cli.js.map +1 -0
- package/dist/db.d.ts +45 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +80 -0
- package/dist/db.js.map +1 -0
- package/dist/extractor.d.ts +23 -0
- package/dist/extractor.d.ts.map +1 -0
- package/dist/extractor.js +121 -0
- package/dist/extractor.js.map +1 -0
- package/dist/hash.d.ts +11 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +14 -0
- package/dist/hash.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/providers/embedding.d.ts +27 -0
- package/dist/providers/embedding.d.ts.map +1 -0
- package/dist/providers/embedding.js +41 -0
- package/dist/providers/embedding.js.map +1 -0
- package/dist/providers/llm.d.ts +29 -0
- package/dist/providers/llm.d.ts.map +1 -0
- package/dist/providers/llm.js +74 -0
- package/dist/providers/llm.js.map +1 -0
- package/dist/schema.d.ts +20 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +78 -0
- package/dist/schema.js.map +1 -0
- package/dist/server/config.d.ts +38 -0
- package/dist/server/config.d.ts.map +1 -0
- package/dist/server/config.js +71 -0
- package/dist/server/config.js.map +1 -0
- package/dist/server/index.d.ts +13 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +372 -0
- package/dist/server/index.js.map +1 -0
- package/dist/similarity.d.ts +41 -0
- package/dist/similarity.d.ts.map +1 -0
- package/dist/similarity.js +70 -0
- package/dist/similarity.js.map +1 -0
- package/dist/strength.d.ts +59 -0
- package/dist/strength.d.ts.map +1 -0
- package/dist/strength.js +76 -0
- package/dist/strength.js.map +1 -0
- package/dist/tools/append-memory-block.d.ts +22 -0
- package/dist/tools/append-memory-block.d.ts.map +1 -0
- package/dist/tools/append-memory-block.js +45 -0
- package/dist/tools/append-memory-block.js.map +1 -0
- package/dist/tools/forget-memory.d.ts +31 -0
- package/dist/tools/forget-memory.d.ts.map +1 -0
- package/dist/tools/forget-memory.js +77 -0
- package/dist/tools/forget-memory.js.map +1 -0
- package/dist/tools/index.d.ts +9 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +9 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/recall-conversation.d.ts +21 -0
- package/dist/tools/recall-conversation.d.ts.map +1 -0
- package/dist/tools/recall-conversation.js +93 -0
- package/dist/tools/recall-conversation.js.map +1 -0
- package/dist/tools/recall-memories.d.ts +29 -0
- package/dist/tools/recall-memories.d.ts.map +1 -0
- package/dist/tools/recall-memories.js +106 -0
- package/dist/tools/recall-memories.js.map +1 -0
- package/dist/tools/recall-memory-block.d.ts +21 -0
- package/dist/tools/recall-memory-block.d.ts.map +1 -0
- package/dist/tools/recall-memory-block.js +36 -0
- package/dist/tools/recall-memory-block.js.map +1 -0
- package/dist/tools/remember-facts.d.ts +30 -0
- package/dist/tools/remember-facts.d.ts.map +1 -0
- package/dist/tools/remember-facts.js +235 -0
- package/dist/tools/remember-facts.js.map +1 -0
- package/dist/tools/replace-memory-block.d.ts +25 -0
- package/dist/tools/replace-memory-block.d.ts.map +1 -0
- package/dist/tools/replace-memory-block.js +69 -0
- package/dist/tools/replace-memory-block.js.map +1 -0
- package/dist/tools/store-memory.d.ts +27 -0
- package/dist/tools/store-memory.d.ts.map +1 -0
- package/dist/tools/store-memory.js +129 -0
- package/dist/tools/store-memory.js.map +1 -0
- package/dist/types.d.ts +86 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/ulid.d.ts +13 -0
- package/dist/ulid.d.ts.map +1 -0
- package/dist/ulid.js +39 -0
- package/dist/ulid.js.map +1 -0
- package/package.json +70 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server configuration — resolved from environment variables.
|
|
3
|
+
*
|
|
4
|
+
* All config comes from env vars. No config files. The server
|
|
5
|
+
* needs: a database path, embedding API credentials, and LLM
|
|
6
|
+
* API credentials.
|
|
7
|
+
*/
|
|
8
|
+
import type { EmbeddingProviderConfig } from "../providers/embedding.js";
|
|
9
|
+
import type { LlmProviderConfig } from "../providers/llm.js";
|
|
10
|
+
/** Fully resolved server configuration. */
|
|
11
|
+
export interface ServerConfig {
|
|
12
|
+
readonly db: string;
|
|
13
|
+
readonly embedding: EmbeddingProviderConfig;
|
|
14
|
+
readonly llm: LlmProviderConfig;
|
|
15
|
+
readonly port: number;
|
|
16
|
+
readonly transport: "http" | "stdio";
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Resolve server configuration from environment variables.
|
|
20
|
+
*
|
|
21
|
+
* Required:
|
|
22
|
+
* HIPPO_DB — SQLite database path
|
|
23
|
+
* HIPPO_EMBED_KEY — Embedding API key
|
|
24
|
+
* HIPPO_LLM_KEY — LLM API key
|
|
25
|
+
*
|
|
26
|
+
* Optional:
|
|
27
|
+
* HIPPO_TRANSPORT — "http" (default) or "stdio"
|
|
28
|
+
* HIPPO_PORT — HTTP port (default: 3100)
|
|
29
|
+
* HIPPO_EMBED_URL — Embedding base URL (default: https://api.openai.com/v1)
|
|
30
|
+
* HIPPO_EMBED_MODEL — Embedding model (default: text-embedding-3-small)
|
|
31
|
+
* HIPPO_EMBED_DIMENSIONS — Embedding dimensions (optional)
|
|
32
|
+
* HIPPO_LLM_URL — LLM base URL (default: https://openrouter.ai/api/v1)
|
|
33
|
+
* HIPPO_LLM_MODEL — LLM model (default: google/gemini-flash-2.0)
|
|
34
|
+
*
|
|
35
|
+
* @returns Resolved ServerConfig
|
|
36
|
+
*/
|
|
37
|
+
export declare function resolveConfig(): ServerConfig;
|
|
38
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/server/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAE7D,2CAA2C;AAC3C,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,uBAAuB,CAAC;IAC5C,QAAQ,CAAC,GAAG,EAAE,iBAAiB,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;CACrC;AA4BD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,aAAa,IAAI,YAAY,CAoB5C"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server configuration — resolved from environment variables.
|
|
3
|
+
*
|
|
4
|
+
* All config comes from env vars. No config files. The server
|
|
5
|
+
* needs: a database path, embedding API credentials, and LLM
|
|
6
|
+
* API credentials.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Read a required environment variable, throwing if missing.
|
|
10
|
+
*
|
|
11
|
+
* @param key - Environment variable name
|
|
12
|
+
* @returns The value
|
|
13
|
+
* @throws Error if the variable is not set
|
|
14
|
+
*/
|
|
15
|
+
function required(key) {
|
|
16
|
+
const value = process.env[key];
|
|
17
|
+
if (!value) {
|
|
18
|
+
throw new Error(`Missing required environment variable: ${key}`);
|
|
19
|
+
}
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Read an optional environment variable with a default.
|
|
24
|
+
*
|
|
25
|
+
* @param key - Environment variable name
|
|
26
|
+
* @param fallback - Default value if not set
|
|
27
|
+
* @returns The value or default
|
|
28
|
+
*/
|
|
29
|
+
function optional(key, fallback) {
|
|
30
|
+
return process.env[key] ?? fallback;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Resolve server configuration from environment variables.
|
|
34
|
+
*
|
|
35
|
+
* Required:
|
|
36
|
+
* HIPPO_DB — SQLite database path
|
|
37
|
+
* HIPPO_EMBED_KEY — Embedding API key
|
|
38
|
+
* HIPPO_LLM_KEY — LLM API key
|
|
39
|
+
*
|
|
40
|
+
* Optional:
|
|
41
|
+
* HIPPO_TRANSPORT — "http" (default) or "stdio"
|
|
42
|
+
* HIPPO_PORT — HTTP port (default: 3100)
|
|
43
|
+
* HIPPO_EMBED_URL — Embedding base URL (default: https://api.openai.com/v1)
|
|
44
|
+
* HIPPO_EMBED_MODEL — Embedding model (default: text-embedding-3-small)
|
|
45
|
+
* HIPPO_EMBED_DIMENSIONS — Embedding dimensions (optional)
|
|
46
|
+
* HIPPO_LLM_URL — LLM base URL (default: https://openrouter.ai/api/v1)
|
|
47
|
+
* HIPPO_LLM_MODEL — LLM model (default: google/gemini-flash-2.0)
|
|
48
|
+
*
|
|
49
|
+
* @returns Resolved ServerConfig
|
|
50
|
+
*/
|
|
51
|
+
export function resolveConfig() {
|
|
52
|
+
const transport = optional("HIPPO_TRANSPORT", "http");
|
|
53
|
+
const dimensionsStr = process.env.HIPPO_EMBED_DIMENSIONS;
|
|
54
|
+
return {
|
|
55
|
+
db: required("HIPPO_DB"),
|
|
56
|
+
embedding: {
|
|
57
|
+
apiKey: required("HIPPO_EMBED_KEY"),
|
|
58
|
+
baseUrl: optional("HIPPO_EMBED_URL", "https://api.openai.com/v1"),
|
|
59
|
+
dimensions: dimensionsStr ? Number.parseInt(dimensionsStr, 10) : undefined,
|
|
60
|
+
model: optional("HIPPO_EMBED_MODEL", "text-embedding-3-small"),
|
|
61
|
+
},
|
|
62
|
+
llm: {
|
|
63
|
+
apiKey: required("HIPPO_LLM_KEY"),
|
|
64
|
+
baseUrl: optional("HIPPO_LLM_URL", "https://openrouter.ai/api/v1"),
|
|
65
|
+
model: optional("HIPPO_LLM_MODEL", "google/gemini-flash-2.0"),
|
|
66
|
+
},
|
|
67
|
+
port: Number.parseInt(optional("HIPPO_PORT", "3100"), 10),
|
|
68
|
+
transport,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/server/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAcH;;;;;;GAMG;AACH,SAAS,QAAQ,CAAC,GAAW;IAC5B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,0CAA0C,GAAG,EAAE,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,SAAS,QAAQ,CAAC,GAAW,EAAE,QAAgB;IAC9C,OAAO,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC;AACrC,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,aAAa;IAC5B,MAAM,SAAS,GAAG,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAqB,CAAC;IAC1E,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC;IAEzD,OAAO;QACN,EAAE,EAAE,QAAQ,CAAC,UAAU,CAAC;QACxB,SAAS,EAAE;YACV,MAAM,EAAE,QAAQ,CAAC,iBAAiB,CAAC;YACnC,OAAO,EAAE,QAAQ,CAAC,iBAAiB,EAAE,2BAA2B,CAAC;YACjE,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS;YAC1E,KAAK,EAAE,QAAQ,CAAC,mBAAmB,EAAE,wBAAwB,CAAC;SAC9D;QACD,GAAG,EAAE;YACJ,MAAM,EAAE,QAAQ,CAAC,eAAe,CAAC;YACjC,OAAO,EAAE,QAAQ,CAAC,eAAe,EAAE,8BAA8B,CAAC;YAClE,KAAK,EAAE,QAAQ,CAAC,iBAAiB,EAAE,yBAAyB,CAAC;SAC7D;QACD,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC;QACzD,SAAS;KACT,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Hippo MCP server — exposes memory tools over MCP protocol.
|
|
4
|
+
*
|
|
5
|
+
* Supports HTTP/SSE (multi-client) and STDIO (single-client) transports.
|
|
6
|
+
* Embedding and LLM are configured via environment variables — consumers
|
|
7
|
+
* send text, hippo handles vectorization and extraction.
|
|
8
|
+
*
|
|
9
|
+
* Every tool call includes an `agent_id` parameter for multi-agent
|
|
10
|
+
* support on a shared database.
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG"}
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Hippo MCP server — exposes memory tools over MCP protocol.
|
|
4
|
+
*
|
|
5
|
+
* Supports HTTP/SSE (multi-client) and STDIO (single-client) transports.
|
|
6
|
+
* Embedding and LLM are configured via environment variables — consumers
|
|
7
|
+
* send text, hippo handles vectorization and extraction.
|
|
8
|
+
*
|
|
9
|
+
* Every tool call includes an `agent_id` parameter for multi-agent
|
|
10
|
+
* support on a shared database.
|
|
11
|
+
*/
|
|
12
|
+
import { createServer } from "node:http";
|
|
13
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
14
|
+
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
15
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
16
|
+
import Database from "better-sqlite3";
|
|
17
|
+
import { z } from "zod";
|
|
18
|
+
import { prepareStatements } from "../db.js";
|
|
19
|
+
import { classifyConflict, extractFacts } from "../extractor.js";
|
|
20
|
+
import { contentHash } from "../hash.js";
|
|
21
|
+
import { createEmbeddingProvider } from "../providers/embedding.js";
|
|
22
|
+
import { createLlmProvider } from "../providers/llm.js";
|
|
23
|
+
import { initSchema, verifyEmbeddingModel } from "../schema.js";
|
|
24
|
+
import { chunkEmbedding, cosineSimilarity, embeddingToBuffer } from "../similarity.js";
|
|
25
|
+
import { effectiveStrength, recencyScore, retrievalBoost, STRENGTH_FLOOR, searchScore, } from "../strength.js";
|
|
26
|
+
import { ulid } from "../ulid.js";
|
|
27
|
+
import { resolveConfig } from "./config.js";
|
|
28
|
+
// ── Setup ────────────────────────────────────────────────────────────
|
|
29
|
+
const config = resolveConfig();
|
|
30
|
+
const db = new Database(config.db);
|
|
31
|
+
initSchema(db);
|
|
32
|
+
verifyEmbeddingModel(db, config.embedding.model);
|
|
33
|
+
const stmts = prepareStatements(db);
|
|
34
|
+
const embed = createEmbeddingProvider(config.embedding);
|
|
35
|
+
const llm = createLlmProvider(config.llm);
|
|
36
|
+
const mcp = new McpServer({
|
|
37
|
+
name: "hippo",
|
|
38
|
+
version: "0.1.0", // x-release-please-version
|
|
39
|
+
});
|
|
40
|
+
// ── Tool: remember_facts ─────────────────────────────────────────────
|
|
41
|
+
mcp.tool("remember_facts", "Extract and store facts from text. Handles conflict resolution: duplicates strengthen, superseding facts replace old ones.", {
|
|
42
|
+
agent_id: z.string().describe("Agent namespace for memory isolation"),
|
|
43
|
+
text: z.string().max(10_000).describe("Text containing facts to extract and remember"),
|
|
44
|
+
}, async ({ agent_id, text }) => {
|
|
45
|
+
const facts = await extractFacts(text, llm);
|
|
46
|
+
if (facts.length === 0) {
|
|
47
|
+
return { content: [{ type: "text", text: "No facts extracted." }] };
|
|
48
|
+
}
|
|
49
|
+
const results = [];
|
|
50
|
+
for (const { fact, intensity } of facts) {
|
|
51
|
+
const embedding = await embed(fact);
|
|
52
|
+
const embeddingBuf = embeddingToBuffer(embedding);
|
|
53
|
+
const now = new Date().toISOString();
|
|
54
|
+
// Find similar existing facts
|
|
55
|
+
const existing = stmts.getActiveChunksByAgent.all(agent_id, "fact", 200);
|
|
56
|
+
let bestSim = 0;
|
|
57
|
+
let bestChunk = null;
|
|
58
|
+
for (const chunk of existing) {
|
|
59
|
+
const sim = cosineSimilarity(embedding, chunkEmbedding(chunk));
|
|
60
|
+
if (sim > bestSim) {
|
|
61
|
+
bestSim = sim;
|
|
62
|
+
bestChunk = chunk;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (bestSim > 0.93 && bestChunk) {
|
|
66
|
+
// Auto-DUPLICATE
|
|
67
|
+
const newIntensity = (bestChunk.running_intensity * bestChunk.encounter_count + intensity) /
|
|
68
|
+
(bestChunk.encounter_count + 1);
|
|
69
|
+
stmts.reinforceChunk.run({
|
|
70
|
+
id: bestChunk.id,
|
|
71
|
+
last_accessed_at: now,
|
|
72
|
+
running_intensity: newIntensity,
|
|
73
|
+
});
|
|
74
|
+
results.push(`reinforced: "${fact}"`);
|
|
75
|
+
}
|
|
76
|
+
else if (bestSim >= 0.78 && bestChunk) {
|
|
77
|
+
// LLM tiebreaker
|
|
78
|
+
const classification = await classifyConflict(fact, bestChunk.content, llm);
|
|
79
|
+
if (classification === "DUPLICATE") {
|
|
80
|
+
const newIntensity = (bestChunk.running_intensity * bestChunk.encounter_count + intensity) /
|
|
81
|
+
(bestChunk.encounter_count + 1);
|
|
82
|
+
stmts.reinforceChunk.run({
|
|
83
|
+
id: bestChunk.id,
|
|
84
|
+
last_accessed_at: now,
|
|
85
|
+
running_intensity: newIntensity,
|
|
86
|
+
});
|
|
87
|
+
results.push(`reinforced: "${fact}"`);
|
|
88
|
+
}
|
|
89
|
+
else if (classification === "SUPERSEDES") {
|
|
90
|
+
const newId = ulid();
|
|
91
|
+
db.transaction(() => {
|
|
92
|
+
stmts.insertChunk.run({
|
|
93
|
+
access_count: 0,
|
|
94
|
+
agent_id,
|
|
95
|
+
content: fact,
|
|
96
|
+
content_hash: null,
|
|
97
|
+
created_at: now,
|
|
98
|
+
embedding: embeddingBuf,
|
|
99
|
+
encounter_count: 1,
|
|
100
|
+
id: newId,
|
|
101
|
+
kind: "fact",
|
|
102
|
+
last_accessed_at: now,
|
|
103
|
+
metadata: null,
|
|
104
|
+
running_intensity: intensity,
|
|
105
|
+
superseded_by: null,
|
|
106
|
+
});
|
|
107
|
+
stmts.supersedeChunk.run(newId, bestChunk.id);
|
|
108
|
+
})();
|
|
109
|
+
results.push(`superseded: "${fact}" (replaced "${bestChunk.content}")`);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
// DISTINCT
|
|
113
|
+
stmts.insertChunk.run({
|
|
114
|
+
access_count: 0,
|
|
115
|
+
agent_id,
|
|
116
|
+
content: fact,
|
|
117
|
+
content_hash: null,
|
|
118
|
+
created_at: now,
|
|
119
|
+
embedding: embeddingBuf,
|
|
120
|
+
encounter_count: 1,
|
|
121
|
+
id: ulid(),
|
|
122
|
+
kind: "fact",
|
|
123
|
+
last_accessed_at: now,
|
|
124
|
+
metadata: null,
|
|
125
|
+
running_intensity: intensity,
|
|
126
|
+
superseded_by: null,
|
|
127
|
+
});
|
|
128
|
+
results.push(`new: "${fact}"`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
// NEW
|
|
133
|
+
stmts.insertChunk.run({
|
|
134
|
+
access_count: 0,
|
|
135
|
+
agent_id,
|
|
136
|
+
content: fact,
|
|
137
|
+
content_hash: null,
|
|
138
|
+
created_at: now,
|
|
139
|
+
embedding: embeddingBuf,
|
|
140
|
+
encounter_count: 1,
|
|
141
|
+
id: ulid(),
|
|
142
|
+
kind: "fact",
|
|
143
|
+
last_accessed_at: now,
|
|
144
|
+
metadata: null,
|
|
145
|
+
running_intensity: intensity,
|
|
146
|
+
superseded_by: null,
|
|
147
|
+
});
|
|
148
|
+
results.push(`new: "${fact}"`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return { content: [{ type: "text", text: results.join("\n") }] };
|
|
152
|
+
});
|
|
153
|
+
// ── Tool: store_memory ───────────────────────────────────────────────
|
|
154
|
+
mcp.tool("store_memory", "Store raw content as a memory chunk. Deduplicates by content hash — storing the same text twice strengthens the existing memory instead of creating a duplicate.", {
|
|
155
|
+
agent_id: z.string().describe("Agent namespace for memory isolation"),
|
|
156
|
+
content: z.string().max(50_000).describe("Content to store as a memory"),
|
|
157
|
+
metadata: z.string().optional().describe("Optional JSON metadata"),
|
|
158
|
+
}, async ({ agent_id, content, metadata }) => {
|
|
159
|
+
const hash = contentHash(content);
|
|
160
|
+
const now = new Date().toISOString();
|
|
161
|
+
// Check for duplicate
|
|
162
|
+
const existing = stmts.getMemoryByHash.get(agent_id, hash);
|
|
163
|
+
if (existing) {
|
|
164
|
+
const boosted = retrievalBoost(existing.running_intensity);
|
|
165
|
+
stmts.reinforceChunk.run({
|
|
166
|
+
id: existing.id,
|
|
167
|
+
last_accessed_at: now,
|
|
168
|
+
running_intensity: boosted,
|
|
169
|
+
});
|
|
170
|
+
return {
|
|
171
|
+
content: [{ type: "text", text: `Memory already exists (strengthened): ${existing.id}` }],
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
const embedding = await embed(content);
|
|
175
|
+
const id = ulid();
|
|
176
|
+
stmts.insertChunk.run({
|
|
177
|
+
access_count: 0,
|
|
178
|
+
agent_id,
|
|
179
|
+
content,
|
|
180
|
+
content_hash: hash,
|
|
181
|
+
created_at: now,
|
|
182
|
+
embedding: embeddingToBuffer(embedding),
|
|
183
|
+
encounter_count: 1,
|
|
184
|
+
id,
|
|
185
|
+
kind: "memory",
|
|
186
|
+
last_accessed_at: now,
|
|
187
|
+
metadata: metadata ?? null,
|
|
188
|
+
running_intensity: 0.5,
|
|
189
|
+
superseded_by: null,
|
|
190
|
+
});
|
|
191
|
+
return { content: [{ type: "text", text: `Stored memory: ${id}` }] };
|
|
192
|
+
});
|
|
193
|
+
// ── Tool: recall_memories ────────────────────────────────────────────
|
|
194
|
+
mcp.tool("recall_memories", "Semantic search over stored facts and memories. Returns results ranked by relevance, strength, and recency.", {
|
|
195
|
+
agent_id: z.string().describe("Agent namespace for memory isolation"),
|
|
196
|
+
limit: z.number().min(1).max(50).default(10).describe("Max results to return"),
|
|
197
|
+
query: z.string().describe("What to search for in memory"),
|
|
198
|
+
}, async ({ agent_id, limit, query }) => {
|
|
199
|
+
const queryEmbedding = await embed(query);
|
|
200
|
+
const now = new Date();
|
|
201
|
+
const allChunks = stmts.getAllActiveChunksByAgent.all(agent_id, 10_000);
|
|
202
|
+
const scored = [];
|
|
203
|
+
for (const chunk of allChunks) {
|
|
204
|
+
const similarity = cosineSimilarity(queryEmbedding, chunkEmbedding(chunk));
|
|
205
|
+
if (similarity < 0.1)
|
|
206
|
+
continue;
|
|
207
|
+
const hoursSince = (now.getTime() - new Date(chunk.last_accessed_at).getTime()) / (1000 * 60 * 60);
|
|
208
|
+
const strength = effectiveStrength(chunk.running_intensity, chunk.access_count, hoursSince);
|
|
209
|
+
if (strength < STRENGTH_FLOOR)
|
|
210
|
+
continue;
|
|
211
|
+
const daysSince = (now.getTime() - new Date(chunk.created_at).getTime()) / (1000 * 60 * 60 * 24);
|
|
212
|
+
const recency = recencyScore(daysSince);
|
|
213
|
+
scored.push({ chunk, score: searchScore(similarity, strength, recency) });
|
|
214
|
+
}
|
|
215
|
+
scored.sort((a, b) => b.score - a.score);
|
|
216
|
+
const top = scored.slice(0, limit);
|
|
217
|
+
// Retrieval boost
|
|
218
|
+
for (const { chunk } of top) {
|
|
219
|
+
try {
|
|
220
|
+
stmts.touchChunk.run({
|
|
221
|
+
id: chunk.id,
|
|
222
|
+
last_accessed_at: now.toISOString(),
|
|
223
|
+
running_intensity: retrievalBoost(chunk.running_intensity),
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
// Non-fatal
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (top.length === 0) {
|
|
231
|
+
return { content: [{ type: "text", text: "No memories found." }] };
|
|
232
|
+
}
|
|
233
|
+
const lines = top.map((r, i) => `${i + 1}. [${r.chunk.kind}] (score: ${r.score.toFixed(3)}) ${r.chunk.content}`);
|
|
234
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
235
|
+
});
|
|
236
|
+
// ── Tool: forget_memory ──────────────────────────────────────────────
|
|
237
|
+
mcp.tool("forget_memory", "Forget memories matching a description. Embeds the description, finds semantically similar chunks, and hard-deletes them.", {
|
|
238
|
+
agent_id: z.string().describe("Agent namespace for memory isolation"),
|
|
239
|
+
description: z.string().describe("Description of what to forget"),
|
|
240
|
+
threshold: z.number().min(0).max(1).default(0.7).describe("Minimum similarity to delete"),
|
|
241
|
+
}, async ({ agent_id, description, threshold }) => {
|
|
242
|
+
const queryEmbedding = await embed(description);
|
|
243
|
+
const allChunks = stmts.getAllActiveChunksByAgent.all(agent_id, 10_000);
|
|
244
|
+
const toDelete = [];
|
|
245
|
+
for (const chunk of allChunks) {
|
|
246
|
+
const sim = cosineSimilarity(queryEmbedding, chunkEmbedding(chunk));
|
|
247
|
+
if (sim >= threshold) {
|
|
248
|
+
toDelete.push(chunk);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
if (toDelete.length === 0) {
|
|
252
|
+
return { content: [{ type: "text", text: "No matching memories found to forget." }] };
|
|
253
|
+
}
|
|
254
|
+
db.transaction(() => {
|
|
255
|
+
for (const chunk of toDelete) {
|
|
256
|
+
stmts.clearSupersededBy.run(chunk.id, agent_id);
|
|
257
|
+
stmts.deleteChunk.run(chunk.id);
|
|
258
|
+
}
|
|
259
|
+
})();
|
|
260
|
+
const lines = toDelete.map((c) => `- [${c.kind}] ${c.content}`);
|
|
261
|
+
return {
|
|
262
|
+
content: [
|
|
263
|
+
{ type: "text", text: `Forgot ${toDelete.length} memory(s):\n${lines.join("\n")}` },
|
|
264
|
+
],
|
|
265
|
+
};
|
|
266
|
+
});
|
|
267
|
+
// ── Tool: recall_memory_block ────────────────────────────────────────
|
|
268
|
+
mcp.tool("recall_memory_block", "Read the contents of a named memory block (key-value text buffer like persona, objectives, etc.).", {
|
|
269
|
+
agent_id: z.string().describe("Agent namespace"),
|
|
270
|
+
key: z.string().describe("Block key (e.g. persona, objectives)"),
|
|
271
|
+
}, async ({ agent_id, key }) => {
|
|
272
|
+
const row = stmts.getBlockByKey.get(agent_id, key);
|
|
273
|
+
if (!row) {
|
|
274
|
+
return { content: [{ type: "text", text: `Block "${key}" not found.` }] };
|
|
275
|
+
}
|
|
276
|
+
return { content: [{ type: "text", text: row.value }] };
|
|
277
|
+
});
|
|
278
|
+
// ── Tool: replace_memory_block ───────────────────────────────────────
|
|
279
|
+
mcp.tool("replace_memory_block", "Find and replace text within a named memory block. Returns error if block doesn't exist or text not found.", {
|
|
280
|
+
agent_id: z.string().describe("Agent namespace"),
|
|
281
|
+
key: z.string().describe("Block key"),
|
|
282
|
+
new_text: z.string().describe("Replacement text"),
|
|
283
|
+
old_text: z.string().min(1).describe("Text to find"),
|
|
284
|
+
}, async ({ agent_id, key, new_text, old_text }) => {
|
|
285
|
+
const row = stmts.getBlockByKey.get(agent_id, key);
|
|
286
|
+
if (!row) {
|
|
287
|
+
return {
|
|
288
|
+
content: [{ type: "text", text: `Block "${key}" not found.` }],
|
|
289
|
+
isError: true,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
if (!row.value.includes(old_text)) {
|
|
293
|
+
return {
|
|
294
|
+
content: [{ type: "text", text: `Text not found in block "${key}".` }],
|
|
295
|
+
isError: true,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
const updated = row.value.replace(old_text, new_text);
|
|
299
|
+
stmts.upsertBlock.run({ agent_id, key, updated_at: new Date().toISOString(), value: updated });
|
|
300
|
+
return { content: [{ type: "text", text: `Updated block "${key}".` }] };
|
|
301
|
+
});
|
|
302
|
+
// ── Tool: append_memory_block ────────────────────────────────────────
|
|
303
|
+
mcp.tool("append_memory_block", "Append text to a named memory block. Creates the block if it doesn't exist.", {
|
|
304
|
+
agent_id: z.string().describe("Agent namespace"),
|
|
305
|
+
content: z.string().describe("Text to append"),
|
|
306
|
+
key: z.string().describe("Block key"),
|
|
307
|
+
}, async ({ agent_id, content, key }) => {
|
|
308
|
+
const row = stmts.getBlockByKey.get(agent_id, key);
|
|
309
|
+
const newValue = row ? row.value + content : content;
|
|
310
|
+
stmts.upsertBlock.run({
|
|
311
|
+
agent_id,
|
|
312
|
+
key,
|
|
313
|
+
updated_at: new Date().toISOString(),
|
|
314
|
+
value: newValue,
|
|
315
|
+
});
|
|
316
|
+
const sizeBytes = new TextEncoder().encode(newValue).byteLength;
|
|
317
|
+
let msg = `Appended to block "${key}" (${sizeBytes} bytes).`;
|
|
318
|
+
if (sizeBytes > 100_000) {
|
|
319
|
+
msg += " Warning: block exceeds 100KB.";
|
|
320
|
+
}
|
|
321
|
+
return { content: [{ type: "text", text: msg }] };
|
|
322
|
+
});
|
|
323
|
+
// ── Transport ────────────────────────────────────────────────────────
|
|
324
|
+
if (config.transport === "stdio") {
|
|
325
|
+
const transport = new StdioServerTransport();
|
|
326
|
+
await mcp.connect(transport);
|
|
327
|
+
console.error("Hippo MCP server running on stdio");
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
const transports = new Map();
|
|
331
|
+
const httpServer = createServer(async (req, res) => {
|
|
332
|
+
const url = new URL(req.url ?? "/", `http://${req.headers.host}`);
|
|
333
|
+
// Health check
|
|
334
|
+
if (url.pathname === "/health") {
|
|
335
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
336
|
+
res.end(JSON.stringify({ status: "ok" }));
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
// SSE endpoint — new connections
|
|
340
|
+
if (url.pathname === "/sse" && req.method === "GET") {
|
|
341
|
+
const transport = new SSEServerTransport("/messages", res);
|
|
342
|
+
transports.set(transport.sessionId, transport);
|
|
343
|
+
transport.onclose = () => {
|
|
344
|
+
transports.delete(transport.sessionId);
|
|
345
|
+
};
|
|
346
|
+
await mcp.connect(transport);
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
// Message endpoint — client POSTs to this
|
|
350
|
+
if (url.pathname === "/messages" && req.method === "POST") {
|
|
351
|
+
const sessionId = url.searchParams.get("sessionId");
|
|
352
|
+
if (!sessionId || !transports.has(sessionId)) {
|
|
353
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
354
|
+
res.end(JSON.stringify({ error: "Invalid or missing sessionId" }));
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
// biome-ignore lint/style/noNonNullAssertion: checked in the guard above
|
|
358
|
+
const transport = transports.get(sessionId);
|
|
359
|
+
await transport.handlePostMessage(req, res);
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
res.writeHead(404);
|
|
363
|
+
res.end("Not found");
|
|
364
|
+
});
|
|
365
|
+
httpServer.listen(config.port, () => {
|
|
366
|
+
console.error(`Hippo MCP server listening on http://localhost:${config.port}`);
|
|
367
|
+
console.error(` SSE endpoint: GET /sse`);
|
|
368
|
+
console.error(` Messages: POST /messages?sessionId=<id>`);
|
|
369
|
+
console.error(` Health: GET /health`);
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compute cosine similarity between two Float32Array embeddings.
|
|
3
|
+
*
|
|
4
|
+
* @param a - First embedding vector
|
|
5
|
+
* @param b - Second embedding vector
|
|
6
|
+
* @returns Cosine similarity in range [-1, 1]
|
|
7
|
+
* @throws If vectors have different lengths or are zero-length
|
|
8
|
+
*/
|
|
9
|
+
export declare function cosineSimilarity(a: Float32Array, b: Float32Array): number;
|
|
10
|
+
/**
|
|
11
|
+
* Deserialize embedding BLOB from SQLite into Float32Array.
|
|
12
|
+
*
|
|
13
|
+
* Copies through Uint8Array to guarantee 4-byte alignment.
|
|
14
|
+
* better-sqlite3 typically returns offset-0 Buffers, but the spec
|
|
15
|
+
* doesn't guarantee it and Float32Array requires aligned access.
|
|
16
|
+
*
|
|
17
|
+
* @param buf - Buffer containing raw float32 bytes
|
|
18
|
+
* @returns Float32Array embedding
|
|
19
|
+
*/
|
|
20
|
+
export declare function bufferToEmbedding(buf: Buffer): Float32Array;
|
|
21
|
+
/**
|
|
22
|
+
* Serialize Float32Array to Buffer for SQLite BLOB storage.
|
|
23
|
+
*
|
|
24
|
+
* Creates a copy so the returned Buffer is independent of the source array.
|
|
25
|
+
*
|
|
26
|
+
* @param embedding - Float32Array embedding
|
|
27
|
+
* @returns Buffer for BLOB column
|
|
28
|
+
*/
|
|
29
|
+
export declare function embeddingToBuffer(embedding: Float32Array): Buffer;
|
|
30
|
+
/**
|
|
31
|
+
* Extract and deserialize a chunk's embedding BLOB into Float32Array.
|
|
32
|
+
*
|
|
33
|
+
* Centralizes the Buffer cast from better-sqlite3's runtime type.
|
|
34
|
+
*
|
|
35
|
+
* @param chunk - A chunk row from SQLite
|
|
36
|
+
* @returns Float32Array embedding
|
|
37
|
+
*/
|
|
38
|
+
export declare function chunkEmbedding(chunk: {
|
|
39
|
+
readonly embedding: Buffer;
|
|
40
|
+
}): Float32Array;
|
|
41
|
+
//# sourceMappingURL=similarity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"similarity.d.ts","sourceRoot":"","sources":["../src/similarity.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,GAAG,MAAM,CA4BzE;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAK3D;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,YAAY,GAAG,MAAM,CAEjE;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE;IAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,YAAY,CAElF"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compute cosine similarity between two Float32Array embeddings.
|
|
3
|
+
*
|
|
4
|
+
* @param a - First embedding vector
|
|
5
|
+
* @param b - Second embedding vector
|
|
6
|
+
* @returns Cosine similarity in range [-1, 1]
|
|
7
|
+
* @throws If vectors have different lengths or are zero-length
|
|
8
|
+
*/
|
|
9
|
+
export function cosineSimilarity(a, b) {
|
|
10
|
+
if (a.length !== b.length) {
|
|
11
|
+
throw new Error(`Vector length mismatch: ${a.length} vs ${b.length}`);
|
|
12
|
+
}
|
|
13
|
+
if (a.length === 0) {
|
|
14
|
+
throw new Error("Cannot compute cosine similarity of zero-length vectors");
|
|
15
|
+
}
|
|
16
|
+
let dot = 0;
|
|
17
|
+
let normA = 0;
|
|
18
|
+
let normB = 0;
|
|
19
|
+
for (let i = 0; i < a.length; i++) {
|
|
20
|
+
// biome-ignore lint/style/noNonNullAssertion: loop bounded by length
|
|
21
|
+
const ai = a[i];
|
|
22
|
+
// biome-ignore lint/style/noNonNullAssertion: loop bounded by length
|
|
23
|
+
const bi = b[i];
|
|
24
|
+
dot += ai * bi;
|
|
25
|
+
normA += ai * ai;
|
|
26
|
+
normB += bi * bi;
|
|
27
|
+
}
|
|
28
|
+
const denom = Math.sqrt(normA) * Math.sqrt(normB);
|
|
29
|
+
if (denom === 0) {
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
return dot / denom;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Deserialize embedding BLOB from SQLite into Float32Array.
|
|
36
|
+
*
|
|
37
|
+
* Copies through Uint8Array to guarantee 4-byte alignment.
|
|
38
|
+
* better-sqlite3 typically returns offset-0 Buffers, but the spec
|
|
39
|
+
* doesn't guarantee it and Float32Array requires aligned access.
|
|
40
|
+
*
|
|
41
|
+
* @param buf - Buffer containing raw float32 bytes
|
|
42
|
+
* @returns Float32Array embedding
|
|
43
|
+
*/
|
|
44
|
+
export function bufferToEmbedding(buf) {
|
|
45
|
+
const bytes = new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
46
|
+
return new Float32Array(bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength));
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Serialize Float32Array to Buffer for SQLite BLOB storage.
|
|
50
|
+
*
|
|
51
|
+
* Creates a copy so the returned Buffer is independent of the source array.
|
|
52
|
+
*
|
|
53
|
+
* @param embedding - Float32Array embedding
|
|
54
|
+
* @returns Buffer for BLOB column
|
|
55
|
+
*/
|
|
56
|
+
export function embeddingToBuffer(embedding) {
|
|
57
|
+
return Buffer.copyBytesFrom(embedding);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Extract and deserialize a chunk's embedding BLOB into Float32Array.
|
|
61
|
+
*
|
|
62
|
+
* Centralizes the Buffer cast from better-sqlite3's runtime type.
|
|
63
|
+
*
|
|
64
|
+
* @param chunk - A chunk row from SQLite
|
|
65
|
+
* @returns Float32Array embedding
|
|
66
|
+
*/
|
|
67
|
+
export function chunkEmbedding(chunk) {
|
|
68
|
+
return bufferToEmbedding(chunk.embedding);
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=similarity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"similarity.js","sourceRoot":"","sources":["../src/similarity.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,CAAe,EAAE,CAAe;IAChE,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC,MAAM,OAAO,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;IACvE,CAAC;IACD,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC5E,CAAC;IAED,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,qEAAqE;QACrE,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACjB,qEAAqE;QACrE,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACjB,GAAG,IAAI,EAAE,GAAG,EAAE,CAAC;QACf,KAAK,IAAI,EAAE,GAAG,EAAE,CAAC;QACjB,KAAK,IAAI,EAAE,GAAG,EAAE,CAAC;IAClB,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;QACjB,OAAO,CAAC,CAAC;IACV,CAAC;IAED,OAAO,GAAG,GAAG,KAAK,CAAC;AACpB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC5C,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;IACzE,OAAO,IAAI,YAAY,CACtB,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC,CACzE,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,SAAuB;IACxD,OAAO,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;AACxC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,KAAqC;IACnE,OAAO,iBAAiB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;AAC3C,CAAC"}
|