truthstack 1.0.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,189 @@
1
+ Metadata-Version: 2.4
2
+ Name: truthstack
3
+ Version: 1.0.0
4
+ Summary: TruthStack supplement safety API SDK. LangChain, LlamaIndex, CrewAI, and OpenAI integrations.
5
+ Home-page: https://github.com/TruthStack1/truthstack-python
6
+ Author: TruthStack
7
+ Author-email: chris@truthstack.co
8
+ License: MIT
9
+ Project-URL: Documentation, https://api.truthstack.co/docs
10
+ Project-URL: MCP Server, https://github.com/TruthStack1/truthstack-mcp
11
+ Project-URL: Bug Tracker, https://github.com/TruthStack1/truthstack-python/issues
12
+ Keywords: supplements drug-interactions langchain llamaindex crewai openai health safety pharmacovigilance glp-1 ozempic
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Requires-Python: >=3.8
25
+ Description-Content-Type: text/markdown
26
+ Provides-Extra: langchain
27
+ Requires-Dist: langchain-core>=0.1.0; extra == "langchain"
28
+ Requires-Dist: pydantic>=2.0; extra == "langchain"
29
+ Provides-Extra: llamaindex
30
+ Requires-Dist: llama-index-core>=0.10.0; extra == "llamaindex"
31
+ Provides-Extra: crewai
32
+ Requires-Dist: crewai>=0.1.0; extra == "crewai"
33
+ Provides-Extra: all
34
+ Requires-Dist: langchain-core>=0.1.0; extra == "all"
35
+ Requires-Dist: pydantic>=2.0; extra == "all"
36
+ Requires-Dist: llama-index-core>=0.10.0; extra == "all"
37
+ Requires-Dist: crewai>=0.1.0; extra == "all"
38
+ Dynamic: author
39
+ Dynamic: author-email
40
+ Dynamic: classifier
41
+ Dynamic: description
42
+ Dynamic: description-content-type
43
+ Dynamic: home-page
44
+ Dynamic: keywords
45
+ Dynamic: license
46
+ Dynamic: project-url
47
+ Dynamic: provides-extra
48
+ Dynamic: requires-python
49
+ Dynamic: summary
50
+
51
+ # truthstack
52
+
53
+ Python SDK for [TruthStack](https://truthstack.co) supplement safety API. Works with LangChain, LlamaIndex, CrewAI, OpenAI function calling, and standalone.
54
+
55
+ ## Install
56
+
57
+ ```bash
58
+ pip install truthstack # Core client (zero deps)
59
+ pip install truthstack[langchain] # + LangChain tools
60
+ pip install truthstack[llamaindex] # + LlamaIndex tools
61
+ pip install truthstack[crewai] # + CrewAI tools
62
+ pip install truthstack[all] # Everything
63
+ ```
64
+
65
+ ## Quick Start
66
+
67
+ ### Standalone
68
+
69
+ ```python
70
+ from truthstack import TruthStackClient
71
+
72
+ client = TruthStackClient(api_key="your-key")
73
+
74
+ # Check interactions (the money endpoint)
75
+ result = client.check_interactions(
76
+ supplements=["berberine", "magnesium", "vitamin_d"],
77
+ medications=["semaglutide"]
78
+ )
79
+ print(result["risk_level"]) # "HIGH"
80
+ print(result["cyp_pathway_conflicts"])
81
+ print(result["evidence_by_compound"])
82
+
83
+ # Get evidence balance
84
+ evidence = client.get_evidence("berberine")
85
+ print(evidence["evidence_balance"]) # {"positive": 8, "null": 2, ...}
86
+ print(evidence["citations"]) # [{"pmid": "12345", ...}]
87
+ ```
88
+
89
+ ### LangChain
90
+
91
+ ```python
92
+ from truthstack import get_langchain_tools
93
+ from langchain_openai import ChatOpenAI
94
+ from langchain.agents import AgentExecutor, create_openai_tools_agent
95
+
96
+ tools = get_langchain_tools(api_key="your-key")
97
+ llm = ChatOpenAI(model="gpt-4")
98
+ agent = create_openai_tools_agent(llm, tools, prompt)
99
+ executor = AgentExecutor(agent=agent, tools=tools)
100
+
101
+ result = executor.invoke({"input": "Can I take berberine while on Ozempic?"})
102
+ ```
103
+
104
+ ### LlamaIndex
105
+
106
+ ```python
107
+ from truthstack import get_llamaindex_tools
108
+ from llama_index.core.agent import ReActAgent
109
+ from llama_index.llms.openai import OpenAI
110
+
111
+ tools = get_llamaindex_tools(api_key="your-key")
112
+ agent = ReActAgent.from_tools(tools, llm=OpenAI(model="gpt-4"))
113
+
114
+ response = agent.chat("What's the evidence for CoQ10?")
115
+ ```
116
+
117
+ ### CrewAI
118
+
119
+ ```python
120
+ from truthstack import get_crewai_tools
121
+ from crewai import Agent, Task, Crew
122
+
123
+ tools = get_crewai_tools(api_key="your-key")
124
+
125
+ analyst = Agent(
126
+ role="Supplement Safety Analyst",
127
+ goal="Check supplement interactions and evidence",
128
+ tools=tools,
129
+ )
130
+ ```
131
+
132
+ ### OpenAI Function Calling
133
+
134
+ ```python
135
+ from truthstack import get_openai_functions, handle_openai_function_call
136
+ from openai import OpenAI
137
+
138
+ client = OpenAI()
139
+ functions = get_openai_functions()
140
+
141
+ response = client.chat.completions.create(
142
+ model="gpt-4",
143
+ messages=[{"role": "user", "content": "Is magnesium safe with sertraline?"}],
144
+ functions=functions,
145
+ function_call="auto",
146
+ )
147
+
148
+ call = response.choices[0].message.function_call
149
+ result = handle_openai_function_call(
150
+ call.name, json.loads(call.arguments), api_key="your-key"
151
+ )
152
+ ```
153
+
154
+ ## System Prompts
155
+
156
+ ```python
157
+ from truthstack import SYSTEM_PROMPTS
158
+
159
+ SYSTEM_PROMPTS["supplement_safety_advisor"] # General safety
160
+ SYSTEM_PROMPTS["glp1_supplement_checker"] # GLP-1/Ozempic focus
161
+ SYSTEM_PROMPTS["evidence_researcher"] # Research analysis
162
+ SYSTEM_PROMPTS["stack_optimizer"] # Stack optimization
163
+ SYSTEM_PROMPTS["clinician_assistant"] # Clinician-facing
164
+ ```
165
+
166
+ ## Tools
167
+
168
+ | Tool | Description |
169
+ |------|-------------|
170
+ | `truthstack_check_interactions` | Check supplement + drug interactions |
171
+ | `truthstack_get_evidence` | Evidence balance + citations |
172
+ | `truthstack_search_supplements` | Fuzzy compound search |
173
+ | `truthstack_safety_signals` | FDA CAERS/FAERS signals |
174
+ | `truthstack_drug_profile` | Drug CYP450 + botanical interactions |
175
+
176
+ ## Environment Variables
177
+
178
+ ```bash
179
+ TRUTHSTACK_API_KEY=your-key
180
+ TRUTHSTACK_BASE_URL=https://api.truthstack.co # optional
181
+ ```
182
+
183
+ ## API Key
184
+
185
+ Get a free key (2,000 calls/month) at [truthstack.co/developers](https://truthstack.co/developers).
186
+
187
+ ## License
188
+
189
+ MIT
@@ -0,0 +1,139 @@
1
+ # truthstack
2
+
3
+ Python SDK for [TruthStack](https://truthstack.co) supplement safety API. Works with LangChain, LlamaIndex, CrewAI, OpenAI function calling, and standalone.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pip install truthstack # Core client (zero deps)
9
+ pip install truthstack[langchain] # + LangChain tools
10
+ pip install truthstack[llamaindex] # + LlamaIndex tools
11
+ pip install truthstack[crewai] # + CrewAI tools
12
+ pip install truthstack[all] # Everything
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ### Standalone
18
+
19
+ ```python
20
+ from truthstack import TruthStackClient
21
+
22
+ client = TruthStackClient(api_key="your-key")
23
+
24
+ # Check interactions (the money endpoint)
25
+ result = client.check_interactions(
26
+ supplements=["berberine", "magnesium", "vitamin_d"],
27
+ medications=["semaglutide"]
28
+ )
29
+ print(result["risk_level"]) # "HIGH"
30
+ print(result["cyp_pathway_conflicts"])
31
+ print(result["evidence_by_compound"])
32
+
33
+ # Get evidence balance
34
+ evidence = client.get_evidence("berberine")
35
+ print(evidence["evidence_balance"]) # {"positive": 8, "null": 2, ...}
36
+ print(evidence["citations"]) # [{"pmid": "12345", ...}]
37
+ ```
38
+
39
+ ### LangChain
40
+
41
+ ```python
42
+ from truthstack import get_langchain_tools
43
+ from langchain_openai import ChatOpenAI
44
+ from langchain.agents import AgentExecutor, create_openai_tools_agent
45
+
46
+ tools = get_langchain_tools(api_key="your-key")
47
+ llm = ChatOpenAI(model="gpt-4")
48
+ agent = create_openai_tools_agent(llm, tools, prompt)
49
+ executor = AgentExecutor(agent=agent, tools=tools)
50
+
51
+ result = executor.invoke({"input": "Can I take berberine while on Ozempic?"})
52
+ ```
53
+
54
+ ### LlamaIndex
55
+
56
+ ```python
57
+ from truthstack import get_llamaindex_tools
58
+ from llama_index.core.agent import ReActAgent
59
+ from llama_index.llms.openai import OpenAI
60
+
61
+ tools = get_llamaindex_tools(api_key="your-key")
62
+ agent = ReActAgent.from_tools(tools, llm=OpenAI(model="gpt-4"))
63
+
64
+ response = agent.chat("What's the evidence for CoQ10?")
65
+ ```
66
+
67
+ ### CrewAI
68
+
69
+ ```python
70
+ from truthstack import get_crewai_tools
71
+ from crewai import Agent, Task, Crew
72
+
73
+ tools = get_crewai_tools(api_key="your-key")
74
+
75
+ analyst = Agent(
76
+ role="Supplement Safety Analyst",
77
+ goal="Check supplement interactions and evidence",
78
+ tools=tools,
79
+ )
80
+ ```
81
+
82
+ ### OpenAI Function Calling
83
+
84
+ ```python
85
+ from truthstack import get_openai_functions, handle_openai_function_call
86
+ from openai import OpenAI
87
+
88
+ client = OpenAI()
89
+ functions = get_openai_functions()
90
+
91
+ response = client.chat.completions.create(
92
+ model="gpt-4",
93
+ messages=[{"role": "user", "content": "Is magnesium safe with sertraline?"}],
94
+ functions=functions,
95
+ function_call="auto",
96
+ )
97
+
98
+ call = response.choices[0].message.function_call
99
+ result = handle_openai_function_call(
100
+ call.name, json.loads(call.arguments), api_key="your-key"
101
+ )
102
+ ```
103
+
104
+ ## System Prompts
105
+
106
+ ```python
107
+ from truthstack import SYSTEM_PROMPTS
108
+
109
+ SYSTEM_PROMPTS["supplement_safety_advisor"] # General safety
110
+ SYSTEM_PROMPTS["glp1_supplement_checker"] # GLP-1/Ozempic focus
111
+ SYSTEM_PROMPTS["evidence_researcher"] # Research analysis
112
+ SYSTEM_PROMPTS["stack_optimizer"] # Stack optimization
113
+ SYSTEM_PROMPTS["clinician_assistant"] # Clinician-facing
114
+ ```
115
+
116
+ ## Tools
117
+
118
+ | Tool | Description |
119
+ |------|-------------|
120
+ | `truthstack_check_interactions` | Check supplement + drug interactions |
121
+ | `truthstack_get_evidence` | Evidence balance + citations |
122
+ | `truthstack_search_supplements` | Fuzzy compound search |
123
+ | `truthstack_safety_signals` | FDA CAERS/FAERS signals |
124
+ | `truthstack_drug_profile` | Drug CYP450 + botanical interactions |
125
+
126
+ ## Environment Variables
127
+
128
+ ```bash
129
+ TRUTHSTACK_API_KEY=your-key
130
+ TRUTHSTACK_BASE_URL=https://api.truthstack.co # optional
131
+ ```
132
+
133
+ ## API Key
134
+
135
+ Get a free key (2,000 calls/month) at [truthstack.co/developers](https://truthstack.co/developers).
136
+
137
+ ## License
138
+
139
+ MIT
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,41 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name="truthstack",
5
+ version="1.0.0",
6
+ description="TruthStack supplement safety API SDK. LangChain, LlamaIndex, CrewAI, and OpenAI integrations.",
7
+ long_description=open("README.md").read(),
8
+ long_description_content_type="text/markdown",
9
+ author="TruthStack",
10
+ author_email="chris@truthstack.co",
11
+ url="https://github.com/TruthStack1/truthstack-python",
12
+ packages=find_packages(),
13
+ python_requires=">=3.8",
14
+ install_requires=[], # Zero deps for core client
15
+ extras_require={
16
+ "langchain": ["langchain-core>=0.1.0", "pydantic>=2.0"],
17
+ "llamaindex": ["llama-index-core>=0.10.0"],
18
+ "crewai": ["crewai>=0.1.0"],
19
+ "all": ["langchain-core>=0.1.0", "pydantic>=2.0", "llama-index-core>=0.10.0", "crewai>=0.1.0"],
20
+ },
21
+ classifiers=[
22
+ "Development Status :: 4 - Beta",
23
+ "Intended Audience :: Developers",
24
+ "License :: OSI Approved :: MIT License",
25
+ "Programming Language :: Python :: 3",
26
+ "Programming Language :: Python :: 3.8",
27
+ "Programming Language :: Python :: 3.9",
28
+ "Programming Language :: Python :: 3.10",
29
+ "Programming Language :: Python :: 3.11",
30
+ "Programming Language :: Python :: 3.12",
31
+ "Topic :: Scientific/Engineering :: Medical Science Apps.",
32
+ "Topic :: Software Development :: Libraries :: Python Modules",
33
+ ],
34
+ keywords="supplements drug-interactions langchain llamaindex crewai openai health safety pharmacovigilance glp-1 ozempic",
35
+ license="MIT",
36
+ project_urls={
37
+ "Documentation": "https://api.truthstack.co/docs",
38
+ "MCP Server": "https://github.com/TruthStack1/truthstack-mcp",
39
+ "Bug Tracker": "https://github.com/TruthStack1/truthstack-python/issues",
40
+ },
41
+ )
@@ -0,0 +1,484 @@
1
+ """
2
+ truthstack - Python SDK for TruthStack supplement safety API.
3
+ Works with LangChain, LlamaIndex, CrewAI, and standalone.
4
+
5
+ pip install truthstack
6
+
7
+ Usage:
8
+ from truthstack import TruthStackClient
9
+ client = TruthStackClient(api_key="your-key")
10
+ result = client.check_interactions(["berberine", "magnesium"], ["semaglutide"])
11
+ """
12
+
13
+ import os
14
+ import json
15
+ import urllib.request
16
+ import urllib.error
17
+ import urllib.parse
18
+ from typing import List, Optional, Dict, Any
19
+
20
+ __version__ = "1.0.0"
21
+ __all__ = [
22
+ "TruthStackClient",
23
+ "get_langchain_tools",
24
+ "get_llamaindex_tools",
25
+ "get_crewai_tools",
26
+ "get_openai_functions",
27
+ "handle_openai_function_call",
28
+ "SYSTEM_PROMPTS",
29
+ ]
30
+
31
+ DEFAULT_BASE_URL = "https://api.truthstack.co"
32
+ CLIENT_ID_BASE = "truthstack-python"
33
+
34
+
35
+ class TruthStackError(Exception):
36
+ """Error from the TruthStack API."""
37
+ def __init__(self, message: str, code: str = "UNKNOWN", status: int = 0,
38
+ suggestions: list = None, hint: str = None):
39
+ super().__init__(message)
40
+ self.code = code
41
+ self.status = status
42
+ self.suggestions = suggestions or []
43
+ self.hint = hint
44
+
45
+
46
+ class TruthStackClient:
47
+ """Client for the TruthStack Vault API."""
48
+
49
+ def __init__(self, api_key: str = None, base_url: str = None, framework: str = None):
50
+ self.api_key = api_key or os.environ.get("TRUTHSTACK_API_KEY", "")
51
+ self.base_url = (base_url or os.environ.get("TRUTHSTACK_BASE_URL", DEFAULT_BASE_URL)).rstrip("/")
52
+ self.framework = framework or "standalone"
53
+ if not self.api_key:
54
+ raise ValueError(
55
+ "TruthStack API key required. Set TRUTHSTACK_API_KEY env var "
56
+ "or pass api_key. Get a free key at truthstack.co/developers"
57
+ )
58
+
59
+ @property
60
+ def _client_id(self) -> str:
61
+ return f"{CLIENT_ID_BASE}-{self.framework}/{__version__}"
62
+
63
+ def _request(self, method: str, path: str, body: dict = None) -> dict:
64
+ url = f"{self.base_url}{path}"
65
+ data = json.dumps(body).encode() if body else None
66
+ headers = {
67
+ "X-API-Key": self.api_key,
68
+ "X-TruthStack-Client": self._client_id,
69
+ "Content-Type": "application/json",
70
+ "Accept": "application/json",
71
+ }
72
+ req = urllib.request.Request(url, data=data, headers=headers, method=method)
73
+ try:
74
+ with urllib.request.urlopen(req, timeout=30) as resp:
75
+ return json.loads(resp.read().decode())
76
+ except urllib.error.HTTPError as e:
77
+ body_str = e.read().decode()
78
+ try:
79
+ parsed = json.loads(body_str)
80
+ raise TruthStackError(
81
+ message=parsed.get("message", str(e)),
82
+ code=parsed.get("error_code", "UNKNOWN"),
83
+ status=e.code,
84
+ suggestions=parsed.get("suggestions", []),
85
+ hint=parsed.get("hint"),
86
+ )
87
+ except (json.JSONDecodeError, TruthStackError):
88
+ if isinstance(e.__context__, TruthStackError):
89
+ raise e.__context__
90
+ raise TruthStackError(str(e), status=e.code)
91
+
92
+ def check_interactions(self, supplements: List[str], medications: List[str] = None) -> dict:
93
+ """Check supplement-supplement and supplement-drug interactions."""
94
+ return self._request("POST", "/api/interactions/check", {
95
+ "supplements": supplements,
96
+ "medications": medications or [],
97
+ })
98
+
99
+ def get_evidence(self, compound_id: str) -> dict:
100
+ """Get evidence balance and citations for a compound."""
101
+ return self._request("GET", f"/api/compounds/{urllib.parse.quote(compound_id)}/evidence")
102
+
103
+ def search_compounds(self, query: str, limit: int = 10) -> dict:
104
+ """Search for compounds by name."""
105
+ return self._request("GET", f"/api/compounds/search?q={urllib.parse.quote(query)}&limit={limit}")
106
+
107
+ def get_compound(self, compound_id: str) -> dict:
108
+ """Get compound details."""
109
+ return self._request("GET", f"/api/compounds/{urllib.parse.quote(compound_id)}")
110
+
111
+ def get_safety_signals(self, compound_id: str) -> dict:
112
+ """Get FDA adverse event safety signals."""
113
+ return self._request("GET", f"/api/compounds/{urllib.parse.quote(compound_id)}/safety-signals")
114
+
115
+ def get_drug(self, drug_id: str) -> dict:
116
+ """Get drug profile with CYP pathways."""
117
+ return self._request("GET", f"/api/drugs/{urllib.parse.quote(drug_id)}")
118
+
119
+ def health(self) -> dict:
120
+ """Check API health."""
121
+ return self._request("GET", "/api/health")
122
+
123
+
124
+ # ============================================================
125
+ # LANGCHAIN INTEGRATION
126
+ # ============================================================
127
+
128
+ def get_langchain_tools(api_key: str = None, base_url: str = None):
129
+ """
130
+ Get TruthStack tools for LangChain.
131
+
132
+ Usage:
133
+ from truthstack import get_langchain_tools
134
+ from langchain.agents import AgentExecutor
135
+
136
+ tools = get_langchain_tools(api_key="your-key")
137
+ agent = AgentExecutor(tools=tools, llm=llm, ...)
138
+ """
139
+ try:
140
+ from langchain_core.tools import StructuredTool
141
+ from pydantic import BaseModel, Field
142
+ except ImportError:
143
+ raise ImportError("Install langchain: pip install langchain-core pydantic")
144
+
145
+ client = TruthStackClient(api_key=api_key, base_url=base_url, framework="langchain")
146
+
147
+ class CheckInteractionsInput(BaseModel):
148
+ supplements: List[str] = Field(description="List of supplement names")
149
+ medications: List[str] = Field(default=[], description="Optional list of medication names")
150
+
151
+ class CompoundInput(BaseModel):
152
+ compound_id: str = Field(description='Supplement ID (lowercase, underscores). E.g. "vitamin_d"')
153
+
154
+ class SearchInput(BaseModel):
155
+ query: str = Field(description='Search query, e.g. "magnesium glycinate"')
156
+
157
+ class DrugInput(BaseModel):
158
+ drug_id: str = Field(description='Drug name, e.g. "sertraline"')
159
+
160
+ def _check_interactions(supplements: List[str], medications: List[str] = []) -> str:
161
+ return json.dumps(client.check_interactions(supplements, medications), indent=2)
162
+
163
+ def _get_evidence(compound_id: str) -> str:
164
+ return json.dumps(client.get_evidence(compound_id), indent=2)
165
+
166
+ def _search(query: str) -> str:
167
+ return json.dumps(client.search_compounds(query), indent=2)
168
+
169
+ def _safety_signals(compound_id: str) -> str:
170
+ return json.dumps(client.get_safety_signals(compound_id), indent=2)
171
+
172
+ def _drug_profile(drug_id: str) -> str:
173
+ return json.dumps(client.get_drug(drug_id), indent=2)
174
+
175
+ return [
176
+ StructuredTool.from_function(
177
+ func=_check_interactions,
178
+ name="truthstack_check_interactions",
179
+ description="Check supplement-supplement and supplement-drug interactions. Returns risk level, CYP conflicts, FDA warnings, evidence balance, citations.",
180
+ args_schema=CheckInteractionsInput,
181
+ ),
182
+ StructuredTool.from_function(
183
+ func=_get_evidence,
184
+ name="truthstack_get_evidence",
185
+ description="Get evidence balance and research citations for a supplement. Returns positive/negative/null counts, evidence level, conditions studied, PMIDs.",
186
+ args_schema=CompoundInput,
187
+ ),
188
+ StructuredTool.from_function(
189
+ func=_search,
190
+ name="truthstack_search_supplements",
191
+ description="Search for supplements by name with fuzzy matching and alias resolution.",
192
+ args_schema=SearchInput,
193
+ ),
194
+ StructuredTool.from_function(
195
+ func=_safety_signals,
196
+ name="truthstack_safety_signals",
197
+ description="Get FDA adverse event (CAERS/FAERS) safety signals for a supplement.",
198
+ args_schema=CompoundInput,
199
+ ),
200
+ StructuredTool.from_function(
201
+ func=_drug_profile,
202
+ name="truthstack_drug_profile",
203
+ description="Get drug CYP450 pathways, transporters, and botanical interactions.",
204
+ args_schema=DrugInput,
205
+ ),
206
+ ]
207
+
208
+
209
+ # ============================================================
210
+ # LLAMAINDEX INTEGRATION
211
+ # ============================================================
212
+
213
+ def get_llamaindex_tools(api_key: str = None, base_url: str = None):
214
+ """
215
+ Get TruthStack tools for LlamaIndex.
216
+
217
+ Usage:
218
+ from truthstack import get_llamaindex_tools
219
+ from llama_index.core.agent import ReActAgent
220
+
221
+ tools = get_llamaindex_tools(api_key="your-key")
222
+ agent = ReActAgent.from_tools(tools, llm=llm, ...)
223
+ """
224
+ try:
225
+ from llama_index.core.tools import FunctionTool
226
+ except ImportError:
227
+ raise ImportError("Install llama-index: pip install llama-index-core")
228
+
229
+ client = TruthStackClient(api_key=api_key, base_url=base_url, framework="llamaindex")
230
+
231
+ def check_interactions(supplements: List[str], medications: List[str] = []) -> str:
232
+ """Check supplement-supplement and supplement-drug interactions for safety.
233
+ Returns risk level, CYP pathway conflicts, FDA warnings, evidence balance, and citations.
234
+ Args:
235
+ supplements: List of supplement names (e.g. ["berberine", "magnesium"])
236
+ medications: Optional list of medication names (e.g. ["semaglutide"])
237
+ """
238
+ return json.dumps(client.check_interactions(supplements, medications), indent=2)
239
+
240
+ def get_evidence(compound_id: str) -> str:
241
+ """Get evidence balance and research citations for a supplement compound.
242
+ Returns positive/negative/null finding counts, evidence level, conditions studied, PMIDs.
243
+ Args:
244
+ compound_id: Supplement ID in lowercase with underscores (e.g. "vitamin_d")
245
+ """
246
+ return json.dumps(client.get_evidence(compound_id), indent=2)
247
+
248
+ def search_supplements(query: str) -> str:
249
+ """Search for supplements by name with fuzzy matching and alias resolution.
250
+ Args:
251
+ query: Search query (e.g. "mag glycinate", "fish oil")
252
+ """
253
+ return json.dumps(client.search_compounds(query), indent=2)
254
+
255
+ def safety_signals(compound_id: str) -> str:
256
+ """Get FDA adverse event (CAERS/FAERS) safety signals for a supplement.
257
+ Args:
258
+ compound_id: Supplement ID in lowercase with underscores
259
+ """
260
+ return json.dumps(client.get_safety_signals(compound_id), indent=2)
261
+
262
+ def drug_profile(drug_id: str) -> str:
263
+ """Get drug CYP450 metabolism pathways, transporters, and botanical interactions.
264
+ Args:
265
+ drug_id: Drug name (e.g. "sertraline", "metformin")
266
+ """
267
+ return json.dumps(client.get_drug(drug_id), indent=2)
268
+
269
+ return [
270
+ FunctionTool.from_defaults(fn=check_interactions, name="truthstack_check_interactions"),
271
+ FunctionTool.from_defaults(fn=get_evidence, name="truthstack_get_evidence"),
272
+ FunctionTool.from_defaults(fn=search_supplements, name="truthstack_search_supplements"),
273
+ FunctionTool.from_defaults(fn=safety_signals, name="truthstack_safety_signals"),
274
+ FunctionTool.from_defaults(fn=drug_profile, name="truthstack_drug_profile"),
275
+ ]
276
+
277
+
278
+ # ============================================================
279
+ # CREWAI INTEGRATION
280
+ # ============================================================
281
+
282
+ def get_crewai_tools(api_key: str = None, base_url: str = None):
283
+ """
284
+ Get TruthStack tools for CrewAI.
285
+
286
+ Usage:
287
+ from truthstack import get_crewai_tools
288
+ from crewai import Agent
289
+
290
+ tools = get_crewai_tools(api_key="your-key")
291
+ agent = Agent(role="Supplement Safety Analyst", tools=tools, ...)
292
+ """
293
+ try:
294
+ from crewai.tools import tool as crewai_tool
295
+ except ImportError:
296
+ raise ImportError("Install crewai: pip install crewai")
297
+
298
+ client = TruthStackClient(api_key=api_key, base_url=base_url, framework="crewai")
299
+
300
+ @crewai_tool("TruthStack Interaction Checker")
301
+ def check_interactions(supplements: str, medications: str = "") -> str:
302
+ """Check supplement-supplement and supplement-drug interactions for safety.
303
+ supplements: Comma-separated supplement names (e.g. "berberine, magnesium")
304
+ medications: Optional comma-separated medication names (e.g. "semaglutide, metformin")
305
+ """
306
+ supps = [s.strip() for s in supplements.split(",") if s.strip()]
307
+ meds = [m.strip() for m in medications.split(",") if m.strip()] if medications else []
308
+ return json.dumps(client.check_interactions(supps, meds), indent=2)
309
+
310
+ @crewai_tool("TruthStack Evidence Lookup")
311
+ def get_evidence(compound_id: str) -> str:
312
+ """Get evidence balance and research citations for a supplement.
313
+ compound_id: Supplement ID in lowercase with underscores (e.g. "vitamin_d")
314
+ """
315
+ return json.dumps(client.get_evidence(compound_id), indent=2)
316
+
317
+ @crewai_tool("TruthStack Supplement Search")
318
+ def search_supplements(query: str) -> str:
319
+ """Search for supplements by name with fuzzy matching.
320
+ query: Search query (e.g. "magnesium glycinate")
321
+ """
322
+ return json.dumps(client.search_compounds(query), indent=2)
323
+
324
+ @crewai_tool("TruthStack Safety Signals")
325
+ def safety_signals(compound_id: str) -> str:
326
+ """Get FDA adverse event safety signals for a supplement.
327
+ compound_id: Supplement ID in lowercase with underscores
328
+ """
329
+ return json.dumps(client.get_safety_signals(compound_id), indent=2)
330
+
331
+ @crewai_tool("TruthStack Drug Profile")
332
+ def drug_profile(drug_id: str) -> str:
333
+ """Get drug CYP450 pathways and botanical interactions.
334
+ drug_id: Drug name (e.g. "sertraline")
335
+ """
336
+ return json.dumps(client.get_drug(drug_id), indent=2)
337
+
338
+ return [check_interactions, get_evidence, search_supplements, safety_signals, drug_profile]
339
+
340
+
341
+ # ============================================================
342
+ # OPENAI FUNCTION CALLING
343
+ # ============================================================
344
+
345
+ def get_openai_functions() -> List[dict]:
346
+ """Get OpenAI function calling definitions for TruthStack tools."""
347
+ return [
348
+ {
349
+ "name": "truthstack_check_interactions",
350
+ "description": "Check supplement-supplement and supplement-drug interactions. Returns risk level, CYP conflicts, FDA warnings, evidence balance, citations.",
351
+ "parameters": {
352
+ "type": "object",
353
+ "properties": {
354
+ "supplements": {"type": "array", "items": {"type": "string"}, "description": "List of supplement names"},
355
+ "medications": {"type": "array", "items": {"type": "string"}, "description": "Optional medication names"},
356
+ },
357
+ "required": ["supplements"],
358
+ },
359
+ },
360
+ {
361
+ "name": "truthstack_get_evidence",
362
+ "description": "Get evidence balance and research citations for a supplement compound.",
363
+ "parameters": {
364
+ "type": "object",
365
+ "properties": {
366
+ "compound_id": {"type": "string", "description": "Supplement ID (lowercase, underscores)"},
367
+ },
368
+ "required": ["compound_id"],
369
+ },
370
+ },
371
+ {
372
+ "name": "truthstack_search_supplements",
373
+ "description": "Search for supplements by name with fuzzy matching.",
374
+ "parameters": {
375
+ "type": "object",
376
+ "properties": {
377
+ "query": {"type": "string", "description": "Search query"},
378
+ },
379
+ "required": ["query"],
380
+ },
381
+ },
382
+ {
383
+ "name": "truthstack_safety_signals",
384
+ "description": "Get FDA adverse event safety signals for a supplement.",
385
+ "parameters": {
386
+ "type": "object",
387
+ "properties": {
388
+ "compound_id": {"type": "string", "description": "Supplement ID"},
389
+ },
390
+ "required": ["compound_id"],
391
+ },
392
+ },
393
+ {
394
+ "name": "truthstack_drug_profile",
395
+ "description": "Get drug CYP450 pathways, transporters, and botanical interactions.",
396
+ "parameters": {
397
+ "type": "object",
398
+ "properties": {
399
+ "drug_id": {"type": "string", "description": "Drug name"},
400
+ },
401
+ "required": ["drug_id"],
402
+ },
403
+ },
404
+ ]
405
+
406
+
407
+ def handle_openai_function_call(function_name: str, arguments: dict,
408
+ api_key: str = None, base_url: str = None) -> dict:
409
+ """Handle an OpenAI function call response."""
410
+ client = TruthStackClient(api_key=api_key, base_url=base_url, framework="openai")
411
+ handlers = {
412
+ "truthstack_check_interactions": lambda a: client.check_interactions(a["supplements"], a.get("medications", [])),
413
+ "truthstack_get_evidence": lambda a: client.get_evidence(a["compound_id"]),
414
+ "truthstack_search_supplements": lambda a: client.search_compounds(a["query"]),
415
+ "truthstack_safety_signals": lambda a: client.get_safety_signals(a["compound_id"]),
416
+ "truthstack_drug_profile": lambda a: client.get_drug(a["drug_id"]),
417
+ }
418
+ handler = handlers.get(function_name)
419
+ if not handler:
420
+ raise ValueError(f"Unknown function: {function_name}")
421
+ return handler(arguments)
422
+
423
+
424
+ # ============================================================
425
+ # SYSTEM PROMPTS
426
+ # ============================================================
427
+
428
+ SYSTEM_PROMPTS = {
429
+ "supplement_safety_advisor": (
430
+ "You are a supplement safety advisor powered by TruthStack's evidence database.\n\n"
431
+ "When a user asks about supplements:\n"
432
+ "1. ALWAYS check interactions first using truthstack_check_interactions\n"
433
+ "2. Look up evidence using truthstack_get_evidence for each supplement\n"
434
+ "3. Check safety signals using truthstack_safety_signals for concerning compounds\n"
435
+ "4. Cite PMIDs when available\n\n"
436
+ "Key safety rules:\n"
437
+ "- Flag hypoglycemia stacking: berberine + chromium + ALA with GLP-1 drugs\n"
438
+ "- Flag CYP3A4 interactions: St. John's Wort, grapefruit, turmeric\n"
439
+ "- Always mention when evidence is insufficient (< 3 findings)\n"
440
+ "- Never recommend stopping prescribed medications\n"
441
+ "- Recommend consulting healthcare provider for medication interactions"
442
+ ),
443
+ "glp1_supplement_checker": (
444
+ "You are a GLP-1 medication supplement safety checker powered by TruthStack.\n\n"
445
+ "50M+ people take GLP-1 receptor agonists (Ozempic, Wegovy, Mounjaro) with supplements.\n\n"
446
+ "Critical interactions:\n"
447
+ "- HYPOGLYCEMIA STACKING: berberine, chromium, alpha-lipoic acid + GLP-1\n"
448
+ "- ABSORPTION CHANGES: B12, iron, vitamin D (GLP-1s slow gastric emptying)\n"
449
+ "- BENEFICIAL: magnesium (constipation), creatine (muscle preservation)\n\n"
450
+ "Always check interactions with the GLP-1 medication included.\n"
451
+ "Recommend CGM monitoring for glucose-active supplements."
452
+ ),
453
+ "evidence_researcher": (
454
+ "You are a supplement evidence researcher powered by TruthStack.\n\n"
455
+ "When asked about a supplement:\n"
456
+ "1. Use truthstack_get_evidence for the evidence balance\n"
457
+ "2. Report positive vs null vs negative ratio\n"
458
+ "3. Cite specific PMIDs and study designs\n"
459
+ "4. Note the evidence level (high/moderate/low/very_low/insufficient)\n"
460
+ "5. Be honest about gaps\n\n"
461
+ "Never overstate evidence. A few positive animal studies != proven effective."
462
+ ),
463
+ "stack_optimizer": (
464
+ "You are a supplement stack optimizer powered by TruthStack.\n\n"
465
+ "When a user shares their stack:\n"
466
+ "1. Check ALL interactions with truthstack_check_interactions\n"
467
+ "2. Get evidence for each compound\n"
468
+ "3. Identify redundancies\n"
469
+ "4. Flag supplements lacking evidence\n"
470
+ "5. Suggest timing optimizations\n"
471
+ "6. Estimate if they're wasting money on unsupported supplements\n\n"
472
+ "Be direct about what lacks evidence."
473
+ ),
474
+ "clinician_assistant": (
475
+ "You are a clinician-facing supplement interaction checker powered by TruthStack.\n\n"
476
+ "When checking patient supplement-drug interactions:\n"
477
+ "1. Run truthstack_check_interactions with full stack\n"
478
+ "2. Check truthstack_drug_profile for CYP pathways\n"
479
+ "3. Report by severity: CRITICAL > HIGH > MODERATE > LOW\n"
480
+ "4. Include FAERS signal data\n"
481
+ "5. Cite PMIDs for all claims\n\n"
482
+ "Use clinical terminology. Flag pharmacokinetic interactions explicitly."
483
+ ),
484
+ }
@@ -0,0 +1,189 @@
1
+ Metadata-Version: 2.4
2
+ Name: truthstack
3
+ Version: 1.0.0
4
+ Summary: TruthStack supplement safety API SDK. LangChain, LlamaIndex, CrewAI, and OpenAI integrations.
5
+ Home-page: https://github.com/TruthStack1/truthstack-python
6
+ Author: TruthStack
7
+ Author-email: chris@truthstack.co
8
+ License: MIT
9
+ Project-URL: Documentation, https://api.truthstack.co/docs
10
+ Project-URL: MCP Server, https://github.com/TruthStack1/truthstack-mcp
11
+ Project-URL: Bug Tracker, https://github.com/TruthStack1/truthstack-python/issues
12
+ Keywords: supplements drug-interactions langchain llamaindex crewai openai health safety pharmacovigilance glp-1 ozempic
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Requires-Python: >=3.8
25
+ Description-Content-Type: text/markdown
26
+ Provides-Extra: langchain
27
+ Requires-Dist: langchain-core>=0.1.0; extra == "langchain"
28
+ Requires-Dist: pydantic>=2.0; extra == "langchain"
29
+ Provides-Extra: llamaindex
30
+ Requires-Dist: llama-index-core>=0.10.0; extra == "llamaindex"
31
+ Provides-Extra: crewai
32
+ Requires-Dist: crewai>=0.1.0; extra == "crewai"
33
+ Provides-Extra: all
34
+ Requires-Dist: langchain-core>=0.1.0; extra == "all"
35
+ Requires-Dist: pydantic>=2.0; extra == "all"
36
+ Requires-Dist: llama-index-core>=0.10.0; extra == "all"
37
+ Requires-Dist: crewai>=0.1.0; extra == "all"
38
+ Dynamic: author
39
+ Dynamic: author-email
40
+ Dynamic: classifier
41
+ Dynamic: description
42
+ Dynamic: description-content-type
43
+ Dynamic: home-page
44
+ Dynamic: keywords
45
+ Dynamic: license
46
+ Dynamic: project-url
47
+ Dynamic: provides-extra
48
+ Dynamic: requires-python
49
+ Dynamic: summary
50
+
51
+ # truthstack
52
+
53
+ Python SDK for [TruthStack](https://truthstack.co) supplement safety API. Works with LangChain, LlamaIndex, CrewAI, OpenAI function calling, and standalone.
54
+
55
+ ## Install
56
+
57
+ ```bash
58
+ pip install truthstack # Core client (zero deps)
59
+ pip install truthstack[langchain] # + LangChain tools
60
+ pip install truthstack[llamaindex] # + LlamaIndex tools
61
+ pip install truthstack[crewai] # + CrewAI tools
62
+ pip install truthstack[all] # Everything
63
+ ```
64
+
65
+ ## Quick Start
66
+
67
+ ### Standalone
68
+
69
+ ```python
70
+ from truthstack import TruthStackClient
71
+
72
+ client = TruthStackClient(api_key="your-key")
73
+
74
+ # Check interactions (the money endpoint)
75
+ result = client.check_interactions(
76
+ supplements=["berberine", "magnesium", "vitamin_d"],
77
+ medications=["semaglutide"]
78
+ )
79
+ print(result["risk_level"]) # "HIGH"
80
+ print(result["cyp_pathway_conflicts"])
81
+ print(result["evidence_by_compound"])
82
+
83
+ # Get evidence balance
84
+ evidence = client.get_evidence("berberine")
85
+ print(evidence["evidence_balance"]) # {"positive": 8, "null": 2, ...}
86
+ print(evidence["citations"]) # [{"pmid": "12345", ...}]
87
+ ```
88
+
89
+ ### LangChain
90
+
91
+ ```python
92
+ from truthstack import get_langchain_tools
93
+ from langchain_openai import ChatOpenAI
94
+ from langchain.agents import AgentExecutor, create_openai_tools_agent
95
+
96
+ tools = get_langchain_tools(api_key="your-key")
97
+ llm = ChatOpenAI(model="gpt-4")
98
+ agent = create_openai_tools_agent(llm, tools, prompt)
99
+ executor = AgentExecutor(agent=agent, tools=tools)
100
+
101
+ result = executor.invoke({"input": "Can I take berberine while on Ozempic?"})
102
+ ```
103
+
104
+ ### LlamaIndex
105
+
106
+ ```python
107
+ from truthstack import get_llamaindex_tools
108
+ from llama_index.core.agent import ReActAgent
109
+ from llama_index.llms.openai import OpenAI
110
+
111
+ tools = get_llamaindex_tools(api_key="your-key")
112
+ agent = ReActAgent.from_tools(tools, llm=OpenAI(model="gpt-4"))
113
+
114
+ response = agent.chat("What's the evidence for CoQ10?")
115
+ ```
116
+
117
+ ### CrewAI
118
+
119
+ ```python
120
+ from truthstack import get_crewai_tools
121
+ from crewai import Agent, Task, Crew
122
+
123
+ tools = get_crewai_tools(api_key="your-key")
124
+
125
+ analyst = Agent(
126
+ role="Supplement Safety Analyst",
127
+ goal="Check supplement interactions and evidence",
128
+ tools=tools,
129
+ )
130
+ ```
131
+
132
+ ### OpenAI Function Calling
133
+
134
+ ```python
135
+ from truthstack import get_openai_functions, handle_openai_function_call
136
+ from openai import OpenAI
137
+
138
+ client = OpenAI()
139
+ functions = get_openai_functions()
140
+
141
+ response = client.chat.completions.create(
142
+ model="gpt-4",
143
+ messages=[{"role": "user", "content": "Is magnesium safe with sertraline?"}],
144
+ functions=functions,
145
+ function_call="auto",
146
+ )
147
+
148
+ call = response.choices[0].message.function_call
149
+ result = handle_openai_function_call(
150
+ call.name, json.loads(call.arguments), api_key="your-key"
151
+ )
152
+ ```
153
+
154
+ ## System Prompts
155
+
156
+ ```python
157
+ from truthstack import SYSTEM_PROMPTS
158
+
159
+ SYSTEM_PROMPTS["supplement_safety_advisor"] # General safety
160
+ SYSTEM_PROMPTS["glp1_supplement_checker"] # GLP-1/Ozempic focus
161
+ SYSTEM_PROMPTS["evidence_researcher"] # Research analysis
162
+ SYSTEM_PROMPTS["stack_optimizer"] # Stack optimization
163
+ SYSTEM_PROMPTS["clinician_assistant"] # Clinician-facing
164
+ ```
165
+
166
+ ## Tools
167
+
168
+ | Tool | Description |
169
+ |------|-------------|
170
+ | `truthstack_check_interactions` | Check supplement + drug interactions |
171
+ | `truthstack_get_evidence` | Evidence balance + citations |
172
+ | `truthstack_search_supplements` | Fuzzy compound search |
173
+ | `truthstack_safety_signals` | FDA CAERS/FAERS signals |
174
+ | `truthstack_drug_profile` | Drug CYP450 + botanical interactions |
175
+
176
+ ## Environment Variables
177
+
178
+ ```bash
179
+ TRUTHSTACK_API_KEY=your-key
180
+ TRUTHSTACK_BASE_URL=https://api.truthstack.co # optional
181
+ ```
182
+
183
+ ## API Key
184
+
185
+ Get a free key (2,000 calls/month) at [truthstack.co/developers](https://truthstack.co/developers).
186
+
187
+ ## License
188
+
189
+ MIT
@@ -0,0 +1,8 @@
1
+ README.md
2
+ setup.py
3
+ truthstack/__init__.py
4
+ truthstack.egg-info/PKG-INFO
5
+ truthstack.egg-info/SOURCES.txt
6
+ truthstack.egg-info/dependency_links.txt
7
+ truthstack.egg-info/requires.txt
8
+ truthstack.egg-info/top_level.txt
@@ -0,0 +1,16 @@
1
+
2
+ [all]
3
+ langchain-core>=0.1.0
4
+ pydantic>=2.0
5
+ llama-index-core>=0.10.0
6
+ crewai>=0.1.0
7
+
8
+ [crewai]
9
+ crewai>=0.1.0
10
+
11
+ [langchain]
12
+ langchain-core>=0.1.0
13
+ pydantic>=2.0
14
+
15
+ [llamaindex]
16
+ llama-index-core>=0.10.0
@@ -0,0 +1 @@
1
+ truthstack