Compare commits

..

1 Commits

Author SHA1 Message Date
kartik-mem0 0c49e1aa0b chore: remove integration page from the docs 2026-04-20 21:15:23 +05:30
115 changed files with 15439 additions and 5911 deletions
+3
View File
@@ -42,6 +42,9 @@ clean:
test:
hatch run test
test-py-3.9:
hatch run dev_py_3_9:test
test-py-3.10:
hatch run dev_py_3_10:test
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@mem0/cli",
"version": "0.2.4",
"version": "0.2.3",
"description": "The official CLI for mem0 — the memory layer for AI agents",
"type": "module",
"bin": {
+3
View File
@@ -15,6 +15,7 @@ export interface AddOptions {
infer?: boolean;
expires?: string;
categories?: string[];
enableGraph?: boolean;
}
export interface SearchOptions {
@@ -28,6 +29,7 @@ export interface SearchOptions {
keyword?: boolean;
filters?: Record<string, unknown>;
fields?: string[];
enableGraph?: boolean;
}
export interface ListOptions {
@@ -40,6 +42,7 @@ export interface ListOptions {
category?: string;
after?: string;
before?: string;
enableGraph?: boolean;
}
export interface DeleteOptions {
+6 -3
View File
@@ -115,9 +115,10 @@ export class PlatformBackend implements Backend {
if (opts.infer === false) payload.infer = false;
if (opts.expires) payload.expiration_date = opts.expires;
if (opts.categories) payload.categories = opts.categories;
if (opts.enableGraph) payload.enable_graph = true;
payload.source = "CLI";
return (await this._request("POST", "/v3/memories/add/", {
return (await this._request("POST", "/v1/memories/", {
json: payload,
})) as Record<string, unknown>;
}
@@ -175,9 +176,10 @@ export class PlatformBackend implements Backend {
if (opts.rerank) payload.rerank = true;
if (opts.keyword) payload.keyword_search = true;
if (opts.fields) payload.fields = opts.fields;
if (opts.enableGraph) payload.enable_graph = true;
payload.source = "CLI";
const result = (await this._request("POST", "/v3/memories/search/", {
const result = (await this._request("POST", "/v2/memories/search/", {
json: payload,
})) as unknown;
if (Array.isArray(result)) return result;
@@ -225,9 +227,10 @@ export class PlatformBackend implements Backend {
extraFilters: Object.keys(extra).length > 0 ? extra : undefined,
});
if (apiFilters) payload.filters = apiFilters;
if (opts.enableGraph) payload.enable_graph = true;
payload.source = "CLI";
const result = (await this._request("POST", "/v3/memories/", {
const result = (await this._request("POST", "/v2/memories/", {
json: payload,
params,
})) as unknown;
+2
View File
@@ -29,6 +29,7 @@ export function cmdConfigShow(opts: { output?: string } = {}): void {
agent_id: config.defaults.agentId || null,
app_id: config.defaults.appId || null,
run_id: config.defaults.runId || null,
enable_graph: config.defaults.enableGraph,
},
platform: {
api_key: redactKey(config.platform.apiKey),
@@ -55,6 +56,7 @@ export function cmdConfigShow(opts: { output?: string } = {}): void {
]);
table.push(["defaults.app_id", config.defaults.appId || dim("(not set)")]);
table.push(["defaults.run_id", config.defaults.runId || dim("(not set)")]);
table.push(["defaults.enable_graph", String(config.defaults.enableGraph)]);
table.push(["", ""]);
// Platform
+6
View File
@@ -49,6 +49,7 @@ export async function cmdAdd(
noInfer: boolean;
expires?: string;
categories?: string;
enableGraph: boolean;
output: string;
},
): Promise<void> {
@@ -139,6 +140,7 @@ export async function cmdAdd(
infer: !opts.noInfer,
expires: opts.expires,
categories: cats,
enableGraph: opts.enableGraph,
});
});
} catch (e) {
@@ -223,6 +225,7 @@ export async function cmdSearch(
keyword: boolean;
filterJson?: string;
fields?: string;
enableGraph: boolean;
output: string;
},
): Promise<void> {
@@ -271,6 +274,7 @@ export async function cmdSearch(
keyword: opts.keyword,
filters,
fields: fieldList,
enableGraph: opts.enableGraph,
});
});
} catch (e) {
@@ -364,6 +368,7 @@ export async function cmdList(
category?: string;
after?: string;
before?: string;
enableGraph: boolean;
output: string;
},
): Promise<void> {
@@ -391,6 +396,7 @@ export async function cmdList(
category: opts.category,
after: opts.after,
before: opts.before,
enableGraph: opts.enableGraph,
});
});
} catch (e) {
+13
View File
@@ -28,6 +28,7 @@ export interface DefaultsConfig {
agentId: string;
appId: string;
runId: string;
enableGraph: boolean;
}
export interface TelemetryConfig {
@@ -49,6 +50,7 @@ export function createDefaultConfig(): Mem0Config {
agentId: "",
appId: "",
runId: "",
enableGraph: false,
},
platform: {
apiKey: "",
@@ -85,6 +87,8 @@ export function loadConfig(): Mem0Config {
config.defaults.agentId = defaults.agent_id ?? "";
config.defaults.appId = defaults.app_id ?? "";
config.defaults.runId = defaults.run_id ?? "";
config.defaults.enableGraph = defaults.enable_graph ?? false;
const telemetry = data.telemetry ?? {};
config.telemetry.anonymousId = telemetry.anonymous_id ?? "";
}
@@ -100,6 +104,12 @@ export function loadConfig(): Mem0Config {
config.defaults.agentId = process.env.MEM0_AGENT_ID;
if (process.env.MEM0_APP_ID) config.defaults.appId = process.env.MEM0_APP_ID;
if (process.env.MEM0_RUN_ID) config.defaults.runId = process.env.MEM0_RUN_ID;
if (process.env.MEM0_ENABLE_GRAPH) {
config.defaults.enableGraph = ["true", "1", "yes"].includes(
process.env.MEM0_ENABLE_GRAPH.toLowerCase(),
);
}
return config;
}
@@ -113,6 +123,7 @@ export function saveConfig(config: Mem0Config): void {
agent_id: config.defaults.agentId,
app_id: config.defaults.appId,
run_id: config.defaults.runId,
enable_graph: config.defaults.enableGraph,
},
platform: {
api_key: config.platform.apiKey,
@@ -143,6 +154,7 @@ const KEY_MAP: Record<string, [keyof Mem0Config, string]> = {
"defaults.agent_id": ["defaults", "agentId"],
"defaults.app_id": ["defaults", "appId"],
"defaults.run_id": ["defaults", "runId"],
"defaults.enable_graph": ["defaults", "enableGraph"],
// Short-form aliases
api_key: ["platform", "apiKey"],
base_url: ["platform", "baseUrl"],
@@ -151,6 +163,7 @@ const KEY_MAP: Record<string, [keyof Mem0Config, string]> = {
agent_id: ["defaults", "agentId"],
app_id: ["defaults", "appId"],
run_id: ["defaults", "runId"],
enable_graph: ["defaults", "enableGraph"],
};
export function getNestedValue(config: Mem0Config, dottedKey: string): unknown {
+24 -1
View File
@@ -134,6 +134,18 @@ function resolveIds(
};
}
/**
* Resolve graph tri-state: --no-graph > --graph > config default.
*/
function resolveGraph(
config: Mem0Config,
opts: { graph?: boolean; noGraph?: boolean },
): boolean {
if (opts.noGraph) return false;
if (opts.graph) return true;
return config.defaults.enableGraph;
}
// ── Main program ──────────────────────────────────────────────────────────
program
@@ -224,6 +236,8 @@ program
.option("--no-infer", "Skip inference, store raw.")
.option("--expires <date>", "Expiration date (YYYY-MM-DD).")
.option("--categories <value>", "Categories (JSON array or comma-separated).")
.option("--graph", "Enable graph memory extraction.", false)
.option("--no-graph", "Disable graph memory extraction.")
.option("-o, --output <format>", "Output format: text, json, quiet.", "text")
.option("--api-key <key>", "Override API key.")
.option("--base-url <url>", "Override API base URL.")
@@ -239,8 +253,9 @@ program
opts.baseUrl,
);
const ids = resolveIds(config, opts);
const enableGraph = resolveGraph(config, opts);
const output = isAgent ? "agent" : opts.output;
await cmdAdd(backend, text, { ...ids, ...opts, output });
await cmdAdd(backend, text, { ...ids, ...opts, enableGraph, output });
});
// ── Memory: search ────────────────────────────────────────────────────────
@@ -270,6 +285,8 @@ program
.option("--keyword", "Use keyword search.", false)
.option("--filter <json>", "Advanced filter expression (JSON).")
.option("--fields <list>", "Specific fields to return (comma-separated).")
.option("--graph", "Enable graph in search.", false)
.option("--no-graph", "Disable graph in search.")
.option("-o, --output <format>", "Output: text, json, table.", "text")
.option("--api-key <key>", "Override API key.")
.option("--base-url <url>", "Override API base URL.")
@@ -293,6 +310,7 @@ program
opts.baseUrl,
);
const ids = resolveIds(config, opts);
const enableGraph = resolveGraph(config, opts);
const output = isAgent ? "agent" : opts.output;
await cmdSearch(backend, resolvedQuery, {
...ids,
@@ -302,6 +320,7 @@ program
keyword: opts.keyword,
filterJson: opts.filter,
fields: opts.fields,
enableGraph,
output,
});
});
@@ -345,6 +364,8 @@ program
.option("--category <name>", "Filter by category.")
.option("--after <date>", "Created after (YYYY-MM-DD).")
.option("--before <date>", "Created before (YYYY-MM-DD).")
.option("--graph", "Enable graph in listing.", false)
.option("--no-graph", "Disable graph in listing.")
.option("-o, --output <format>", "Output: text, json, table.", "table")
.option("--api-key <key>", "Override API key.")
.option("--base-url <url>", "Override API base URL.")
@@ -360,6 +381,7 @@ program
opts.baseUrl,
);
const ids = resolveIds(config, opts);
const enableGraph = resolveGraph(config, opts);
const output = isAgent ? "agent" : opts.output;
await cmdList(backend, {
...ids,
@@ -368,6 +390,7 @@ program
category: opts.category,
after: opts.after,
before: opts.before,
enableGraph,
output,
});
});
+6 -6
View File
@@ -107,22 +107,22 @@ describe("CLI Integration — help and version", () => {
expect(result.exitCode).toBe(0);
});
it("add help has --output flag", () => {
it("add help has --graph flag", () => {
const result = run(["add", "--help"]);
expect(result.exitCode).toBe(0);
expect(result.stdout).toContain("--output");
expect(result.stdout).toContain("--graph");
});
it("search help has --rerank flag", () => {
it("search help has --graph flag", () => {
const result = run(["search", "--help"]);
expect(result.exitCode).toBe(0);
expect(result.stdout).toContain("--rerank");
expect(result.stdout).toContain("--graph");
});
it("list help has --category flag", () => {
it("list help has --graph flag", () => {
const result = run(["list", "--help"]);
expect(result.exitCode).toBe(0);
expect(result.stdout).toContain("--category");
expect(result.stdout).toContain("--graph");
});
});
+15 -15
View File
@@ -42,7 +42,7 @@ describe("cmdAdd", () => {
userId: "alice",
immutable: false,
noInfer: false,
enableGraph: false,
output: "text",
});
expect(mockBackend.add).toHaveBeenCalledOnce();
@@ -55,7 +55,7 @@ describe("cmdAdd", () => {
messages: JSON.stringify([{ role: "user", content: "I love Python" }]),
immutable: false,
noInfer: false,
enableGraph: false,
output: "text",
});
expect(mockBackend.add).toHaveBeenCalledOnce();
@@ -67,7 +67,7 @@ describe("cmdAdd", () => {
userId: "alice",
immutable: false,
noInfer: false,
enableGraph: false,
output: "json",
});
expect(output).toContain("results");
@@ -79,7 +79,7 @@ describe("cmdAdd", () => {
userId: "alice",
immutable: false,
noInfer: false,
enableGraph: false,
output: "quiet",
});
expect(output).not.toContain("dark mode");
@@ -101,7 +101,7 @@ describe("cmdAdd deduplicates PENDING", () => {
userId: "alice",
immutable: false,
noInfer: false,
enableGraph: false,
output: "text",
});
expect(output.match(/Queued/g)?.length).toBe(1);
@@ -114,7 +114,7 @@ describe("cmdAdd deduplicates PENDING", () => {
userId: "alice",
immutable: false,
noInfer: false,
enableGraph: false,
output: "json",
});
const data = JSON.parse(output);
@@ -130,7 +130,7 @@ describe("cmdAdd deduplicates PENDING", () => {
userId: "alice",
immutable: false,
noInfer: false,
enableGraph: false,
output: "agent",
});
const data = JSON.parse(output);
@@ -148,7 +148,7 @@ describe("cmdSearch", () => {
threshold: 0.3,
rerank: false,
keyword: false,
enableGraph: false,
output: "text",
});
expect(output).toContain("Found 2");
@@ -162,7 +162,7 @@ describe("cmdSearch", () => {
threshold: 0.3,
rerank: false,
keyword: false,
enableGraph: false,
output: "json",
});
expect(output).toContain("memory");
@@ -177,7 +177,7 @@ describe("cmdSearch", () => {
threshold: 0.3,
rerank: false,
keyword: false,
enableGraph: false,
output: "text",
});
expect(errOutput).toContain("No memories found");
@@ -205,7 +205,7 @@ describe("cmdList", () => {
userId: "alice",
page: 1,
pageSize: 100,
enableGraph: false,
output: "table",
});
expect(output).toContain("dark mode");
@@ -218,7 +218,7 @@ describe("cmdList", () => {
userId: "alice",
page: 1,
pageSize: 100,
enableGraph: false,
output: "text",
});
expect(errOutput).toContain("No memories found");
@@ -316,7 +316,7 @@ describe("agent mode", () => {
userId: "alice",
immutable: false,
noInfer: false,
enableGraph: false,
output: "agent",
});
const parsed = JSON.parse(output.trim());
@@ -336,7 +336,7 @@ describe("agent mode", () => {
threshold: 0.3,
rerank: false,
keyword: false,
enableGraph: false,
output: "agent",
});
const parsed = JSON.parse(output.trim());
@@ -361,7 +361,7 @@ describe("agent mode", () => {
userId: "alice",
page: 1,
pageSize: 100,
enableGraph: false,
output: "agent",
});
const parsed = JSON.parse(output.trim());
+6
View File
@@ -64,6 +64,7 @@ describe("createDefaultConfig", () => {
expect(config.platform.baseUrl).toBe("https://api.mem0.ai");
expect(config.platform.apiKey).toBe("");
expect(config.defaults.userId).toBe("");
expect(config.defaults.enableGraph).toBe(false);
});
});
@@ -104,4 +105,9 @@ describe("setNestedValue", () => {
expect(config.defaults.userId).toBe("bob");
});
it("coerces boolean for enable_graph", () => {
const config = createDefaultConfig();
expect(setNestedValue(config, "defaults.enable_graph", "true")).toBe(true);
expect(config.defaults.enableGraph).toBe(true);
});
});
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "mem0-cli"
version = "0.2.4"
version = "0.2.3"
description = "The official CLI for mem0 — the memory layer for AI agents"
readme = "README.md"
license = "Apache-2.0"
+1 -1
View File
@@ -1,3 +1,3 @@
"""mem0 CLI — the command-line interface for the mem0 memory layer."""
__version__ = "0.2.4"
__version__ = "0.2.3"
+38
View File
@@ -267,6 +267,8 @@ def add(
categories: str | None = typer.Option(
None, "--categories", help="Categories (JSON array or comma-separated)."
),
graph: bool = typer.Option(False, "--graph", help="Enable graph memory extraction."),
no_graph: bool = typer.Option(False, "--no-graph", help="Disable graph memory extraction."),
output: str = typer.Option(
"text", "--output", "-o", help="Output format: text, json, quiet.", rich_help_panel="Output"
),
@@ -293,6 +295,13 @@ def add(
backend, config = _get_backend_and_config(api_key, base_url)
ids = _resolve_ids(config, user_id=user_id, agent_id=agent_id, app_id=app_id, run_id=run_id)
if no_graph:
graph_enabled = False
elif graph:
graph_enabled = True
else:
graph_enabled = config.defaults.enable_graph
cmd_add(
backend,
text,
@@ -304,6 +313,7 @@ def add(
no_infer=no_infer,
expires=expires,
categories=categories,
enable_graph=graph_enabled,
output=output,
)
@@ -347,6 +357,12 @@ def search(
help="Specific fields to return (comma-separated).",
rich_help_panel="Search",
),
graph: bool = typer.Option(
False, "--graph", help="Enable graph in search.", rich_help_panel="Search"
),
no_graph: bool = typer.Option(
False, "--no-graph", help="Disable graph in search.", rich_help_panel="Search"
),
output: str = typer.Option(
"text", "--output", "-o", help="Output: text, json, table.", rich_help_panel="Output"
),
@@ -380,6 +396,13 @@ def search(
backend, config = _get_backend_and_config(api_key, base_url)
ids = _resolve_ids(config, user_id=user_id, agent_id=agent_id, app_id=app_id, run_id=run_id)
if no_graph:
graph_enabled = False
elif graph:
graph_enabled = True
else:
graph_enabled = config.defaults.enable_graph
cmd_search(
backend,
query,
@@ -390,6 +413,7 @@ def search(
keyword=keyword,
filter_json=filter_json,
fields=fields,
enable_graph=graph_enabled,
output=output,
)
@@ -456,6 +480,12 @@ def list_cmd(
before: str | None = typer.Option(
None, "--before", help="Created before (YYYY-MM-DD).", rich_help_panel="Filters"
),
graph: bool = typer.Option(
False, "--graph", help="Enable graph in listing.", rich_help_panel="Filters"
),
no_graph: bool = typer.Option(
False, "--no-graph", help="Disable graph in listing.", rich_help_panel="Filters"
),
output: str = typer.Option(
"table", "--output", "-o", help="Output: text, json, table.", rich_help_panel="Output"
),
@@ -481,6 +511,13 @@ def list_cmd(
backend, config = _get_backend_and_config(api_key, base_url)
ids = _resolve_ids(config, user_id=user_id, agent_id=agent_id, app_id=app_id, run_id=run_id)
if no_graph:
graph_enabled = False
elif graph:
graph_enabled = True
else:
graph_enabled = config.defaults.enable_graph
cmd_list(
backend,
**ids,
@@ -489,6 +526,7 @@ def list_cmd(
category=category,
after=after,
before=before,
enable_graph=graph_enabled,
output=output,
)
+3
View File
@@ -26,6 +26,7 @@ class Backend(ABC):
infer: bool = True,
expires: str | None = None,
categories: list[str] | None = None,
enable_graph: bool = False,
) -> dict: ...
@abstractmethod
@@ -43,6 +44,7 @@ class Backend(ABC):
keyword: bool = False,
filters: dict | None = None,
fields: list[str] | None = None,
enable_graph: bool = False,
) -> list[dict]: ...
@abstractmethod
@@ -61,6 +63,7 @@ class Backend(ABC):
category: str | None = None,
after: str | None = None,
before: str | None = None,
enable_graph: bool = False,
) -> list[dict]: ...
@abstractmethod
+14 -5
View File
@@ -64,6 +64,7 @@ class PlatformBackend(Backend):
infer: bool = True,
expires: str | None = None,
categories: list[str] | None = None,
enable_graph: bool = False,
) -> dict:
payload: dict[str, Any] = {}
@@ -90,9 +91,11 @@ class PlatformBackend(Backend):
payload["expiration_date"] = expires
if categories:
payload["categories"] = categories
if enable_graph:
payload["enable_graph"] = True
payload["source"] = "CLI"
return self._request("POST", "/v3/memories/add/", json=payload)
return self._request("POST", "/v1/memories/", json=payload)
def _build_filters(
self,
@@ -103,7 +106,7 @@ class PlatformBackend(Backend):
run_id: str | None = None,
extra_filters: dict | None = None,
) -> dict | None:
"""Build a filters dict for v3 API endpoints.
"""Build a filters dict for v2 API endpoints.
Entity IDs are ANDed (all provided IDs must match).
Extra filters (date ranges, categories) are also ANDed.
@@ -149,6 +152,7 @@ class PlatformBackend(Backend):
keyword: bool = False,
filters: dict | None = None,
fields: list[str] | None = None,
enable_graph: bool = False,
) -> list[dict]:
payload: dict[str, Any] = {"query": query, "top_k": top_k, "threshold": threshold}
@@ -167,9 +171,11 @@ class PlatformBackend(Backend):
payload["keyword_search"] = True
if fields:
payload["fields"] = fields
if enable_graph:
payload["enable_graph"] = True
payload["source"] = "CLI"
result = self._request("POST", "/v3/memories/search/", json=payload)
result = self._request("POST", "/v2/memories/search/", json=payload)
return (
result
if isinstance(result, list)
@@ -191,11 +197,12 @@ class PlatformBackend(Backend):
category: str | None = None,
after: str | None = None,
before: str | None = None,
enable_graph: bool = False,
) -> list[dict]:
payload: dict[str, Any] = {}
params = {"page": str(page), "page_size": str(page_size)}
# Build filters — entity IDs and date filters go inside "filters"
# Build filters for v2 API — entity IDs and date filters go inside "filters"
extra: dict[str, Any] = {}
if category:
extra["categories"] = {"contains": category}
@@ -213,9 +220,11 @@ class PlatformBackend(Backend):
)
if api_filters:
payload["filters"] = api_filters
if enable_graph:
payload["enable_graph"] = True
payload["source"] = "CLI"
result = self._request("POST", "/v3/memories/", json=payload, params=params)
result = self._request("POST", "/v2/memories/", json=payload, params=params)
return (
result
if isinstance(result, list)
@@ -39,6 +39,7 @@ def cmd_config_show(*, output: str = "text") -> None:
"agent_id": config.defaults.agent_id or None,
"app_id": config.defaults.app_id or None,
"run_id": config.defaults.run_id or None,
"enable_graph": config.defaults.enable_graph,
},
"platform": {
"api_key": redact_key(config.platform.api_key),
@@ -72,6 +73,10 @@ def cmd_config_show(*, output: str = "text") -> None:
"defaults.run_id",
config.defaults.run_id or f"[{DIM_COLOR}](not set)[/]",
)
table.add_row(
"defaults.enable_graph",
str(config.defaults.enable_graph).lower(),
)
table.add_row("", "")
# Platform
@@ -62,6 +62,7 @@ def cmd_add(
no_infer: bool,
expires: str | None,
categories: str | None,
enable_graph: bool = False,
output: str = "text",
) -> None:
"""Add a memory."""
@@ -144,6 +145,7 @@ def cmd_add(
infer=not no_infer,
expires=expires,
categories=cats,
enable_graph=enable_graph,
)
except Exception as e:
ts.error_msg = str(e)
@@ -224,6 +226,7 @@ def cmd_search(
keyword: bool,
filter_json: str | None,
fields: str | None,
enable_graph: bool = False,
output: str = "text",
) -> None:
"""Search memories."""
@@ -266,6 +269,7 @@ def cmd_search(
keyword=keyword,
filters=filters,
fields=field_list,
enable_graph=enable_graph,
)
except Exception as e:
print_error(err_console, str(e))
@@ -352,6 +356,7 @@ def cmd_list(
category: str | None,
after: str | None,
before: str | None,
enable_graph: bool = False,
output: str = "table",
) -> None:
"""List memories."""
@@ -380,6 +385,7 @@ def cmd_list(
category=category,
after=after,
before=before,
enable_graph=enable_graph,
)
except Exception as e:
print_error(err_console, str(e))
+9
View File
@@ -36,6 +36,7 @@ class DefaultsConfig:
agent_id: str = ""
app_id: str = ""
run_id: str = ""
enable_graph: bool = False
@dataclass
@@ -59,6 +60,7 @@ SHORT_KEY_ALIASES: dict[str, str] = {
"agent_id": "defaults.agent_id",
"app_id": "defaults.app_id",
"run_id": "defaults.run_id",
"enable_graph": "defaults.enable_graph",
}
@@ -89,6 +91,8 @@ def load_config() -> Mem0Config:
config.defaults.agent_id = defaults.get("agent_id", "")
config.defaults.app_id = defaults.get("app_id", "")
config.defaults.run_id = defaults.get("run_id", "")
config.defaults.enable_graph = defaults.get("enable_graph", False)
telemetry = data.get("telemetry", {})
config.telemetry.anonymous_id = telemetry.get("anonymous_id", "")
@@ -117,6 +121,10 @@ def load_config() -> Mem0Config:
if env_run_id:
config.defaults.run_id = env_run_id
env_graph = os.environ.get("MEM0_ENABLE_GRAPH")
if env_graph:
config.defaults.enable_graph = env_graph.lower() in ("true", "1", "yes")
return config
@@ -131,6 +139,7 @@ def save_config(config: Mem0Config) -> None:
"agent_id": config.defaults.agent_id,
"app_id": config.defaults.app_id,
"run_id": config.defaults.run_id,
"enable_graph": config.defaults.enable_graph,
},
"platform": {
"api_key": config.platform.api_key,
+13 -2
View File
@@ -224,13 +224,24 @@ class TestCLIIsolated:
class TestCLINewFeatures:
"""Tests for MCP parity features: --limit, entities delete."""
"""Tests for MCP parity features: --graph, --limit, entities delete."""
def test_search_help_has_limit(self):
def test_add_help_has_graph(self):
result = _run(["add", "--help"])
assert result.returncode == 0
assert "--graph" in result.stdout
def test_search_help_has_graph_and_limit(self):
result = _run(["search", "--help"])
assert result.returncode == 0
assert "--graph" in result.stdout
assert "--limit" in result.stdout
def test_list_help_has_graph(self):
result = _run(["list", "--help"])
assert result.returncode == 0
assert "--graph" in result.stdout
def test_delete_entity_via_delete_flag(self):
"""delete --entity should appear in help output."""
result = _run(["delete", "--help"])
+79
View File
@@ -997,6 +997,85 @@ class TestEntitiesDeleteCommand:
mock_backend.delete_entities.assert_not_called()
class TestEnableGraph:
def test_add_with_graph(self, mock_backend):
console, _buf = _make_console()
err_console, _err_buf = _make_err_console()
with (
patch("mem0_cli.commands.memory.console", console),
patch("mem0_cli.commands.memory.err_console", err_console),
):
cmd_add(
mock_backend,
"test",
user_id="alice",
agent_id=None,
app_id=None,
run_id=None,
messages=None,
file=None,
metadata=None,
immutable=False,
no_infer=False,
expires=None,
categories=None,
enable_graph=True,
output="text",
)
call_kwargs = mock_backend.add.call_args
assert call_kwargs.kwargs.get("enable_graph") is True
def test_search_with_graph(self, mock_backend):
console, _buf = _make_console()
err_console, _err_buf = _make_err_console()
with (
patch("mem0_cli.commands.memory.console", console),
patch("mem0_cli.commands.memory.err_console", err_console),
):
cmd_search(
mock_backend,
"test",
user_id="alice",
agent_id=None,
app_id=None,
run_id=None,
top_k=10,
threshold=0.3,
rerank=False,
keyword=False,
filter_json=None,
fields=None,
enable_graph=True,
output="text",
)
call_kwargs = mock_backend.search.call_args
assert call_kwargs.kwargs.get("enable_graph") is True
def test_list_with_graph(self, mock_backend):
console, _buf = _make_console()
err_console, _err_buf = _make_err_console()
with (
patch("mem0_cli.commands.memory.console", console),
patch("mem0_cli.commands.memory.err_console", err_console),
):
cmd_list(
mock_backend,
user_id="alice",
agent_id=None,
app_id=None,
run_id=None,
page=1,
page_size=100,
category=None,
after=None,
before=None,
enable_graph=True,
output="table",
)
call_kwargs = mock_backend.list_memories.call_args
assert call_kwargs.kwargs.get("enable_graph") is True
class TestEventCommands:
def test_event_list_table(self, mock_backend):
console, buf = _make_console()
+45
View File
@@ -121,6 +121,46 @@ class TestConfig:
assert config.defaults.agent_id == ""
assert config.defaults.app_id == ""
assert config.defaults.run_id == ""
assert config.defaults.enable_graph is False
def test_enable_graph_save_and_load(self, isolate_config):
config = Mem0Config()
config.defaults.enable_graph = True
save_config(config)
loaded = load_config()
assert loaded.defaults.enable_graph is True
def test_enable_graph_env_var_true(self, isolate_config, monkeypatch):
monkeypatch.setenv("MEM0_ENABLE_GRAPH", "true")
loaded = load_config()
assert loaded.defaults.enable_graph is True
def test_enable_graph_env_var_false(self, isolate_config, monkeypatch):
config = Mem0Config()
config.defaults.enable_graph = True
save_config(config)
monkeypatch.setenv("MEM0_ENABLE_GRAPH", "false")
loaded = load_config()
assert loaded.defaults.enable_graph is False
def test_backward_compat_no_enable_graph_key(self, isolate_config):
"""Old config files without 'enable_graph' key should default to False."""
import json
from mem0_cli.config import CONFIG_FILE, ensure_config_dir
ensure_config_dir()
data = {
"version": 1,
"defaults": {"user_id": "alice"},
"platform": {"api_key": "m0-test", "base_url": "https://api.mem0.ai"},
}
with open(CONFIG_FILE, "w") as f:
json.dump(data, f)
loaded = load_config()
assert loaded.defaults.enable_graph is False
assert loaded.defaults.user_id == "alice"
class TestNestedAccess:
@@ -152,6 +192,11 @@ class TestNestedAccess:
assert set_nested_value(config, "defaults.user_id", "bob")
assert config.defaults.user_id == "bob"
def test_set_defaults_enable_graph(self):
config = Mem0Config()
assert set_nested_value(config, "defaults.enable_graph", "true")
assert config.defaults.enable_graph is True
class TestResolveIds:
def test_cli_flag_overrides_default(self):
-10
View File
@@ -1269,16 +1269,6 @@ See the [TypeScript SDK migration guide](https://docs.mem0.ai/migration/ts-v2-to
<Tab title="CLI">
<Update label="2026-04-22" description="Python v0.2.4 / Node v0.2.4">
**New Features:**
- **V3 API Routes:** Migrated `add`, `search`, and `list` commands from v1/v2 to v3 API endpoints — `POST /v3/memories/add/`, `POST /v3/memories/search/`, `POST /v3/memories/`. Aligns both CLIs with the Python and TypeScript SDKs which already use v3 ([#4916](https://github.com/mem0ai/mem0/pull/4916))
**Breaking Changes:**
- **`--graph` / `--no-graph` removed:** The `enable_graph` config option, `--graph` and `--no-graph` CLI flags, and `MEM0_ENABLE_GRAPH` environment variable have been removed from both CLIs. Graph memory is now a project-level setting on the Platform ([#4916](https://github.com/mem0ai/mem0/pull/4916))
</Update>
<Update label="2026-04-11" description="Python v0.2.3 / Node v0.2.3">
**Bug Fixes:**
@@ -216,7 +216,7 @@ memory.delete_all(user_id="alice")
## Put it into practice
- Review the <Link href="/api-reference/memory/delete-memory">Delete Memory API reference</Link>, plus <Link href="/api-reference/memory/batch-delete">Batch Delete</Link> and <Link href="/api-reference/memory/delete-memories">Filtered Delete</Link>.
- Pair deletes with <Link href="/platform/features/platform-overview">Expiration Policies</Link> to automate retention.
- Pair deletes with <Link href="/platform/features/expiration-date">Expiration Policies</Link> to automate retention.
## See it live
@@ -236,6 +236,6 @@ memory.delete_all(user_id="alice")
title="Enable Expiration Policies"
description="Automate retention with the platform’s expiration feature."
icon="clock"
href="/platform/features/platform-overview"
href="/platform/features/expiration-date"
/>
</CardGroup>
+29 -8
View File
@@ -399,8 +399,6 @@
"integrations/langgraph",
"integrations/llama-index",
"integrations/crewai",
"integrations/autogen",
"integrations/agno",
"integrations/camel-ai",
"integrations/openai-agents-sdk",
"integrations/google-ai-adk",
@@ -429,12 +427,7 @@
"group": "Developer Tools",
"icon": "wrench",
"pages": [
"integrations/dify",
"integrations/flowise",
"integrations/langchain-tools",
"integrations/agentops",
"integrations/keywords",
"integrations/raycast"
"integrations/langchain-tools"
]
}
]
@@ -1101,6 +1094,34 @@
"source": "/v0x/faqs",
"destination": "/platform/faqs"
},
{
"source": "/integrations/raycast",
"destination": "/integrations"
},
{
"source": "/integrations/autogen",
"destination": "/integrations"
},
{
"source": "/integrations/keywords",
"destination": "/integrations"
},
{
"source": "/integrations/agentops",
"destination": "/integrations"
},
{
"source": "/integrations/flowise",
"destination": "/integrations"
},
{
"source": "/integrations/agno",
"destination": "/integrations"
},
{
"source": "/integrations/dify",
"destination": "/integrations"
},
{
"source": "/integrations/multion",
"destination": "/integrations"
-122
View File
@@ -20,23 +20,6 @@ Here are the available integrations for Mem0:
## Integrations
<CardGroup cols={2}>
<Card
title="AgentOps"
icon={
<svg
xmlns="http://www.w3.org/2000/svg"
width="25"
height="26"
viewBox="0 0 30 36"
fill="none"
>
<path d="M10.4659 6.47277C10.45 6.37428 10.4381 6.27986 10.4303 6.18101L10.4285 6.16388C10.4212 6.09482 10.414 6.02566 10.4106 5.95626L1.18538 21.8752C0.505422 23.0493 0.323356 24.4208 0.675227 25.7289C0.849119 26.3869 1.14971 26.9859 1.55323 27.5098C1.95675 28.0338 2.46282 28.4751 3.05175 28.8143C3.83464 29.2675 4.70856 29.5 5.59028 29.5C6.03318 29.5 6.4798 29.4408 6.91899 29.3226C8.23581 28.972 9.3349 28.1326 10.0152 26.9545L15.9268 16.749V16.7449L16.5001 15.7637L17.6431 13.7936L16.5001 11.8234L15.9309 10.8381L15.9268 10.8341L13.7836 7.13406C13.6651 6.933 13.5741 6.72418 13.5109 6.51165C13.2817 5.80223 13.3292 5.04172 13.6097 4.37599L13.8115 4.02535C14.3532 3.09155 15.31 2.53987 16.3184 2.47692C16.3738 2.46915 16.4251 2.46915 16.4804 2.46915C16.5421 2.46915 16.6038 2.47257 16.6654 2.47599L16.6822 2.47692C17.6906 2.53987 18.6474 3.09155 19.1892 4.02535L21.2216 7.52838L21.8146 8.55289L21.8421 8.60399L30.1024 22.8601C30.5174 23.5814 30.6281 24.4167 30.4148 25.2205C30.1975 26.0244 29.6832 26.6942 28.9598 27.1081C28.2364 27.5258 27.3977 27.6361 26.5911 27.4195C25.7844 27.2066 25.1123 26.6905 24.6968 25.9696L18.2119 14.7788L17.069 16.7449L22.9847 26.9545C23.6646 28.1326 24.7641 28.972 26.0809 29.3226C26.5197 29.4408 26.9626 29.5 27.4096 29.5C28.2914 29.5 29.1612 29.2675 29.9482 28.8143C31.1264 28.1367 31.9728 27.0411 32.3247 25.7289C32.6766 24.4208 32.4949 23.0493 31.8145 21.8752L21.1261 3.43034C20.7029 2.51617 20.0033 1.72011 19.0621 1.18027C18.5281 0.877027 17.9708 0.675975 17.3975 0.581189C17.3027 0.565268 17.2076 0.549717 17.1129 0.537868C17.0099 0.52602 16.9074 0.518244 16.8045 0.510469C16.6027 0.498621 16.3972 0.494548 16.1914 0.510469C16.0885 0.518244 15.9859 0.52639 15.883 0.537868C15.795 0.54887 15.7067 0.563384 15.6187 0.577852L15.5984 0.581189C15.0291 0.675605 14.4673 0.876657 13.9375 1.18027C12.9885 1.72789 12.2766 2.53579 11.8537 3.46181C11.7742 3.63473 11.707 3.81282 11.6471 3.99314C11.6361 4.02668 11.6269 4.06051 11.6177 4.09435C11.612 4.11503 11.6064 4.13579 11.6003 4.15642C11.5624 4.28601 11.5275 4.41634 11.4996 4.54853C11.4885 4.60231 11.4794 4.65668 11.4703 4.71111L11.4666 4.73329C11.4443 4.86399 11.4264 4.99543 11.4145 5.12762C11.4093 5.18686 11.4045 5.24573 11.4012 5.30534C11.3934 5.44567 11.3923 5.58637 11.3963 5.72744C11.3969 5.74403 11.3962 5.76062 11.3956 5.7772C11.3949 5.79616 11.3942 5.81512 11.3952 5.83407C11.3952 5.86184 11.3952 5.88924 11.3993 5.92071C11.3998 5.9291 11.4006 5.93736 11.4014 5.94564C11.402 5.95125 11.4026 5.95687 11.403 5.96255C11.4045 5.98181 11.4064 6.00106 11.4082 6.02031C11.4097 6.03577 11.4109 6.05122 11.4122 6.06674C11.4142 6.09134 11.4163 6.11621 11.419 6.14139L11.4428 6.32282C11.4506 6.38983 11.4625 6.46092 11.4744 6.52757C11.5063 6.68863 11.5468 6.84896 11.5936 7.0078C11.5944 7.0102 11.5949 7.0127 11.5955 7.0152C11.5958 7.01662 11.5961 7.01804 11.5965 7.01944C11.5967 7.02051 11.597 7.02157 11.5974 7.02261C11.6483 7.19293 11.7081 7.36177 11.7787 7.52838C11.8619 7.72943 11.9607 7.92641 12.0715 8.11932L12.3245 8.5566V8.56067L12.4984 8.85614L12.7199 9.24232H12.7239L12.728 9.25417L14.7802 12.7927V12.7968L14.7883 12.805V12.809L15.3576 13.7943L14.7883 14.7796L8.30344 25.9703C7.88431 26.6912 7.21216 27.2077 6.40921 27.4202C6.14019 27.4913 5.86338 27.5306 5.59474 27.5306C5.053 27.5306 4.51906 27.3888 4.04085 27.1089C3.31705 26.6953 2.79909 26.0251 2.58581 25.2213C2.36845 24.4174 2.47917 23.5821 2.89829 22.8609L11.1585 8.60473L11.186 8.56141V8.55734C11.1266 8.45478 11.0753 8.35629 11.024 8.25409C11.0105 8.22496 10.9969 8.19611 10.9834 8.16739C10.9458 8.08735 10.9086 8.00836 10.8739 7.92715C10.8718 7.92504 10.8708 7.92194 10.8698 7.91887C10.8688 7.91602 10.8679 7.91319 10.8661 7.91123V7.90346C10.8423 7.8483 10.8186 7.79311 10.7989 7.73795C10.7476 7.60799 10.7041 7.47803 10.6644 7.3477C10.6012 7.15479 10.5536 6.96152 10.518 6.76861C10.4942 6.67012 10.4786 6.5757 10.4667 6.47684C10.4667 6.47684 10.47 6.47684 10.4659 6.47277Z" fill="currentColor"></path>
</svg>
}
href="/integrations/agentops"
>
Monitor and analyze Mem0 operations with comprehensive AI agent analytics and LLM observability.
</Card>
<Card
title="Camel AI"
href="/integrations/camel-ai"
@@ -103,27 +86,6 @@ Here are the available integrations for Mem0:
>
Build RAG applications with LlamaIndex and Mem0.
</Card>
<Card
title="AutoGen"
icon={
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 96 85"
fill="none"
>
<rect width="96" height="85" rx="6" fill="#2D2D2F" />
<path
d="M32.6484 28.7109L23.3672 57H15.8906L28.5703 22.875H33.3281L32.6484 28.7109ZM40.3594 57L31.0547 28.7109L30.3047 22.875H35.1094L47.8594 57H40.3594ZM39.9375 44.2969V49.8047H21.9141V44.2969H39.9375ZM77.6484 39.1641V52.6875C77.1172 53.3281 76.2969 54.0234 75.1875 54.7734C74.0781 55.5078 72.6484 56.1406 70.8984 56.6719C69.1484 57.2031 67.0312 57.4688 64.5469 57.4688C62.3438 57.4688 60.3359 57.1094 58.5234 56.3906C56.7109 55.6562 55.1484 54.5859 53.8359 53.1797C52.5391 51.7734 51.5391 50.0547 50.8359 48.0234C50.1328 45.9766 49.7812 43.6406 49.7812 41.0156V38.8828C49.7812 36.2578 50.1172 33.9219 50.7891 31.875C51.4766 29.8281 52.4531 28.1016 53.7188 26.6953C54.9844 25.2891 56.4922 24.2188 58.2422 23.4844C59.9922 22.75 61.9375 22.3828 64.0781 22.3828C67.0469 22.3828 69.4844 22.8672 71.3906 23.8359C73.2969 24.7891 74.75 26.1172 75.75 27.8203C76.7656 29.5078 77.3906 31.4453 77.625 33.6328H70.8047C70.6328 32.4766 70.3047 31.4688 69.8203 30.6094C69.3359 29.75 68.6406 29.0781 67.7344 28.5938C66.8438 28.1094 65.6875 27.8672 64.2656 27.8672C63.0938 27.8672 62.0469 28.1094 61.125 28.5938C60.2188 29.0625 59.4531 29.7578 58.8281 30.6797C58.2031 31.6016 57.7266 32.7422 57.3984 34.1016C57.0703 35.4609 56.9062 37.0391 56.9062 38.8359V41.0156C56.9062 42.7969 57.0781 44.375 57.4219 45.75C57.7656 47.1094 58.2734 48.2578 58.9453 49.1953C59.6328 50.1172 60.4766 50.8125 61.4766 51.2812C62.4766 51.75 63.6406 51.9844 64.9688 51.9844C66.0781 51.9844 67 51.8906 67.7344 51.7031C68.4844 51.5156 69.0859 51.2891 69.5391 51.0234C70.0078 50.7422 70.3672 50.4766 70.6172 50.2266V44.1797H64.1953V39.1641H77.6484Z"
fill="white"
/>
</svg>
}
href="/integrations/autogen"
>
Build multi-agent systems with persistent memory capabilities.
</Card>
<Card
title="CrewAI"
icon={
@@ -205,26 +167,6 @@ Here are the available integrations for Mem0:
>
Use Mem0 with LangChain Tools for enhanced agent capabilities.
</Card>
<Card
title="Dify"
icon={
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 200 200"
fill="none"
>
<path
d="M40 20 H120 C160 20, 160 180, 120 180 H40 V20"
fill="currentColor"
/>
</svg>
}
href="/integrations/dify"
>
Build AI applications with persistent memory using Dify and Mem0.
</Card>
<Card
title="Livekit"
icon={
@@ -290,63 +232,6 @@ Here are the available integrations for Mem0:
>
Build conversational AI agents with memory using Pipecat.
</Card>
<Card
title="Agno"
icon={
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
>
<path d="M8 4h8v12h8" stroke="currentColor" strokeWidth="2" fill="none" transform="rotate(15, 12, 12)"/>
</svg>
}
href="/integrations/agno"
>
Build autonomous agents with memory using Agno framework.
</Card>
<Card
title="Keywords AI"
icon={
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
>
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.07513 1.1863C9.21663 1.07722 9.39144 1.01009 9.56624 1.01009C9.83261 1.01009 10.0823 1.12756 10.2405 1.33734L15.0101 7.4964V12.4136L16.4335 13.8401C16.7582 14.1673 16.7582 14.7043 16.4335 15.0316C16.1089 15.3588 15.5762 15.3588 15.2515 15.0316L13.3453 13.1016V8.07538L8.92529 2.36944V2.36105C8.64228 2.00024 8.70887 1.4716 9.07513 1.1863ZM18.976 14.4133C18.8344 14.3778 18.7003 14.3042 18.5894 14.1925L16.9163 12.5059C16.7249 12.3129 16.6416 12.0528 16.6749 11.8094V6.88385H16.6499L11.8553 0.691225C11.7282 0.529117 11.6716 0.333133 11.6803 0.140562C11.134 0.0481292 10.5726 0 10 0C4.47715 0 0 4.47715 0 10C0 15.5228 4.47715 20 10 20C13.9387 20 17.3456 17.7229 18.976 14.4133Z" fill="currentColor"></path>
</svg>
}
href="/integrations/keywords"
>
Build AI applications with persistent memory and comprehensive LLM observability.
</Card>
<Card
title="Raycast"
icon={
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
>
<path
d="M3 12L21 12M12 3L12 21M7.5 7.5L16.5 16.5M16.5 7.5L7.5 16.5"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
/>
</svg>
}
href="/integrations/raycast"
>
Mem0 Raycast extension for intelligent memory management and retrieval.
</Card>
<Card
title="Mastra"
icon={
@@ -395,13 +280,6 @@ Here are the available integrations for Mem0:
>
Integrate Mem0 with Google Agent Development Kit for persistent memory across multi-agent workflows.
</Card>
<Card
title="Flowise"
icon="diagram-project"
href="/integrations/flowise"
>
Add persistent Mem0 memory to Flowise chatflows for context-aware conversations in the low-code builder.
</Card>
<Card
title="AWS Bedrock"
icon="cloud"
-175
View File
@@ -1,175 +0,0 @@
---
title: AgentOps
description: "Integrate Mem0 with AgentOps for automatic monitoring, analytics, and real-time tracking of memory operations."
---
Integrate [**Mem0**](https://github.com/mem0ai/mem0) with [AgentOps](https://agentops.ai), a comprehensive monitoring and analytics platform for AI agents. This integration enables automatic tracking and analysis of memory operations, providing insights into agent performance and memory usage patterns.
## Overview
1. Automatic monitoring of Mem0 operations and performance metrics
2. Real-time tracking of memory add, search, and retrieval operations
3. Analytics dashboard with memory usage patterns and insights
4. Error tracking and debugging capabilities for memory operations
## Prerequisites
Before setting up Mem0 with AgentOps, ensure you have:
1. Installed the required packages:
```bash
pip install mem0ai agentops python-dotenv
```
2. Valid API keys:
- [AgentOps API Key](https://app.agentops.ai/dashboard/api-keys)
- OpenAI API Key (for LLM operations)
- <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 API Key</a> (optional, for cloud operations)
## Basic Integration Example
The following example demonstrates how to integrate Mem0 with AgentOps monitoring for comprehensive memory operation tracking:
```python
#Import the required libraries for local memory management with Mem0
from mem0 import Memory, AsyncMemory
import os
import asyncio
import logging
from dotenv import load_dotenv
import agentops
import openai
load_dotenv()
#Set up environment variables for API keys
os.environ["AGENTOPS_API_KEY"] = os.getenv("AGENTOPS_API_KEY")
os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY")
#Set up the configuration for local memory storage and define sample user data.
local_config = {
"llm": {
"provider": "openai",
"config": {
"model": "gpt-5-mini",
"temperature": 0.1,
"max_tokens": 2000,
},
}
}
user_id = "alice_demo"
agent_id = "assistant_demo"
run_id = "session_001"
sample_messages = [
{"role": "user", "content": "I'm planning to watch a movie tonight. Any recommendations?"},
{"role": "assistant", "content": "How about a thriller? They can be quite engaging."},
{"role": "user", "content": "I'm not a big fan of thriller movies but I love sci-fi movies."},
{
"role": "assistant",
"content": "Got it! I'll avoid thriller recommendations and suggest sci-fi movies in the future.",
},
]
sample_preferences = [
"I prefer dark roast coffee over light roast",
"I exercise every morning at 6 AM",
"I'm vegetarian and avoid all meat products",
"I love reading science fiction novels",
"I work in software engineering",
]
#This function demonstrates sequential memory operations using the synchronous Memory class
def demonstrate_sync_memory(local_config, sample_messages, sample_preferences, user_id):
"""
Demonstrate synchronous Memory class operations.
"""
agentops.start_trace("mem0_memory_example", tags=["mem0_memory_example"])
try:
memory = Memory.from_config(local_config)
result = memory.add(
sample_messages, user_id=user_id, metadata={"category": "movie_preferences", "session": "demo"}
)
for i, preference in enumerate(sample_preferences):
result = memory.add(preference, user_id=user_id, metadata={"type": "preference", "index": i})
search_queries = [
"What movies does the user like?",
"What are the user's food preferences?",
"When does the user exercise?",
]
for query in search_queries:
results = memory.search(query, filters={"user_id": user_id})
if results and "results" in results:
for j, result in enumerate(results['results']):
print(f"Result {j+1}: {result.get('memory', 'N/A')}")
else:
print("No results found")
all_memories = memory.get_all(filters={"user_id": user_id})
if all_memories and "results" in all_memories:
print(f"Total memories: {len(all_memories['results'])}")
delete_all_result = memory.delete_all(user_id=user_id)
print(f"Delete all result: {delete_all_result}")
agentops.end_trace(end_state="success")
except Exception as e:
agentops.end_trace(end_state="error")
# Execute sync demonstrations
demonstrate_sync_memory(local_config, sample_messages, sample_preferences, user_id)
```
For detailed information on this integration, refer to the official [Agentops Mem0 integration documentation](https://docs.agentops.ai/v2/integrations/mem0).
## Key Features
### 1. Automatic Operation Tracking
AgentOps automatically monitors all Mem0 operations:
- **Memory Operations**: Track add, search, get_all, delete operations and much more
- **Performance Metrics**: Monitor response times and success rates
- **Error Tracking**: Capture and analyze operation failures
### 2. Real-time Analytics Dashboard
Access comprehensive analytics through the AgentOps dashboard:
- **Usage Patterns**: Visualize memory usage trends over time
- **User Behavior**: Analyze how different users interact with memory
- **Performance Insights**: Identify bottlenecks and optimization opportunities
### 3. Session Management
Organize your monitoring with structured sessions:
- **Session Tracking**: Group related operations into logical sessions
- **Success/Failure Rates**: Track session outcomes for reliability monitoring
- **Custom Metadata**: Add context to sessions for better analysis
## Best Practices
1. **Initialize Early**: Always initialize AgentOps before importing Mem0 classes
2. **Session Management**: Use meaningful session names and end sessions appropriately
3. **Error Handling**: Wrap operations in try-catch blocks and report failures
4. **Tagging**: Use tags to organize different types of memory operations
5. **Environment Separation**: Use different projects or tags for dev/staging/prod
<CardGroup cols={2}>
<Card title="CrewAI Integration" icon="users" href="/integrations/crewai">
Monitor multi-agent CrewAI systems
</Card>
<Card title="LangChain Integration" icon="link" href="/integrations/langchain">
Track LangChain agent performance
</Card>
</CardGroup>
-207
View File
@@ -1,207 +0,0 @@
---
title: Agno
description: "Add persistent multimodal memory to Agno-based agents using Mem0 for text and image interactions."
---
This integration of [**Mem0**](https://github.com/mem0ai/mem0) with [Agno](https://github.com/agno-agi/agno) enables persistent, multimodal memory for Agno-based agents - improving personalization, context awareness, and continuity across conversations.
## Overview
1. Store and retrieve memories from Mem0 within Agno agents
2. Support for multimodal interactions (text and images)
3. Semantic search for relevant past conversations
4. Personalized responses based on user history
5. One-line memory integration via `Mem0Tools`
## Prerequisites
Before setting up Mem0 with Agno, ensure you have:
1. Installed the required packages:
```bash
pip install agno mem0ai python-dotenv
```
2. Valid API keys:
- <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 API Key</a>
- OpenAI API Key (for the agent model)
## Quick Integration (Using `Mem0Tools`)
The simplest way to integrate Mem0 with Agno Agents is to use Mem0 as a tool using built-in `Mem0Tools`:
```python
from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.tools.mem0 import Mem0Tools
agent = Agent(
name="Memory Agent",
model=OpenAIChat(id="gpt-5-mini"),
tools=[Mem0Tools()],
description="An assistant that remembers and personalizes using Mem0 memory."
)
```
This enables memory functionality out of the box:
- **Persistent memory writing**: `Mem0Tools` uses `MemoryClient.add(...)` to store messages from user-agent interactions, including optional metadata such as user ID or session.
- **Contextual memory search**: Compatible queries use `MemoryClient.search(...)` to retrieve relevant past messages, improving contextual understanding.
- **Multimodal support**: Both text and image inputs are supported, allowing richer memory records.
> `Mem0Tools` uses the `MemoryClient` under the hood and requires no additional setup. You can customize its behavior by modifying your tools list or extending it in code.
## Full Manual Example
> Note: Mem0 can also be used with Agno Agents as a separate memory layer.
The following example demonstrates how to create an Agno agent with Mem0 memory integration, including support for image processing:
```python
import base64
from pathlib import Path
from typing import Optional
from agno.agent import Agent
from agno.media import Image
from agno.models.openai import OpenAIChat
from mem0 import MemoryClient
# Initialize the Mem0 client
client = MemoryClient()
# Define the agent
agent = Agent(
name="Personal Agent",
model=OpenAIChat(id="gpt-4"),
description="You are a helpful personal agent that helps me with day to day activities."
"You can process both text and images.",
markdown=True
)
def chat_user(
user_input: Optional[str] = None,
user_id: str = "alex",
image_path: Optional[str] = None
) -> str:
"""
Handle user input with memory integration, supporting both text and images.
Args:
user_input: The user's text input
user_id: Unique identifier for the user
image_path: Path to an image file if provided
Returns:
The agent's response as a string
"""
if image_path:
# Convert image to base64
with open(image_path, "rb") as image_file:
base64_image = base64.b64encode(image_file.read()).decode("utf-8")
# Create message objects for text and image
messages = []
if user_input:
messages.append({
"role": "user",
"content": user_input
})
messages.append({
"role": "user",
"content": {
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{base64_image}"
}
}
})
# Store messages in memory
client.add(messages, user_id=user_id)
print("✅ Image and text stored in memory.")
if user_input:
# Search for relevant memories
memories = client.search(user_input, filters={"user_id": user_id})
memory_context = "\n".join(f"- {m['memory']}" for m in memories['results'])
# Construct the prompt
prompt = f"""
You are a helpful personal assistant who helps users with their day-to-day activities and keeps track of everything.
Your task is to:
1. Analyze the given image (if present) and extract meaningful details to answer the user's question.
2. Use your past memory of the user to personalize your answer.
3. Combine the image content and memory to generate a helpful, context-aware response.
Here is what I remember about the user:
{memory_context}
User question:
{user_input}
"""
# Get response from agent
if image_path:
response = agent.run(prompt, images=[Image(filepath=Path(image_path))])
else:
response = agent.run(prompt)
# Store the interaction in memory
interaction_message = [{"role": "user", "content": f"User: {user_input}\nAssistant: {response.content}"}]
client.add(interaction_message, user_id=user_id)
return response.content
return "No user input or image provided."
# Example Usage
if __name__ == "__main__":
response = chat_user(
"I like to travel and my favorite destination is London",
image_path="travel_items.jpeg",
user_id="alex"
)
print(response)
```
## Key Features
### 1. Multimodal Memory Storage
The integration supports storing both text and image data:
- **Text Storage**: Conversation history is saved in a structured format
- **Image Analysis**: Agents can analyze images and store visual information
- **Combined Context**: Memory retrieval combines both text and visual data
### 2. Personalized Agent Responses
Improve your agent's context awareness:
- **Memory Retrieval**: Semantic search finds relevant past interactions
- **User Preferences**: Personalize responses based on stored user information
- **Continuity**: Maintain conversation threads across multiple sessions
### 3. Flexible Configuration
Customize the integration to your needs:
- **Use `Mem0Tools()`** for drop-in memory support
- **Use `MemoryClient` directly** for advanced control
- **User Identification**: Organize memories by user ID
- **Memory Search**: Configure search relevance and result count
- **Memory Formatting**: Support for various OpenAI message formats
<CardGroup cols={2}>
<Card title="OpenAI Agents SDK" icon="cube" href="/integrations/openai-agents-sdk">
Build agents with OpenAI SDK and Mem0
</Card>
<Card title="Mastra Integration" icon="star" href="/integrations/mastra">
Create intelligent agents with Mastra framework
</Card>
</CardGroup>
-142
View File
@@ -1,142 +0,0 @@
---
title: AutoGen
description: "Build conversational AI agents with AutoGen and Mem0 for context-aware, personalized interactions."
---
Build conversational AI agents with memory capabilities. This integration combines AutoGen for creating AI agents with Mem0 for memory management, enabling context-aware and personalized interactions.
## Overview
This guide demonstrates creating a conversational AI system with memory. We'll build a customer service bot that can recall previous interactions and provide personalized responses.
## Setup and Configuration
Install necessary libraries:
```bash
pip install autogen mem0ai openai python-dotenv
```
First, we'll import the necessary libraries and set up our configurations.
<Note>Remember to get the Mem0 API key from <a href="https://app.mem0.ai" rel="nofollow">Mem0 Platform</a>.</Note>
```python
import os
from autogen import ConversableAgent
from mem0 import MemoryClient
from openai import OpenAI
from dotenv import load_dotenv
load_dotenv()
# Configuration
# OPENAI_API_KEY = 'sk-xxx' # Replace with your actual OpenAI API key
# MEM0_API_KEY = 'your-mem0-key' # Replace with your actual Mem0 API key from https://app.mem0.ai
USER_ID = "alice"
# Set up OpenAI API key
OPENAI_API_KEY = os.environ.get('OPENAI_API_KEY')
# os.environ['MEM0_API_KEY'] = MEM0_API_KEY
# Initialize Mem0 and AutoGen agents
memory_client = MemoryClient()
agent = ConversableAgent(
"chatbot",
llm_config={"config_list": [{"model": "gpt-4", "api_key": OPENAI_API_KEY}]},
code_execution_config=False,
human_input_mode="NEVER",
)
```
## Storing Conversations in Memory
Add conversation history to Mem0 for future reference:
```python
conversation = [
{"role": "assistant", "content": "Hi, I'm Best Buy's chatbot! How can I help you?"},
{"role": "user", "content": "I'm seeing horizontal lines on my TV."},
{"role": "assistant", "content": "I'm sorry to hear that. Can you provide your TV model?"},
{"role": "user", "content": "It's a Sony - 77\" Class BRAVIA XR A80K OLED 4K UHD Smart Google TV"},
{"role": "assistant", "content": "Thank you for the information. Let's troubleshoot this issue..."}
]
memory_client.add(messages=conversation, user_id=USER_ID)
print("Conversation added to memory.")
```
## Retrieving and Using Memory
Create a function to get context-aware responses based on user's question and previous interactions:
```python
def get_context_aware_response(question):
relevant_memories = memory_client.search(question, filters={"user_id": USER_ID})
context = "\n".join([m["memory"] for m in relevant_memories.get('results', [])])
prompt = f"""Answer the user question considering the previous interactions:
Previous interactions:
{context}
Question: {question}
"""
reply = agent.generate_reply(messages=[{"content": prompt, "role": "user"}])
return reply
# Example usage
question = "What was the issue with my TV?"
answer = get_context_aware_response(question)
print("Context-aware answer:", answer)
```
## Multi-Agent Conversation
For more complex scenarios, you can create multiple agents:
```python
manager = ConversableAgent(
"manager",
system_message="You are a manager who helps in resolving complex customer issues.",
llm_config={"config_list": [{"model": "gpt-4", "api_key": OPENAI_API_KEY}]},
human_input_mode="NEVER"
)
def escalate_to_manager(question):
relevant_memories = memory_client.search(question, filters={"user_id": USER_ID})
context = "\n".join([m["memory"] for m in relevant_memories.get('results', [])])
prompt = f"""
Context from previous interactions:
{context}
Customer question: {question}
As a manager, how would you address this issue?
"""
manager_response = manager.generate_reply(messages=[{"content": prompt, "role": "user"}])
return manager_response
# Example usage
complex_question = "I'm not satisfied with the troubleshooting steps. What else can be done?"
manager_answer = escalate_to_manager(complex_question)
print("Manager's response:", manager_answer)
```
## Conclusion
By integrating AutoGen with Mem0, you've created a conversational AI system with memory capabilities. This example demonstrates a customer service bot that can recall previous interactions and provide context-aware responses, with the ability to escalate complex issues to a manager agent.
This integration enables the creation of more intelligent and personalized AI agents for various applications, such as customer support, virtual assistants, and interactive chatbots.
<CardGroup cols={2}>
<Card title="CrewAI Integration" icon="users" href="/integrations/crewai">
Build multi-agent systems with CrewAI and Mem0
</Card>
<Card title="LangGraph Integration" icon="diagram-project" href="/integrations/langgraph">
Create stateful workflows with LangGraph
</Card>
</CardGroup>
+2 -2
View File
@@ -237,7 +237,7 @@ By adding Mem0 as a memory store in ChatDev, your multi-agent workflows gain per
<Card title="CrewAI Integration" icon="users" href="/integrations/crewai">
Build multi-agent systems with CrewAI and Mem0
</Card>
<Card title="AutoGen Integration" icon="robot" href="/integrations/autogen">
Build conversational agents with AutoGen and Mem0
<Card title="OpenAI Agents SDK" icon="robot" href="/integrations/openai-agents-sdk">
Build conversational agents with OpenAI Agents SDK and Mem0
</Card>
</CardGroup>
+5 -12
View File
@@ -32,19 +32,12 @@ export MEM0_API_KEY="m0-your-api-key"
### Option A — Plugin Marketplace (Recommended)
Install the full plugin including MCP server, lifecycle hooks, and SDK skill.
Install the full plugin including MCP server, lifecycle hooks, and SDK skill:
1. Add the Mem0 marketplace:
```
/plugin marketplace add mem0ai/mem0
```
2. Install the plugin:
```
/plugin install mem0@mem0-plugins
```
```
/plugin marketplace add mem0ai/mem0
/plugin install mem0@mem0-plugins
```
**Claude Cowork desktop app:** Open the Cowork tab, click **Customize** in the sidebar, click **Browse plugins**, and install Mem0.
+2 -2
View File
@@ -162,8 +162,8 @@ if __name__ == "__main__":
By combining CrewAI with Mem0, you can create sophisticated AI systems that maintain context and provide personalized experiences while leveraging the power of autonomous agents.
<CardGroup cols={2}>
<Card title="AutoGen Integration" icon="users" href="/integrations/autogen">
Build multi-agent systems with AutoGen and Mem0
<Card title="OpenAI Agents SDK" icon="users" href="/integrations/openai-agents-sdk">
Build multi-agent systems with OpenAI Agents SDK and Mem0
</Card>
<Card title="LangGraph Integration" icon="diagram-project" href="/integrations/langgraph">
Create stateful agent workflows with memory
-42
View File
@@ -1,42 +0,0 @@
---
title: Dify
description: "Integrate Mem0 as a plugin in Dify AI workflows for persistent conversation storage and retrieval."
---
# Integrating Mem0 with Dify AI
Mem0 brings a robust memory layer to Dify AI, empowering your AI agents with persistent conversation storage and retrieval capabilities. With Mem0, your Dify applications gain the ability to recall past interactions and maintain context, ensuring more natural and insightful conversations.
---
## How to Integrate Mem0 in Your Dify Workflow
1. **Install the Mem0 Plugin:**
Head to the [Dify Marketplace](https://marketplace.dify.ai/plugins/yevanchen/mem0) and install the Mem0 plugin. This is your first step toward adding intelligent memory to your AI applications.
2. **Create or Open Your Dify Project:**
Whether you're starting fresh or updating an existing project, simply create or open your Dify workspace.
3. **Add the Mem0 Plugin to Your Project:**
Within your project, add the Mem0 plugin. This integration connects Mem0’s memory management capabilities directly to your Dify application.
4. **Configure Your Mem0 Settings:**
Customize Mem0 to suit your needs—set preferences for how conversation history is stored, the search parameters, and any other context-aware features.
5. **Leverage Mem0 in Your Workflow:**
Use Mem0 to store every conversation turn and retrieve past interactions seamlessly. This integration ensures that your AI agents can refer back to important context, making multi-turn dialogues more effective and user-centric.
---
![Mem0 Dify Integration](/images/dify-mem0-integration.png)
Enhance your Dify-powered AI with Mem0 and transform your conversational experiences. Start integrating intelligent memory management today and give your agents the context they need to excel!
<CardGroup cols={2}>
<Card title="Flowise Integration" icon="share-nodes" href="/integrations/flowise">
Build visual AI workflows with Flowise
</Card>
<Card title="LangChain Integration" icon="link" href="/integrations/langchain">
Create LangChain-powered applications
</Card>
</CardGroup>
-127
View File
@@ -1,127 +0,0 @@
---
title: Flowise
description: "Add persistent Mem0 memory to Flowise chatflows for context-aware conversations in the low-code builder."
---
The [**Mem0 Memory**](https://github.com/mem0ai/mem0) integration with [Flowise](https://github.com/FlowiseAI/Flowise) enables persistent memory capabilities for your AI chatflows. [Flowise](https://flowiseai.com/) is an open-source low-code tool for developers to build customized LLM orchestration flows & AI agents using a drag & drop interface.
## Overview
1. Provides persistent memory storage for Flowise chatflows
2. Seamless integration with existing Flowise templates
3. Compatible with various LLM nodes in Flowise
4. Supports custom memory configurations
5. Easy to set up and manage
## Prerequisites
Before setting up Mem0 with Flowise, ensure you have:
1. [Flowise installed](https://github.com/FlowiseAI/Flowise#⚡quick-start) (NodeJS >= 18.15.0 required):
```bash
npm install -g flowise
npx flowise start
```
2. Access to the Flowise UI at http://localhost:3000
3. Basic familiarity with [Flowise's LLM orchestration](https://flowiseai.com/#features) concepts
## Setup and Configuration
### 1. Set Up Flowise
1. Open the Flowise application and create a new canvas, or select a template from the Flowise marketplace.
2. In this example, we use the **Conversation Chain** template.
3. Replace the default **Buffer Memory** with **Mem0 Memory**.
![Flowise Memory Integration](https://raw.githubusercontent.com/FlowiseAI/FlowiseDocs/main/en/.gitbook/assets/mem0/flowise-flow.png)
### 2. Obtain Your Mem0 API Key
1. Navigate to the <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 API Key dashboard</a>.
2. Generate or copy your existing Mem0 API Key.
![Mem0 API Key](https://raw.githubusercontent.com/FlowiseAI/FlowiseDocs/main/en/.gitbook/assets/mem0/api-key.png)
### 3. Configure Mem0 Credentials
1. Enter the **Mem0 API Key** in the Mem0 Credentials section.
2. Configure additional settings as needed:
```typescript
{
"apiKey": "m0-xxx",
"userId": "user-123", // Optional: Specify user ID
"projectId": "proj-xxx", // Optional: Specify project ID
"orgId": "org-xxx" // Optional: Specify organization ID
}
```
<figure>
<img src="https://raw.githubusercontent.com/FlowiseAI/FlowiseDocs/main/en/.gitbook/assets/mem0/creds.png" alt="Mem0 Credentials" />
<figcaption>Configure API Credentials</figcaption>
</figure>
## Memory Features
### 1. Basic Memory Storage
Test your memory configuration:
1. Save your Flowise configuration
2. Run a test chat and store some information
3. Verify the stored memories in the <a href="https://app.mem0.ai/dashboard/requests" rel="nofollow">Mem0 Dashboard</a>
![Flowise Test Chat](https://raw.githubusercontent.com/FlowiseAI/FlowiseDocs/main/en/.gitbook/assets/mem0/flowise-chat-1.png)
### 2. Memory Retention
Validate memory persistence:
1. Clear the chat history in Flowise
2. Ask a question about previously stored information
3. Confirm that the AI remembers the context
![Testing Memory Retention](https://raw.githubusercontent.com/FlowiseAI/FlowiseDocs/main/en/.gitbook/assets/mem0/flowise-chat-2.png)
## Advanced Configuration
### Memory Settings
![Mem0 Settings](https://raw.githubusercontent.com/FlowiseAI/FlowiseDocs/main/en/.gitbook/assets/mem0/settings.png)
Available settings include:
1. **Search Only Mode**: Enable memory retrieval without creating new memories
2. **Mem0 Entities**: Configure identifiers:
- `user_id`: Unique identifier for each user
- `run_id`: Specific conversation session ID
- `app_id`: Application identifier
- `agent_id`: AI agent identifier
3. **Project ID**: Assign memories to specific projects
4. **Organization ID**: Organize memories by organization
### Platform Configuration
Additional settings available in <a href="https://app.mem0.ai/dashboard/project-settings" rel="nofollow">Mem0 Project Settings</a>:
1. **Custom Instructions**: Define memory extraction rules
2. **Expiration Date**: Set automatic memory cleanup periods
![Mem0 Project Settings](https://raw.githubusercontent.com/FlowiseAI/FlowiseDocs/main/en/.gitbook/assets/mem0/mem0-settings.png)
## Best Practices
1. **User Identification**: Use consistent `user_id` values for reliable memory retrieval
2. **Memory Organization**: Utilize projects and organizations for better memory management
3. **Regular Maintenance**: Monitor and clean up unused memories periodically
<CardGroup cols={2}>
<Card title="LangChain Integration" icon="link" href="/integrations/langchain">
Build LangChain-powered flows with memory
</Card>
<Card title="Dify Integration" icon="blocks" href="/integrations/dify">
Create AI workflows with Dify platform
</Card>
</CardGroup>
-142
View File
@@ -1,142 +0,0 @@
---
title: Keywords AI
description: "Combine Mem0 persistent memory with Keywords AI observability for tracked, cost-optimized AI applications."
---
Build AI applications with persistent memory and comprehensive LLM observability by integrating Mem0 with Keywords AI.
## Overview
Mem0 is a self-improving memory layer for LLM applications, enabling personalized AI experiences that save costs and delight users. Keywords AI provides complete LLM observability.
Combining Mem0 with Keywords AI allows you to:
1. Add persistent memory to your AI applications
2. Track interactions across sessions
3. Monitor memory usage and retrieval with Keywords AI observability
4. Optimize token usage and reduce costs
<Note>
You can get your Mem0 API key from the <a href="https://app.mem0.ai/" rel="nofollow">Mem0 dashboard</a>.
</Note>
## Setup and Configuration
Install the necessary libraries:
```bash
pip install mem0ai keywordsai-sdk
```
Set up your environment variables:
```python
import os
# Set your API keys
os.environ["MEM0_API_KEY"] = "your-mem0-api-key"
os.environ["KEYWORDSAI_API_KEY"] = "your-keywords-api-key"
os.environ["KEYWORDSAI_BASE_URL"] = "https://api.keywordsai.co/api/"
```
## Basic Integration Example
Here's a simple example of using Mem0 with Keywords AI:
```python
from mem0 import Memory
import os
# Configuration
api_key = os.getenv("MEM0_API_KEY")
keywordsai_api_key = os.getenv("KEYWORDSAI_API_KEY")
base_url = os.getenv("KEYWORDSAI_BASE_URL") # "https://api.keywordsai.co/api/"
# Set up Mem0 with Keywords AI as the LLM provider
config = {
"llm": {
"provider": "openai",
"config": {
"model": "gpt-5-mini",
"temperature": 0.0,
"api_key": keywordsai_api_key,
"openai_base_url": base_url,
},
}
}
# Initialize Memory
memory = Memory.from_config(config)
# Add a memory
result = memory.add(
"I like to take long walks on weekends.",
user_id="alice",
metadata={"category": "hobbies"},
)
print(result)
```
## Advanced Integration with OpenAI SDK
For more advanced use cases, you can integrate Keywords AI with Mem0 through the OpenAI SDK:
```python
from openai import OpenAI
import os
import json
# Initialize client
client = OpenAI(
api_key=os.environ.get("KEYWORDSAI_API_KEY"),
base_url=os.environ.get("KEYWORDSAI_BASE_URL"),
)
# Sample conversation messages
messages = [
{"role": "user", "content": "I'm planning to watch a movie tonight. Any recommendations?"},
{"role": "assistant", "content": "How about thriller movies? They can be quite engaging."},
{"role": "user", "content": "I'm not a big fan of thriller movies but I love sci-fi movies."},
{"role": "assistant", "content": "Got it! I'll avoid thriller recommendations and suggest sci-fi movies in the future."}
]
# Add memory and generate a response
response = client.chat.completions.create(
model="openai/gpt-4.1-nano",
messages=messages,
extra_body={
"mem0_params": {
"user_id": "test_user",
"api_key": os.environ.get("MEM0_API_KEY"),
"add_memories": {
"messages": messages,
},
}
},
)
print(json.dumps(response.model_dump(), indent=4))
```
For detailed information on this integration, refer to the official [Keywords AI Mem0 integration documentation](https://docs.keywordsai.co/integration/development-frameworks/mem0).
## Key Features
1. **Memory Integration**: Store and retrieve relevant information from past interactions
2. **LLM Observability**: Track memory usage and retrieval patterns with Keywords AI
3. **Session Persistence**: Maintain context across multiple user sessions
4. **Cost Optimization**: Reduce token usage through efficient memory retrieval
## Conclusion
Integrating Mem0 with Keywords AI provides a powerful combination for building AI applications with persistent memory and comprehensive observability. This integration enables more personalized user experiences while providing insights into your application's memory usage.
<CardGroup cols={2}>
<Card title="OpenAI Agents SDK" icon="cube" href="/integrations/openai-agents-sdk">
Build monitored agents with OpenAI SDK
</Card>
<Card title="AgentOps Integration" icon="chart-line" href="/integrations/agentops">
Monitor agent performance with AgentOps
</Card>
</CardGroup>
-50
View File
@@ -1,50 +0,0 @@
---
title: "Raycast Extension"
description: "Mem0 Raycast extension for intelligent memory management"
---
Mem0 is a self-improving memory layer for LLM applications, enabling personalized AI experiences that save costs and delight users. This extension lets you store and retrieve text snippets using Mem0's intelligent memory system. Find Mem0 in [Raycast Store](https://www.raycast.com/dev_khant/mem0) for using it.
## Getting Started
**Get your API Key**: You'll need a Mem0 API key to use this extension:
a. Sign up at <a href="https://app.mem0.ai" rel="nofollow">app.mem0.ai</a>
b. Navigate to your API Keys page
c. Copy your API key
d. Enter this key in the extension preferences
**Basic Usage**:
- Store memories and text snippets
- Retrieve context-aware information
- Manage persistent user preferences
- Search through stored memories
## Features
**Remember Everything**: Never lose important information. Store notes, preferences, and conversations that your AI can recall later.
**Smart Connections**: Automatically links related topics, helping you discover useful connections.
**Cost Saver**: Spend less on AI usage by efficiently retrieving relevant information instead of regenerating responses.
## How This Helps You
**More Personal Experience**: Your AI remembers your preferences and past conversations, making interactions feel more natural.
**Learn Your Style**: Adapts to how you work and what you like, becoming more helpful over time.
**No More Repetition**: Stop explaining the same things repeatedly. Your AI remembers your context and preferences.
<CardGroup cols={2}>
<Card title="OpenAI Agents SDK" icon="cube" href="/integrations/openai-agents-sdk">
Build desktop AI agents with OpenAI SDK
</Card>
<Card title="Mastra Integration" icon="star" href="/integrations/mastra">
Create intelligent desktop workflows
</Card>
</CardGroup>
-8
View File
@@ -231,8 +231,6 @@ If the user is on a pre-current major (Python < 2, TS < 3, or Platform `output_f
- [LangChain Tools](https://docs.mem0.ai/integrations/langchain-tools) [Both]: Use when Mem0 should be exposed as a LangChain tool.
- [LlamaIndex](https://docs.mem0.ai/integrations/llama-index) [Both]: Use when layering memory on a LlamaIndex RAG app.
- [CrewAI](https://docs.mem0.ai/integrations/crewai) [Both]: Use when building CrewAI multi-agent systems.
- [AutoGen](https://docs.mem0.ai/integrations/autogen) [Both]: Use when the user is on Microsoft AutoGen.
- [Agno](https://docs.mem0.ai/integrations/agno) [Both]: Use when the user is on Agno.
- [Camel AI](https://docs.mem0.ai/integrations/camel-ai) [Both]: Use when the user is on Camel AI.
- [ChatDev](https://docs.mem0.ai/integrations/chatdev) [Both]: Use when the user is on ChatDev.
- [Hermes](https://docs.mem0.ai/integrations/hermes) [Both]: Use when the user is on Hermes.
@@ -255,12 +253,6 @@ If the user is on a pre-current major (Python < 2, TS < 3, or Platform `output_f
### Cloud & Infrastructure
- [AWS Bedrock](https://docs.mem0.ai/integrations/aws-bedrock) [Both]: Use when the user is on AWS Bedrock managed AI services.
### Developer Tools
- [Dify](https://docs.mem0.ai/integrations/dify) [Both]: Use when the user is on Dify LLMOps.
- [Flowise](https://docs.mem0.ai/integrations/flowise) [Both]: Use when the user is on Flowise no-code.
- [AgentOps](https://docs.mem0.ai/integrations/agentops) [Both]: Use when tracking agent observability with memory metadata.
- [Keywords AI](https://docs.mem0.ai/integrations/keywords) [Both]: Use when monitoring with Keywords AI.
- [Raycast](https://docs.mem0.ai/integrations/raycast) [Both]: Use when the user wants quick memory access via Raycast.
## Cookbooks
+57
View File
@@ -0,0 +1,57 @@
---
title: 'Full Stack'
---
The Full Stack app example can be found [here](https://github.com/mem0ai/mem0/tree/main/embedchain/examples/full_stack).
This guide will help you setup the full stack app on your local machine.
### 🐳 Docker Setup
- Create a `docker-compose.yml` file and paste the following code in it.
```yaml
version: "3.9"
services:
backend:
container_name: embedchain-backend
restart: unless-stopped
build:
context: backend
dockerfile: Dockerfile
image: embedchain/backend
ports:
- "8000:8000"
frontend:
container_name: embedchain-frontend
restart: unless-stopped
build:
context: frontend
dockerfile: Dockerfile
image: embedchain/frontend
ports:
- "3000:3000"
depends_on:
- "backend"
```
- Run the following command,
```bash
docker-compose up
```
📝 Note: The build command might take a while to install all the packages depending on your system resources.
![Fullstack App](https://github.com/embedchain/embedchain/assets/73601258/c7c04bbb-9be7-4669-a6af-039e7e972a13)
### 🚀 Usage Instructions
- Go to [http://localhost:3000/](http://localhost:3000/) in your browser to view the dashboard.
- Add your `OpenAI API key` 🔑 in the Settings.
- Create a new bot and you'll be navigated to its page.
- Here you can add your data sources and then chat with the bot.
🎉 Happy Chatting! 🎉
+1
View File
@@ -182,6 +182,7 @@
"examples/rest-api/check-status"
]
},
"examples/full_stack",
"examples/openai-assistant",
"examples/opensource-assistant",
"examples/nextjs-assistant",
+3
View File
@@ -17,6 +17,9 @@ Chatbots, especially those powered by Large Language Models (LLMs), have a wide
Embedchain provides the right set of tools to create chatbots for the above use cases. Refer to the following examples of chatbots on and you can built on top of these examples:
<CardGroup cols={2}>
<Card title="Full Stack Chatbot" href="/examples/full_stack" icon="link">
Learn to integrate a chatbot within a full-stack application.
</Card>
<Card title="Custom GPT Creation" href="https://app.embedchain.ai/create-your-gpt/" target="_blank" icon="link">
Build a tailored GPT chatbot suited for your specific needs.
</Card>
@@ -1,2 +1,2 @@
gradio>=4.14.0
gradio==4.11.0
embedchain
@@ -1,2 +1,2 @@
chainlit==0.7.700
embedchain==0.1.57
embedchain==0.1.31
@@ -1,3 +1,3 @@
discord==2.3.1
embedchain==0.1.57
embedchain==0.0.58
python-dotenv==1.0.0
@@ -0,0 +1 @@
.git
+18
View File
@@ -0,0 +1,18 @@
## 🐳 Docker Setup
- To setup full stack app using docker, run the following command inside this folder using your terminal.
```bash
docker-compose up --build
```
📝 Note: The build command might take a while to install all the packages depending on your system resources.
## 🚀 Usage Instructions
- Go to [http://localhost:3000/](http://localhost:3000/) in your browser to view the dashboard.
- Add your `OpenAI API key` 🔑 in the Settings.
- Create a new bot and you'll be navigated to its page.
- Here you can add your data sources and then chat with the bot.
🎉 Happy Chatting! 🎉
@@ -0,0 +1,7 @@
__pycache__/
database
pyenv
venv
.env
.git
trash_files/
@@ -0,0 +1,6 @@
__pycache__
database
pyenv
venv
.env
trash_files/
@@ -0,0 +1,11 @@
FROM python:3.11-slim AS backend
WORKDIR /usr/src/app/backend
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "server.py"]
@@ -0,0 +1,14 @@
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class APIKey(db.Model):
id = db.Column(db.Integer, primary_key=True)
key = db.Column(db.String(255), nullable=False)
class BotList(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), nullable=False)
slug = db.Column(db.String(255), nullable=False, unique=True)
@@ -0,0 +1,5 @@
import os
ROOT_DIRECTORY = os.getcwd()
DB_DIRECTORY_OPEN_AI = os.path.join(os.getcwd(), "database", "open_ai")
DB_DIRECTORY_OPEN_SOURCE = os.path.join(os.getcwd(), "database", "open_source")
@@ -0,0 +1,32 @@
import os
from flask import Blueprint, jsonify, make_response, request
from models import APIKey
from paths import DB_DIRECTORY_OPEN_AI
from embedchain import App
chat_response_bp = Blueprint("chat_response", __name__)
# Chat Response for user query
@chat_response_bp.route("/api/get_answer", methods=["POST"])
def get_answer():
try:
data = request.get_json()
query = data.get("query")
embedding_model = data.get("embedding_model")
app_type = data.get("app_type")
if embedding_model == "open_ai":
os.chdir(DB_DIRECTORY_OPEN_AI)
api_key = APIKey.query.first().key
os.environ["OPENAI_API_KEY"] = api_key
if app_type == "app":
chat_bot = App()
response = chat_bot.chat(query)
return make_response(jsonify({"response": response}), 200)
except Exception as e:
return make_response(jsonify({"error": str(e)}), 400)
@@ -0,0 +1,72 @@
from flask import Blueprint, jsonify, make_response, request
from models import APIKey, BotList, db
dashboard_bp = Blueprint("dashboard", __name__)
# Set Open AI Key
@dashboard_bp.route("/api/set_key", methods=["POST"])
def set_key():
data = request.get_json()
api_key = data["openAIKey"]
existing_key = APIKey.query.first()
if existing_key:
existing_key.key = api_key
else:
new_key = APIKey(key=api_key)
db.session.add(new_key)
db.session.commit()
return make_response(jsonify(message="API key saved successfully"), 200)
# Check OpenAI Key
@dashboard_bp.route("/api/check_key", methods=["GET"])
def check_key():
existing_key = APIKey.query.first()
if existing_key:
return make_response(jsonify(status="ok", message="OpenAI Key exists"), 200)
else:
return make_response(jsonify(status="fail", message="No OpenAI Key present"), 200)
# Create a bot
@dashboard_bp.route("/api/create_bot", methods=["POST"])
def create_bot():
data = request.get_json()
name = data["name"]
slug = name.lower().replace(" ", "_")
existing_bot = BotList.query.filter_by(slug=slug).first()
if existing_bot:
return (make_response(jsonify(message="Bot already exists"), 400),)
new_bot = BotList(name=name, slug=slug)
db.session.add(new_bot)
db.session.commit()
return make_response(jsonify(message="Bot created successfully"), 200)
# Delete a bot
@dashboard_bp.route("/api/delete_bot", methods=["POST"])
def delete_bot():
data = request.get_json()
slug = data.get("slug")
bot = BotList.query.filter_by(slug=slug).first()
if bot:
db.session.delete(bot)
db.session.commit()
return make_response(jsonify(message="Bot deleted successfully"), 200)
return make_response(jsonify(message="Bot not found"), 400)
# Get the list of bots
@dashboard_bp.route("/api/get_bots", methods=["GET"])
def get_bots():
bots = BotList.query.all()
bot_list = []
for bot in bots:
bot_list.append(
{
"name": bot.name,
"slug": bot.slug,
}
)
return jsonify(bot_list)
@@ -0,0 +1,27 @@
import os
from flask import Blueprint, jsonify, make_response, request
from models import APIKey
from paths import DB_DIRECTORY_OPEN_AI
from embedchain import App
sources_bp = Blueprint("sources", __name__)
# API route to add data sources
@sources_bp.route("/api/add_sources", methods=["POST"])
def add_sources():
try:
embedding_model = request.json.get("embedding_model")
name = request.json.get("name")
value = request.json.get("value")
if embedding_model == "open_ai":
os.chdir(DB_DIRECTORY_OPEN_AI)
api_key = APIKey.query.first().key
os.environ["OPENAI_API_KEY"] = api_key
chat_bot = App()
chat_bot.add(name, value)
return make_response(jsonify(message="Sources added successfully"), 200)
except Exception as e:
return make_response(jsonify(message=f"Error adding sources: {str(e)}"), 400)
@@ -0,0 +1,27 @@
import os
from flask import Flask
from models import db
from paths import DB_DIRECTORY_OPEN_AI, ROOT_DIRECTORY
from routes.chat_response import chat_response_bp
from routes.dashboard import dashboard_bp
from routes.sources import sources_bp
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///" + os.path.join(ROOT_DIRECTORY, "database", "user_data.db")
app.register_blueprint(dashboard_bp)
app.register_blueprint(sources_bp)
app.register_blueprint(chat_response_bp)
# Initialize the app on startup
def load_app():
os.makedirs(DB_DIRECTORY_OPEN_AI, exist_ok=True)
db.init_app(app)
with app.app_context():
db.create_all()
if __name__ == "__main__":
load_app()
app.run(host="0.0.0.0", debug=True, port=8000)
@@ -0,0 +1,24 @@
version: "3.9"
services:
backend:
container_name: embedchain-backend
restart: unless-stopped
build:
context: backend
dockerfile: Dockerfile
image: embedchain/backend
ports:
- "8000:8000"
frontend:
container_name: embedchain-frontend
restart: unless-stopped
build:
context: frontend
dockerfile: Dockerfile
image: embedchain/frontend
ports:
- "3000:3000"
depends_on:
- "backend"
@@ -0,0 +1,7 @@
node_modules/
build
dist
.env
.git
.next/
trash_files/
@@ -0,0 +1,3 @@
{
"extends": ["next/babel", "next/core-web-vitals"]
}
@@ -0,0 +1,38 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
vscode/
trash_files/
@@ -0,0 +1,14 @@
FROM node:18-slim AS frontend
WORKDIR /usr/src/app/frontend
COPY package.json .
COPY package-lock.json .
RUN npm install
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]
@@ -0,0 +1,7 @@
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
}
}
}
@@ -0,0 +1,26 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
async rewrites() {
return [
{
source: "/api/:path*",
destination: "http://backend:8000/api/:path*",
},
];
},
reactStrictMode: true,
experimental: {
proxyTimeout: 6000000,
},
webpack(config) {
config.module.rules.push({
test: /\.svg$/i,
issuer: /\.[jt]sx?$/,
use: ["@svgr/webpack"],
});
return config;
},
};
module.exports = nextConfig;
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,25 @@
{
"name": "frontend",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"autoprefixer": "^10.4.14",
"eslint": "8.44.0",
"eslint-config-next": "13.4.9",
"flowbite": "^1.7.0",
"next": "13.4.9",
"postcss": "8.4.25",
"react": "18.2.0",
"react-dom": "18.2.0",
"tailwindcss": "3.3.2"
},
"devDependencies": {
"@svgr/webpack": "^8.0.1"
}
}
@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

@@ -0,0 +1,20 @@
<svg
viewBox="0 0 24 24"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
<g
id="SVGRepo_tracerCarrier"
stroke-linecap="round"
stroke-linejoin="round"
></g>
<g id="SVGRepo_iconCarrier">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M14 2C14 2.74028 13.5978 3.38663 13 3.73244V4H20C21.6569 4 23 5.34315 23 7V19C23 20.6569 21.6569 22 20 22H4C2.34315 22 1 20.6569 1 19V7C1 5.34315 2.34315 4 4 4H11V3.73244C10.4022 3.38663 10 2.74028 10 2C10 0.895431 10.8954 0 12 0C13.1046 0 14 0.895431 14 2ZM4 6H11H13H20C20.5523 6 21 6.44772 21 7V19C21 19.5523 20.5523 20 20 20H4C3.44772 20 3 19.5523 3 19V7C3 6.44772 3.44772 6 4 6ZM15 11.5C15 10.6716 15.6716 10 16.5 10C17.3284 10 18 10.6716 18 11.5C18 12.3284 17.3284 13 16.5 13C15.6716 13 15 12.3284 15 11.5ZM16.5 8C14.567 8 13 9.567 13 11.5C13 13.433 14.567 15 16.5 15C18.433 15 20 13.433 20 11.5C20 9.567 18.433 8 16.5 8ZM7.5 10C6.67157 10 6 10.6716 6 11.5C6 12.3284 6.67157 13 7.5 13C8.32843 13 9 12.3284 9 11.5C9 10.6716 8.32843 10 7.5 10ZM4 11.5C4 9.567 5.567 8 7.5 8C9.433 8 11 9.567 11 11.5C11 13.433 9.433 15 7.5 15C5.567 15 4 13.433 4 11.5ZM10.8944 16.5528C10.6474 16.0588 10.0468 15.8586 9.55279 16.1056C9.05881 16.3526 8.85858 16.9532 9.10557 17.4472C9.68052 18.5971 10.9822 19 12 19C13.0178 19 14.3195 18.5971 14.8944 17.4472C15.1414 16.9532 14.9412 16.3526 14.4472 16.1056C13.9532 15.8586 13.3526 16.0588 13.1056 16.5528C13.0139 16.7362 12.6488 17 12 17C11.3512 17 10.9861 16.7362 10.8944 16.5528Z"
fill="currentColor"
></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

@@ -0,0 +1,14 @@
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 14 14"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"
/>
</svg>

After

Width:  |  Height:  |  Size: 252 B

@@ -0,0 +1,15 @@
<svg
fill="currentColor"
viewBox="0 0 32 32"
xmlns="http://www.w3.org/2000/svg"
>
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
<g
id="SVGRepo_tracerCarrier"
stroke-linecap="round"
stroke-linejoin="round"
></g>
<g id="SVGRepo_iconCarrier">
<path d="M18.8,16l5.5-5.5c0.8-0.8,0.8-2,0-2.8l0,0C24,7.3,23.5,7,23,7c-0.5,0-1,0.2-1.4,0.6L16,13.2l-5.5-5.5 c-0.8-0.8-2.1-0.8-2.8,0C7.3,8,7,8.5,7,9.1s0.2,1,0.6,1.4l5.5,5.5l-5.5,5.5C7.3,21.9,7,22.4,7,23c0,0.5,0.2,1,0.6,1.4 C8,24.8,8.5,25,9,25c0.5,0,1-0.2,1.4-0.6l5.5-5.5l5.5,5.5c0.8,0.8,2.1,0.8,2.8,0c0.8-0.8,0.8-2.1,0-2.8L18.8,16z"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 625 B

@@ -0,0 +1,9 @@
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
viewBox="0 0 22 21"
>
<path d="M16.975 11H10V4.025a1 1 0 0 0-1.066-.998 8.5 8.5 0 1 0 9.039 9.039.999.999 0 0 0-1-1.066h.002Z" />
<path d="M12.5 0c-.157 0-.311.01-.565.027A1 1 0 0 0 11 1.02V10h8.975a1 1 0 0 0 1-.935c.013-.188.028-.374.028-.565A8.51 8.51 0 0 0 12.5 0Z" />
</svg>

After

Width:  |  Height:  |  Size: 369 B

@@ -0,0 +1,15 @@
<svg
fill="currentColor"
viewBox="0 0 56 56"
xmlns="http://www.w3.org/2000/svg"
>
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
<g
id="SVGRepo_tracerCarrier"
stroke-linecap="round"
stroke-linejoin="round"
></g>
<g id="SVGRepo_iconCarrier">
<path d="M 15.5547 53.125 L 40.4453 53.125 C 45.2969 53.125 47.7109 50.6640 47.7109 45.7890 L 47.7109 24.5078 L 30.7422 24.5078 C 27.7422 24.5078 26.3359 23.0781 26.3359 20.0781 L 26.3359 2.8750 L 15.5547 2.8750 C 10.7266 2.8750 8.2891 5.3594 8.2891 10.2344 L 8.2891 45.7890 C 8.2891 50.6875 10.7266 53.125 15.5547 53.125 Z M 30.8125 21.2969 L 47.4531 21.2969 C 47.2891 20.3359 46.6094 19.3984 45.5078 18.2500 L 32.5703 5.1015 C 31.4922 3.9766 30.5078 3.2969 29.5234 3.1328 L 29.5234 20.0313 C 29.5234 20.875 29.9687 21.2969 30.8125 21.2969 Z M 18.9766 34.6562 C 18.0156 34.6562 17.3359 33.9766 17.3359 33.0625 C 17.3359 32.1484 18.0156 31.4687 18.9766 31.4687 L 37.0469 31.4687 C 37.9844 31.4687 38.7109 32.1484 38.7109 33.0625 C 38.7109 33.9766 37.9844 34.6562 37.0469 34.6562 Z M 18.9766 43.5859 C 18.0156 43.5859 17.3359 42.9062 17.3359 41.9922 C 17.3359 41.0781 18.0156 40.3984 18.9766 40.3984 L 37.0469 40.3984 C 37.9844 40.3984 38.7109 41.0781 38.7109 41.9922 C 38.7109 42.9062 37.9844 43.5859 37.0469 43.5859 Z"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@@ -0,0 +1,12 @@
<svg
aria-hidden="true"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
clip-rule="evenodd"
fill-rule="evenodd"
d="M2 4.75A.75.75 0 012.75 4h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 4.75zm0 10.5a.75.75 0 01.75-.75h7.5a.75.75 0 010 1.5h-7.5a.75.75 0 01-.75-.75zM2 10a.75.75 0 01.75-.75h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 10z"
></path>
</svg>

After

Width:  |  Height:  |  Size: 415 B

@@ -0,0 +1,14 @@
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 10 6"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="m1 1 4 4 4-4"
/>
</svg>

After

Width:  |  Height:  |  Size: 230 B

@@ -0,0 +1,14 @@
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 10 6"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 5 5 1 1 5"
/>
</svg>

After

Width:  |  Height:  |  Size: 254 B

@@ -0,0 +1,39 @@
<svg
viewBox="0 0 20 20"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="currentColor"
>
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
<g
id="SVGRepo_tracerCarrier"
stroke-linecap="round"
stroke-linejoin="round"
></g>
<g id="SVGRepo_iconCarrier">
<title>github [#142]</title> <desc>Created with Sketch.</desc>
<defs> </defs>
<g
id="Page-1"
stroke="none"
stroke-width="1"
fill="none"
fill-rule="evenodd"
>
<g
id="Dribbble-Light-Preview"
transform="translate(-140.000000, -7559.000000)"
fill="currentColor"
>
<g id="icons" transform="translate(56.000000, 160.000000)">
<path
d="M94,7399 C99.523,7399 104,7403.59 104,7409.253 C104,7413.782 101.138,7417.624 97.167,7418.981 C96.66,7419.082 96.48,7418.762 96.48,7418.489 C96.48,7418.151 96.492,7417.047 96.492,7415.675 C96.492,7414.719 96.172,7414.095 95.813,7413.777 C98.04,7413.523 100.38,7412.656 100.38,7408.718 C100.38,7407.598 99.992,7406.684 99.35,7405.966 C99.454,7405.707 99.797,7404.664 99.252,7403.252 C99.252,7403.252 98.414,7402.977 96.505,7404.303 C95.706,7404.076 94.85,7403.962 94,7403.958 C93.15,7403.962 92.295,7404.076 91.497,7404.303 C89.586,7402.977 88.746,7403.252 88.746,7403.252 C88.203,7404.664 88.546,7405.707 88.649,7405.966 C88.01,7406.684 87.619,7407.598 87.619,7408.718 C87.619,7412.646 89.954,7413.526 92.175,7413.785 C91.889,7414.041 91.63,7414.493 91.54,7415.156 C90.97,7415.418 89.522,7415.871 88.63,7414.304 C88.63,7414.304 88.101,7413.319 87.097,7413.247 C87.097,7413.247 86.122,7413.234 87.029,7413.87 C87.029,7413.87 87.684,7414.185 88.139,7415.37 C88.139,7415.37 88.726,7417.2 91.508,7416.58 C91.513,7417.437 91.522,7418.245 91.522,7418.489 C91.522,7418.76 91.338,7419.077 90.839,7418.982 C86.865,7417.627 84,7413.783 84,7409.253 C84,7403.59 88.478,7399 94,7399"
id="github-[#142]"
>
</path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

@@ -0,0 +1,17 @@
<svg
fill="currentColor"
viewBox="0 0 32 32"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
>
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
<g
id="SVGRepo_tracerCarrier"
stroke-linecap="round"
stroke-linejoin="round"
></g>
<g id="SVGRepo_iconCarrier">
<title>linkedin</title>
<path d="M28.778 1.004h-25.56c-0.008-0-0.017-0-0.027-0-1.199 0-2.172 0.964-2.186 2.159v25.672c0.014 1.196 0.987 2.161 2.186 2.161 0.010 0 0.019-0 0.029-0h25.555c0.008 0 0.018 0 0.028 0 1.2 0 2.175-0.963 2.194-2.159l0-0.002v-25.67c-0.019-1.197-0.994-2.161-2.195-2.161-0.010 0-0.019 0-0.029 0h0.001zM9.9 26.562h-4.454v-14.311h4.454zM7.674 10.293c-1.425 0-2.579-1.155-2.579-2.579s1.155-2.579 2.579-2.579c1.424 0 2.579 1.154 2.579 2.578v0c0 0.001 0 0.002 0 0.004 0 1.423-1.154 2.577-2.577 2.577-0.001 0-0.002 0-0.003 0h0zM26.556 26.562h-4.441v-6.959c0-1.66-0.034-3.795-2.314-3.795-2.316 0-2.669 1.806-2.669 3.673v7.082h-4.441v-14.311h4.266v1.951h0.058c0.828-1.395 2.326-2.315 4.039-2.315 0.061 0 0.121 0.001 0.181 0.003l-0.009-0c4.5 0 5.332 2.962 5.332 6.817v7.855z"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@@ -0,0 +1,28 @@
<svg
viewBox="0 0 15 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
<g
id="SVGRepo_tracerCarrier"
stroke-linecap="round"
stroke-linejoin="round"
></g>
<g id="SVGRepo_iconCarrier">
<path
d="M3.5 8H3V7H3.5C3.77614 7 4 7.22386 4 7.5C4 7.77614 3.77614 8 3.5 8Z"
fill="currentColor"
></path>
<path
d="M7 10V7H7.5C7.77614 7 8 7.22386 8 7.5V9.5C8 9.77614 7.77614 10 7.5 10H7Z"
fill="currentColor"
></path>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M1 1.5C1 0.671573 1.67157 0 2.5 0H10.7071L14 3.29289V13.5C14 14.3284 13.3284 15 12.5 15H2.5C1.67157 15 1 14.3284 1 13.5V1.5ZM3.5 6H2V11H3V9H3.5C4.32843 9 5 8.32843 5 7.5C5 6.67157 4.32843 6 3.5 6ZM7.5 6H6V11H7.5C8.32843 11 9 10.3284 9 9.5V7.5C9 6.67157 8.32843 6 7.5 6ZM10 11V6H13V7H11V8H12V9H11V11H10Z"
fill="currentColor"
></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 947 B

@@ -0,0 +1,13 @@
<svg
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M12 6v6m0 0v6m0-6h6m-6 0H6"
/>
</svg>

After

Width:  |  Height:  |  Size: 227 B

@@ -0,0 +1,57 @@
<svg
viewBox="-0.5 0 25 25"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
<g
id="SVGRepo_tracerCarrier"
stroke-linecap="round"
stroke-linejoin="round"
></g>
<g id="SVGRepo_iconCarrier">
{" "}
<path
d="M12 7.82001H22"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
></path>{" "}
<path
d="M2 7.82001H4"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
></path>{" "}
<path
d="M20 16.82H22"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
></path>{" "}
<path
d="M2 16.82H12"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
></path>{" "}
<path
d="M8 11.82C10.2091 11.82 12 10.0291 12 7.82001C12 5.61087 10.2091 3.82001 8 3.82001C5.79086 3.82001 4 5.61087 4 7.82001C4 10.0291 5.79086 11.82 8 11.82Z"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
></path>{" "}
<path
d="M16 20.82C18.2091 20.82 20 19.0291 20 16.82C20 14.6109 18.2091 12.82 16 12.82C13.7909 12.82 12 14.6109 12 16.82C12 19.0291 13.7909 20.82 16 20.82Z"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
></path>{" "}
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

@@ -0,0 +1,61 @@
<svg
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
<g
id="SVGRepo_tracerCarrier"
stroke-linecap="round"
stroke-linejoin="round"
></g>
<g id="SVGRepo_iconCarrier">
<rect
height="4"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
width="4"
x="10"
y="4"
></rect>
<rect
height="4"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
width="4"
x="10"
y="16"
></rect>
<rect
height="4"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
width="4"
x="3"
y="16"
></rect>
<rect
height="4"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
width="4"
x="17"
y="16"
></rect>
<path
d="M12 8V12M12 16V12M12 12H17C18.1046 12 19 12.8954 19 14V16M12 12H7C5.89543 12 5 12.8954 5 14V16"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@@ -0,0 +1,21 @@
<svg
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
<g
id="SVGRepo_tracerCarrier"
stroke-linecap="round"
stroke-linejoin="round"
></g>
<g id="SVGRepo_iconCarrier">
<path
d="M12 3V21M9 21H15M19 6V3H5V6"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 445 B

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="svg5" xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1668.56 1221.19"
style="enable-background:new 0 0 1668.56 1221.19;" xml:space="preserve">
<g id="layer1" transform="translate(52.390088,-25.058597)">
<path id="path1009" d="M283.94,167.31l386.39,516.64L281.5,1104h87.51l340.42-367.76L984.48,1104h297.8L874.15,558.3l361.92-390.99
h-87.51l-313.51,338.7l-253.31-338.7H283.94z M412.63,231.77h136.81l604.13,807.76h-136.81L412.63,231.77z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 722 B

@@ -0,0 +1,20 @@
<svg
fill="currentColor"
version="1.1"
id="Layer_1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 24 24"
enable-background="new 0 0 24 24"
xml:space="preserve"
>
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
<g
id="SVGRepo_tracerCarrier"
stroke-linecap="round"
stroke-linejoin="round"
></g>
<g id="SVGRepo_iconCarrier">
<path d="M18.41,0.01H4V9h2V2.01h10v6h6v14H4v2h20V5.6L18.41,0.01z M18,2.43l3.59,3.59H18V2.43z M21,18v2h-1h-1h-1v-8h2v6H21z M7,12 H6v2h1v6h2v-6h1v-2H9H7z M15,12l-1,1.61L13,12v0h-2v8h2v-4.21l1,1.61l1-1.61V20h2v-8L15,12L15,12z M3,15H2v-3H0v8h2v-3h1v3h2v-8H3 V15z"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 689 B

@@ -0,0 +1,39 @@
<svg
viewBox="0 -3 20 20"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="currentColor"
>
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
<g
id="SVGRepo_tracerCarrier"
stroke-linecap="round"
stroke-linejoin="round"
></g>
<g id="SVGRepo_iconCarrier">
<title>youtube [#168]</title> <desc>Created with Sketch.</desc>
<defs> </defs>
<g
id="Page-1"
stroke="none"
stroke-width="1"
fill="none"
fill-rule="evenodd"
>
<g
id="Dribbble-Light-Preview"
transform="translate(-300.000000, -7442.000000)"
fill="currentColor"
>
<g id="icons" transform="translate(56.000000, 160.000000)">
<path
d="M251.988432,7291.58588 L251.988432,7285.97425 C253.980638,7286.91168 255.523602,7287.8172 257.348463,7288.79353 C255.843351,7289.62824 253.980638,7290.56468 251.988432,7291.58588 M263.090998,7283.18289 C262.747343,7282.73013 262.161634,7282.37809 261.538073,7282.26141 C259.705243,7281.91336 248.270974,7281.91237 246.439141,7282.26141 C245.939097,7282.35515 245.493839,7282.58153 245.111335,7282.93357 C243.49964,7284.42947 244.004664,7292.45151 244.393145,7293.75096 C244.556505,7294.31342 244.767679,7294.71931 245.033639,7294.98558 C245.376298,7295.33761 245.845463,7295.57995 246.384355,7295.68865 C247.893451,7296.0008 255.668037,7296.17532 261.506198,7295.73552 C262.044094,7295.64178 262.520231,7295.39147 262.895762,7295.02447 C264.385932,7293.53455 264.28433,7285.06174 263.090998,7283.18289"
id="youtube-[#168]"
>
</path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

@@ -0,0 +1,9 @@
export default function PageWrapper({ children }) {
return (
<>
<div className="flex pt-4 px-4 sm:ml-64 min-h-screen">
<div className="flex-grow pt-4 px-4 rounded-lg">{children}</div>
</div>
</>
);
}
@@ -0,0 +1,16 @@
export default function BotWrapper({ children }) {
return (
<>
<div className="rounded-lg">
<div className="flex flex-row items-center">
<div className="flex items-center justify-center h-10 w-10 rounded-full bg-black text-white flex-shrink-0">
B
</div>
<div className="ml-3 text-sm bg-white py-2 px-4 shadow-lg rounded-xl">
<div>{children}</div>
</div>
</div>
</div>
</>
);
}
@@ -0,0 +1,16 @@
export default function HumanWrapper({ children }) {
return (
<>
<div className="rounded-lg">
<div className="flex items-center justify-start flex-row-reverse">
<div className="flex items-center justify-center h-10 w-10 rounded-full bg-blue-800 text-white flex-shrink-0">
H
</div>
<div className="mr-3 text-sm bg-blue-200 py-2 px-4 shadow-lg rounded-xl">
<div>{children}</div>
</div>
</div>
</div>
</>
);
}
@@ -0,0 +1,73 @@
import { useState } from "react";
import { useRouter } from "next/router";
export default function CreateBot() {
const [botName, setBotName] = useState("");
const [status, setStatus] = useState("");
const router = useRouter();
const handleCreateBot = async (e) => {
e.preventDefault();
const data = {
name: botName,
};
const response = await fetch("/api/create_bot", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
});
if (response.ok) {
const botSlug = botName.toLowerCase().replace(/\s+/g, "_");
router.push(`/${botSlug}/app`);
} else {
setBotName("");
setStatus("fail");
setTimeout(() => {
setStatus("");
}, 3000);
}
};
return (
<>
<div className="w-full">
{/* Create Bot */}
<h2 className="text-xl font-bold text-gray-800">CREATE BOT</h2>
<form className="py-2" onSubmit={handleCreateBot}>
<label
htmlFor="bot_name"
className="block mb-2 text-sm font-medium text-gray-900"
>
Name of Bot
</label>
<div className="flex flex-col sm:flex-row gap-x-4 gap-y-4">
<input
type="text"
id="bot_name"
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
placeholder="Eg. Naval Ravikant"
required
value={botName}
onChange={(e) => setBotName(e.target.value)}
/>
<button
type="submit"
className="h-fit text-white bg-black hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center"
>
Submit
</button>
</div>
{status === "fail" && (
<div className="text-red-600 text-sm font-bold py-1">
An error occurred while creating your bot!
</div>
)}
</form>
</div>
</>
);
}
@@ -0,0 +1,71 @@
import { useEffect, useState } from "react";
import { useRouter } from "next/router";
export default function DeleteBot() {
const [bots, setBots] = useState([]);
const router = useRouter();
useEffect(() => {
const fetchBots = async () => {
const response = await fetch("/api/get_bots");
const data = await response.json();
setBots(data);
};
fetchBots();
}, []);
const handleDeleteBot = async (event) => {
event.preventDefault();
const selectedBotSlug = event.target.bot_name.value;
if (selectedBotSlug === "none") {
return;
}
const response = await fetch("/api/delete_bot", {
method: "POST",
body: JSON.stringify({ slug: selectedBotSlug }),
headers: {
"Content-Type": "application/json",
},
});
if (response.ok) {
router.reload();
}
};
return (
<>
{bots.length !== 0 && (
<div className="w-full">
{/* Delete Bot */}
<h2 className="text-xl font-bold text-gray-800">DELETE BOTS</h2>
<form className="py-2" onSubmit={handleDeleteBot}>
<label className="block mb-2 text-sm font-medium text-gray-900">
List of Bots
</label>
<div className="flex flex-col sm:flex-row gap-x-4 gap-y-4">
<select
name="bot_name"
defaultValue="none"
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
>
<option value="none">Select a Bot</option>
{bots.map((bot) => (
<option key={bot.slug} value={bot.slug}>
{bot.name}
</option>
))}
</select>
<button
type="submit"
className="h-fit text-white bg-red-600 hover:bg-red-600/90 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center"
>
Delete
</button>
</div>
</form>
</div>
)}
</>
);
}
@@ -0,0 +1,47 @@
import { useState } from "react";
export default function PurgeChats() {
const [status, setStatus] = useState("");
const handleChatsPurge = (event) => {
event.preventDefault();
localStorage.clear();
setStatus("success");
setTimeout(() => {
setStatus(false);
}, 3000);
};
return (
<>
<div className="w-full">
{/* Purge Chats */}
<h2 className="text-xl font-bold text-gray-800">PURGE CHATS</h2>
<form className="py-2" onSubmit={handleChatsPurge}>
<label className="block mb-2 text-sm font-medium text-red-600">
Warning
</label>
<div className="flex flex-col sm:flex-row gap-x-4 gap-y-4">
<div
type="text"
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
>
The following action will clear all your chat logs. Proceed with
caution!
</div>
<button
type="submit"
className="h-fit text-white bg-red-600 hover:bg-red-600/80 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center"
>
Purge
</button>
</div>
{status === "success" && (
<div className="text-green-600 text-sm font-bold py-1">
Your chats have been purged!
</div>
)}
</form>
</div>
</>
);
}
@@ -0,0 +1,73 @@
import { useState } from "react";
export default function SetOpenAIKey({ setIsKeyPresent }) {
const [openAIKey, setOpenAIKey] = useState("");
const [status, setStatus] = useState("");
const handleOpenAIKey = async (e) => {
e.preventDefault();
const response = await fetch("/api/set_key", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ openAIKey }),
});
if (response.ok) {
setOpenAIKey("");
setStatus("success");
setIsKeyPresent(true);
} else {
setStatus("fail");
}
setTimeout(() => {
setStatus("");
}, 3000);
};
return (
<>
<div className="w-full">
{/* Set Open AI Key */}
<h2 className="text-xl font-bold text-gray-800">SET OPENAI KEY</h2>
<form className="py-2" onSubmit={handleOpenAIKey}>
<label
htmlFor="openai_key"
className="block mb-2 text-sm font-medium text-gray-900"
>
OpenAI Key
</label>
<div className="flex flex-col sm:flex-row gap-x-4 gap-y-4">
<input
type="password"
id="openai_key"
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
placeholder="Enter Open AI Key here"
required
value={openAIKey}
onChange={(e) => setOpenAIKey(e.target.value)}
/>
<button
type="submit"
className="h-fit text-white bg-black hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center"
>
Submit
</button>
</div>
{status === "success" && (
<div className="text-green-600 text-sm font-bold py-1">
Your Open AI key has been saved successfully!
</div>
)}
{status === "fail" && (
<div className="text-red-600 text-sm font-bold py-1">
An error occurred while saving your OpenAI Key!
</div>
)}
</form>
</div>
</>
);
}
@@ -0,0 +1,156 @@
import { useRouter } from "next/router";
import React, { useState, useEffect } from "react";
import BotWrapper from "@/components/chat/BotWrapper";
import HumanWrapper from "@/components/chat/HumanWrapper";
import SetSources from "@/containers/SetSources";
export default function ChatWindow({ embedding_model, app_type, setBotTitle }) {
const [bot, setBot] = useState(null);
const [chats, setChats] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [selectChat, setSelectChat] = useState(true);
const router = useRouter();
const { bot_slug } = router.query;
useEffect(() => {
if (bot_slug) {
const fetchBots = async () => {
const response = await fetch("/api/get_bots");
const data = await response.json();
const matchingBot = data.find((item) => item.slug === bot_slug);
setBot(matchingBot);
setBotTitle(matchingBot.name);
};
fetchBots();
}
}, [bot_slug]);
useEffect(() => {
const storedChats = localStorage.getItem(`chat_${bot_slug}_${app_type}`);
if (storedChats) {
const parsedChats = JSON.parse(storedChats);
setChats(parsedChats.chats);
}
}, [app_type, bot_slug]);
const handleChatResponse = async (e) => {
e.preventDefault();
setIsLoading(true);
const queryInput = e.target.query.value;
e.target.query.value = "";
const chatEntry = {
sender: "H",
message: queryInput,
};
setChats((prevChats) => [...prevChats, chatEntry]);
const response = await fetch("/api/get_answer", {
method: "POST",
body: JSON.stringify({
query: queryInput,
embedding_model,
app_type,
}),
headers: {
"Content-Type": "application/json",
},
});
const data = await response.json();
if (response.ok) {
const botResponse = data.response;
const botEntry = {
sender: "B",
message: botResponse,
};
setIsLoading(false);
setChats((prevChats) => [...prevChats, botEntry]);
const savedChats = {
chats: [...chats, chatEntry, botEntry],
};
localStorage.setItem(
`chat_${bot_slug}_${app_type}`,
JSON.stringify(savedChats)
);
} else {
router.reload();
}
};
return (
<>
<div className="flex flex-col justify-between h-full">
<div className="space-y-4 overflow-x-auto h-full pb-8">
{/* Greeting Message */}
<BotWrapper>
Hi, I am {bot?.name}. How can I help you today?
</BotWrapper>
{/* Chat Messages */}
{chats.map((chat, index) => (
<React.Fragment key={index}>
{chat.sender === "B" ? (
<BotWrapper>{chat.message}</BotWrapper>
) : (
<HumanWrapper>{chat.message}</HumanWrapper>
)}
</React.Fragment>
))}
{/* Loader */}
{isLoading && (
<BotWrapper>
<div className="flex items-center justify-center space-x-2 animate-pulse">
<div className="w-2 h-2 bg-black rounded-full"></div>
<div className="w-2 h-2 bg-black rounded-full"></div>
<div className="w-2 h-2 bg-black rounded-full"></div>
</div>
</BotWrapper>
)}
</div>
<div className="bg-white fixed bottom-0 left-0 right-0 h-28 sm:h-16"></div>
{/* Query Form */}
<div className="flex flex-row gap-x-2 sticky bottom-3">
<SetSources
setChats={setChats}
embedding_model={embedding_model}
setSelectChat={setSelectChat}
/>
{selectChat && (
<form
onSubmit={handleChatResponse}
className="w-full flex flex-col sm:flex-row gap-y-2 gap-x-2"
>
<div className="w-full">
<input
id="query"
name="query"
type="text"
placeholder="Enter your query..."
className="text-sm w-full border-2 border-black rounded-xl focus:outline-none focus:border-blue-800 sm:pl-4 h-11"
required
/>
</div>
<div className="w-full sm:w-fit">
<button
type="submit"
id="sender"
disabled={isLoading}
className={`${
isLoading ? "opacity-60" : ""
} w-full bg-black hover:bg-blue-800 rounded-xl text-lg text-white px-6 h-11`}
>
Send
</button>
</div>
</form>
)}
</div>
</div>
</>
);
}
@@ -0,0 +1,160 @@
import { useState } from "react";
import PlusIcon from "../../public/icons/plus.svg";
import CrossIcon from "../../public/icons/cross.svg";
import YoutubeIcon from "../../public/icons/youtube.svg";
import PDFIcon from "../../public/icons/pdf.svg";
import WebIcon from "../../public/icons/web.svg";
import DocIcon from "../../public/icons/doc.svg";
import SitemapIcon from "../../public/icons/sitemap.svg";
import TextIcon from "../../public/icons/text.svg";
export default function SetSources({
setChats,
embedding_model,
setSelectChat,
}) {
const [sourceName, setSourceName] = useState("");
const [sourceValue, setSourceValue] = useState("");
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const dataTypes = {
youtube_video: "YouTube Video",
pdf_file: "PDF File",
web_page: "Web Page",
doc_file: "Doc File",
sitemap: "Sitemap",
text: "Text",
};
const dataIcons = {
youtube_video: <YoutubeIcon className="w-5 h-5 mr-3" />,
pdf_file: <PDFIcon className="w-5 h-5 mr-3" />,
web_page: <WebIcon className="w-5 h-5 mr-3" />,
doc_file: <DocIcon className="w-5 h-5 mr-3" />,
sitemap: <SitemapIcon className="w-5 h-5 mr-3" />,
text: <TextIcon className="w-5 h-5 mr-3" />,
};
const handleDropdownClose = () => {
setIsDropdownOpen(false);
setSourceName("");
setSelectChat(true);
};
const handleDropdownSelect = (dataType) => {
setSourceName(dataType);
setSourceValue("");
setIsDropdownOpen(false);
setSelectChat(false);
};
const handleAddDataSource = async (e) => {
e.preventDefault();
setIsLoading(true);
const addDataSourceEntry = {
sender: "B",
message: `Adding the following ${dataTypes[sourceName]}: ${sourceValue}`,
};
setChats((prevChats) => [...prevChats, addDataSourceEntry]);
let name = sourceName;
let value = sourceValue;
setSourceValue("");
const response = await fetch("/api/add_sources", {
method: "POST",
body: JSON.stringify({
embedding_model,
name,
value,
}),
headers: {
"Content-Type": "application/json",
},
});
if (response.ok) {
const successEntry = {
sender: "B",
message: `Successfully added ${dataTypes[sourceName]}!`,
};
setChats((prevChats) => [...prevChats, successEntry]);
} else {
const errorEntry = {
sender: "B",
message: `Failed to add ${dataTypes[sourceName]}. Please try again.`,
};
setChats((prevChats) => [...prevChats, errorEntry]);
}
setSourceName("");
setIsLoading(false);
setSelectChat(true);
};
return (
<>
<div className="w-fit">
<button
type="button"
onClick={() => setIsDropdownOpen(!isDropdownOpen)}
className="w-fit p-2.5 rounded-xl text-white bg-black hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300"
>
<PlusIcon className="w-6 h-6" />
</button>
{isDropdownOpen && (
<div className="absolute left-0 bottom-full bg-white border border-gray-300 rounded-lg shadow-lg mb-2">
<ul className="py-1">
<li
className="block px-4 py-2 text-sm text-black cursor-pointer hover:bg-gray-200"
onClick={handleDropdownClose}
>
<span className="flex items-center text-red-600">
<CrossIcon className="w-5 h-5 mr-3" />
Close
</span>
</li>
{Object.entries(dataTypes).map(([key, value]) => (
<li
key={key}
className="block px-4 py-2 text-sm text-black cursor-pointer hover:bg-gray-200"
onClick={() => handleDropdownSelect(key)}
>
<span className="flex items-center">
{dataIcons[key]}
{value}
</span>
</li>
))}
</ul>
</div>
)}
</div>
{sourceName && (
<form
onSubmit={handleAddDataSource}
className="w-full flex flex-col sm:flex-row gap-y-2 gap-x-2 items-center"
>
<div className="w-full">
<input
type="text"
placeholder="Enter URL, Data or File path here..."
className="text-sm w-full border-2 border-black rounded-xl focus:outline-none focus:border-blue-800 sm:pl-4 h-11"
required
value={sourceValue}
onChange={(e) => setSourceValue(e.target.value)}
/>
</div>
<div className="w-full sm:w-fit">
<button
type="submit"
disabled={isLoading}
className={`${
isLoading ? "opacity-60" : ""
} w-full bg-black hover:bg-blue-800 rounded-xl text-lg text-white px-6 h-11`}
>
Send
</button>
</div>
</form>
)}
</>
);
}
@@ -0,0 +1,131 @@
import Link from "next/link";
import Image from "next/image";
import React, { useState, useEffect } from "react";
import DrawerIcon from "../../public/icons/drawer.svg";
import SettingsIcon from "../../public/icons/settings.svg";
import BotIcon from "../../public/icons/bot.svg";
import DropdownIcon from "../../public/icons/dropdown.svg";
import TwitterIcon from "../../public/icons/twitter.svg";
import GithubIcon from "../../public/icons/github.svg";
import LinkedinIcon from "../../public/icons/linkedin.svg";
export default function Sidebar() {
const [bots, setBots] = useState([]);
useEffect(() => {
const fetchBots = async () => {
const response = await fetch("/api/get_bots");
const data = await response.json();
setBots(data);
};
fetchBots();
}, []);
const toggleDropdown = () => {
const dropdown = document.getElementById("dropdown-toggle");
dropdown.classList.toggle("hidden");
};
return (
<>
{/* Mobile Toggle */}
<button
data-drawer-target="logo-sidebar"
data-drawer-toggle="logo-sidebar"
aria-controls="logo-sidebar"
type="button"
className="inline-flex items-center p-2 mt-2 ml-3 text-sm text-gray-500 rounded-lg sm:hidden hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-gray-200"
>
<DrawerIcon className="w-6 h-6" />
</button>
{/* Sidebar */}
<div
id="logo-sidebar"
className="fixed top-0 left-0 z-40 w-64 h-screen transition-transform -translate-x-full sm:translate-x-0"
>
<div className="flex flex-col h-full px-3 py-4 overflow-y-auto bg-gray-100">
<div className="pb-10">
<Link href="/" className="flex items-center justify-evenly mb-5">
<Image
src="/images/embedchain.png"
alt="Embedchain Logo"
width={45}
height={0}
className="block h-auto w-auto"
/>
<span className="self-center text-2xl font-bold whitespace-nowrap">
Embedchain
</span>
</Link>
<ul className="space-y-2 font-medium text-lg">
{/* Settings */}
<li>
<Link
href="/"
className="flex items-center p-2 text-gray-900 rounded-lg hover:bg-gray-200 group"
>
<SettingsIcon className="w-6 h-6 text-gray-600 transition duration-75 group-hover:text-gray-900" />
<span className="ml-3">Settings</span>
</Link>
</li>
{/* Bots */}
{bots.length !== 0 && (
<li>
<button
type="button"
className="flex items-center w-full p-2 text-base text-gray-900 transition duration-75 rounded-lg group hover:bg-gray-200"
onClick={toggleDropdown}
>
<BotIcon className="w-6 h-6 text-gray-600 transition duration-75 group-hover:text-gray-900" />
<span className="flex-1 ml-3 text-left whitespace-nowrap">
Bots
</span>
<DropdownIcon className="w-3 h-3" />
</button>
<ul
id="dropdown-toggle"
className="hidden text-sm py-2 space-y-2"
>
{bots.map((bot, index) => (
<React.Fragment key={index}>
<li>
<Link
href={`/${bot.slug}/app`}
className="flex items-center w-full p-2 text-gray-900 transition duration-75 rounded-lg pl-11 group hover:bg-gray-200"
>
{bot.name}
</Link>
</li>
</React.Fragment>
))}
</ul>
</li>
)}
</ul>
</div>
<div className="bg-gray-200 absolute bottom-0 left-0 right-0 h-20"></div>
{/* Social Icons */}
<div className="mt-auto mb-3 flex flex-row justify-evenly sticky bottom-3">
<a href="https://twitter.com/embedchain" target="blank">
<TwitterIcon className="w-6 h-6 text-gray-600 transition duration-75 hover:text-gray-900" />
</a>
<a href="https://github.com/embedchain/embedchain" target="blank">
<GithubIcon className="w-6 h-6 text-gray-600 transition duration-75 hover:text-gray-900" />
</a>
<a
href="https://www.linkedin.com/company/embedchain"
target="blank"
>
<LinkedinIcon className="w-6 h-6 text-gray-600 transition duration-75 hover:text-gray-900" />
</a>
</div>
</div>
</div>
</>
);
}
@@ -0,0 +1,25 @@
import Wrapper from "@/components/PageWrapper";
import Sidebar from "@/containers/Sidebar";
import ChatWindow from "@/containers/ChatWindow";
import { useState } from "react";
import Head from "next/head";
export default function App() {
const [botTitle, setBotTitle] = useState("");
return (
<>
<Head>
<title>{botTitle}</title>
</Head>
<Sidebar />
<Wrapper>
<ChatWindow
embedding_model="open_ai"
app_type="app"
setBotTitle={setBotTitle}
/>
</Wrapper>
</>
);
}
@@ -0,0 +1,14 @@
import "@/styles/globals.css";
import Script from "next/script";
export default function App({ Component, pageProps }) {
return (
<>
<Script
src="https://cdnjs.cloudflare.com/ajax/libs/flowbite/1.7.0/flowbite.min.js"
strategy="beforeInteractive"
/>
<Component {...pageProps} />
</>
);
}
@@ -0,0 +1,18 @@
import { Html, Head, Main, NextScript } from "next/document";
export default function Document() {
return (
<Html lang="en">
<Head>
<link
href="https://cdnjs.cloudflare.com/ajax/libs/flowbite/1.7.0/flowbite.min.css"
rel="stylesheet"
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
@@ -0,0 +1,52 @@
import Wrapper from "@/components/PageWrapper";
import Sidebar from "@/containers/Sidebar";
import CreateBot from "@/components/dashboard/CreateBot";
import SetOpenAIKey from "@/components/dashboard/SetOpenAIKey";
import PurgeChats from "@/components/dashboard/PurgeChats";
import DeleteBot from "@/components/dashboard/DeleteBot";
import { useEffect, useState } from "react";
export default function Home() {
const [isKeyPresent, setIsKeyPresent] = useState(false);
useEffect(() => {
fetch("/api/check_key")
.then((response) => response.json())
.then((data) => {
if (data.status === "ok") {
setIsKeyPresent(true);
}
});
}, []);
return (
<>
<Sidebar />
<Wrapper>
<div className="text-center">
<h1 className="mb-4 text-4xl font-extrabold leading-none tracking-tight text-gray-900 md:text-5xl">
Welcome to Embedchain Playground
</h1>
<p className="mb-6 text-lg font-normal text-gray-500 lg:text-xl">
Embedchain is a Data Platform for LLMs - Load, index, retrieve, and sync any unstructured data
dataset
</p>
</div>
<div
className={`pt-6 gap-y-4 gap-x-8 ${
isKeyPresent ? "grid lg:grid-cols-2" : "w-[50%] mx-auto"
}`}
>
<SetOpenAIKey setIsKeyPresent={setIsKeyPresent} />
{isKeyPresent && (
<>
<CreateBot />
<DeleteBot />
<PurgeChats />
</>
)}
</div>
</Wrapper>
</>
);
}
@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

Some files were not shown because too many files have changed in this diff Show More