langchain-ceramic 0.1.0__tar.gz

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,111 @@
1
+ Metadata-Version: 2.4
2
+ Name: langchain-ceramic
3
+ Version: 0.1.0
4
+ Summary: An integration package connecting Ceramic and LangChain
5
+ License: MIT
6
+ Author: Ceramic Team
7
+ Author-email: info@ceramic.ai
8
+ Requires-Python: >=3.10,<4.0
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Programming Language :: Python :: 3.14
16
+ Requires-Dist: ceramic-ai (>=0.1.0)
17
+ Requires-Dist: langchain-core (>=0.3.0,<1.0.0)
18
+ Project-URL: Repository, https://github.com/CeramicTeam/langchain-ceramic
19
+ Description-Content-Type: text/markdown
20
+
21
+ # LangChain Ceramic
22
+
23
+ LangChain integration for [Ceramic](https://ceramic.ai) — a web search API built for LLMs.
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ pip install langchain-ceramic
29
+ ```
30
+
31
+ ## Setup
32
+
33
+ Generate an API key at [platform.ceramic.ai/keys](https://platform.ceramic.ai/keys), then export it:
34
+
35
+ ```bash
36
+ export CERAMIC_API_KEY="your-api-key"
37
+ ```
38
+
39
+ Or pass it directly when constructing the retriever or tool.
40
+
41
+ ## Usage
42
+
43
+ ### CeramicRetriever in a RAG chain
44
+
45
+ ```python
46
+ from langchain_ceramic import CeramicRetriever
47
+ from langchain_core.prompts import ChatPromptTemplate
48
+ from langchain_core.output_parsers import StrOutputParser
49
+ from langchain_core.runnables import RunnablePassthrough
50
+ from langchain_openai import ChatOpenAI
51
+
52
+ retriever = CeramicRetriever(k=5) # reads CERAMIC_API_KEY from env
53
+
54
+ prompt = ChatPromptTemplate.from_template(
55
+ "Answer the question based only on the following context:\n\n{context}\n\nQuestion: {question}"
56
+ )
57
+
58
+ chain = (
59
+ {"context": retriever, "question": RunnablePassthrough()}
60
+ | prompt
61
+ | ChatOpenAI(model="gpt-5.5")
62
+ | StrOutputParser()
63
+ )
64
+
65
+ answer = chain.invoke("What are the latest AI chip export restrictions?")
66
+ print(answer)
67
+ ```
68
+
69
+ Each retrieved `Document` has:
70
+ - `page_content`: the result description
71
+ - `metadata["title"]`: page title
72
+ - `metadata["url"]`: source URL
73
+
74
+ ### CeramicSearch in an agent
75
+
76
+ ```python
77
+ from langchain_ceramic import CeramicSearch
78
+ from langchain_openai import ChatOpenAI
79
+ from langchain.agents import create_agent
80
+
81
+ tools = [CeramicSearch(max_results=5)]
82
+ agent = create_agent(ChatOpenAI(model="gpt-5.5"), tools=tools)
83
+
84
+ result = agent.invoke({"messages": [{"role": "user", "content": "Find recent news about GLP-1 drugs"}]})
85
+ print(result["messages"][-1].content)
86
+ ```
87
+
88
+ ### Async usage
89
+
90
+ Both `CeramicRetriever` and `CeramicSearch` support async:
91
+
92
+ ```python
93
+ docs = await retriever.ainvoke("California rental laws")
94
+ ```
95
+
96
+ ## API reference
97
+
98
+ ### `CeramicRetriever`
99
+
100
+ | Parameter | Type | Default | Description |
101
+ |-----------|------|---------|-------------|
102
+ | `api_key` | `str \| None` | `None` | Ceramic API key (falls back to `CERAMIC_API_KEY` env var) |
103
+ | `k` | `int` | `10` | Maximum number of results to return |
104
+
105
+ ### `CeramicSearch`
106
+
107
+ | Parameter | Type | Default | Description |
108
+ |-----------|------|---------|-------------|
109
+ | `api_key` | `str \| None` | `None` | Ceramic API key (falls back to `CERAMIC_API_KEY` env var) |
110
+ | `max_results` | `int` | `5` | Maximum number of results to include in the response string |
111
+
@@ -0,0 +1,90 @@
1
+ # LangChain Ceramic
2
+
3
+ LangChain integration for [Ceramic](https://ceramic.ai) — a web search API built for LLMs.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install langchain-ceramic
9
+ ```
10
+
11
+ ## Setup
12
+
13
+ Generate an API key at [platform.ceramic.ai/keys](https://platform.ceramic.ai/keys), then export it:
14
+
15
+ ```bash
16
+ export CERAMIC_API_KEY="your-api-key"
17
+ ```
18
+
19
+ Or pass it directly when constructing the retriever or tool.
20
+
21
+ ## Usage
22
+
23
+ ### CeramicRetriever in a RAG chain
24
+
25
+ ```python
26
+ from langchain_ceramic import CeramicRetriever
27
+ from langchain_core.prompts import ChatPromptTemplate
28
+ from langchain_core.output_parsers import StrOutputParser
29
+ from langchain_core.runnables import RunnablePassthrough
30
+ from langchain_openai import ChatOpenAI
31
+
32
+ retriever = CeramicRetriever(k=5) # reads CERAMIC_API_KEY from env
33
+
34
+ prompt = ChatPromptTemplate.from_template(
35
+ "Answer the question based only on the following context:\n\n{context}\n\nQuestion: {question}"
36
+ )
37
+
38
+ chain = (
39
+ {"context": retriever, "question": RunnablePassthrough()}
40
+ | prompt
41
+ | ChatOpenAI(model="gpt-5.5")
42
+ | StrOutputParser()
43
+ )
44
+
45
+ answer = chain.invoke("What are the latest AI chip export restrictions?")
46
+ print(answer)
47
+ ```
48
+
49
+ Each retrieved `Document` has:
50
+ - `page_content`: the result description
51
+ - `metadata["title"]`: page title
52
+ - `metadata["url"]`: source URL
53
+
54
+ ### CeramicSearch in an agent
55
+
56
+ ```python
57
+ from langchain_ceramic import CeramicSearch
58
+ from langchain_openai import ChatOpenAI
59
+ from langchain.agents import create_agent
60
+
61
+ tools = [CeramicSearch(max_results=5)]
62
+ agent = create_agent(ChatOpenAI(model="gpt-5.5"), tools=tools)
63
+
64
+ result = agent.invoke({"messages": [{"role": "user", "content": "Find recent news about GLP-1 drugs"}]})
65
+ print(result["messages"][-1].content)
66
+ ```
67
+
68
+ ### Async usage
69
+
70
+ Both `CeramicRetriever` and `CeramicSearch` support async:
71
+
72
+ ```python
73
+ docs = await retriever.ainvoke("California rental laws")
74
+ ```
75
+
76
+ ## API reference
77
+
78
+ ### `CeramicRetriever`
79
+
80
+ | Parameter | Type | Default | Description |
81
+ |-----------|------|---------|-------------|
82
+ | `api_key` | `str \| None` | `None` | Ceramic API key (falls back to `CERAMIC_API_KEY` env var) |
83
+ | `k` | `int` | `10` | Maximum number of results to return |
84
+
85
+ ### `CeramicSearch`
86
+
87
+ | Parameter | Type | Default | Description |
88
+ |-----------|------|---------|-------------|
89
+ | `api_key` | `str \| None` | `None` | Ceramic API key (falls back to `CERAMIC_API_KEY` env var) |
90
+ | `max_results` | `int` | `5` | Maximum number of results to include in the response string |
@@ -0,0 +1,4 @@
1
+ from langchain_ceramic.retrievers import CeramicRetriever
2
+ from langchain_ceramic.tools import CeramicSearch
3
+
4
+ __all__ = ["CeramicRetriever", "CeramicSearch"]
File without changes
@@ -0,0 +1,78 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from typing import Optional
5
+
6
+ from langchain_core.callbacks import (
7
+ AsyncCallbackManagerForRetrieverRun,
8
+ CallbackManagerForRetrieverRun,
9
+ )
10
+ from langchain_core.documents import Document
11
+ from langchain_core.retrievers import BaseRetriever
12
+ from pydantic import ConfigDict, PrivateAttr, model_validator
13
+
14
+ from ceramic_ai import AsyncCeramic, Ceramic
15
+
16
+
17
+ class CeramicRetriever(BaseRetriever):
18
+ """Retriever that uses Ceramic's web search API.
19
+
20
+ Setup:
21
+ Install the package and set your API key:
22
+
23
+ .. code-block:: bash
24
+
25
+ pip install langchain-ceramic
26
+ export CERAMIC_API_KEY="your-api-key"
27
+
28
+ Example:
29
+ .. code-block:: python
30
+
31
+ from langchain_ceramic import CeramicRetriever
32
+
33
+ retriever = CeramicRetriever(k=5)
34
+ docs = retriever.invoke("latest AI chip export restrictions")
35
+ """
36
+
37
+ model_config = ConfigDict(arbitrary_types_allowed=True)
38
+
39
+ api_key: Optional[str] = None
40
+ k: int = 10
41
+
42
+ _client: Ceramic = PrivateAttr(default=None)
43
+ _async_client: AsyncCeramic = PrivateAttr(default=None)
44
+
45
+ @model_validator(mode="after")
46
+ def validate_api_key(self) -> "CeramicRetriever":
47
+ key = self.api_key or os.environ.get("CERAMIC_API_KEY")
48
+ if not key:
49
+ raise ValueError(
50
+ "Ceramic API key required. Pass api_key= or set CERAMIC_API_KEY."
51
+ )
52
+ self._client = Ceramic(api_key=key)
53
+ self._async_client = AsyncCeramic(api_key=key)
54
+ return self
55
+
56
+ def _get_relevant_documents(
57
+ self, query: str, *, run_manager: CallbackManagerForRetrieverRun
58
+ ) -> list[Document]:
59
+ response = self._client.search(query=query)
60
+ return [
61
+ Document(
62
+ page_content=result.description or "",
63
+ metadata={"title": result.title, "url": result.url},
64
+ )
65
+ for result in response.result.results[: self.k]
66
+ ]
67
+
68
+ async def _aget_relevant_documents(
69
+ self, query: str, *, run_manager: AsyncCallbackManagerForRetrieverRun
70
+ ) -> list[Document]:
71
+ response = await self._async_client.search(query=query)
72
+ return [
73
+ Document(
74
+ page_content=result.description or "",
75
+ metadata={"title": result.title, "url": result.url},
76
+ )
77
+ for result in response.result.results[: self.k]
78
+ ]
@@ -0,0 +1,73 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from typing import Optional, Type
5
+
6
+ from langchain_core.tools import BaseTool
7
+ from pydantic import BaseModel, ConfigDict, Field, PrivateAttr, model_validator
8
+
9
+ from ceramic_ai import AsyncCeramic, Ceramic
10
+
11
+
12
+ class CeramicSearchInput(BaseModel):
13
+ query: str = Field(description="Search query to look up on the web.")
14
+
15
+
16
+ class CeramicSearch(BaseTool):
17
+ """Tool that queries the Ceramic web search API.
18
+
19
+ Setup:
20
+ .. code-block:: bash
21
+
22
+ pip install langchain-ceramic
23
+ export CERAMIC_API_KEY="your-api-key"
24
+
25
+ Example:
26
+ .. code-block:: python
27
+
28
+ from langchain_ceramic import CeramicSearch
29
+
30
+ tool = CeramicSearch(max_results=5)
31
+ tool.invoke("latest developments in GLP-1 drugs")
32
+ """
33
+
34
+ model_config = ConfigDict(arbitrary_types_allowed=True)
35
+
36
+ name: str = "ceramic_search"
37
+ description: str = (
38
+ "A web search tool powered by Ceramic. "
39
+ "Use this to find current information from the web. "
40
+ "Input should be a search query string."
41
+ )
42
+ args_schema: Type[BaseModel] = CeramicSearchInput
43
+
44
+ api_key: Optional[str] = None
45
+ max_results: int = 5
46
+
47
+ _client: Ceramic = PrivateAttr(default=None)
48
+ _async_client: AsyncCeramic = PrivateAttr(default=None)
49
+
50
+ @model_validator(mode="after")
51
+ def validate_api_key(self) -> "CeramicSearch":
52
+ key = self.api_key or os.environ.get("CERAMIC_API_KEY")
53
+ if not key:
54
+ raise ValueError(
55
+ "Ceramic API key required. Pass api_key= or set CERAMIC_API_KEY."
56
+ )
57
+ self._client = Ceramic(api_key=key)
58
+ self._async_client = AsyncCeramic(api_key=key)
59
+ return self
60
+
61
+ def _run(self, query: str) -> str:
62
+ response = self._client.search(query=query)
63
+ results = response.result.results[: self.max_results]
64
+ return "\n\n".join(
65
+ f"**{r.title}**\n{r.description}\nSource: {r.url}" for r in results
66
+ )
67
+
68
+ async def _arun(self, query: str) -> str:
69
+ response = await self._async_client.search(query=query)
70
+ results = response.result.results[: self.max_results]
71
+ return "\n\n".join(
72
+ f"**{r.title}**\n{r.description}\nSource: {r.url}" for r in results
73
+ )
@@ -0,0 +1,33 @@
1
+ [tool.poetry]
2
+ name = "langchain-ceramic"
3
+ version = "0.1.0"
4
+ description = "An integration package connecting Ceramic and LangChain"
5
+ authors = ["Ceramic Team <info@ceramic.ai>"]
6
+ readme = "README.md"
7
+ repository = "https://github.com/CeramicTeam/langchain-ceramic"
8
+ license = "MIT"
9
+ include = ["langchain_ceramic/py.typed"]
10
+
11
+ [tool.poetry.dependencies]
12
+ python = ">=3.10,<4.0"
13
+ langchain-core = ">=0.3.0,<1.0.0"
14
+ ceramic-ai = ">=0.1.0"
15
+
16
+ [tool.poetry.group.dev.dependencies]
17
+ pytest = "^7.4.0"
18
+ pytest-asyncio = "^0.21.0"
19
+ langchain = ">=0.3.0"
20
+
21
+ [tool.pytest.ini_options]
22
+ addopts = "--strict-markers --strict-config --durations=5"
23
+ asyncio_mode = "auto"
24
+ markers = [
25
+ "integration: marks tests as integration tests (require CERAMIC_API_KEY)",
26
+ ]
27
+
28
+ [tool.ruff.lint]
29
+ select = ["E", "F", "I"]
30
+
31
+ [build-system]
32
+ requires = ["poetry-core"]
33
+ build-backend = "poetry.core.masonry.api"