cortexdb-langchain 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,29 @@
1
+ """CortexDB integration for LangChain.
2
+
3
+ Provides chat-message history, retrievers, and tools that connect LangChain
4
+ applications to CortexDB's long-term memory system.
5
+ """
6
+
7
+ from cortexdb_langchain.memory import CortexDBChatMessageHistory
8
+ from cortexdb_langchain.retriever import CortexDBRetriever
9
+ from cortexdb_langchain.tools import (
10
+ CortexDBForgetTool,
11
+ CortexDBSearchTool,
12
+ CortexDBStoreTool,
13
+ )
14
+
15
+ __all__ = [
16
+ "CortexDBChatMessageHistory",
17
+ "CortexDBRetriever",
18
+ "CortexDBForgetTool",
19
+ "CortexDBSearchTool",
20
+ "CortexDBStoreTool",
21
+ ]
22
+
23
+ # Legacy BaseMemory backend — only present on langchain-core < 1.0.
24
+ try:
25
+ from cortexdb_langchain.memory import CortexDBMemory # noqa: F401
26
+
27
+ __all__.append("CortexDBMemory")
28
+ except ImportError:
29
+ pass
@@ -0,0 +1,141 @@
1
+ """LangChain memory backed by CortexDB.
2
+
3
+ Primary, version-agnostic primitive: :class:`CortexDBChatMessageHistory`, a
4
+ ``BaseChatMessageHistory`` (available in langchain-core 0.3 **and** 1.x). Use it
5
+ with ``RunnableWithMessageHistory`` to give a chain/agent long-term memory:
6
+ messages are persisted to CortexDB and relevant context is recalled back.
7
+
8
+ The legacy :class:`CortexDBMemory` (built on the pre-1.0 ``BaseMemory``) is kept
9
+ only when that base class is importable (langchain-core < 1.0), since 1.x removed
10
+ the ``BaseMemory`` framework entirely.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from typing import Any, Optional
16
+
17
+ from langchain_core.chat_history import BaseChatMessageHistory
18
+ from langchain_core.messages import AIMessage, BaseMessage
19
+
20
+ from cortexdb import Cortex
21
+
22
+
23
+ class CortexDBChatMessageHistory(BaseChatMessageHistory):
24
+ """Chat-message history backed by CortexDB (langchain-core 0.3 + 1.x).
25
+
26
+ - ``add_message`` / ``add_messages`` persist each message via ``experience``.
27
+ - ``messages`` recalls relevant long-term context for ``recall_query`` and
28
+ surfaces it as a single ``AIMessage`` (CortexDB is semantic memory, not a
29
+ literal per-session log). Set ``recall_query`` to the current user input.
30
+ - ``clear`` forgets the scope.
31
+
32
+ Example::
33
+
34
+ from cortexdb import Cortex
35
+ from cortexdb_langchain import CortexDBChatMessageHistory
36
+
37
+ client = Cortex("https://api-v1.cortexdb.ai", actor="user:app", bearer="v4.public...")
38
+ history = CortexDBChatMessageHistory(client=client, scope="user:my-app")
39
+ """
40
+
41
+ def __init__(
42
+ self,
43
+ client: Cortex,
44
+ scope: str = "user:default",
45
+ recall_query: str = "",
46
+ ) -> None:
47
+ self._client = client
48
+ self.scope = scope
49
+ self.recall_query = recall_query
50
+
51
+ @property
52
+ def messages(self) -> list[BaseMessage]:
53
+ query = self.recall_query
54
+ if not query:
55
+ return []
56
+ result = self._client.recall(self.scope, query=str(query))
57
+ block = result.get("context_block", "")
58
+ return [AIMessage(content=block)] if block else []
59
+
60
+ def add_message(self, message: BaseMessage) -> None:
61
+ self._client.experience(
62
+ self.scope, text=f"{message.type}: {message.content}"
63
+ )
64
+
65
+ def add_messages(self, messages: list[BaseMessage]) -> None:
66
+ for message in messages:
67
+ self.add_message(message)
68
+
69
+ def clear(self) -> None:
70
+ self._client.forget(
71
+ self.scope,
72
+ confirm_all=True,
73
+ cascade="redact_events",
74
+ reason="LangChain memory clear requested",
75
+ )
76
+
77
+
78
+ # ── Legacy BaseMemory backend (langchain-core < 1.0 only) ────────────────────
79
+ # langchain-core 1.x removed BaseMemory and the classic `memory=` chain hook, so
80
+ # we only define this when the base class is importable.
81
+ try:
82
+ from langchain_core.memory import BaseMemory as _BaseMemory
83
+ except ImportError: # langchain-core >= 1.0
84
+ _BaseMemory = None
85
+
86
+ if _BaseMemory is not None:
87
+ from pydantic import PrivateAttr
88
+
89
+ class CortexDBMemory(_BaseMemory): # type: ignore[misc,valid-type]
90
+ """Deprecated: classic BaseMemory backend (langchain-core < 1.0).
91
+
92
+ Prefer :class:`CortexDBChatMessageHistory` with
93
+ ``RunnableWithMessageHistory`` on langchain-core 1.x.
94
+ """
95
+
96
+ memory_key: str = "cortex_context"
97
+ input_key: Optional[str] = None
98
+ output_key: Optional[str] = None
99
+ scope: str = "user:default"
100
+
101
+ _client: Cortex = PrivateAttr()
102
+
103
+ def __init__(self, client: Cortex, **kwargs: Any) -> None:
104
+ super().__init__(**kwargs)
105
+ self._client = client
106
+
107
+ @property
108
+ def memory_variables(self) -> list[str]:
109
+ return [self.memory_key]
110
+
111
+ def load_memory_variables(self, inputs: dict[str, Any]) -> dict[str, Any]:
112
+ if self.input_key is not None:
113
+ query = inputs.get(self.input_key, "")
114
+ else:
115
+ query = next(iter(inputs.values()), "") if inputs else ""
116
+ if not query:
117
+ return {self.memory_key: ""}
118
+ result = self._client.recall(self.scope, query=str(query))
119
+ return {self.memory_key: result.get("context_block", "")}
120
+
121
+ def save_context(
122
+ self, inputs: dict[str, Any], outputs: dict[str, str]
123
+ ) -> None:
124
+ if self.output_key is not None:
125
+ output_text = outputs.get(self.output_key, "")
126
+ else:
127
+ output_text = next(iter(outputs.values()), "") if outputs else ""
128
+ if self.input_key is not None:
129
+ input_text = inputs.get(self.input_key, "")
130
+ else:
131
+ input_text = next(iter(inputs.values()), "") if inputs else ""
132
+ content = f"User: {input_text}\nAssistant: {output_text}"
133
+ self._client.experience(self.scope, text=content)
134
+
135
+ def clear(self) -> None:
136
+ self._client.forget(
137
+ self.scope,
138
+ confirm_all=True,
139
+ cascade="redact_events",
140
+ reason="LangChain memory clear requested",
141
+ )
@@ -0,0 +1,74 @@
1
+ """LangChain retriever backed by CortexDB.
2
+
3
+ Provides a standard LangChain retriever interface for semantic search
4
+ over CortexDB's memory store, compatible with retrieval chains and
5
+ retrieval-augmented generation (RAG) pipelines.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from typing import Any, Optional
11
+
12
+ from langchain_core.callbacks import CallbackManagerForRetrieverRun
13
+ from langchain_core.documents import Document
14
+ from langchain_core.retrievers import BaseRetriever
15
+ from pydantic import Field, PrivateAttr
16
+
17
+ from cortexdb import Cortex
18
+
19
+
20
+ class CortexDBRetriever(BaseRetriever):
21
+ """LangChain retriever that queries CortexDB's memory store.
22
+
23
+ Wraps CortexDB's ``recall`` API as a standard LangChain retriever,
24
+ returning results as LangChain ``Document`` objects.
25
+
26
+ Args:
27
+ client: An initialized CortexDB client instance.
28
+ scope: The scope path for memory isolation (hierarchical string).
29
+
30
+ Example::
31
+
32
+ from cortexdb import Cortex
33
+ from cortexdb_langchain import CortexDBRetriever
34
+
35
+ client = Cortex(
36
+ "https://api-v1.cortexdb.ai",
37
+ actor="user:app",
38
+ bearer="v4.public...",
39
+ )
40
+ retriever = CortexDBRetriever(client=client, scope="user:my-app")
41
+
42
+ docs = retriever.invoke("What happened in the last sprint?")
43
+ for doc in docs:
44
+ print(doc.page_content)
45
+ """
46
+
47
+ scope: str = "user:default"
48
+
49
+ _client: Cortex = PrivateAttr()
50
+
51
+ def __init__(self, client: Cortex, **kwargs: Any) -> None:
52
+ super().__init__(**kwargs)
53
+ self._client = client
54
+
55
+ def _get_relevant_documents(
56
+ self,
57
+ query: str,
58
+ *,
59
+ run_manager: CallbackManagerForRetrieverRun,
60
+ ) -> list[Document]:
61
+ result = self._client.recall(self.scope, query=query)
62
+
63
+ metadata = {
64
+ "source": "cortexdb",
65
+ "scope": self.scope,
66
+ "pack_id": result.get("pack_id"),
67
+ }
68
+
69
+ return [
70
+ Document(
71
+ page_content=result.get("context_block", ""),
72
+ metadata=metadata,
73
+ )
74
+ ]
@@ -0,0 +1,121 @@
1
+ """LangChain tools for interacting with CortexDB.
2
+
3
+ Provides search, store, and forget tools that allow LangChain agents
4
+ to interact with CortexDB's memory system as part of their tool-use
5
+ capabilities.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from typing import Any, Optional, Type
11
+
12
+ from langchain_core.callbacks import CallbackManagerForToolRun
13
+ from langchain_core.tools import BaseTool
14
+ from pydantic import BaseModel, Field
15
+
16
+ from cortexdb import Cortex
17
+
18
+
19
+ class _SearchInput(BaseModel):
20
+ query: str = Field(description="The search query to find relevant memories.")
21
+
22
+
23
+ class CortexDBSearchTool(BaseTool):
24
+ """LangChain tool for searching memories in CortexDB."""
25
+
26
+ name: str = "cortexdb_search"
27
+ description: str = (
28
+ "Search CortexDB for relevant memories and past context. "
29
+ "Use this when you need to recall information from previous "
30
+ "conversations or stored knowledge."
31
+ )
32
+ args_schema: Type[BaseModel] = _SearchInput
33
+ scope: str = "user:default"
34
+
35
+ _client: Cortex
36
+
37
+ def __init__(self, client: Cortex, **kwargs: Any) -> None:
38
+ super().__init__(**kwargs)
39
+ self._client = client
40
+
41
+ def _run(
42
+ self,
43
+ query: str,
44
+ run_manager: Optional[CallbackManagerForToolRun] = None,
45
+ ) -> str:
46
+ result = self._client.recall(self.scope, query=query)
47
+
48
+ context = result.get("context_block", "")
49
+ if not context:
50
+ return "No relevant memories found."
51
+
52
+ return context
53
+
54
+
55
+ class _StoreInput(BaseModel):
56
+ content: str = Field(description="The content to store as a memory.")
57
+
58
+
59
+ class CortexDBStoreTool(BaseTool):
60
+ """LangChain tool for storing memories in CortexDB."""
61
+
62
+ name: str = "cortexdb_store"
63
+ description: str = (
64
+ "Store information in CortexDB's long-term memory. "
65
+ "Use this to save important facts, decisions, or context "
66
+ "that should be remembered for future interactions."
67
+ )
68
+ args_schema: Type[BaseModel] = _StoreInput
69
+ scope: str = "user:default"
70
+
71
+ _client: Cortex
72
+
73
+ def __init__(self, client: Cortex, **kwargs: Any) -> None:
74
+ super().__init__(**kwargs)
75
+ self._client = client
76
+
77
+ def _run(
78
+ self,
79
+ content: str,
80
+ run_manager: Optional[CallbackManagerForToolRun] = None,
81
+ ) -> str:
82
+ resp = self._client.experience(self.scope, text=content)
83
+ return f"Memory stored successfully (event_id: {resp.get('event_id')})."
84
+
85
+
86
+ class _ForgetInput(BaseModel):
87
+ query: str = Field(description="Query identifying the memories to forget.")
88
+ reason: str = Field(description="The reason for forgetting these memories.")
89
+
90
+
91
+ class CortexDBForgetTool(BaseTool):
92
+ """LangChain tool for forgetting memories in CortexDB."""
93
+
94
+ name: str = "cortexdb_forget"
95
+ description: str = (
96
+ "Forget or remove memories from CortexDB. "
97
+ "Use this when information should no longer be retained, "
98
+ "such as for privacy compliance or data correction."
99
+ )
100
+ args_schema: Type[BaseModel] = _ForgetInput
101
+ scope: str = "user:default"
102
+
103
+ _client: Cortex
104
+
105
+ def __init__(self, client: Cortex, **kwargs: Any) -> None:
106
+ super().__init__(**kwargs)
107
+ self._client = client
108
+
109
+ def _run(
110
+ self,
111
+ query: str,
112
+ reason: str,
113
+ run_manager: Optional[CallbackManagerForToolRun] = None,
114
+ ) -> str:
115
+ resp = self._client.forget(
116
+ self.scope,
117
+ confirm_all=True,
118
+ cascade="redact_events",
119
+ reason=reason,
120
+ )
121
+ return f"Forget request accepted (audit_id: {resp.get('audit_id')})."
@@ -0,0 +1,53 @@
1
+ Metadata-Version: 2.4
2
+ Name: cortexdb-langchain
3
+ Version: 0.1.0
4
+ Summary: LangChain integration for CortexDB — long-term memory for AI systems
5
+ License-Expression: Apache-2.0
6
+ Requires-Python: >=3.10
7
+ Requires-Dist: cortexdbai>=0.1.0
8
+ Requires-Dist: langchain-core>=0.3
9
+ Provides-Extra: dev
10
+ Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
11
+ Requires-Dist: pytest>=7.0; extra == 'dev'
12
+ Description-Content-Type: text/markdown
13
+
14
+ # cortexdb-langchain
15
+
16
+ LangChain integration for CortexDB long-term memory.
17
+
18
+ > **LLM provider note (audit BLK-2):** the canonical quickstart uses
19
+ > `from langchain_openai import ChatOpenAI` for the example agent. CortexDB
20
+ > itself is LLM-agnostic — the LangChain example just needs *some* model to
21
+ > drive the agent. Swap with one line:
22
+ >
23
+ > ```python
24
+ > # OpenAI (default in the docs)
25
+ > from langchain_openai import ChatOpenAI
26
+ > llm = ChatOpenAI(model="gpt-4o")
27
+ >
28
+ > # Anthropic
29
+ > from langchain_anthropic import ChatAnthropic
30
+ > llm = ChatAnthropic(model="claude-sonnet-4-6")
31
+ >
32
+ > # Google
33
+ > from langchain_google_genai import ChatGoogleGenerativeAI
34
+ > llm = ChatGoogleGenerativeAI(model="gemini-1.5-pro")
35
+ >
36
+ > # Local / Ollama (no API key)
37
+ > from langchain_community.chat_models import ChatOllama
38
+ > llm = ChatOllama(model="llama3.1")
39
+ > ```
40
+ >
41
+ > Nothing in `cortexdb-langchain` reads `OPENAI_API_KEY`. The retriever and
42
+ > memory classes only talk to the CortexDB v1 surface.
43
+
44
+ ## Install
45
+
46
+ ```bash
47
+ pip install cortexdb-langchain
48
+ ```
49
+
50
+ ## API base URL
51
+
52
+ The SDK and integration default to `https://api-v1.cortexdb.ai` (audit FRI-8).
53
+ Override with `CORTEXDB_API_URL` if you self-host.
@@ -0,0 +1,7 @@
1
+ cortexdb_langchain/__init__.py,sha256=k7DwyE8EJUq-fy-pLozMENjFOtWW_pOxL1KfttzawA4,803
2
+ cortexdb_langchain/memory.py,sha256=wVzgfTKR8sP3NHhDByVh_htqtfeUVP-FSooSzJEC7qk,5356
3
+ cortexdb_langchain/retriever.py,sha256=GImZOZvUEezJqnetPctRvTbZXqxazxp-DbXhLtiYP5s,2180
4
+ cortexdb_langchain/tools.py,sha256=_mjDRQUNm4_ISZD7hI1cSjm6ibMI1IvJhdl8ZjcPG5I,3607
5
+ cortexdb_langchain-0.1.0.dist-info/METADATA,sha256=Vr4iddBlO-_AHFuSJ9_ae8oroJAFxkb0OVRLDXLfiog,1595
6
+ cortexdb_langchain-0.1.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
7
+ cortexdb_langchain-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.30.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any