langchain-pythia 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,7 @@
1
+ __pycache__/
2
+ *.pyc
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .pytest_cache/
7
+ .mypy_cache/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Pythia Oracle
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,120 @@
1
+ Metadata-Version: 2.4
2
+ Name: langchain-pythia
3
+ Version: 0.1.0
4
+ Summary: LangChain integration for Pythia Oracle — on-chain calculated crypto indicators (EMA, RSI, Bollinger, Volatility) via Chainlink
5
+ Project-URL: Homepage, https://pythia.c3x-solutions.com
6
+ Project-URL: Repository, https://github.com/pythia-the-oracle/langchain-pythia
7
+ Project-URL: Documentation, https://github.com/pythia-the-oracle/langchain-pythia#readme
8
+ Author-email: Pythia Oracle <ivan.jeremic@c3x-solutions.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: ai-agent,bollinger,chainlink,crypto,defi,ema,langchain,on-chain,oracle,rsi,smart-contracts,technical-analysis,volatility
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Topic :: Office/Business :: Financial
17
+ Classifier: Topic :: Software Development :: Libraries
18
+ Requires-Python: >=3.10
19
+ Requires-Dist: httpx<1.0.0,>=0.25.0
20
+ Requires-Dist: langchain-core<2.0.0,>=1.2.21
21
+ Provides-Extra: dev
22
+ Requires-Dist: pytest-asyncio>=0.20; extra == 'dev'
23
+ Requires-Dist: pytest>=7.0; extra == 'dev'
24
+ Description-Content-Type: text/markdown
25
+
26
+ # langchain-pythia
27
+
28
+ [![PyPI](https://img.shields.io/pypi/v/langchain-pythia)](https://pypi.org/project/langchain-pythia/)
29
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
30
+
31
+ **LangChain integration for Pythia Oracle — on-chain calculated crypto indicators via Chainlink.**
32
+
33
+ Access EMA, RSI, Bollinger Bands, Volatility, and more for 22 crypto tokens directly from your LangChain agents. Pythia is the first oracle delivering calculated technical indicators on-chain, not just prices.
34
+
35
+ ## Installation
36
+
37
+ ```bash
38
+ pip install langchain-pythia
39
+ ```
40
+
41
+ ## Quick Start
42
+
43
+ ```python
44
+ from langchain_pythia import PythiaListTokensTool, PythiaTokenFeedsTool
45
+
46
+ # Use with any LangChain agent
47
+ tools = [PythiaListTokensTool(), PythiaTokenFeedsTool()]
48
+
49
+ # Or call directly
50
+ list_tool = PythiaListTokensTool()
51
+ print(list_tool.invoke(""))
52
+
53
+ feeds_tool = PythiaTokenFeedsTool()
54
+ print(feeds_tool.invoke({"engine_id": "bitcoin"}))
55
+ ```
56
+
57
+ ## With a LangChain Agent
58
+
59
+ ```python
60
+ from langchain_openai import ChatOpenAI
61
+ from langgraph.prebuilt import create_react_agent
62
+ from langchain_pythia import (
63
+ PythiaListTokensTool,
64
+ PythiaTokenFeedsTool,
65
+ PythiaHealthCheckTool,
66
+ PythiaContractsTool,
67
+ PythiaPricingTool,
68
+ )
69
+
70
+ tools = [
71
+ PythiaListTokensTool(),
72
+ PythiaTokenFeedsTool(),
73
+ PythiaHealthCheckTool(),
74
+ PythiaContractsTool(),
75
+ PythiaPricingTool(),
76
+ ]
77
+
78
+ llm = ChatOpenAI(model="gpt-4o")
79
+ agent = create_react_agent(llm, tools)
80
+
81
+ # Ask about on-chain indicators
82
+ response = agent.invoke(
83
+ {"messages": [{"role": "user", "content": "What RSI feeds does Pythia have for Bitcoin?"}]}
84
+ )
85
+ ```
86
+
87
+ ## Available Tools
88
+
89
+ | Tool | Description |
90
+ |------|-------------|
91
+ | `PythiaListTokensTool` | List all 22 tracked tokens with status, uptime, and data sources |
92
+ | `PythiaTokenFeedsTool` | Get all indicator feed names (EMA, RSI, Bollinger, Volatility) for a token |
93
+ | `PythiaHealthCheckTool` | Per-token 30-day uptime, data source health, incident report |
94
+ | `PythiaContractsTool` | Contract addresses (operator, consumers, faucet, LINK) for on-chain integration |
95
+ | `PythiaPricingTool` | Pricing tiers and free trial faucet info |
96
+
97
+ ## What Pythia Provides
98
+
99
+ - **484 indicator feeds** across 22 tokens (BTC, SOL, TAO, RENDER, ONDO, AAVE, UNI, and more)
100
+ - **5 indicator types:** EMA, RSI, Bollinger (upper/lower), Volatility, USD Price
101
+ - **4 timeframes:** 5-minute, 1-hour, 1-day, 1-week
102
+ - **On-chain delivery** via Chainlink on Polygon
103
+ - **Free trial** via PythiaFaucet — no LINK needed, 5 requests/day
104
+
105
+ ## Use Cases
106
+
107
+ - **AI trading agents** that need on-chain technical signals
108
+ - **DeFi vault rebalancing** based on RSI or volatility thresholds
109
+ - **Risk management** using Bollinger Band width
110
+ - **Portfolio analysis** with real-time calculated metrics
111
+
112
+ ## Related
113
+
114
+ - [Pythia MCP Server](https://pypi.org/project/pythia-oracle-mcp/) — MCP integration for Claude, Cursor, VS Code
115
+ - [Integration Examples](https://github.com/pythia-the-oracle/pythia-oracle-examples) — Solidity contracts with Hardhat
116
+ - [Website & Feed Explorer](https://pythia.c3x-solutions.com)
117
+
118
+ ## License
119
+
120
+ MIT
@@ -0,0 +1,95 @@
1
+ # langchain-pythia
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/langchain-pythia)](https://pypi.org/project/langchain-pythia/)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ **LangChain integration for Pythia Oracle — on-chain calculated crypto indicators via Chainlink.**
7
+
8
+ Access EMA, RSI, Bollinger Bands, Volatility, and more for 22 crypto tokens directly from your LangChain agents. Pythia is the first oracle delivering calculated technical indicators on-chain, not just prices.
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ pip install langchain-pythia
14
+ ```
15
+
16
+ ## Quick Start
17
+
18
+ ```python
19
+ from langchain_pythia import PythiaListTokensTool, PythiaTokenFeedsTool
20
+
21
+ # Use with any LangChain agent
22
+ tools = [PythiaListTokensTool(), PythiaTokenFeedsTool()]
23
+
24
+ # Or call directly
25
+ list_tool = PythiaListTokensTool()
26
+ print(list_tool.invoke(""))
27
+
28
+ feeds_tool = PythiaTokenFeedsTool()
29
+ print(feeds_tool.invoke({"engine_id": "bitcoin"}))
30
+ ```
31
+
32
+ ## With a LangChain Agent
33
+
34
+ ```python
35
+ from langchain_openai import ChatOpenAI
36
+ from langgraph.prebuilt import create_react_agent
37
+ from langchain_pythia import (
38
+ PythiaListTokensTool,
39
+ PythiaTokenFeedsTool,
40
+ PythiaHealthCheckTool,
41
+ PythiaContractsTool,
42
+ PythiaPricingTool,
43
+ )
44
+
45
+ tools = [
46
+ PythiaListTokensTool(),
47
+ PythiaTokenFeedsTool(),
48
+ PythiaHealthCheckTool(),
49
+ PythiaContractsTool(),
50
+ PythiaPricingTool(),
51
+ ]
52
+
53
+ llm = ChatOpenAI(model="gpt-4o")
54
+ agent = create_react_agent(llm, tools)
55
+
56
+ # Ask about on-chain indicators
57
+ response = agent.invoke(
58
+ {"messages": [{"role": "user", "content": "What RSI feeds does Pythia have for Bitcoin?"}]}
59
+ )
60
+ ```
61
+
62
+ ## Available Tools
63
+
64
+ | Tool | Description |
65
+ |------|-------------|
66
+ | `PythiaListTokensTool` | List all 22 tracked tokens with status, uptime, and data sources |
67
+ | `PythiaTokenFeedsTool` | Get all indicator feed names (EMA, RSI, Bollinger, Volatility) for a token |
68
+ | `PythiaHealthCheckTool` | Per-token 30-day uptime, data source health, incident report |
69
+ | `PythiaContractsTool` | Contract addresses (operator, consumers, faucet, LINK) for on-chain integration |
70
+ | `PythiaPricingTool` | Pricing tiers and free trial faucet info |
71
+
72
+ ## What Pythia Provides
73
+
74
+ - **484 indicator feeds** across 22 tokens (BTC, SOL, TAO, RENDER, ONDO, AAVE, UNI, and more)
75
+ - **5 indicator types:** EMA, RSI, Bollinger (upper/lower), Volatility, USD Price
76
+ - **4 timeframes:** 5-minute, 1-hour, 1-day, 1-week
77
+ - **On-chain delivery** via Chainlink on Polygon
78
+ - **Free trial** via PythiaFaucet — no LINK needed, 5 requests/day
79
+
80
+ ## Use Cases
81
+
82
+ - **AI trading agents** that need on-chain technical signals
83
+ - **DeFi vault rebalancing** based on RSI or volatility thresholds
84
+ - **Risk management** using Bollinger Band width
85
+ - **Portfolio analysis** with real-time calculated metrics
86
+
87
+ ## Related
88
+
89
+ - [Pythia MCP Server](https://pypi.org/project/pythia-oracle-mcp/) — MCP integration for Claude, Cursor, VS Code
90
+ - [Integration Examples](https://github.com/pythia-the-oracle/pythia-oracle-examples) — Solidity contracts with Hardhat
91
+ - [Website & Feed Explorer](https://pythia.c3x-solutions.com)
92
+
93
+ ## License
94
+
95
+ MIT
@@ -0,0 +1,17 @@
1
+ """LangChain integration for Pythia Oracle — on-chain calculated crypto indicators."""
2
+
3
+ from langchain_pythia.tools import (
4
+ PythiaListTokensTool,
5
+ PythiaTokenFeedsTool,
6
+ PythiaHealthCheckTool,
7
+ PythiaContractsTool,
8
+ PythiaPricingTool,
9
+ )
10
+
11
+ __all__ = [
12
+ "PythiaListTokensTool",
13
+ "PythiaTokenFeedsTool",
14
+ "PythiaHealthCheckTool",
15
+ "PythiaContractsTool",
16
+ "PythiaPricingTool",
17
+ ]
@@ -0,0 +1,42 @@
1
+ """Internal HTTP client for fetching Pythia Oracle data."""
2
+
3
+ from datetime import datetime, timezone
4
+
5
+ import httpx
6
+
7
+ DATA_URL = "https://pythia.c3x-solutions.com/feed-status.json"
8
+ CACHE_TTL_SECONDS = 60
9
+
10
+ _cache: dict = {}
11
+
12
+
13
+ async def fetch_data() -> dict:
14
+ """Fetch feed-status.json with 60s cache."""
15
+ now = datetime.now(timezone.utc)
16
+ cached = _cache.get("data")
17
+ if cached and (now - cached["at"]).total_seconds() < CACHE_TTL_SECONDS:
18
+ return cached["data"]
19
+
20
+ async with httpx.AsyncClient(timeout=15) as client:
21
+ resp = await client.get(DATA_URL)
22
+ resp.raise_for_status()
23
+ data = resp.json()
24
+
25
+ _cache["data"] = {"data": data, "at": now}
26
+ return data
27
+
28
+
29
+ def fetch_data_sync() -> dict:
30
+ """Synchronous version of fetch_data."""
31
+ now = datetime.now(timezone.utc)
32
+ cached = _cache.get("data")
33
+ if cached and (now - cached["at"]).total_seconds() < CACHE_TTL_SECONDS:
34
+ return cached["data"]
35
+
36
+ with httpx.Client(timeout=15) as client:
37
+ resp = client.get(DATA_URL)
38
+ resp.raise_for_status()
39
+ data = resp.json()
40
+
41
+ _cache["data"] = {"data": data, "at": now}
42
+ return data
File without changes
@@ -0,0 +1,317 @@
1
+ """Pythia Oracle tools for LangChain.
2
+
3
+ Provides access to on-chain calculated crypto indicators (EMA, RSI,
4
+ Bollinger Bands, Volatility) for 22 tokens via Chainlink on Polygon.
5
+ """
6
+
7
+ import json
8
+ from typing import Optional, Type
9
+
10
+ from langchain_core.callbacks import (
11
+ AsyncCallbackManagerForToolRun,
12
+ CallbackManagerForToolRun,
13
+ )
14
+ from langchain_core.tools import BaseTool
15
+ from pydantic import BaseModel, Field
16
+
17
+ from langchain_pythia._client import fetch_data, fetch_data_sync
18
+
19
+ # ---------------------------------------------------------------------------
20
+ # Contracts (static, rarely changes)
21
+ # ---------------------------------------------------------------------------
22
+
23
+ CONTRACTS = {
24
+ "chain": "Polygon",
25
+ "chain_id": 137,
26
+ "link_token_erc677": "0xb0897686c545045aFc77CF20eC7A532E3120E0F1",
27
+ "operator": "0xAA37710aF244514691629Aa15f4A5c271EaE6891",
28
+ "faucet": "0x640fC3B9B607E324D7A3d89Fcb62C77Cc0Bd420A",
29
+ "consumers": {
30
+ "discovery": {
31
+ "address": "0xeC2865d66ae6Af47926B02edd942A756b394F820",
32
+ "fee": "0.01 LINK",
33
+ "returns": "uint256 (single indicator)",
34
+ },
35
+ "analysis": {
36
+ "address": "0x3b3aC62d73E537E3EF84D97aB5B84B51aF8dB316",
37
+ "fee": "0.03 LINK",
38
+ "returns": "uint256[] (1H/1D/1W bundle)",
39
+ },
40
+ "speed": {
41
+ "address": "0xC406e7d9AC385e7AB43cBD56C74ad487f085d47B",
42
+ "fee": "0.05 LINK",
43
+ "returns": "uint256[] (5M bundle)",
44
+ },
45
+ "complete": {
46
+ "address": "0x2dEC98fd7173802b351d1E28d0Cd5DdD20C24252",
47
+ "fee": "0.10 LINK",
48
+ "returns": "uint256[] (all indicators)",
49
+ },
50
+ },
51
+ }
52
+
53
+
54
+ # ---------------------------------------------------------------------------
55
+ # Tool: List Tokens
56
+ # ---------------------------------------------------------------------------
57
+
58
+
59
+ class PythiaListTokensTool(BaseTool):
60
+ """List all tokens tracked by Pythia Oracle with status and reliability.
61
+
62
+ Returns token symbols, categories, data source count, 30-day uptime,
63
+ and operational status. Covers cross-chain tokens (BTC, SOL, TAO,
64
+ RENDER, ONDO, etc.) and Polygon DeFi tokens.
65
+ """
66
+
67
+ name: str = "pythia_list_tokens"
68
+ description: str = (
69
+ "List all crypto tokens tracked by Pythia Oracle with their status, "
70
+ "30-day uptime, and data source count. Covers 22 tokens including "
71
+ "BTC, SOL, TAO, RENDER, ONDO, AAVE, UNI, and more."
72
+ )
73
+
74
+ def _run(
75
+ self, run_manager: Optional[CallbackManagerForToolRun] = None
76
+ ) -> str:
77
+ data = fetch_data_sync()
78
+ return _format_token_list(data)
79
+
80
+ async def _arun(
81
+ self, run_manager: Optional[AsyncCallbackManagerForToolRun] = None
82
+ ) -> str:
83
+ data = await fetch_data()
84
+ return _format_token_list(data)
85
+
86
+
87
+ def _format_token_list(data: dict) -> str:
88
+ tokens = data.get("tokens", [])
89
+ stats = data.get("stats", {})
90
+ lines = [
91
+ f"Pythia Oracle — {stats.get('tokens', len(tokens))} tokens, "
92
+ f"{stats.get('total_indicators', '?')} indicator feeds\n"
93
+ ]
94
+ lines.append(
95
+ f"{'Symbol':<8} {'Engine ID':<28} {'Category':<16} "
96
+ f"{'Status':<6} {'Uptime':>7} {'Src':>3}"
97
+ )
98
+ lines.append("-" * 78)
99
+ for t in sorted(tokens, key=lambda x: x.get("category", "")):
100
+ uptime = (
101
+ f"{t['uptime_30d']:.1f}%"
102
+ if t.get("uptime_30d") is not None
103
+ else "?"
104
+ )
105
+ lines.append(
106
+ f"{t['symbol']:<8} {t['engine_id']:<28} "
107
+ f"{t.get('category', '?'):<16} {t.get('status', '?'):<6} "
108
+ f"{uptime:>7} {t.get('sources', '?'):>3}"
109
+ )
110
+ lines.append(f"\nWebsite: https://pythia.c3x-solutions.com")
111
+ return "\n".join(lines)
112
+
113
+
114
+ # ---------------------------------------------------------------------------
115
+ # Tool: Token Feeds
116
+ # ---------------------------------------------------------------------------
117
+
118
+
119
+ class _TokenFeedsInput(BaseModel):
120
+ engine_id: str = Field(
121
+ description=(
122
+ "Token engine ID, e.g. 'bitcoin', 'solana', 'bittensor', "
123
+ "'aave', 'render-token'. Use pythia_list_tokens to see all IDs."
124
+ )
125
+ )
126
+
127
+
128
+ class PythiaTokenFeedsTool(BaseTool):
129
+ """Get all indicator feed names for a specific token.
130
+
131
+ Shows every available feed (EMA, RSI, Bollinger, Volatility across
132
+ all timeframes) plus the token's reliability stats.
133
+ """
134
+
135
+ name: str = "pythia_token_feeds"
136
+ description: str = (
137
+ "Get all available on-chain indicator feeds (EMA, RSI, Bollinger, "
138
+ "Volatility) for a specific crypto token from Pythia Oracle. "
139
+ "Returns feed names that can be used in smart contract calls."
140
+ )
141
+ args_schema: Type[BaseModel] = _TokenFeedsInput
142
+
143
+ def _run(
144
+ self,
145
+ engine_id: str,
146
+ run_manager: Optional[CallbackManagerForToolRun] = None,
147
+ ) -> str:
148
+ data = fetch_data_sync()
149
+ return _format_token_feeds(data, engine_id)
150
+
151
+ async def _arun(
152
+ self,
153
+ engine_id: str,
154
+ run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
155
+ ) -> str:
156
+ data = await fetch_data()
157
+ return _format_token_feeds(data, engine_id)
158
+
159
+
160
+ def _format_token_feeds(data: dict, engine_id: str) -> str:
161
+ tokens = data.get("tokens", [])
162
+ token = next((t for t in tokens if t["engine_id"] == engine_id), None)
163
+ if not token:
164
+ available = sorted(t["engine_id"] for t in tokens)
165
+ return f"No token found for '{engine_id}'.\nAvailable: {', '.join(available)}"
166
+
167
+ feed_names = token.get("feed_names", [])
168
+ lines = [
169
+ f"{token['symbol']} ({token['name']}) — {token.get('pair', '?')}",
170
+ f"Status: {token.get('status', '?')} | "
171
+ f"30d uptime: {token.get('uptime_30d', '?')}% | "
172
+ f"Data sources: {token.get('sources', '?')}",
173
+ f"\n{len(feed_names)} indicator feeds:\n",
174
+ ]
175
+ groups: dict[str, list[str]] = {}
176
+ for name in sorted(feed_names):
177
+ suffix = name[len(engine_id) + 1 :]
178
+ cat = suffix.split("_")[0]
179
+ groups.setdefault(cat, []).append(name)
180
+ for cat, feeds in sorted(groups.items()):
181
+ lines.append(f" {cat}:")
182
+ for feed in feeds:
183
+ lines.append(f" {feed}")
184
+ lines.append("")
185
+ return "\n".join(lines)
186
+
187
+
188
+ # ---------------------------------------------------------------------------
189
+ # Tool: Health Check
190
+ # ---------------------------------------------------------------------------
191
+
192
+
193
+ class PythiaHealthCheckTool(BaseTool):
194
+ """Check Pythia Oracle reliability and uptime.
195
+
196
+ Returns per-token 30-day uptime (worst-first), data source health,
197
+ infrastructure status, and active incidents.
198
+ """
199
+
200
+ name: str = "pythia_health_check"
201
+ description: str = (
202
+ "Check the reliability and uptime of Pythia Oracle. Returns "
203
+ "per-token 30-day uptime, data source health, infrastructure "
204
+ "status, and active incidents. Use before integrating."
205
+ )
206
+
207
+ def _run(
208
+ self, run_manager: Optional[CallbackManagerForToolRun] = None
209
+ ) -> str:
210
+ data = fetch_data_sync()
211
+ return _format_health(data)
212
+
213
+ async def _arun(
214
+ self, run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
215
+ ) -> str:
216
+ data = await fetch_data()
217
+ return _format_health(data)
218
+
219
+
220
+ def _format_health(data: dict) -> str:
221
+ tokens = data.get("tokens", [])
222
+ system = data.get("system", {})
223
+ stats = data.get("stats", {})
224
+ generated = data.get("generated_at", "unknown")
225
+
226
+ lines = [f"Pythia Oracle — Health Report ({generated})\n"]
227
+
228
+ incidents = stats.get("active_incidents", 0)
229
+ lines.append(
230
+ f" *** {incidents} ACTIVE INCIDENT(S) ***\n"
231
+ if incidents > 0
232
+ else " No active incidents.\n"
233
+ )
234
+
235
+ sources = system.get("sources", [])
236
+ for s in sources:
237
+ marker = " " if s["status"] == "ok" else "!"
238
+ lines.append(f" {marker} {s['name']:<15} {s['status']}")
239
+ lines.append("")
240
+
241
+ lines.append(f"{'Token':<8} {'Uptime 30d':>10} {'Status':<6} {'Src':>3}")
242
+ lines.append("-" * 40)
243
+ for t in sorted(tokens, key=lambda x: x.get("uptime_30d", 0)):
244
+ uptime = (
245
+ f"{t['uptime_30d']:.1f}%"
246
+ if t.get("uptime_30d") is not None
247
+ else "?"
248
+ )
249
+ lines.append(
250
+ f"{t['symbol']:<8} {uptime:>10} "
251
+ f"{t.get('status', '?'):<6} {t.get('sources', '?'):>3}"
252
+ )
253
+ return "\n".join(lines)
254
+
255
+
256
+ # ---------------------------------------------------------------------------
257
+ # Tool: Contracts
258
+ # ---------------------------------------------------------------------------
259
+
260
+
261
+ class PythiaContractsTool(BaseTool):
262
+ """Get Pythia contract addresses for on-chain integration."""
263
+
264
+ name: str = "pythia_contracts"
265
+ description: str = (
266
+ "Get Pythia Oracle contract addresses on Polygon for smart contract "
267
+ "integration. Returns operator, LINK token, faucet, and consumer "
268
+ "contract addresses for all pricing tiers."
269
+ )
270
+
271
+ def _run(
272
+ self, run_manager: Optional[CallbackManagerForToolRun] = None
273
+ ) -> str:
274
+ return json.dumps(CONTRACTS, indent=2)
275
+
276
+ async def _arun(
277
+ self, run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
278
+ ) -> str:
279
+ return json.dumps(CONTRACTS, indent=2)
280
+
281
+
282
+ # ---------------------------------------------------------------------------
283
+ # Tool: Pricing
284
+ # ---------------------------------------------------------------------------
285
+
286
+
287
+ class PythiaPricingTool(BaseTool):
288
+ """Get Pythia Oracle pricing tiers and free trial info."""
289
+
290
+ name: str = "pythia_pricing"
291
+ description: str = (
292
+ "Get Pythia Oracle pricing tiers (Discovery 0.01 LINK, Analysis "
293
+ "0.03, Speed 0.05, Complete 0.10) and free trial faucet info."
294
+ )
295
+
296
+ def _run(
297
+ self, run_manager: Optional[CallbackManagerForToolRun] = None
298
+ ) -> str:
299
+ return _PRICING_TEXT
300
+
301
+ async def _arun(
302
+ self, run_manager: Optional[AsyncCallbackManagerForToolRun] = None,
303
+ ) -> str:
304
+ return _PRICING_TEXT
305
+
306
+
307
+ _PRICING_TEXT = """Pythia Oracle Pricing
308
+
309
+ DISCOVERY — 0.01 LINK: Any single indicator. Returns uint256.
310
+ ANALYSIS — 0.03 LINK: All 1H/1D/1W indicators bundled. Returns uint256[].
311
+ SPEED — 0.05 LINK: All 5-minute indicators bundled. Returns uint256[].
312
+ COMPLETE — 0.10 LINK: Every indicator for a token. Returns uint256[].
313
+
314
+ FREE TRIAL — PythiaFaucet (0x640fC3B9B607E324D7A3d89Fcb62C77Cc0Bd420A)
315
+ No LINK needed. 5 requests/day/address. Real data.
316
+
317
+ Website: https://pythia.c3x-solutions.com"""
@@ -0,0 +1,42 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "langchain-pythia"
7
+ version = "0.1.0"
8
+ description = "LangChain integration for Pythia Oracle — on-chain calculated crypto indicators (EMA, RSI, Bollinger, Volatility) via Chainlink"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.10"
12
+ authors = [
13
+ { name = "Pythia Oracle", email = "ivan.jeremic@c3x-solutions.com" },
14
+ ]
15
+ keywords = [
16
+ "langchain", "oracle", "chainlink", "defi", "crypto",
17
+ "ema", "rsi", "bollinger", "volatility", "on-chain",
18
+ "technical-analysis", "ai-agent", "smart-contracts",
19
+ ]
20
+ classifiers = [
21
+ "Development Status :: 4 - Beta",
22
+ "Intended Audience :: Developers",
23
+ "License :: OSI Approved :: MIT License",
24
+ "Programming Language :: Python :: 3",
25
+ "Topic :: Software Development :: Libraries",
26
+ "Topic :: Office/Business :: Financial",
27
+ ]
28
+ dependencies = [
29
+ "langchain-core>=1.2.21,<2.0.0",
30
+ "httpx>=0.25.0,<1.0.0",
31
+ ]
32
+
33
+ [project.optional-dependencies]
34
+ dev = [
35
+ "pytest>=7.0",
36
+ "pytest-asyncio>=0.20",
37
+ ]
38
+
39
+ [project.urls]
40
+ Homepage = "https://pythia.c3x-solutions.com"
41
+ Repository = "https://github.com/pythia-the-oracle/langchain-pythia"
42
+ Documentation = "https://github.com/pythia-the-oracle/langchain-pythia#readme"
File without changes
File without changes
@@ -0,0 +1,68 @@
1
+ """Unit tests for Pythia Oracle LangChain tools."""
2
+
3
+ from langchain_pythia import (
4
+ PythiaListTokensTool,
5
+ PythiaTokenFeedsTool,
6
+ PythiaHealthCheckTool,
7
+ PythiaContractsTool,
8
+ PythiaPricingTool,
9
+ )
10
+
11
+
12
+ def test_tool_names():
13
+ """Each tool has a unique, descriptive name."""
14
+ tools = [
15
+ PythiaListTokensTool(),
16
+ PythiaTokenFeedsTool(),
17
+ PythiaHealthCheckTool(),
18
+ PythiaContractsTool(),
19
+ PythiaPricingTool(),
20
+ ]
21
+ names = [t.name for t in tools]
22
+ assert len(names) == len(set(names)), "Tool names must be unique"
23
+ for name in names:
24
+ assert name.startswith("pythia_"), f"Tool name should start with pythia_: {name}"
25
+
26
+
27
+ def test_tool_descriptions():
28
+ """Each tool has a non-empty description."""
29
+ tools = [
30
+ PythiaListTokensTool(),
31
+ PythiaTokenFeedsTool(),
32
+ PythiaHealthCheckTool(),
33
+ PythiaContractsTool(),
34
+ PythiaPricingTool(),
35
+ ]
36
+ for tool in tools:
37
+ assert len(tool.description) > 20, f"Description too short for {tool.name}"
38
+
39
+
40
+ def test_contracts_tool_returns_json():
41
+ """Contracts tool returns valid JSON with expected keys."""
42
+ import json
43
+
44
+ tool = PythiaContractsTool()
45
+ result = tool._run()
46
+ data = json.loads(result)
47
+ assert "operator" in data
48
+ assert "faucet" in data
49
+ assert "consumers" in data
50
+ assert "discovery" in data["consumers"]
51
+
52
+
53
+ def test_pricing_tool_returns_tiers():
54
+ """Pricing tool mentions all 4 tiers."""
55
+ tool = PythiaPricingTool()
56
+ result = tool._run()
57
+ assert "DISCOVERY" in result
58
+ assert "ANALYSIS" in result
59
+ assert "SPEED" in result
60
+ assert "COMPLETE" in result
61
+ assert "FREE TRIAL" in result
62
+
63
+
64
+ def test_token_feeds_input_schema():
65
+ """Token feeds tool has proper input schema."""
66
+ tool = PythiaTokenFeedsTool()
67
+ schema = tool.args_schema.model_json_schema()
68
+ assert "engine_id" in schema["properties"]